1# -*-Makefile-*-
2# This Makefile fragment tries to be general-purpose enough to be
3# used by many projects via the gnulib maintainer-makefile module.
4
5## Copyright (C) 2001-2009 Free Software Foundation, Inc.
6##
7## This program is free software: you can redistribute it and/or modify
8## it under the terms of the GNU General Public License as published by
9## the Free Software Foundation, either version 3 of the License, or
10## (at your option) any later version.
11##
12## This program is distributed in the hope that it will be useful,
13## but WITHOUT ANY WARRANTY; without even the implied warranty of
14## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15## GNU General Public License for more details.
16##
17## You should have received a copy of the GNU General Public License
18## along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20# This is reported not to work with make-3.79.1
21# ME := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
22ME := maint.mk
23
24# Override this in cfg.mk if you use a non-standard build-aux directory.
25build_aux ?= $(srcdir)/build-aux
26
27# Do not save the original name or timestamp in the .tar.gz file.
28# Use --rsyncable if available.
29gzip_rsyncable := \
30  $(shell gzip --help 2>/dev/null|grep rsyncable >/dev/null && echo --rsyncable)
31GZIP_ENV = '--no-name --best $(gzip_rsyncable)'
32
33# cfg.mk must define the gpg_key_ID used by this package.
34GIT = git
35VC = $(GIT)
36VC-tag = git tag -s -m '$(VERSION)' -u '$(gpg_key_ID)'
37
38VC_LIST = $(build_aux)/vc-list-files -C $(srcdir)
39
40VC_LIST_EXCEPT = \
41  $(VC_LIST) | if test -f $(srcdir)/.x-$@; then grep -vEf $(srcdir)/.x-$@; \
42	       else grep -Ev "$${VC_LIST_EXCEPT_DEFAULT-ChangeLog}"; fi
43
44ifeq ($(origin prev_version_file), undefined)
45  prev_version_file = $(srcdir)/.prev-version
46endif
47
48PREV_VERSION := $(shell cat $(prev_version_file) 2>/dev/null)
49VERSION_REGEXP = $(subst .,\.,$(VERSION))
50PREV_VERSION_REGEXP = $(subst .,\.,$(PREV_VERSION))
51
52ifeq ($(VC),$(GIT))
53this-vc-tag = v$(VERSION)
54this-vc-tag-regexp = v$(VERSION_REGEXP)
55else
56tag-package = $(shell echo "$(PACKAGE)" | tr '[:lower:]' '[:upper:]')
57tag-this-version = $(subst .,_,$(VERSION))
58this-vc-tag = $(tag-package)-$(tag-this-version)
59this-vc-tag-regexp = $(this-vc-tag)
60endif
61my_distdir = $(PACKAGE)-$(VERSION)
62
63# Old releases are stored here.
64release_archive_dir ?= ../release
65
66# Prevent programs like 'sort' from considering distinct strings to be equal.
67# Doing it here saves us from having to set LC_ALL elsewhere in this file.
68export LC_ALL = C
69
70## --------------- ##
71## Sanity checks.  ##
72## --------------- ##
73
74_cfg_mk := $(shell test -f $(srcdir)/cfg.mk && echo '$(srcdir)/cfg.mk')
75
76# Collect the names of rules starting with `sc_'.
77syntax-check-rules := $(sort $(shell sed -n 's/^\(sc_[a-zA-Z0-9_-]*\):.*/\1/p' \
78			$(srcdir)/$(ME) $(_cfg_mk)))
79.PHONY: $(syntax-check-rules)
80
81local-checks-available = \
82  $(syntax-check-rules)
83.PHONY: $(local-checks-available)
84
85# Arrange to print the name of each syntax-checking rule just before running it.
86$(syntax-check-rules): %: %.m
87$(patsubst %, %.m, $(syntax-check-rules)):
88	@echo $(patsubst sc_%.m, %, $@)
89
90local-check := $(filter-out $(local-checks-to-skip), $(local-checks-available))
91
92syntax-check: $(local-check)
93#	@grep -nE '#  *include <(limits|std(def|arg|bool))\.h>'		\
94#	    $$(find -type f -name '*.[chly]') &&			\
95#	  { echo '$(ME): found conditional include' 1>&2;		\
96#	    exit 1; } || :
97
98#	grep -nE '^#  *include <(string|stdlib)\.h>'			\
99#	    $(srcdir)/{lib,src}/*.[chy] &&				\
100#	  { echo '$(ME): FIXME' 1>&2;					\
101#	    exit 1; } || :
102# FIXME: don't allow `#include .strings\.h' anywhere
103
104# By default, _prohibit_regexp does not ignore case.
105export ignore_case =
106_ignore_case = $$(test -n "$$ignore_case" && echo -i || :)
107
108# There are many rules below that prohibit constructs in this package.
109# If the offending construct can be matched with a grep-E-style regexp,
110# use this macro.  The shell variables "re" and "msg" must be defined.
111define _prohibit_regexp
112  dummy=; : so we do not need a semicolon before each use;		\
113  test "x$$re" != x || { echo '$(ME): re not defined' 1>&2; exit 1; };	\
114  test "x$$msg" != x || { echo '$(ME): msg not defined' 1>&2; exit 1; };\
115  grep $(_ignore_case) -nE "$$re" $$($(VC_LIST_EXCEPT)) &&		\
116    { echo '$(ME): '"$$msg" 1>&2; exit 1; } || :
117endef
118
119sc_avoid_if_before_free:
120	@$(build_aux)/useless-if-before-free				\
121		$(useless_free_options)					\
122	    $$($(VC_LIST_EXCEPT) | grep -v useless-if-before-free) &&	\
123	  { echo '$(ME): found useless "if" before "free" above' 1>&2;	\
124	    exit 1; } || :
125
126sc_cast_of_argument_to_free:
127	@re='\<free *\( *\(' msg='don'\''t cast free argument'		\
128	  $(_prohibit_regexp)
129
130sc_cast_of_x_alloc_return_value:
131	@re='\*\) *x(m|c|re)alloc\>'					\
132	msg='don'\''t cast x*alloc return value'			\
133	  $(_prohibit_regexp)
134
135sc_cast_of_alloca_return_value:
136	@re='\*\) *alloca\>' msg='don'\''t cast alloca return value'	\
137	  $(_prohibit_regexp)
138
139sc_space_tab:
140	@re='[ ]	' msg='found SPACE-TAB sequence; remove the SPACE' \
141	  $(_prohibit_regexp)
142
143# Don't use *scanf or the old ato* functions in `real' code.
144# They provide no error checking mechanism.
145# Instead, use strto* functions.
146sc_prohibit_atoi_atof:
147	@re='\<([fs]?scanf|ato([filq]|ll)) *\('				\
148	msg='do not use *scan''f, ato''f, ato''i, ato''l, ato''ll or ato''q' \
149	  $(_prohibit_regexp)
150
151# Use STREQ rather than comparing strcmp == 0, or != 0.
152sc_prohibit_strcmp:
153	@grep -nE '! *str''cmp *\(|\<str''cmp *\([^)]+\) *=='		\
154	    $$($(VC_LIST_EXCEPT))					\
155	  | grep -vE ':# *define STREQ\(' &&				\
156	  { echo '$(ME): use STREQ in place of the above uses of str''cmp' \
157		1>&2; exit 1; } || :
158
159# Using EXIT_SUCCESS as the first argument to error is misleading,
160# since when that parameter is 0, error does not exit.  Use `0' instead.
161sc_error_exit_success:
162	@grep -nE 'error \(EXIT_SUCCESS,'				\
163	    $$($(VC_LIST_EXCEPT) | grep -E '\.[chly]$$') &&		\
164	  { echo '$(ME): found error (EXIT_SUCCESS' 1>&2; exit 1; } || :
165
166# `FATAL:' should be fully upper-cased in error messages
167# `WARNING:' should be fully upper-cased, or fully lower-cased
168sc_error_message_warn_fatal:
169	@grep -nEA2 '[^rp]error \(' $$($(VC_LIST_EXCEPT))		\
170	    | grep -E '"Warning|"Fatal|"fatal' &&			\
171	  { echo '$(ME): use FATAL, WARNING or warning'	1>&2;		\
172	    exit 1; } || :
173
174# Error messages should not start with a capital letter
175sc_error_message_uppercase:
176	@grep -nEA2 '[^rp]error \(' $$($(VC_LIST_EXCEPT))		\
177	    | grep -E '"[A-Z]'						\
178	    | grep -vE '"FATAL|"WARNING|"Java|"C#|PRIuMAX' &&		\
179	  { echo '$(ME): found capitalized error message' 1>&2;		\
180	    exit 1; } || :
181
182# Error messages should not end with a period
183sc_error_message_period:
184	@grep -nEA2 '[^rp]error \(' $$($(VC_LIST_EXCEPT))		\
185	    | grep -E '[^."]\."' &&					\
186	  { echo '$(ME): found error message ending in period' 1>&2;	\
187	    exit 1; } || :
188
189sc_file_system:
190	@re=file''system ignore_case=1					\
191	msg='found use of "file''system"; spell it "file system"'	\
192	  $(_prohibit_regexp)
193
194# Don't use cpp tests of this symbol.  All code assumes config.h is included.
195sc_prohibit_have_config_h:
196	@grep -n '^# *if.*HAVE''_CONFIG_H' $$($(VC_LIST_EXCEPT)) &&	\
197	  { echo '$(ME): found use of HAVE''_CONFIG_H; remove'		\
198		1>&2; exit 1; } || :
199
200# Nearly all .c files must include <config.h>.  However, we also permit this
201# via inclusion of a package-specific header, if cfg.mk specified one.
202# config_h_header must be suitable for grep -E.
203config_h_header ?= <config\.h>
204sc_require_config_h:
205	@if $(VC_LIST_EXCEPT) | grep -l '\.c$$' > /dev/null; then	\
206	  grep -EL '^# *include $(config_h_header)'			\
207		$$($(VC_LIST_EXCEPT) | grep '\.c$$')			\
208	      | grep . &&						\
209	  { echo '$(ME): the above files do not include <config.h>'	\
210		1>&2; exit 1; } || :;					\
211	else :;								\
212	fi
213
214# You must include <config.h> before including any other header file.
215# This can possibly be via a package-specific header, if given by cfg.mk.
216sc_require_config_h_first:
217	@if $(VC_LIST_EXCEPT) | grep -l '\.c$$' > /dev/null; then	\
218	  fail=0;							\
219	  for i in $$($(VC_LIST_EXCEPT) | grep '\.c$$'); do		\
220	    grep '^# *include\>' $$i | sed 1q				\
221		| grep -E '^# *include $(config_h_header)' > /dev/null	\
222	      || { echo $$i; fail=1; };					\
223	  done;								\
224	  test $$fail = 1 &&						\
225	    { echo '$(ME): the above files include some other header'	\
226		'before <config.h>' 1>&2; exit 1; } || :;		\
227	else :;								\
228	fi
229
230sc_prohibit_HAVE_MBRTOWC:
231	@re='\bHAVE_MBRTOWC\b' msg="do not use $$re; it is always defined" \
232	  $(_prohibit_regexp)
233
234# To use this "command" macro, you must first define two shell variables:
235# h: the header, enclosed in <> or ""
236# re: a regular expression that matches IFF something provided by $h is used.
237define _header_without_use
238  dummy=; : so we do not need a semicolon before each use;		\
239  h_esc=`echo "$$h"|sed 's/\./\\\\./g'`;				\
240  if $(VC_LIST_EXCEPT) | grep -l '\.c$$' > /dev/null; then		\
241    files=$$(grep -l '^# *include '"$$h_esc"				\
242	     $$($(VC_LIST_EXCEPT) | grep '\.c$$')) &&			\
243    grep -LE "$$re" $$files | grep . &&					\
244      { echo "$(ME): the above files include $$h but don't use it"	\
245	1>&2; exit 1; } || :;						\
246  else :;								\
247  fi
248endef
249
250# Prohibit the inclusion of assert.h without an actual use of assert.
251sc_prohibit_assert_without_use:
252	@h='<assert.h>' re='\<assert *\(' $(_header_without_use)
253
254# Prohibit the inclusion of getopt.h without an actual use.
255sc_prohibit_getopt_without_use:
256	@h='<getopt.h>' re='\<getopt(_long)? *\(' $(_header_without_use)
257
258# Don't include quotearg.h unless you use one of its functions.
259sc_prohibit_quotearg_without_use:
260	@h='"quotearg.h"' re='\<quotearg(_[^ ]+)? *\(' $(_header_without_use)
261
262# Don't include quote.h unless you use one of its functions.
263sc_prohibit_quote_without_use:
264	@h='"quote.h"' re='\<quote(_n)? *\(' $(_header_without_use)
265
266# Don't include this header unless you use one of its functions.
267sc_prohibit_long_options_without_use:
268	@h='"long-options.h"' re='\<parse_long_options *\(' \
269	  $(_header_without_use)
270
271# Don't include this header unless you use one of its functions.
272sc_prohibit_inttostr_without_use:
273	@h='"inttostr.h"' re='\<(off|[iu]max|uint)tostr *\(' \
274	  $(_header_without_use)
275
276# Don't include this header unless you use one of its functions.
277sc_prohibit_error_without_use:
278	@h='"error.h"' \
279	re='\<error(_at_line|_print_progname|_one_per_line|_message_count)? *\('\
280	  $(_header_without_use)
281
282sc_prohibit_safe_read_without_use:
283	@h='"safe-read.h"' re='(\<SAFE_READ_ERROR\>|\<safe_read *\()' \
284	  $(_header_without_use)
285
286sc_prohibit_argmatch_without_use:
287	@h='"argmatch.h"' \
288	re='(\<(ARRAY_CARDINALITY|X?ARGMATCH(|_TO_ARGUMENT|_VERIFY))\>|\<argmatch(_exit_fn|_(in)?valid) *\()' \
289	  $(_header_without_use)
290
291sc_prohibit_root_dev_ino_without_use:
292	@h='"root-dev-ino.h"' \
293	re='(\<ROOT_DEV_INO_(CHECK|WARN)\>|\<get_root_dev_ino *\()' \
294	  $(_header_without_use)
295
296# Prohibit the inclusion of c-ctype.h without an actual use.
297ctype_re = isalnum|isalpha|isascii|isblank|iscntrl|isdigit|isgraph|islower\
298|isprint|ispunct|isspace|isupper|isxdigit|tolower|toupper
299sc_prohibit_c_ctype_without_use:
300	@h='[<"]c-ctype.h[">]' re='\<c_($(ctype_re)) *\(' $(_header_without_use)
301
302_empty =
303_sp = $(_empty) $(_empty)
304# The following list was generated by running:
305# man signal.h|col -b|perl -ne '/bsd_signal.*;/.../sigwaitinfo.*;/ and print' \
306#   | perl -lne '/^\s+(?:int|void).*?(\w+).*/ and print $1' | fmt
307_sig_functions = \
308  bsd_signal kill killpg pthread_kill pthread_sigmask raise sigaction \
309  sigaddset sigaltstack sigdelset sigemptyset sigfillset sighold sigignore \
310  siginterrupt sigismember signal sigpause sigpending sigprocmask sigqueue \
311  sigrelse sigset sigsuspend sigtimedwait sigwait sigwaitinfo
312_sig_function_re = $(subst $(_sp),|,$(strip $(_sig_functions)))
313# The following were extracted from "man signal.h" manually.
314_sig_types_and_consts =							\
315  MINSIGSTKSZ SA_NOCLDSTOP SA_NOCLDWAIT SA_NODEFER SA_ONSTACK		\
316  SA_RESETHAND SA_RESTART SA_SIGINFO SIGEV_NONE SIGEV_SIGNAL		\
317  SIGEV_THREAD SIGSTKSZ SIG_BLOCK SIG_SETMASK SIG_UNBLOCK SS_DISABLE	\
318  SS_ONSTACK mcontext_t pid_t sig_atomic_t sigevent siginfo_t sigset_t	\
319  sigstack sigval stack_t ucontext_t
320# generated via this:
321# perl -lne '/^#ifdef (SIG\w+)/ and print $1' lib/sig2str.c|sort -u|fmt -70
322_sig_names =								\
323  SIGABRT SIGALRM SIGALRM1 SIGBUS SIGCANCEL SIGCHLD SIGCLD SIGCONT	\
324  SIGDANGER SIGDIL SIGEMT SIGFPE SIGFREEZE SIGGRANT SIGHUP SIGILL	\
325  SIGINFO SIGINT SIGIO SIGIOT SIGKAP SIGKILL SIGKILLTHR SIGLOST SIGLWP	\
326  SIGMIGRATE SIGMSG SIGPHONE SIGPIPE SIGPOLL SIGPRE SIGPROF SIGPWR	\
327  SIGQUIT SIGRETRACT SIGSAK SIGSEGV SIGSOUND SIGSTKFLT SIGSTOP SIGSYS	\
328  SIGTERM SIGTHAW SIGTRAP SIGTSTP SIGTTIN SIGTTOU SIGURG SIGUSR1	\
329  SIGUSR2 SIGVIRT SIGVTALRM SIGWAITING SIGWINCH SIGWIND SIGWINDOW	\
330  SIGXCPU SIGXFSZ
331_sig_syms_re = $(subst $(_sp),|,$(strip $(_sig_names) $(_sig_types_and_consts)))
332
333# Prohibit the inclusion of signal.h without an actual use.
334sc_prohibit_signal_without_use:
335	@h='<signal.h>'							\
336	re='\<($(_sig_function_re)) *\(|\<($(_sig_syms_re))\>'		\
337	  $(_header_without_use)
338
339sc_obsolete_symbols:
340	@re='\<(HAVE''_FCNTL_H|O''_NDELAY)\>'				\
341	msg='do not use HAVE''_FCNTL_H or O'_NDELAY			\
342	  $(_prohibit_regexp)
343
344# FIXME: warn about definitions of EXIT_FAILURE, EXIT_SUCCESS, STREQ
345
346# Each nonempty ChangeLog line must start with a year number, or a TAB.
347sc_changelog:
348	@if $(VC_LIST_EXCEPT) | grep -l '^ChangeLog$$' >/dev/null; then	\
349	  grep -n '^[^12	]'					\
350	    $$($(VC_LIST_EXCEPT) | grep '^ChangeLog$$') &&		\
351	  { echo '$(ME): found unexpected prefix in a ChangeLog' 1>&2;	\
352	    exit 1; } || :;						\
353	fi
354
355# Ensure that each .c file containing a "main" function also
356# calls set_program_name.
357sc_program_name:
358	@if $(VC_LIST_EXCEPT) | grep -l '\.c$$' > /dev/null; then	\
359	  files=$$(grep -l '^main *(' $$($(VC_LIST_EXCEPT) | grep '\.c$$')); \
360	  grep -LE 'set_program_name *\(m?argv\[0\]\);' $$files		\
361	      | grep . &&						\
362	  { echo '$(ME): the above files do not call set_program_name'	\
363		1>&2; exit 1; } || :;					\
364	else :;								\
365	fi
366
367# Require that the final line of each test-lib.sh-using test be this one:
368# Exit $fail
369# Note: this test requires GNU grep's --label= option.
370Exit_witness_file ?= tests/test-lib.sh
371Exit_base := $(notdir $(Exit_witness_file))
372sc_require_test_exit_idiom:
373	@if test -f $(srcdir)/$(Exit_witness_file); then		\
374	  die=0;							\
375	  for i in $$(grep -l -F 'srcdir/$(Exit_base)'			\
376		$$($(VC_LIST) tests)); do				\
377	    tail -n1 $$i | grep '^Exit .' > /dev/null			\
378	      && : || { die=1; echo $$i; }				\
379	  done;								\
380	  test $$die = 1 &&						\
381	    { echo 1>&2 '$(ME): the final line in each of the above is not:'; \
382	      echo 1>&2 'Exit something';				\
383	      exit 1; } || :;						\
384	fi
385
386sc_the_the:
387	@re='\<the ''the\>'						\
388	ignore_case=1 msg='found use of "the ''the";'			\
389	  $(_prohibit_regexp)
390
391sc_trailing_blank:
392	@re='[	 ]$$'							\
393	msg='found trailing blank(s)'					\
394	  $(_prohibit_regexp)
395
396# Match lines like the following, but where there is only one space
397# between the options and the description:
398#   -D, --all-repeated[=delimit-method]  print all duplicate lines\n
399longopt_re = --[a-z][0-9A-Za-z-]*(\[?=[0-9A-Za-z-]*\]?)?
400sc_two_space_separator_in_usage:
401	@grep -nE '^   *(-[A-Za-z],)? $(longopt_re) [^ ].*\\$$'		\
402	    $$($(VC_LIST_EXCEPT)) &&					\
403	  { echo "$(ME): help2man requires at least two spaces between"; \
404	    echo "$(ME): an option and its description";		\
405		1>&2; exit 1; } || :
406
407# Look for diagnostics that aren't marked for translation.
408# This won't find any for which error's format string is on a separate line.
409sc_unmarked_diagnostics:
410	@grep -nE							\
411	    '\<error \([^"]*"[^"]*[a-z]{3}' $$($(VC_LIST_EXCEPT))	\
412	  | grep -v '_''(' &&						\
413	  { echo '$(ME): found unmarked diagnostic(s)' 1>&2;		\
414	    exit 1; } || :
415
416# Avoid useless parentheses like those in this example:
417# #if defined (SYMBOL) || defined (SYM2)
418sc_useless_cpp_parens:
419	@grep -n '^# *if .*defined *(' $$($(VC_LIST_EXCEPT)) &&		\
420	  { echo '$(ME): found useless parentheses in cpp directive'	\
421		1>&2; exit 1; } || :
422
423# Require the latest GPL.
424sc_GPL_version:
425	@re='either ''version [^3]' msg='GPL vN, N!=3'			\
426	  $(_prohibit_regexp)
427
428cvs_keywords = \
429  Author|Date|Header|Id|Name|Locker|Log|RCSfile|Revision|Source|State
430
431sc_prohibit_cvs_keyword:
432	@re='\$$($(cvs_keywords))\$$'					\
433	    msg='do not use CVS keyword expansion'			\
434	  $(_prohibit_regexp)
435
436# Make sure we don't use st_blocks.  Use ST_NBLOCKS instead.
437# This is a bit of a kludge, since it prevents use of the string
438# even in comments, but for now it does the job with no false positives.
439sc_prohibit_stat_st_blocks:
440	@re='[.>]st_blocks' msg='do not use st_blocks; use ST_NBLOCKS'	\
441	  $(_prohibit_regexp)
442
443# Make sure we don't define any S_IS* macros in src/*.c files.
444# They're already defined via gnulib's sys/stat.h replacement.
445sc_prohibit_S_IS_definition:
446	@re='^ *# *define  *S_IS'					\
447	msg='do not define S_IS* macros; include <sys/stat.h>'		\
448	  $(_prohibit_regexp)
449
450# Each program that uses proper_name_utf8 must link with
451# one of the ICONV libraries.
452sc_proper_name_utf8_requires_ICONV:
453	@progs=$$(grep -l 'proper_name_utf8 ''("' $$($(VC_LIST_EXCEPT)));\
454	if test "x$$progs" != x; then					\
455	  fail=0;							\
456	  for p in $$progs; do						\
457	    dir=$$(dirname "$$p");					\
458	    base=$$(basename "$$p" .c);					\
459	    grep "$${base}_LDADD.*ICONV)" $$dir/Makefile.am > /dev/null	\
460	      || { fail=1; echo 1>&2 "$(ME): $$p uses proper_name_utf8"; }; \
461	  done;								\
462	  test $$fail = 1 &&						\
463	    { echo 1>&2 '$(ME): the above do not link with any ICONV library'; \
464	      exit 1; } || :;						\
465	fi
466
467# Warn about "c0nst struct Foo const foo[]",
468# but not about "char const *const foo" or "#define const const".
469sc_redundant_const:
470	@re='\bconst\b[[:space:][:alnum:]]{2,}\bconst\b'		\
471	msg='redundant "const" in declarations'				\
472	  $(_prohibit_regexp)
473
474sc_const_long_option:
475	@grep '^ *static.*struct option ' $$($(VC_LIST_EXCEPT))		\
476	  | grep -Ev 'const struct option|struct option const' && {	\
477	      echo 1>&2 '$(ME): add "const" to the above declarations'; \
478	      exit 1; } || :
479
480NEWS_hash =								\
481  $$(sed -n '/^\*.* $(PREV_VERSION_REGEXP) ([0-9-]*)/,$$p'		\
482       $(srcdir)/NEWS							\
483     | grep -v '^Copyright .*Free Software'				\
484     | md5sum -								\
485     | sed 's/ .*//')
486
487# Ensure that we don't accidentally insert an entry into an old NEWS block.
488sc_immutable_NEWS:
489	@if test -f $(srcdir)/NEWS; then				\
490	  test "$(NEWS_hash)" = '$(old_NEWS_hash)' && : ||		\
491	    { echo '$(ME): you have modified old NEWS' 1>&2; exit 1; };	\
492	fi
493
494# Update the hash stored above.  Do this after each release and
495# for any corrections to old entries.
496update-NEWS-hash: NEWS
497	perl -pi -e 's/^(old_NEWS_hash[ \t]+:?=[ \t]+).*/$${1}'"$(NEWS_hash)/" \
498	  $(srcdir)/cfg.mk
499
500# Ensure that we use only the standard $(VAR) notation,
501# not @...@ in Makefile.am, now that we can rely on automake
502# to emit a definition for each substituted variable.
503# We use perl rather than "grep -nE ..." to exempt a single
504# use of an @...@-delimited variable name in src/Makefile.am.
505sc_makefile_check:
506	@perl -ne '/\@[A-Z_0-9]+\@/ && !/^cu_install_program =/'	\
507	  -e 'and (print "$$ARGV:$$.: $$_"), $$m=1; END {exit !$$m}'	\
508	    $$($(VC_LIST_EXCEPT) | grep -E '(^|/)Makefile\.am$$')	\
509	  && { echo '$(ME): use $$(...), not @...@' 1>&2; exit 1; } || :
510
511news-date-check: NEWS
512	today=`date +%Y-%m-%d`;						\
513	if head $(srcdir)/NEWS | grep '^\*.* $(VERSION_REGEXP) ('$$today')' \
514	    >/dev/null; then						\
515	  :;								\
516	else								\
517	  echo "version or today's date is not in NEWS" 1>&2;		\
518	  exit 1;							\
519	fi
520
521sc_makefile_TAB_only_indentation:
522	@grep -nE '^	[ ]{8}'						\
523	    $$($(VC_LIST_EXCEPT) | grep -E 'akefile|\.mk$$')		\
524	  && { echo '$(ME): found TAB-8-space indentation' 1>&2;	\
525	       exit 1; } || :
526
527sc_m4_quote_check:
528	@grep -nE '(AC_DEFINE(_UNQUOTED)?|AC_DEFUN)\([^[]'		\
529	    $$($(VC_LIST_EXCEPT) | grep -E '(^configure\.ac|\.m4)$$')	\
530	  && { echo '$(ME): quote the first arg to AC_DEF*' 1>&2;	\
531	       exit 1; } || :
532
533fix_po_file_diag = \
534'you have changed the set of files with translatable diagnostics;\n\
535apply the above patch\n'
536
537# Verify that all source files using _() are listed in po/POTFILES.in.
538po_file = po/POTFILES.in
539sc_po_check:
540	@if test -f $(po_file); then					\
541	  grep -E -v '^(#|$$)' $(po_file)				\
542	    | grep -v '^src/false\.c$$' | sort > $@-1;			\
543	  files=;							\
544	  for file in $$($(VC_LIST_EXCEPT)) lib/*.[ch]; do		\
545	    test -r $$file || continue;					\
546	    case $$file in						\
547	      *.m4|*.mk) continue ;;					\
548	      *.?|*.??) ;;						\
549	      *) continue;;						\
550	    esac;							\
551	    case $$file in						\
552	    *.[ch])							\
553	      base=`expr " $$file" : ' \(.*\)\..'`;			\
554	      { test -f $$base.l || test -f $$base.y; } && continue;;	\
555	    esac;							\
556	    files="$$files $$file";					\
557	  done;								\
558	  grep -E -l '\b(N?_|gettext *)\([^)"]*("|$$)' $$files		\
559	    | sort -u > $@-2;						\
560	  diff -u -L $(po_file) -L $(po_file) $@-1 $@-2			\
561	    || { printf '$(ME): '$(fix_po_file_diag) 1>&2; exit 1; };	\
562	  rm -f $@-1 $@-2;						\
563	fi
564
565# Sometimes it is useful to change the PATH environment variable
566# in Makefiles.  When doing so, it's better not to use the Unix-centric
567# path separator of `:', but rather the automake-provided `$(PATH_SEPARATOR)'.
568msg = '$(ME): Do not use `:'\'' above; use $$(PATH_SEPARATOR) instead'
569sc_makefile_path_separator_check:
570	@grep -nE 'PATH[=].*:'						\
571	    $$($(VC_LIST_EXCEPT) | grep -E 'akefile|\.mk$$')		\
572	  && { echo $(msg) 1>&2; exit 1; } || :
573
574# Check that `make alpha' will not fail at the end of the process.
575writable-files:
576	if test -d $(release_archive_dir); then :; else			\
577	  for file in $(distdir).tar.gz					\
578		      $(release_archive_dir)/$(distdir).tar.gz; do	\
579	    test -e $$file || continue;					\
580	    test -w $$file						\
581	      || { echo ERROR: $$file is not writable; fail=1; };	\
582	  done;								\
583	  test "$$fail" && exit 1 || : ;				\
584	fi
585
586v_etc_file = lib/version-etc.c
587sample-test = tests/sample-test
588texi = doc/$(PACKAGE).texi
589# Make sure that the copyright date in $(v_etc_file) is up to date.
590# Do the same for the $(sample-test) and the main doc/.texi file.
591sc_copyright_check:
592	@if test -f $(v_etc_file); then					\
593	  grep 'enum { COPYRIGHT_YEAR = '$$(date +%Y)' };' $(v_etc_file) \
594	    >/dev/null							\
595	  || { echo 'out of date copyright in $(v_etc_file); update it' 1>&2; \
596	       exit 1; };						\
597	fi
598	@if test -f $(sample-test); then				\
599	  grep '# Copyright (C) '$$(date +%Y)' Free' $(sample-test)	\
600	    >/dev/null							\
601	  || { echo 'out of date copyright in $(sample-test); update it' 1>&2; \
602	       exit 1; };						\
603	fi
604	@if test -f $(texi); then					\
605	  grep 'Copyright @copyright{} .*'$$(date +%Y)' Free' $(texi)	\
606	    >/dev/null							\
607	  || { echo 'out of date copyright in $(texi); update it' 1>&2;	\
608	       exit 1; };						\
609	fi
610
611vc-diff-check:
612	(unset CDPATH; cd $(srcdir) && $(VC) diff) > vc-diffs || :
613	if test -s vc-diffs; then				\
614	  cat vc-diffs;						\
615	  echo "Some files are locally modified:" 1>&2;		\
616	  exit 1;						\
617	else							\
618	  rm vc-diffs;						\
619	fi
620
621# Use this to make sure we don't run these programs when building
622# from a virgin tgz file, below.
623null_AM_MAKEFLAGS = \
624  ACLOCAL=false \
625  AUTOCONF=false \
626  AUTOMAKE=false \
627  AUTOHEADER=false \
628  MAKEINFO=false
629
630built_programs = $$(cd src && MAKEFLAGS= $(MAKE) -s built_programs.list)
631
632rel-files = $(DIST_ARCHIVES)
633
634gnulib_dir ?= $(srcdir)/gnulib
635gnulib-version = $$(cd $(gnulib_dir) && git describe)
636bootstrap-tools ?= autoconf,automake,gnulib
637
638announcement: NEWS ChangeLog $(rel-files)
639	@$(build_aux)/announce-gen					\
640	    --release-type=$(RELEASE_TYPE)				\
641	    --package=$(PACKAGE)					\
642	    --prev=$(PREV_VERSION)					\
643	    --curr=$(VERSION)						\
644	    --gpg-key-id=$(gpg_key_ID)					\
645	    --news=NEWS							\
646	    --bootstrap-tools=$(bootstrap-tools)			\
647	    --gnulib-version=$(gnulib-version)				\
648	    --no-print-checksums					\
649	    $(addprefix --url-dir=, $(url_dir_list))
650
651## ---------------- ##
652## Updating files.  ##
653## ---------------- ##
654
655ftp-gnu = ftp://ftp.gnu.org/gnu
656www-gnu = http://www.gnu.org
657
658emit_upload_commands:
659	@echo =====================================
660	@echo =====================================
661	@echo "$(build_aux)/gnupload $(GNUPLOADFLAGS) \\"
662	@echo "    --to $(gnu_rel_host):$(PACKAGE) \\"
663	@echo "  $(rel-files)"
664	@echo '# send the /tmp/announcement e-mail'
665	@echo =====================================
666	@echo =====================================
667
668noteworthy = * Noteworthy changes in release ?.? (????-??-??) [?]
669define emit-commit-log
670  printf '%s\n' 'post-release administrivia' '' \
671    '* NEWS: Add header line for next release.' \
672    '* .prev-version: Record previous version.' \
673    '* cfg.mk (old_NEWS_hash): Auto-update.'
674endef
675
676.PHONY: no-submodule-changes
677no-submodule-changes:
678	if test -d $(srcdir)/.git; then					\
679	  diff=$$(cd $(srcdir) && git submodule -q foreach		\
680		  git diff-index --name-only HEAD)			\
681	    || exit 1;							\
682	  case $$diff in '') ;;						\
683	    *) echo '$(ME): submodule files are locally modified:';	\
684		echo "$$diff"; exit 1;; esac;				\
685	else								\
686	  : ;								\
687	fi
688
689.PHONY: alpha beta major
690ALL_RECURSIVE_TARGETS += alpha beta major
691alpha beta major: $(local-check) writable-files no-submodule-changes
692	test $@ = major						\
693	  && { echo $(VERSION) | grep -E '^[0-9]+(\.[0-9]+)+$$'	\
694	       || { echo "invalid version string: $(VERSION)" 1>&2; exit 1;};}\
695	  || :
696	$(MAKE) vc-diff-check
697	$(MAKE) news-date-check
698	$(MAKE) distcheck
699	$(MAKE) dist XZ_OPT=-9ev
700	$(MAKE) -s announcement RELEASE_TYPE=$@ > /tmp/announce-$(my_distdir)
701	if test -d $(release_archive_dir); then			\
702	  ln $(rel-files) $(release_archive_dir);		\
703	  chmod a-w $(rel-files);				\
704	fi
705	$(MAKE) -s emit_upload_commands RELEASE_TYPE=$@
706	echo $(VERSION) > $(prev_version_file)
707	$(MAKE) update-NEWS-hash
708	perl -pi -e '$$. == 3 and print "$(noteworthy)\n\n\n"' NEWS
709	$(emit-commit-log) > .ci-msg
710	$(VC) commit -F .ci-msg -a
711
712.PHONY: web-manual
713web-manual:
714	@test -z "$(manual_title)" \
715	  && { echo define manual_title in cfg.mk 1>&2; exit 1; } || :
716	@cd '$(srcdir)/doc'; \
717	  $(SHELL) ../build-aux/gendocs.sh -o '$(abs_builddir)/doc/manual' \
718	     --email $(PACKAGE_BUGREPORT) $(PACKAGE) \
719	    "$(PACKAGE_NAME) - $(manual_title)"
720	@echo " *** Upload the doc/manual directory to web-cvs."
721
722# Code Coverage
723
724init-coverage:
725	$(MAKE) $(AM_MAKEFLAGS) clean
726	lcov --directory . --zerocounters
727
728COVERAGE_CCOPTS ?= "-g --coverage"
729COVERAGE_OUT ?= doc/coverage
730
731build-coverage:
732	$(MAKE) $(AM_MAKEFLAGS) CFLAGS=$(COVERAGE_CCOPTS) CXXFLAGS=$(COVERAGE_CCOPTS)
733	$(MAKE) $(AM_MAKEFLAGS) CFLAGS=$(COVERAGE_CCOPTS) CXXFLAGS=$(COVERAGE_CCOPTS) check
734	mkdir -p $(COVERAGE_OUT)
735	lcov --directory . --output-file $(COVERAGE_OUT)/$(PACKAGE).info \
736		--capture
737
738gen-coverage:
739	genhtml --output-directory $(COVERAGE_OUT) \
740		$(COVERAGE_OUT)/$(PACKAGE).info \
741		--highlight --frames --legend \
742		--title "$(PACKAGE_NAME)"
743
744coverage: init-coverage build-coverage gen-coverage
745
746# Update gettext files.
747PACKAGE ?= $(shell basename $(PWD))
748PO_DOMAIN ?= $(PACKAGE)
749POURL = http://translationproject.org/latest/$(PO_DOMAIN)/
750PODIR ?= po
751refresh-po:
752	rm -f $(PODIR)/*.po && \
753	echo "$(ME): getting translations into po (please ignore the robots.txt ERROR 404)..." && \
754	wget --no-verbose --directory-prefix $(PODIR) --no-directories --recursive --level 1 --accept .po --accept .po.1 $(POURL) && \
755	echo 'en@boldquot' > $(PODIR)/LINGUAS && \
756	echo 'en@quot' >> $(PODIR)/LINGUAS && \
757	ls $(PODIR)/*.po | sed 's/\.po//' | sed 's,$(PODIR)/,,' | sort >> $(PODIR)/LINGUAS
758
759INDENT_SOURCES ?= $(C_SOURCES)
760.PHONY: indent
761indent:
762	indent $(INDENT_SOURCES)
763
764# If you want to set UPDATE_COPYRIGHT_* environment variables,
765# put the assignments in this variable.
766update-copyright-env ?=
767
768# Run this rule once per year (usually early in January)
769# to update all FSF copyright year lists in your project.
770# If you have an additional project-specific rule,
771# add it in cfg.mk along with a line 'update-copyright: prereq'.
772# By default, exclude all variants of COPYING; you can also
773# add exemptions (such as ChangeLog..* for rotated change logs)
774# in the file .x-update-copyright.
775.PHONY: update-copyright
776update-copyright:
777	grep -l -w Copyright                                             \
778	  $$(export VC_LIST_EXCEPT_DEFAULT=COPYING && $(VC_LIST_EXCEPT)) \
779	  | $(update-copyright-env) xargs $(build_aux)/$@
780