# Customize maint.mk -*- makefile -*-
# Copyright (C) 2009-2022 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 .
# 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 = 0d8ee2e693cfd7d9eca3def373e20561
# 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='\/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='\' \
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='\' \
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 ?= (|"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