summaryrefslogtreecommitdiff
path: root/cfg.mk
blob: 9d7dce49e97ce21f370d6615c6629497f2ed448b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
# Customize maint.mk                           -*- makefile -*-
# Copyright (C) 2009-2023 Free Software Foundation, Inc.

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

# When running a 'check' target, adjust the $PATH to use the newly built
# sed binary - expanding coverage testing, and enabling sophisticated
# rules in syntax-check.
_is-check-target ?= $(filter-out install%, \
                         $(filter %check check%,$(MAKECMDGOALS)))
ifneq (,$(_is-check-target))
  export PATH := $(srcdir)/sed:${PATH}
endif

# Used in maint.mk's web-manual rule
manual_title = GNU Sed: a stream editor

# Use the direct link.  This is guaranteed to work immediately, while
# it can take a while for the faster mirror links to become usable.
url_dir_list = https://ftp.gnu.org/gnu/$(PACKAGE)

# Tests not to run as part of "make distcheck".
local-checks-to-skip =			\
  sc_GPL_version			\
  sc_bindtextdomain			\
  sc_error_message_uppercase		\
  sc_indent				\
  sc_preprocessor_indentation		\
  sc_prohibit_atoi_atof			\
  sc_prohibit_magic_number_exit		\
  sc_prohibit_strcmp			\
  sc_unmarked_diagnostics		\
  sc_useless_cpp_parens

# Tools used to bootstrap this package, used for "announcement".
bootstrap-tools = autoconf,automake,gnulib

# Override the default Cc: used in generating an announcement.
announcement_Cc_ = $(translation_project_), $(PACKAGE)-devel@gnu.org

# Now that we have better tests, make this the default.
export VERBOSE = yes

# Comparing tarball sizes compressed using different xz presets, we see
# that -6e adds only 60 bytes to the size of the tarball, yet reduces
# (from -9) the decompression memory requirement from 64 MiB to 9 MiB.
# Don't be tempted by -5e, since -6 and -5 use the same dictionary size.
# $ for i in {4,5,6,7,8,9}{e,}; do
#   (n=$(xz -$i < sed-4.2.2.tar |wc -c);echo $n $i) & done |sort -nr
# 900032 4
# 854932 5
# 844572 4e
# 843780 9
# 843780 8
# 843780 7
# 843780 6
# 837892 5e
# 836832 9e
# 836832 8e
# 836832 7e
# 836832 6e
export XZ_OPT = -6e

old_NEWS_hash = 31db53b519338cc4b1527a682e88493f

# Many m4 macros names once began with 'jm_'.
# Make sure that none are inadvertently reintroduced.
sc_prohibit_jm_in_m4:
	@grep -nE 'jm_[A-Z]'						\
		$$($(VC_LIST) m4 |grep '\.m4$$'; echo /dev/null) &&	\
	    { echo '$(ME): do not use jm_ in m4 macro names'		\
	      1>&2; exit 1; } || :

sc_prohibit_echo_minus_en:
	@prohibit='\<echo -[en]'					\
	halt='do not use echo ''-e or echo ''-n; use printf instead'	\
	  $(_sc_search_regexp)

# Look for lines longer than 80 characters, except omit:
# - program-generated long lines in diff headers,
# - the help2man script copied from upstream,
# - tests involving long checksum lines, and
# - the 'pr' test cases.
LINE_LEN_MAX = 80
FILTER_LONG_LINES =						\
  /^[^:]*\.diff:[^:]*:@@ / d;					\
  \|^[^:]*doc/fdl.texi:| d;						\
  \|^[^:]*man/help2man:| d;			\
  \|^[^:]*tests/misc/sha[0-9]*sum.*\.pl[-:]| d;			\
  \|^[^:]*tests/pr/|{ \|^[^:]*tests/pr/pr-tests:| !d; };
sc_long_lines:
	@files=$$($(VC_LIST_EXCEPT))					\
	halt='line(s) with more than $(LINE_LEN_MAX) characters; reindent'; \
	for file in $$files; do						\
	  expand $$file | grep -nE '^.{$(LINE_LEN_MAX)}.' |		\
	  sed -e "s|^|$$file:|" -e '$(FILTER_LONG_LINES)';		\
	done | grep . && { msg="$$halt" $(_sc_say_and_exit) } || :

# Indent only with spaces.
sc_prohibit_tab_based_indentation:
	@prohibit='^ *	'						\
	halt='TAB in indentation; use only spaces'			\
	  $(_sc_search_regexp)

# Don't use "indent-tabs-mode: nil" anymore.  No longer needed.
sc_prohibit_emacs__indent_tabs_mode__setting:
	@prohibit='^( *[*#] *)?indent-tabs-mode:'			\
	halt='use of emacs indent-tabs-mode: setting'			\
	  $(_sc_search_regexp)

# Enforce recommended preprocessor indentation style.
sc_preprocessor_indentation:
	@if cppi --version >/dev/null 2>&1; then			\
	  $(VC_LIST_EXCEPT) | grep '\.[ch]$$' | xargs cppi -a -c	\
	    || { echo '$(ME): incorrect preprocessor indentation' 1>&2;	\
		exit 1; };						\
	else								\
	  echo '$(ME): skipping test $@: cppi not installed' 1>&2;	\
	fi

# THANKS.in is a list of name/email pairs for people who are mentioned in
# commit logs (and generated ChangeLog), but who are not also listed as an
# author of a commit.  Name/email pairs of commit authors are automatically
# extracted from the repository.  As a very minor factorization, when
# someone who was initially listed only in THANKS.in later authors a commit,
# this rule detects that their pair may now be removed from THANKS.in.
sc_THANKS_in_duplicates:
	@{ git log --pretty=format:%aN | sort -u;			\
	    cut -b-36 THANKS.in | sed '/^$$/d;s/  *$$//'; }		\
	  | sort | uniq -d | grep .					\
	    && { echo '$(ME): remove the above names from THANKS.in'	\
		  1>&2; exit 1; } || :

# Ensure the contributor list stays sorted.  However, if the system's
# en_US.utf8 locale data is erroneous, give a diagnostic and skip
# this test.  This affects Ubuntu up to at least 22.04.
sc_THANKS_in_sorted:
	@printf '%s\n' J.T. Jakub | LC_ALL=en_US.utf8 sort -fc 2>/dev/null \
	  && {								\
	    sed '/^$$/,/^$$/!d;/^$$/d' $(srcdir)/THANKS.in > $@.1 &&	\
	    LC_ALL=en_US.UTF-8 sort -f -k1,1 $@.1 > $@.2 &&		\
	    diff -u $@.1 $@.2; diff=$$?;				\
	    rm -f $@.1 $@.2;						\
	    test "$$diff" = 0						\
	      || { echo '$(ME): THANKS.in is unsorted' 1>&2; exit 1; };	\
	    }								\
	  || { echo '$(ME): this system has erroneous locale data;'	\
		    'skipping $@' 1>&2; }

###########################################################
_p0 = \([^"'/]\|"\([^\"]\|[\].\)*"\|'\([^\']\|[\].\)*'
_pre = $(_p0)\|[/][^"'/*]\|[/]"\([^\"]\|[\].\)*"\|[/]'\([^\']\|[\].\)*'\)*
_pre_anchored = ^\($(_pre)\)
_comment_and_close = [^*]\|[*][^/*]\)*[*][*]*/
# help font-lock mode: '

# A sed expression that removes ANSI C and ISO C99 comments.
# Derived from the one in GNU gettext's 'moopp' preprocessor.
_sed_remove_comments =					\
/[/][/*]/{						\
  ta;							\
  :a;							\
  s,$(_pre_anchored)//.*,\1,;				\
  te;							\
  s,$(_pre_anchored)/[*]\($(_comment_and_close),\1 ,;	\
  ta;							\
  /^$(_pre)[/][*]/{					\
    s,$(_pre_anchored)/[*].*,\1 ,;			\
    tu;							\
    :u;							\
    n;							\
    s,^\($(_comment_and_close),,;			\
    tv;							\
    s,^.*$$,,;						\
    bu;							\
    :v;							\
  };							\
  :e;							\
}
# Quote all single quotes.
_sed_rm_comments_q = $(subst ','\'',$(_sed_remove_comments))
# help font-lock mode: '

_space_before_paren_exempt =? \\n\\$$
_space_before_paren_exempt = \
  (^ *\#|\\n\\$$|%s\(to %s|(date|group|character)\(s\))
# Ensure that there is a space before each open parenthesis in C code.
sc_space_before_open_paren:
	@if $(VC_LIST_EXCEPT) | grep -l '\.[ch]$$' > /dev/null; then	\
	  fail=0;							\
	  for c in $$($(VC_LIST_EXCEPT) | grep '\.[ch]$$'); do		\
	    sed '$(_sed_rm_comments_q)' $$c 2>/dev/null			\
	      | grep -i '[[:alnum:]]('					\
	      | grep -vE '$(_space_before_paren_exempt)'		\
	      | grep . && { fail=1; echo "*** $$c"; };			\
	  done;								\
	  test $$fail = 1 &&						\
	    { echo '$(ME): the above files lack a space-before-open-paren' \
		1>&2; exit 1; } || :;					\
	else :;								\
	fi
###########################################################

sc_prohibit-form-feed:
	@prohibit=$$'\f' \
	in_vc_files='\.[chly]$$' \
	halt='Form Feed (^L) detected' \
	  $(_sc_search_regexp)


# Ensure gnulib generated files are ignored
# TODO: Perhaps augment gnulib-tool to do this in lib/.gitignore?
sc_gitignore_missing:
	@{ sed -n '/^\/.*\.h$$/{p;p}' $(srcdir)/lib/.gitignore;	\
	    find lib -name '*.in*' ! -name '*~' ! -name 'sys_*' |	\
	      sed 's|^lib||; s|_\(.*in\.h\)|/\1|; s/\.in//'; } |	\
	      sort | uniq -u | grep . && { echo '$(ME): Add above'	\
		'entries to lib/.gitignore' >&2; exit 1; } || :


# Similar to the gnulib maint.mk rule for sc_prohibit_strcmp
# Use STREQ_LEN or STRPREFIX rather than comparing strncmp == 0, or != 0.
sc_prohibit_strncmp:
	@prohibit='^[^#].*str''ncmp *\('				\
	halt='use STREQ_LEN or STRPREFIX instead of str''ncmp'		\
	  $(_sc_search_regexp)

# Ensure that tests don't include a redundant fail=0.
sc_prohibit_fail_0:
	@prohibit='\<fail=0\>'						\
	halt='fail=0 initialization'					\
	  $(_sc_search_regexp)

# Ensure that tests don't use 'cmd ... && fail=1' as that hides crashes.
# The "exclude" expression allows common idioms like 'test ... && fail=1'
# and the 2>... portion allows commands that redirect stderr and so probably
# independently check its contents and thus detect any crash messages.
sc_prohibit_and_fail_1:
	@prohibit='&& fail=1'						\
	exclude='(returns_|stat|kill|test |EGREP|grep|compare|2> *[^/])' \
	halt='&& fail=1 detected. Please use: returns_ 1 ... || fail=1'	\
	in_vc_files='^tests/'						\
	  $(_sc_search_regexp)

# Ensure that env vars are not passed through returns_ as
# that was seen to fail on FreeBSD /bin/sh at least
sc_prohibit_env_returns:
	@prohibit='=[^ ]* returns_ '					\
	exclude='_ returns_ '						\
	halt='Passing env vars to returns_ is non portable'		\
	in_vc_files='^tests/'						\
	  $(_sc_search_regexp)

sc_prohibit_perl_hash_quotes:
	@prohibit="\{'[A-Z_]+' *[=}]"					\
	halt="in Perl code, write \$$hash{KEY}, not \$$hash{'K''EY'}"	\
	  $(_sc_search_regexp)

# Use print_ver_ (from init.cfg), not open-coded $VERBOSE check.
sc_prohibit_verbose_version:
	@prohibit='test "\$$VERBOSE" = yes && .* --version'		\
	halt='use the print_ver_ function instead...'			\
	  $(_sc_search_regexp)


# Use framework_failure_, not the old name without the trailing underscore.
sc_prohibit_framework_failure:
	@prohibit='\<framework_''failure\>'				\
	halt='use framework_failure_ instead'				\
	  $(_sc_search_regexp)

# Prohibit the use of `...` in tests/.  Use $(...) instead.
sc_prohibit_test_backticks:
	@prohibit='`' in_vc_files='^tests/'				\
	halt='use $$(...), not `...` in tests/'				\
	  $(_sc_search_regexp)

# Ensure that compare is used to check empty files
# so that the unexpected contents are displayed
sc_prohibit_test_empty:
	@prohibit='test -s.*&&' in_vc_files='^tests/'			\
	halt='use "compare /dev/null ...", not "test -s ..." in tests/'	\
	  $(_sc_search_regexp)

# With split lines, don't leave an operator at end of line.
# Instead, put it on the following line, where it is more apparent.
# Don't bother checking for "*" at end of line, since it provokes
# far too many false positives, matching constructs like "TYPE *".
# Similarly, omit "=" (initializers).
binop_re_ ?= [-/+^!<>]|[-/+*^!<>=]=|&&?|\|\|?|<<=?|>>=?
sc_prohibit_operator_at_end_of_line:
	@prohibit='. ($(binop_re_))$$'					\
	in_vc_files='\.[chly]$$'					\
	halt='found operator at end of line'				\
	  $(_sc_search_regexp)

update-copyright-env = \
  UPDATE_COPYRIGHT_USE_INTERVALS=2 \
  UPDATE_COPYRIGHT_MAX_LINE_LENGTH=79

config_h_header ?= (<config\.h>|"sed\.h")

exclude_file_name_regexp--sc_long_lines = ^tests/.*$$
exclude_file_name_regexp--sc_prohibit_doubled_word = \
  ^testsuite/(mac-mf|uniq)\.(good|inp)$$

exclude_file_name_regexp--sc_program_name = ^testsuite/.*\.c$$

exclude_file_name_regexp--sc_space_tab = ^testsuite/.*$$
exclude_file_name_regexp--sc_prohibit_always_true_header_tests = \
  ^configure\.ac$$

tbi_1 = (^testsuite/.*|^gl/lib/reg.*\.c\.diff|\.mk|/help2man)$$
tbi_2 = (GNU)?[Mm]akefile(\.am)?$$
exclude_file_name_regexp--sc_prohibit_tab_based_indentation = \
  $(tbi_1)|$(tbi_2)

exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \
  ^testsuite/(bkslashes.good|(noeolw?|empty|zero-anchor)\.(2?good|inp))$$

# Exempt test-related files from our 80-column limitation, for now.
exclude_file_name_regexp--sc_long_lines = (^testsuite/|/help2man$$)

# Exempt test-related files from space-before-parens requirements.
exclude_file_name_regexp--sc_space_before_open_paren = ^testsuite/

# Exempt makefiles from 'fail=0' detection (it is only relevant to shell
# script tests).
exclude_file_name_regexp--sc_prohibit_fail_0 = cfg\.mk


# static analysis
STAN_CFLAGS ?= "-g -O0"

.PHONY: static-analysis-init
static-analysis-init:
	type scan-build 1>/dev/null 2>&1 || \
	    { echo "scan-build program not found" >&2; exit 1; }
	$(MAKE) clean

.PHONY: static-analysis-config
static-analysis-config:
	test -x ./configure || \
	    { echo "./configure script not found" >&2; exit 1; }
	scan-build ./configure CFLAGS=$(STAN_CFLAGS)

.PHONY: static-analysis-make
static-analysis-make:
	scan-build $(MAKE)

.PHONY: static-analysis
static-analysis: static-analysis-init static-analysis-config \
                 static-analysis-make

ASAN_FLAGS=-fsanitize=address -fno-omit-frame-pointer
ASAN_CFLAGS=-O0 -g -Dlint $(ASAN_FLAGS)
ASAN_LDFLAGS=$(ASAN_FLAGS)

.PHONY: build-asan
build-asan:
	test -x ./configure || \
	    { echo "./configure script not found" >&2; exit 1; }
	./configure CFLAGS="$(ASAN_CFLAGS)" LDFLAGS="$(ASAN_LDFLAGS)"
	make

# NOTE: These options require a recent gcc (tested with gcc 8.2)
UBSAN_FLAGS=-fsanitize=undefined \
	-fsanitize=signed-integer-overflow \
	-fsanitize=bounds-strict \
	-fsanitize=shift \
	-fsanitize=shift-exponent \
	-fsanitize=shift-base \
	-fsanitize=integer-divide-by-zero \
	-fsanitize=null \
	-fsanitize=return \
	-fsanitize=alignment \
	-fsanitize=object-size \
	-fsanitize=nonnull-attribute \
	-fsanitize=returns-nonnull-attribute \
	-fsanitize=bool \
	-fsanitize=enum \
	-fsanitize=pointer-overflow \
	-fsanitize=builtin
UBSAN_CFLAGS=-O0 -g -Dlint $(UBSAN_FLAGS)
UBSAN_LDFLAGS=$(UBSAN_FLAGS)

.PHONY: build-ubsan
build-ubsan:
	test -x ./configure || \
	    { echo "./configure script not found" >&2; exit 1; }
	./configure CFLAGS="$(UBSAN_CFLAGS)" LDFLAGS="$(UBSAN_LDFLAGS)"
	make