From d9825f3c747000fe39ed79aa8e41566bdf30fcd9 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 1 Feb 2012 14:46:53 +0000 Subject: Import GNULIB rules for syntax checking code --- GNUmakefile | 132 ++++ Makefile.am | 6 + autobuild.sh | 12 + build-aux/useless-if-before-free | 207 ++++++ build-aux/vc-list-files | 113 +++ cfg.mk | 131 ++++ configure.ac | 11 + maint.mk | 1511 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 2123 insertions(+) create mode 100644 GNUmakefile create mode 100755 build-aux/useless-if-before-free create mode 100755 build-aux/vc-list-files create mode 100644 cfg.mk create mode 100644 maint.mk diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..ca88b6b --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,132 @@ +# Having a separate GNUmakefile lets me `include' the dynamically +# generated rules created via cfg.mk (package-local configuration) +# as well as maint.mk (generic maintainer rules). +# This makefile is used only if you run GNU Make. +# It is necessary if you want to build targets usually of interest +# only to the maintainer. + +# Copyright (C) 2001, 2003, 2006-2011 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 . + +# Systems where /bin/sh is not the default shell need this. The $(shell) +# command below won't work with e.g. stock DOS/Windows shells. +ifeq ($(wildcard /bin/s[h]),/bin/sh) +SHELL = /bin/sh +else +# will be used only with the next shell-test line, then overwritten +# by a configured-in value +SHELL = sh +endif + +# If the user runs GNU make but has not yet run ./configure, +# give them a diagnostic. +_have-Makefile := $(shell test -f Makefile && echo yes) +ifeq ($(_have-Makefile),yes) + +# Make tar archive easier to reproduce. +export TAR_OPTIONS = --owner=0 --group=0 --numeric-owner + +# Allow the user to add to this in the Makefile. +ALL_RECURSIVE_TARGETS = + +include Makefile + +# Some projects override e.g., _autoreconf here. +-include $(srcdir)/cfg.mk + +# Allow cfg.mk to override these. +_build-aux ?= build-aux +_autoreconf ?= autoreconf -v + +include $(srcdir)/maint.mk + +# Ensure that $(VERSION) is up to date for dist-related targets, but not +# for others: rerunning autoreconf and recompiling everything isn't cheap. +_have-git-version-gen := \ + $(shell test -f $(srcdir)/$(_build-aux)/git-version-gen && echo yes) +ifeq ($(_have-git-version-gen)0,yes$(MAKELEVEL)) + _is-dist-target ?= $(filter-out %clean, \ + $(filter maintainer-% dist% alpha beta stable,$(MAKECMDGOALS))) + _is-install-target ?= $(filter-out %check, $(filter install%,$(MAKECMDGOALS))) + ifneq (,$(_is-dist-target)$(_is-install-target)) + _curr-ver := $(shell cd $(srcdir) \ + && $(_build-aux)/git-version-gen \ + .tarball-version \ + $(git-version-gen-tag-sed-script)) + ifneq ($(_curr-ver),$(VERSION)) + ifeq ($(_curr-ver),UNKNOWN) + $(info WARNING: unable to verify if $(VERSION) is the correct version) + else + ifneq (,$(_is-install-target)) + # GNU Coding Standards state that 'make install' should not cause + # recompilation after 'make all'. But as long as changing the version + # string alters config.h, the cost of having 'make all' always have an + # up-to-date version is prohibitive. So, as a compromise, we merely + # warn when installing a version string that is out of date; the user + # should run 'autoreconf' (or something like 'make distcheck') to + # fix the version, 'make all' to propagate it, then 'make install'. + $(info WARNING: version string $(VERSION) is out of date;) + $(info run '$(MAKE) _version' to fix it) + else + $(info INFO: running autoreconf for new version string: $(_curr-ver)) +GNUmakefile: _version + touch GNUmakefile + endif + endif + endif + endif +endif + +.PHONY: _version +_version: + cd $(srcdir) && rm -rf autom4te.cache .version && $(_autoreconf) + $(MAKE) $(AM_MAKEFLAGS) Makefile + +else + +.DEFAULT_GOAL := abort-due-to-no-makefile +srcdir = . + +# The package can override .DEFAULT_GOAL to run actions like autoreconf. +-include ./cfg.mk +include ./maint.mk + +ifeq ($(.DEFAULT_GOAL),abort-due-to-no-makefile) +$(MAKECMDGOALS): abort-due-to-no-makefile +endif + +abort-due-to-no-makefile: + @echo There seems to be no Makefile in this directory. 1>&2 + @echo "You must run ./configure before running \`make'." 1>&2 + @exit 1 + +endif + +# Tell version 3.79 and up of GNU make to not build goals in this +# directory in parallel, in case someone tries to build multiple +# targets, and one of them can cause a recursive target to be invoked. + +# Only set this if Automake doesn't provide it. +AM_RECURSIVE_TARGETS ?= $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) \ + dist distcheck tags ctags + +ALL_RECURSIVE_TARGETS += $(AM_RECURSIVE_TARGETS) + +ifneq ($(word 2, $(MAKECMDGOALS)), ) +ifneq ($(filter $(ALL_RECURSIVE_TARGETS), $(MAKECMDGOALS)), ) +.NOTPARALLEL: +endif +endif diff --git a/Makefile.am b/Makefile.am index ab26f40..6d43a9f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,6 +9,12 @@ EXTRA_DIST = \ intltool-extract.in \ intltool-merge.in \ intltool-update.in \ + GNUmakefile \ + maint.mk \ + cfg.mk \ + build-aux/gitlog-to-changelog \ + build-aux/useless-if-before-free \ + build-aux/vc-list-files \ $(NULL) DISTCLEAN_FILES = \ diff --git a/autobuild.sh b/autobuild.sh index 3c8e896..f37fb0e 100755 --- a/autobuild.sh +++ b/autobuild.sh @@ -3,6 +3,8 @@ set -e set -v +test -n "$1" && RESULTS=$1 || RESULTS=results.log + # Make things clean. test -f Makefile && make -k distclean || : @@ -30,6 +32,16 @@ if test $? = 0 ; then make install fi +# set -o pipefail is a bashism; this use of exec is the POSIX alternative +exec 3>&1 +st=$( + exec 4>&1 >&3 + { make syntax-check 2>&1 3>&- 4>&-; echo $? >&4; } | tee "$RESULTS" +) +exec 3>&- +test "$st" = 0 + + rm -f *.tar.gz make dist diff --git a/build-aux/useless-if-before-free b/build-aux/useless-if-before-free new file mode 100755 index 0000000..b8f5a26 --- /dev/null +++ b/build-aux/useless-if-before-free @@ -0,0 +1,207 @@ +eval '(exit $?0)' && eval 'exec perl -wST "$0" ${1+"$@"}' + & eval 'exec perl -wST "$0" $argv:q' + if 0; +# Detect instances of "if (p) free (p);". +# Likewise "if (p != 0)", "if (0 != p)", or with NULL; and with braces. + +my $VERSION = '2011-04-20 13:43'; # UTC +# The definition above must lie within the first 8 lines in order +# for the Emacs time-stamp write hook (at end) to update it. +# If you change this file with Emacs, please let the write hook +# do its job. Otherwise, update this string manually. + +# Copyright (C) 2008-2011 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 . + +# Written by Jim Meyering + +use strict; +use warnings; +use Getopt::Long; + +(my $ME = $0) =~ s|.*/||; + +# use File::Coda; # http://meyering.net/code/Coda/ +END { + defined fileno STDOUT or return; + close STDOUT and return; + warn "$ME: failed to close standard output: $!\n"; + $? ||= 1; +} + +sub usage ($) +{ + my ($exit_code) = @_; + my $STREAM = ($exit_code == 0 ? *STDOUT : *STDERR); + if ($exit_code != 0) + { + print $STREAM "Try `$ME --help' for more information.\n"; + } + else + { + print $STREAM < sub { usage 0 }, + version => sub { print "$ME version $VERSION\n"; exit }, + list => \$list, + 'name=s@' => \@name, + ) or usage 1; + + # Make sure we have the right number of non-option arguments. + # Always tell the user why we fail. + @ARGV < 1 + and (warn "$ME: missing FILE argument\n"), usage EXIT_ERROR; + + my $or = join '|', @name; + my $regexp = qr/(?:$or)/; + + # Set the input record separator. + # Note: this makes it impractical to print line numbers. + $/ = '"'; + + my $found_match = 0; + FILE: + foreach my $file (@ARGV) + { + open FH, '<', $file + or (warn "$ME: can't open `$file' for reading: $!\n"), + $err = EXIT_ERROR, next; + while (defined (my $line = )) + { + while ($line =~ + /\b(if\s*\(\s*([^)]+?)(?:\s*!=\s*([^)]+?))?\s*\) + # 1 2 3 + (?: \s*$regexp\s*\((?:\s*\([^)]+\))?\s*([^)]+)\)\s*;| + \s*\{\s*$regexp\s*\((?:\s*\([^)]+\))?\s*([^)]+)\)\s*;\s*\}))/sxg) + { + my $all = $1; + my ($lhs, $rhs) = ($2, $3); + my ($free_opnd, $braced_free_opnd) = ($4, $5); + my $non_NULL; + if (!defined $rhs) { $non_NULL = $lhs } + elsif (is_NULL $rhs) { $non_NULL = $lhs } + elsif (is_NULL $lhs) { $non_NULL = $rhs } + else { next } + + # Compare the non-NULL part of the "if" expression and the + # free'd expression, without regard to white space. + $non_NULL =~ tr/ \t//d; + my $e2 = defined $free_opnd ? $free_opnd : $braced_free_opnd; + $e2 =~ tr/ \t//d; + if ($non_NULL eq $e2) + { + $found_match = 1; + $list + and (print "$file\0"), next FILE; + print "$file: $all\n"; + } + } + } + } + continue + { + close FH; + } + + $found_match && $err == EXIT_NO_MATCH + and $err = EXIT_MATCH; + + exit $err; +} + +my $foo = <<'EOF'; +# The above is to *find* them. +# This adjusts them, removing the unnecessary "if (p)" part. + +# FIXME: do something like this as an option (doesn't do braces): +free=xfree +git grep -l -z "$free *(" \ + | xargs -0 useless-if-before-free -l --name="$free" \ + | xargs -0 perl -0x3b -pi -e \ + 's/\bif\s*\(\s*(\S+?)(?:\s*!=\s*(?:0|NULL))?\s*\)\s+('"$free"'\s*\((?:\s*\([^)]+\))?\s*\1\s*\)\s*;)/$2/s' + +# Use the following to remove redundant uses of kfree inside braces. +# Note that -0777 puts perl in slurp-whole-file mode; +# but we have plenty of memory, these days... +free=kfree +git grep -l -z "$free *(" \ + | xargs -0 useless-if-before-free -l --name="$free" \ + | xargs -0 perl -0777 -pi -e \ + 's/\bif\s*\(\s*(\S+?)(?:\s*!=\s*(?:0|NULL))?\s*\)\s*\{\s*('"$free"'\s*\((?:\s*\([^)]+\))?\s*\1\s*\);)\s*\}[^\n]*$/$2/gms' + +Be careful that the result of the above transformation is valid. +If the matched string is followed by "else", then obviously, it won't be. + +When modifying files, refuse to process anything other than a regular file. +EOF + +## Local Variables: +## mode: perl +## indent-tabs-mode: nil +## eval: (add-hook 'write-file-hooks 'time-stamp) +## time-stamp-start: "my $VERSION = '" +## time-stamp-format: "%:y-%02m-%02d %02H:%02M" +## time-stamp-time-zone: "UTC" +## time-stamp-end: "'; # UTC" +## End: diff --git a/build-aux/vc-list-files b/build-aux/vc-list-files new file mode 100755 index 0000000..405e458 --- /dev/null +++ b/build-aux/vc-list-files @@ -0,0 +1,113 @@ +#!/bin/sh +# List version-controlled file names. + +# Print a version string. +scriptversion=2011-05-16.22; # UTC + +# Copyright (C) 2006-2011 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 . + + +# List the specified version-controlled files. +# With no argument, list them all. With a single DIRECTORY argument, +# list the version-controlled files in that directory. + +# If there's an argument, it must be a single, "."-relative directory name. +# cvsu is part of the cvsutils package: http://www.red-bean.com/cvsutils/ + +postprocess= +case $1 in + --help) cat <. +EOF + exit ;; + + --version) + year=`echo "$scriptversion" | sed 's/[^0-9].*//'` + cat < +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. +EOF + exit ;; + + -C) + test "$2" = . || postprocess="| sed 's|^|$2/|'" + cd "$2" || exit 1 + shift; shift ;; +esac + +test $# = 0 && set . + +for dir +do + if test -d .git; then + test "x$dir" = x. \ + && dir= sed_esc= \ + || { dir="$dir/"; sed_esc=`echo "$dir"|env sed 's,\([\\/]\),\\\\\1,g'`; } + # Ignore git symlinks - either they point into the tree, in which case + # we don't need to visit the target twice, or they point somewhere + # else (often into a submodule), in which case the content does not + # belong to this package. + eval exec git ls-tree -r 'HEAD:"$dir"' \ + \| sed -n '"s/^100[^ ]*./$sed_esc/p"' $postprocess + elif test -d .hg; then + eval exec hg locate '"$dir/*"' $postprocess + elif test -d .bzr; then + test "$postprocess" = '' && postprocess="| sed 's|^\./||'" + eval exec bzr ls -R --versioned '"$dir"' $postprocess + elif test -d CVS; then + test "$postprocess" = '' && postprocess="| sed 's|^\./||'" + if test -x build-aux/cvsu; then + eval build-aux/cvsu --find --types=AFGM '"$dir"' $postprocess + elif (cvsu --help) >/dev/null 2>&1; then + eval cvsu --find --types=AFGM '"$dir"' $postprocess + else + eval awk -F/ \''{ \ + if (!$1 && $3 !~ /^-/) { \ + f=FILENAME; \ + if (f ~ /CVS\/Entries$/) \ + f = substr(f, 1, length(f)-11); \ + print f $2; \ + }}'\'' \ + `find "$dir" -name Entries -print` /dev/null' $postprocess + fi + elif test -d .svn; then + eval exec svn list -R '"$dir"' $postprocess + else + echo "$0: Failed to determine type of version control used in `pwd`" 1>&2 + exit 1 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/cfg.mk b/cfg.mk new file mode 100644 index 0000000..0b6d9ac --- /dev/null +++ b/cfg.mk @@ -0,0 +1,131 @@ +# Customize Makefile.maint. -*- makefile -*- +# Copyright (C) 2008-2011 Red Hat, Inc. +# Copyright (C) 2003-2008 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 . + +# Tests not to run as part of "make distcheck". +local-checks-to-skip = \ + changelog-check \ + check-AUTHORS \ + makefile-check \ + makefile_path_separator_check \ + patch-check \ + sc_GPL_version \ + sc_always_defined_macros \ + sc_cast_of_alloca_return_value \ + sc_cross_check_PATH_usage_in_tests \ + sc_dd_max_sym_length \ + sc_error_exit_success \ + sc_file_system \ + sc_immutable_NEWS \ + sc_makefile_path_separator_check \ + sc_obsolete_symbols \ + sc_prohibit_always_true_header_tests \ + sc_prohibit_S_IS_definition \ + sc_prohibit_atoi_atof \ + sc_prohibit_hash_without_use \ + sc_prohibit_jm_in_m4 \ + sc_prohibit_quote_without_use \ + sc_prohibit_quotearg_without_use \ + sc_prohibit_stat_st_blocks \ + sc_root_tests \ + sc_space_tab \ + sc_sun_os_names \ + sc_system_h_headers \ + sc_texinfo_acronym \ + sc_tight_scope \ + sc_two_space_separator_in_usage \ + sc_error_message_uppercase \ + sc_program_name \ + sc_require_test_exit_idiom \ + sc_makefile_check \ + sc_useless_cpp_parens + +# Files that should never cause syntax check failures. +VC_LIST_ALWAYS_EXCLUDE_REGEX = \ + (^HACKING|\.po|maint.mk)$$ + +# Functions like free() that are no-ops on NULL arguments. +useless_free_options = \ + --name=g_free \ + --name=xmlBufferFree \ + --name=xmlFree \ + --name=xmlFreeDoc \ + --name=xmlXPathFreeContext \ + --name=xmlFreeParserContext \ + --name=xmlXPathFreeObject + +# Ensure that no C source file, docs, or rng schema uses TABs for +# indentation. Also match *.h.in files, to get libvirt.h.in. Exclude +# files in gnulib, since they're imported. +space_indent_files=(\.(rng|s?[ch](\.in)?|html.in|py)|(daemon|tools)/.*\.in) +sc_TAB_in_indentation: + @prohibit='^ * ' \ + in_vc_files='$(space_indent_files)$$' \ + halt='indent with space, not TAB, in C, sh, html, py, and RNG schemas' \ + $(_sc_search_regexp) + +# G_GNUC_UNUSED should only be applied in implementations, not +# header declarations +sc_avoid_attribute_unused_in_header: + @prohibit='^[^#]*G_GNUC_UNUSED([^:]|$$)' \ + in_vc_files='\.h$$' \ + halt='use G_GNUC_UNUSED in .c rather than .h files' \ + $(_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 + +sc_copyright_format: + @require='Copyright .*Red 'Hat', Inc\.' \ + containing='Copyright .*Red 'Hat \ + halt='Red Hat copyright is missing Inc.' \ + $(_sc_search_regexp) + @prohibit='Copyright [^(].*Red 'Hat \ + halt='consistently use (C) in Red Hat copyright' \ + $(_sc_search_regexp) + @prohibit='\' \ + halt='spell Red Hat as two words' \ + $(_sc_search_regexp) + +# We don't use this feature of maint.mk. +prev_version_file = /dev/null + +# Give credit where due: +# Ensure that each commit author email address (possibly mapped via +# git log's .mailmap) appears in our AUTHORS file. +sc_check_author_list: + @fail=0; \ + for i in $$(git log --pretty=format:%aE%n|sort -u|grep -v '^$$'); do \ + sanitized=$$(echo "$$i"|LC_ALL=C sed 's/\([^a-zA-Z0-9_@-]\)/\\\1/g'); \ + grep -iq "<$$sanitized>" $(srcdir)/AUTHORS \ + || { printf '%s\n' "$$i" >&2; fail=1; }; \ + done; \ + test $$fail = 1 \ + && echo '$(ME): committer(s) not listed in AUTHORS' >&2; \ + test $$fail = 0 + + +exclude_file_name_regexp--sc_preprocessor_indentation = ^*/*.[ch] +exclude_file_name_regexp--sc_prohibit_strcmp = ^*/*.[ch] +exclude_file_name_regexp--sc_require_config_h = ^plugin/ +exclude_file_name_regexp--sc_require_config_h_first = ^plugin/ diff --git a/configure.ac b/configure.ac index 5733a69..7c19800 100644 --- a/configure.ac +++ b/configure.ac @@ -26,6 +26,17 @@ AC_CONFIG_LIBOBJ_DIR([src]) AC_DEFINE([_GNU_SOURCE], [], [Enable GNU extensions]) +# Autoconf 2.61a.99 and earlier don't support linking a file only +# in VPATH builds. But since GNUmakefile is for maintainer use +# only, it does not matter if we skip the link with older autoconf. +# Automake 1.10.1 and earlier try to remove GNUmakefile in non-VPATH +# builds, so use a shell variable to bypass this. +GNUmakefile=GNUmakefile +m4_if(m4_version_compare([2.61a.100], + m4_defn([m4_PACKAGE_VERSION])), [1], [], + [AC_CONFIG_LINKS([$GNUmakefile:$GNUmakefile], [], + [GNUmakefile=$GNUmakefile])]) + VIRT_VIEWER_COMPILE_WARNINGS(maximum) GETTEXT_PACKAGE=virt-viewer diff --git a/maint.mk b/maint.mk new file mode 100644 index 0000000..405c6d0 --- /dev/null +++ b/maint.mk @@ -0,0 +1,1511 @@ +# -*-Makefile-*- +# This Makefile fragment tries to be general-purpose enough to be +# used by many projects via the gnulib maintainer-makefile module. + +## Copyright (C) 2001-2011 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 . + +# This is reported not to work with make-3.79.1 +# ME := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)) +ME := maint.mk + +# Diagnostic for continued use of deprecated variable. +# Remove in 2013 +ifneq ($(build_aux),) + $(error "$(ME): \ +set $$(_build-aux) relative to $$(srcdir) instead of $$(build_aux)") +endif + +# Do not save the original name or timestamp in the .tar.gz file. +# Use --rsyncable if available. +gzip_rsyncable := \ + $(shell gzip --help 2>/dev/null|grep rsyncable >/dev/null \ + && printf %s --rsyncable) +GZIP_ENV = '--no-name --best $(gzip_rsyncable)' + +GIT = git +VC = $(GIT) + +VC_LIST = $(srcdir)/$(_build-aux)/vc-list-files -C $(srcdir) + +# You can override this variable in cfg.mk to set your own regexp +# matching files to ignore. +VC_LIST_ALWAYS_EXCLUDE_REGEX ?= ^$$ + +# This is to preprocess robustly the output of $(VC_LIST), so that even +# when $(srcdir) is a pathological name like "....", the leading sed command +# removes only the intended prefix. +_dot_escaped_srcdir = $(subst .,\.,$(srcdir)) + +# Post-process $(VC_LIST) output, prepending $(srcdir)/, but only +# when $(srcdir) is not ".". +ifeq ($(srcdir),.) +_prepend_srcdir_prefix = +else +_prepend_srcdir_prefix = | sed 's|^|$(srcdir)/|' +endif + +# In order to be able to consistently filter "."-relative names, +# (i.e., with no $(srcdir) prefix), this definition is careful to +# remove any $(srcdir) prefix, and to restore what it removes. +_sc_excl = \ + $(if $(exclude_file_name_regexp--$@),$(exclude_file_name_regexp--$@),^$$) +VC_LIST_EXCEPT = \ + $(VC_LIST) | sed 's|^$(_dot_escaped_srcdir)/||' \ + | if test -f $(srcdir)/.x-$@; then grep -vEf $(srcdir)/.x-$@; \ + else grep -Ev -e "$${VC_LIST_EXCEPT_DEFAULT-ChangeLog}"; fi \ + | grep -Ev -e '($(VC_LIST_ALWAYS_EXCLUDE_REGEX)|$(_sc_excl))' \ + $(_prepend_srcdir_prefix) + +ifeq ($(origin prev_version_file), undefined) + prev_version_file = $(srcdir)/.prev-version +endif + +PREV_VERSION := $(shell cat $(prev_version_file) 2>/dev/null) +VERSION_REGEXP = $(subst .,\.,$(VERSION)) +PREV_VERSION_REGEXP = $(subst .,\.,$(PREV_VERSION)) + +ifeq ($(VC),$(GIT)) +this-vc-tag = v$(VERSION) +this-vc-tag-regexp = v$(VERSION_REGEXP) +else +tag-package = $(shell echo "$(PACKAGE)" | tr '[:lower:]' '[:upper:]') +tag-this-version = $(subst .,_,$(VERSION)) +this-vc-tag = $(tag-package)-$(tag-this-version) +this-vc-tag-regexp = $(this-vc-tag) +endif +my_distdir = $(PACKAGE)-$(VERSION) + +# Old releases are stored here. +release_archive_dir ?= ../release + +# Override gnu_rel_host and url_dir_list in cfg.mk if these are not right. +# Use alpha.gnu.org for alpha and beta releases. +# Use ftp.gnu.org for stable releases. +gnu_ftp_host-alpha = alpha.gnu.org +gnu_ftp_host-beta = alpha.gnu.org +gnu_ftp_host-stable = ftp.gnu.org +gnu_rel_host ?= $(gnu_ftp_host-$(RELEASE_TYPE)) + +ifeq ($(gnu_rel_host),ftp.gnu.org) +url_dir_list ?= http://ftpmirror.gnu.org/$(PACKAGE) +else +url_dir_list ?= ftp://$(gnu_rel_host)/gnu/$(PACKAGE) +endif + +# Override this in cfg.mk if you are using a different format in your +# NEWS file. +today = $(shell date +%Y-%m-%d) + +# Select which lines of NEWS are searched for $(news-check-regexp). +# This is a sed line number spec. The default says that we search +# lines 1..10 of NEWS for $(news-check-regexp). +# If you want to search only line 3 or only lines 20-22, use "3" or "20,22". +news-check-lines-spec ?= 1,10 +news-check-regexp ?= '^\*.* $(VERSION_REGEXP) \($(today)\)' + +# Prevent programs like 'sort' from considering distinct strings to be equal. +# Doing it here saves us from having to set LC_ALL elsewhere in this file. +export LC_ALL = C + +## --------------- ## +## Sanity checks. ## +## --------------- ## + +_cfg_mk := $(shell test -f $(srcdir)/cfg.mk && echo '$(srcdir)/cfg.mk') + +# Collect the names of rules starting with `sc_'. +syntax-check-rules := $(sort $(shell sed -n 's/^\(sc_[a-zA-Z0-9_-]*\):.*/\1/p' \ + $(srcdir)/$(ME) $(_cfg_mk))) +.PHONY: $(syntax-check-rules) + +ifeq ($(shell $(VC_LIST) >/dev/null 2>&1; echo $$?),0) +local-checks-available += $(syntax-check-rules) +else +local-checks-available += no-vc-detected +no-vc-detected: + @echo "No version control files detected; skipping syntax check" +endif +.PHONY: $(local-checks-available) + +# Arrange to print the name of each syntax-checking rule just before running it. +$(syntax-check-rules): %: %.m +sc_m_rules_ = $(patsubst %, %.m, $(syntax-check-rules)) +.PHONY: $(sc_m_rules_) +$(sc_m_rules_): + @echo $(patsubst sc_%.m, %, $@) + @date +%s.%N > .sc-start-$(basename $@) + +# Compute and print the elapsed time for each syntax-check rule. +sc_z_rules_ = $(patsubst %, %.z, $(syntax-check-rules)) +.PHONY: $(sc_z_rules_) +$(sc_z_rules_): %.z: % + @end=$$(date +%s.%N); \ + start=$$(cat .sc-start-$*); \ + rm -f .sc-start-$*; \ + awk -v s=$$start -v e=$$end \ + 'END {printf "%.2f $(patsubst sc_%,%,$*)\n", e - s}' < /dev/null + +# The patsubst here is to replace each sc_% rule with its sc_%.z wrapper +# that computes and prints elapsed time. +local-check := \ + $(patsubst sc_%, sc_%.z, \ + $(filter-out $(local-checks-to-skip), $(local-checks-available))) + +syntax-check: $(local-check) + +# _sc_search_regexp +# +# This macro searches for a given construct in the selected files and +# then takes some action. +# +# Parameters (shell variables): +# +# prohibit | require +# +# Regular expression (ERE) denoting either a forbidden construct +# or a required construct. Those arguments are exclusive. +# +# in_vc_files | in_files +# +# grep-E-style regexp denoting the files to check. If no files +# are specified the default are all the files that are under +# version control. +# +# containing | non_containing +# +# Select the files (non) containing strings matching this regexp. +# If both arguments are specified then CONTAINING takes +# precedence. +# +# with_grep_options +# +# Extra options for grep. +# +# ignore_case +# +# Ignore case. +# +# halt +# +# Message to display before to halting execution. +# +# Finally, you may exempt files based on an ERE matching file names. +# For example, to exempt from the sc_space_tab check all files with the +# .diff suffix, set this Make variable: +# +# exclude_file_name_regexp--sc_space_tab = \.diff$ +# +# Note that while this functionality is mostly inherited via VC_LIST_EXCEPT, +# when filtering by name via in_files, we explicitly filter out matching +# names here as well. + +# By default, _sc_search_regexp does not ignore case. +export ignore_case = +_ignore_case = $$(test -n "$$ignore_case" && printf %s -i || :) + +define _sc_say_and_exit + dummy=; : so we do not need a semicolon before each use; \ + { printf '%s\n' "$(ME): $$msg" 1>&2; exit 1; }; +endef + +# _sc_search_regexp used to be named _prohibit_regexp. However, +# upgrading to the new definition and leaving the old name undefined +# would usually convert each custom rule using $(_prohibit_regexp) +# (usually defined in cfg.mk) into a no-op. This definition ensures +# that people know right away if they're still using the old name. +# FIXME: remove in 2012. +_prohibit_regexp = \ + $(error '*** you need to s/_prohibit_regexp/_sc_search_regexp/, and adapt') + +define _sc_search_regexp + dummy=; : so we do not need a semicolon before each use; \ + \ + : Check arguments; \ + test -n "$$prohibit" && test -n "$$require" \ + && { msg='Cannot specify both prohibit and require' \ + $(_sc_say_and_exit) } || :; \ + test -z "$$prohibit" && test -z "$$require" \ + && { msg='Should specify either prohibit or require' \ + $(_sc_say_and_exit) } || :; \ + test -n "$$in_vc_files" && test -n "$$in_files" \ + && { msg='Cannot specify both in_vc_files and in_files' \ + $(_sc_say_and_exit) } || :; \ + test "x$$halt" != x \ + || { msg='halt not defined' $(_sc_say_and_exit) }; \ + \ + : Filter by file name; \ + if test -n "$$in_files"; then \ + files=$$(find $(srcdir) | grep -E "$$in_files" \ + | grep -Ev '$(exclude_file_name_regexp--$@)'); \ + else \ + files=$$($(VC_LIST_EXCEPT)); \ + if test -n "$$in_vc_files"; then \ + files=$$(echo "$$files" | grep -E "$$in_vc_files"); \ + fi; \ + fi; \ + \ + : Filter by content; \ + test -n "$$files" && test -n "$$containing" \ + && { files=$$(grep -l "$$containing" $$files); } || :; \ + test -n "$$files" && test -n "$$non_containing" \ + && { files=$$(grep -vl "$$non_containing" $$files); } || :; \ + \ + : Check for the construct; \ + if test -n "$$files"; then \ + if test -n "$$prohibit"; then \ + grep $$with_grep_options $(_ignore_case) -nE "$$prohibit" $$files \ + && { msg="$$halt" $(_sc_say_and_exit) } || :; \ + else \ + grep $$with_grep_options $(_ignore_case) -LE "$$require" $$files \ + | grep . \ + && { msg="$$halt" $(_sc_say_and_exit) } || :; \ + fi \ + else :; \ + fi || :; +endef + +sc_avoid_if_before_free: + @$(srcdir)/$(_build-aux)/useless-if-before-free \ + $(useless_free_options) \ + $$($(VC_LIST_EXCEPT) | grep -v useless-if-before-free) && \ + { echo '$(ME): found useless "if" before "free" above' 1>&2; \ + exit 1; } || : + +sc_cast_of_argument_to_free: + @prohibit='\&2; exit 1; } || : + +# Pass EXIT_*, not number, to usage, exit, and error (when exiting) +# Convert all uses automatically, via these two commands: +# git grep -l '\&2; \ + exit 1; } || : + +# Error messages should not start with a capital letter +sc_error_message_uppercase: + @grep -nEA2 '[^rp]error *\(' $$($(VC_LIST_EXCEPT)) \ + | grep -E '"[A-Z]' \ + | grep -vE '"FATAL|"WARNING|"Java|"C#|PRIuMAX' && \ + { echo '$(ME): found capitalized error message' 1>&2; \ + exit 1; } || : + +# Error messages should not end with a period +sc_error_message_period: + @grep -nEA2 '[^rp]error *\(' $$($(VC_LIST_EXCEPT)) \ + | grep -E '[^."]\."' && \ + { echo '$(ME): found error message ending in period' 1>&2; \ + exit 1; } || : + +sc_file_system: + @prohibit=file''system \ + ignore_case=1 \ + halt='found use of "file''system"; spell it "file system"' \ + $(_sc_search_regexp) + +# Don't use cpp tests of this symbol. All code assumes config.h is included. +sc_prohibit_have_config_h: + @prohibit='^# *if.*HAVE''_CONFIG_H' \ + halt='found use of HAVE''_CONFIG_H; remove' \ + $(_sc_search_regexp) + +# Nearly all .c files must include . However, we also permit this +# via inclusion of a package-specific header, if cfg.mk specified one. +# config_h_header must be suitable for grep -E. +config_h_header ?= +sc_require_config_h: + @require='^# *include $(config_h_header)' \ + in_vc_files='\.c$$' \ + halt='the above files do not include ' \ + $(_sc_search_regexp) + +# You must include before including any other header file. +# This can possibly be via a package-specific header, if given by cfg.mk. +sc_require_config_h_first: + @if $(VC_LIST_EXCEPT) | grep -l '\.c$$' > /dev/null; then \ + fail=0; \ + for i in $$($(VC_LIST_EXCEPT) | grep '\.c$$'); do \ + grep '^# *include\>' $$i | sed 1q \ + | grep -E '^# *include $(config_h_header)' > /dev/null \ + || { echo $$i; fail=1; }; \ + done; \ + test $$fail = 1 && \ + { echo '$(ME): the above files include some other header' \ + 'before ' 1>&2; exit 1; } || :; \ + else :; \ + fi + +sc_prohibit_HAVE_MBRTOWC: + @prohibit='\bHAVE_MBRTOWC\b' \ + halt="do not use $$prohibit; it is always defined" \ + $(_sc_search_regexp) + +# To use this "command" macro, you must first define two shell variables: +# h: the header name, with no enclosing <> or "" +# re: a regular expression that matches IFF something provided by $h is used. +define _sc_header_without_use + dummy=; : so we do not need a semicolon before each use; \ + h_esc=`echo '[<"]'"$$h"'[">]'|sed 's/\./\\\\./g'`; \ + if $(VC_LIST_EXCEPT) | grep -l '\.c$$' > /dev/null; then \ + files=$$(grep -l '^# *include '"$$h_esc" \ + $$($(VC_LIST_EXCEPT) | grep '\.c$$')) && \ + grep -LE "$$re" $$files | grep . && \ + { echo "$(ME): the above files include $$h but don't use it" \ + 1>&2; exit 1; } || :; \ + else :; \ + fi +endef + +# Prohibit the inclusion of assert.h without an actual use of assert. +sc_prohibit_assert_without_use: + @h='assert.h' re='\new(file => "/dev/stdin")->as_string'|sed 's/\?://g' +# Note this was produced by the above: +# _xa1 = \ +#x(((2n?)?re|c(har)?|n(re|m)|z)alloc|alloc_(oversized|die)|m(alloc|emdup)|strdup) +# But we can do better, in at least two ways: +# 1) take advantage of two "dup"-suffixed strings: +# x(((2n?)?re|c(har)?|n(re|m)|[mz])alloc|alloc_(oversized|die)|(mem|str)dup) +# 2) notice that "c(har)?|[mz]" is equivalent to the shorter and more readable +# "char|[cmz]" +# x(((2n?)?re|char|n(re|m)|[cmz])alloc|alloc_(oversized|die)|(mem|str)dup) +_xa1 = x(((2n?)?re|char|n(re|m)|[cmz])alloc|alloc_(oversized|die)|(mem|str)dup) +_xa2 = X([CZ]|N?M)ALLOC +sc_prohibit_xalloc_without_use: + @h='xalloc.h' \ + re='\<($(_xa1)|$(_xa2)) *\('\ + $(_sc_header_without_use) + +# Extract function names: +# perl -lne '/^(?:extern )?(?:void|char) \*?(\w+) *\(/ and print $1' lib/hash.h +_hash_re = \ +clear|delete|free|get_(first|next)|insert|lookup|print_statistics|reset_tuning +_hash_fn = \<($(_hash_re)) *\( +_hash_struct = (struct )?\<[Hh]ash_(table|tuning)\> +sc_prohibit_hash_without_use: + @h='hash.h' \ + re='$(_hash_fn)|$(_hash_struct)'\ + $(_sc_header_without_use) + +sc_prohibit_cloexec_without_use: + @h='cloexec.h' re='\<(set_cloexec_flag|dup_cloexec) *\(' \ + $(_sc_header_without_use) + +sc_prohibit_posixver_without_use: + @h='posixver.h' re='\' \ + halt='do not use HAVE''_FCNTL_H or O'_NDELAY \ + $(_sc_search_regexp) + +# FIXME: warn about definitions of EXIT_FAILURE, EXIT_SUCCESS, STREQ + +# Each nonempty ChangeLog line must start with a year number, or a TAB. +sc_changelog: + @prohibit='^[^12 ]' \ + in_vc_files='^ChangeLog$$' \ + halt='found unexpected prefix in a ChangeLog' \ + $(_sc_search_regexp) + +# Ensure that each .c file containing a "main" function also +# calls set_program_name. +sc_program_name: + @require='set_program_name *\(m?argv\[0\]\);' \ + in_vc_files='\.c$$' \ + containing='\
/dev/null \ + && : || { die=1; echo $$i; } \ + done; \ + test $$die = 1 && \ + { echo 1>&2 '$(ME): the final line in each of the above is not:'; \ + echo 1>&2 'Exit something'; \ + exit 1; } || :; \ + fi + +sc_trailing_blank: + @prohibit='[ ]$$' \ + halt='found trailing blank(s)' \ + $(_sc_search_regexp) + +# Match lines like the following, but where there is only one space +# between the options and the description: +# -D, --all-repeated[=delimit-method] print all duplicate lines\n +longopt_re = --[a-z][0-9A-Za-z-]*(\[?=[0-9A-Za-z-]*\]?)? +sc_two_space_separator_in_usage: + @prohibit='^ *(-[A-Za-z],)? $(longopt_re) [^ ].*\\$$' \ + halt='help2man requires at least two spaces between an option and its description'\ + $(_sc_search_regexp) + +# A regexp matching function names like "error" that may be used +# to emit translatable messages. +_gl_translatable_diag_func_re ?= error + +# Look for diagnostics that aren't marked for translation. +# This won't find any for which error's format string is on a separate line. +sc_unmarked_diagnostics: + @grep -nE \ + '\<$(_gl_translatable_diag_func_re) *\([^"]*"[^"]*[a-z]{3}' \ + $$($(VC_LIST_EXCEPT)) \ + | grep -Ev '(_|ngettext ?)\(' && \ + { echo '$(ME): found unmarked diagnostic(s)' 1>&2; \ + exit 1; } || : + +# Avoid useless parentheses like those in this example: +# #if defined (SYMBOL) || defined (SYM2) +sc_useless_cpp_parens: + @prohibit='^# *if .*defined *\(' \ + halt='found useless parentheses in cpp directive' \ + $(_sc_search_regexp) + +# List headers for which HAVE_HEADER_H is always true, assuming you are +# using the appropriate gnulib module. CAUTION: for each "unnecessary" +# #if HAVE_HEADER_H that you remove, be sure that your project explicitly +# requires the gnulib module that guarantees the usability of that header. +gl_assured_headers_ = \ + cd $(gnulib_dir)/lib && echo *.in.h|sed 's/\.in\.h//g' + +# Convert the list of names to upper case, and replace each space with "|". +az_ = abcdefghijklmnopqrstuvwxyz +AZ_ = ABCDEFGHIJKLMNOPQRSTUVWXYZ +gl_header_upper_case_or_ = \ + $$($(gl_assured_headers_) \ + | tr $(az_)/.- $(AZ_)___ \ + | tr -s ' ' '|' \ + ) +sc_prohibit_always_true_header_tests: + @or=$(gl_header_upper_case_or_); \ + re="HAVE_($$or)_H"; \ + prohibit='\<'"$$re"'\>' \ + halt=$$(printf '%s\n' \ + 'do not test the above HAVE_
_H symbol(s);' \ + ' with the corresponding gnulib module, they are always true') \ + $(_sc_search_regexp) + +# ================================================================== +gl_other_headers_ ?= \ + intprops.h \ + openat.h \ + stat-macros.h + +# Perl -lne code to extract "significant" cpp-defined symbols from a +# gnulib header file, eliminating a few common false-positives. +# The exempted names below are defined only conditionally in gnulib, +# and hence sometimes must/may be defined in application code. +gl_extract_significant_defines_ = \ + /^\# *define ([^_ (][^ (]*)(\s*\(|\s+\w+)/\ + && $$2 !~ /(?:rpl_|_used_without_)/\ + && $$1 !~ /^(?:NSIG|ENODATA)$$/\ + && $$1 !~ /^(?:SA_RESETHAND|SA_RESTART)$$/\ + and print $$1 + +# Create a list of regular expressions matching the names +# of macros that are guaranteed to be defined by parts of gnulib. +define def_sym_regex + gen_h=$(gl_generated_headers_); \ + (cd $(gnulib_dir)/lib; \ + for f in *.in.h $(gl_other_headers_); do \ + test -f $$f \ + && perl -lne '$(gl_extract_significant_defines_)' $$f; \ + done; \ + ) | sort -u \ + | sed 's/^/^ *# *(define|undef) */;s/$$/\\>/' +endef + +# Don't define macros that we already get from gnulib header files. +sc_prohibit_always-defined_macros: + @if test -d $(gnulib_dir); then \ + case $$(echo all: | grep -l -f - Makefile) in Makefile);; *) \ + echo '$(ME): skipping $@: you lack GNU grep' 1>&2; exit 0;; \ + esac; \ + $(def_sym_regex) | grep -E -f - $$($(VC_LIST_EXCEPT)) \ + && { echo '$(ME): define the above via some gnulib .h file' \ + 1>&2; exit 1; } || :; \ + fi +# ================================================================== + +# Prohibit checked in backup files. +sc_prohibit_backup_files: + @$(VC_LIST) | grep '~$$' && \ + { echo '$(ME): found version controlled backup file' 1>&2; \ + exit 1; } || : + +# Require the latest GPL. +sc_GPL_version: + @prohibit='either ''version [^3]' \ + halt='GPL vN, N!=3' \ + $(_sc_search_regexp) + +# Require the latest GFDL. Two regexp, since some .texi files end up +# line wrapping between 'Free Documentation License,' and 'Version'. +_GFDL_regexp = (Free ''Documentation.*Version 1\.[^3]|Version 1\.[^3] or any) +sc_GFDL_version: + @prohibit='$(_GFDL_regexp)' \ + halt='GFDL vN, N!=3' \ + $(_sc_search_regexp) + +# Don't use Texinfo's @acronym{}. +# http://lists.gnu.org/archive/html/bug-gnulib/2010-03/msg00321.html +texinfo_suffix_re_ ?= \.(txi|texi(nfo)?)$$ +sc_texinfo_acronym: + @prohibit='@acronym\{' \ + in_vc_files='$(texinfo_suffix_re_)' \ + halt='found use of Texinfo @acronym{}' \ + $(_sc_search_regexp) + +cvs_keywords = \ + Author|Date|Header|Id|Name|Locker|Log|RCSfile|Revision|Source|State + +sc_prohibit_cvs_keyword: + @prohibit='\$$($(cvs_keywords))\$$' \ + halt='do not use CVS keyword expansion' \ + $(_sc_search_regexp) + +# This Perl code is slightly obfuscated. Not only is each "$" doubled +# because it's in a Makefile, but the $$c's are comments; we cannot +# use "#" due to the way the script ends up concatenated onto one line. +# It would be much more concise, and would produce better output (including +# counts) if written as: +# perl -ln -0777 -e '/\n(\n+)$/ and print "$ARGV: ".length $1' ... +# but that would be far less efficient, reading the entire contents +# of each file, rather than just the last two bytes of each. +# In addition, while the code below detects both blank lines and a missing +# newline at EOF, the above detects only the former. +# +# This is a perl script that is expected to be the single-quoted argument +# to a command-line "-le". The remaining arguments are file names. +# Print the name of each file that ends in exactly one newline byte. +# I.e., warn if there are blank lines (2 or more newlines), or if the +# last byte is not a newline. However, currently we don't complain +# about any file that contains exactly one byte. +# Exit nonzero if at least one such file is found, otherwise, exit 0. +# Warn about, but otherwise ignore open failure. Ignore seek/read failure. +# +# Use this if you want to remove trailing empty lines from selected files: +# perl -pi -0777 -e 's/\n\n+$/\n/' files... +# +require_exactly_one_NL_at_EOF_ = \ + foreach my $$f (@ARGV) \ + { \ + open F, "<", $$f or (warn "failed to open $$f: $$!\n"), next; \ + my $$p = sysseek (F, -2, 2); \ + my $$c = "seek failure probably means file has < 2 bytes; ignore"; \ + my $$last_two_bytes; \ + defined $$p and $$p = sysread F, $$last_two_bytes, 2; \ + close F; \ + $$c = "ignore read failure"; \ + $$p && ($$last_two_bytes eq "\n\n" \ + || substr ($$last_two_bytes,1) ne "\n") \ + and (print $$f), $$fail=1; \ + } \ + END { exit defined $$fail } +sc_prohibit_empty_lines_at_EOF: + @perl -le '$(require_exactly_one_NL_at_EOF_)' $$($(VC_LIST_EXCEPT)) \ + || { echo '$(ME): empty line(s) or no newline at EOF' \ + 1>&2; exit 1; } || : + +# Make sure we don't use st_blocks. Use ST_NBLOCKS instead. +# This is a bit of a kludge, since it prevents use of the string +# even in comments, but for now it does the job with no false positives. +sc_prohibit_stat_st_blocks: + @prohibit='[.>]st_blocks' \ + halt='do not use st_blocks; use ST_NBLOCKS' \ + $(_sc_search_regexp) + +# Make sure we don't define any S_IS* macros in src/*.c files. +# They're already defined via gnulib's sys/stat.h replacement. +sc_prohibit_S_IS_definition: + @prohibit='^ *# *define *S_IS' \ + halt='do not define S_IS* macros; include ' \ + $(_sc_search_regexp) + +# Perl block to convert a match to FILE_NAME:LINENO:TEST, +# that is shared by two definitions below. +perl_filename_lineno_text_ = \ + -e ' {' \ + -e ' $$n = ($$` =~ tr/\n/\n/ + 1);' \ + -e ' ($$v = $$&) =~ s/\n/\\n/g;' \ + -e ' print "$$ARGV:$$n:$$v\n";' \ + -e ' }' + +prohibit_doubled_word_RE_ ?= \ + /\b(then?|[iao]n|i[fst]|but|f?or|at|and|[dt]o)\s+\1\b/gims +prohibit_doubled_word_ = \ + -e 'while ($(prohibit_doubled_word_RE_))' \ + $(perl_filename_lineno_text_) + +# Define this to a regular expression that matches +# any filename:dd:match lines you want to ignore. +# The default is to ignore no matches. +ignore_doubled_word_match_RE_ ?= ^$$ + +sc_prohibit_doubled_word: + @perl -n -0777 $(prohibit_doubled_word_) $$($(VC_LIST_EXCEPT)) \ + | grep -vE '$(ignore_doubled_word_match_RE_)' \ + | grep . && { echo '$(ME): doubled words' 1>&2; exit 1; } || : + +# A regular expression matching undesirable combinations of words like +# "can not"; this matches them even when the two words appear on different +# lines, but not when there is an intervening delimiter like "#" or "*". +prohibit_undesirable_word_seq_RE_ ?= \ + /\bcan\s+not\b/gims +prohibit_undesirable_word_seq_ = \ + -e 'while ($(prohibit_undesirable_word_seq_RE_))' \ + $(perl_filename_lineno_text_) +# Define this to a regular expression that matches +# any filename:dd:match lines you want to ignore. +# The default is to ignore no matches. +ignore_undesirable_word_sequence_RE_ ?= ^$$ + +sc_prohibit_undesirable_word_seq: + @perl -n -0777 $(prohibit_undesirable_word_seq_) \ + $$($(VC_LIST_EXCEPT)) \ + | grep -vE '$(ignore_undesirable_word_sequence_RE_)' | grep . \ + && { echo '$(ME): undesirable word sequence' >&2; exit 1; } || : + +_ptm1 = use "test C1 && test C2", not "test C1 -''a C2" +_ptm2 = use "test C1 || test C2", not "test C1 -''o C2" +# Using test's -a and -o operators is not portable. +# We prefer test over [, since the latter is spelled [[ in configure.ac. +sc_prohibit_test_minus_ao: + @prohibit='(\ /dev/null \ + || { fail=1; echo 1>&2 "$(ME): $$p uses proper_name_utf8"; }; \ + done; \ + test $$fail = 1 && \ + { echo 1>&2 '$(ME): the above do not link with any ICONV library'; \ + exit 1; } || :; \ + fi + +# Warn about "c0nst struct Foo const foo[]", +# but not about "char const *const foo" or "#define const const". +sc_redundant_const: + @prohibit='\bconst\b[[:space:][:alnum:]]{2,}\bconst\b' \ + halt='redundant "const" in declarations' \ + $(_sc_search_regexp) + +sc_const_long_option: + @grep '^ *static.*struct option ' $$($(VC_LIST_EXCEPT)) \ + | grep -Ev 'const struct option|struct option const' && { \ + echo 1>&2 '$(ME): add "const" to the above declarations'; \ + exit 1; } || : + +NEWS_hash = \ + $$(sed -n '/^\*.* $(PREV_VERSION_REGEXP) ([0-9-]*)/,$$p' \ + $(srcdir)/NEWS \ + | perl -0777 -pe \ + 's/^Copyright.+?Free\sSoftware\sFoundation,\sInc\.\n//ms' \ + | md5sum - \ + | sed 's/ .*//') + +# Ensure that we don't accidentally insert an entry into an old NEWS block. +sc_immutable_NEWS: + @if test -f $(srcdir)/NEWS; then \ + test "$(NEWS_hash)" = '$(old_NEWS_hash)' && : || \ + { echo '$(ME): you have modified old NEWS' 1>&2; exit 1; }; \ + fi + +# Update the hash stored above. Do this after each release and +# for any corrections to old entries. +update-NEWS-hash: NEWS + perl -pi -e 's/^(old_NEWS_hash[ \t]+:?=[ \t]+).*/$${1}'"$(NEWS_hash)/" \ + $(srcdir)/cfg.mk + +# Ensure that we use only the standard $(VAR) notation, +# not @...@ in Makefile.am, now that we can rely on automake +# to emit a definition for each substituted variable. +# However, there is still one case in which @VAR@ use is not just +# legitimate, but actually required: when augmenting an automake-defined +# variable with a prefix. For example, gettext uses this: +# MAKEINFO = env LANG= LC_MESSAGES= LC_ALL= LANGUAGE= @MAKEINFO@ +# otherwise, makeinfo would put German or French (current locale) +# navigation hints in the otherwise-English documentation. +# +# Allow the package to add exceptions via a hook in cfg.mk; +# for example, @PRAGMA_SYSTEM_HEADER@ can be permitted by +# setting this to ' && !/PRAGMA_SYSTEM_HEADER/'. +_makefile_at_at_check_exceptions ?= +sc_makefile_at_at_check: + @perl -ne '/\@[A-Z_0-9]+\@/' \ + -e ' && !/([A-Z_0-9]+)\s+=.*\@\1\@$$/' \ + -e ''$(_makefile_at_at_check_exceptions) \ + -e 'and (print "$$ARGV:$$.: $$_"), $$m=1; END {exit !$$m}' \ + $$($(VC_LIST_EXCEPT) | grep -E '(^|/)(Makefile\.am|[^/]+\.mk)$$') \ + && { echo '$(ME): use $$(...), not @...@' 1>&2; exit 1; } || : + +news-check: NEWS + if sed -n $(news-check-lines-spec)p $(srcdir)/NEWS \ + | grep -E $(news-check-regexp) >/dev/null; then \ + :; \ + else \ + echo 'NEWS: $$(news-check-regexp) failed to match' 1>&2; \ + exit 1; \ + fi + +sc_makefile_TAB_only_indentation: + @prohibit='^ [ ]{8}' \ + in_vc_files='akefile|\.mk$$' \ + halt='found TAB-8-space indentation' \ + $(_sc_search_regexp) + +sc_m4_quote_check: + @prohibit='(AC_DEFINE(_UNQUOTED)?|AC_DEFUN)\([^[]' \ + in_vc_files='(^configure\.ac|\.m4)$$' \ + halt='quote the first arg to AC_DEF*' \ + $(_sc_search_regexp) + +fix_po_file_diag = \ +'you have changed the set of files with translatable diagnostics;\n\ +apply the above patch\n' + +# Verify that all source files using _() are listed in po/POTFILES.in. +po_file ?= $(srcdir)/po/POTFILES.in +generated_files ?= $(srcdir)/lib/*.[ch] +sc_po_check: + @if test -f $(po_file); then \ + grep -E -v '^(#|$$)' $(po_file) \ + | grep -v '^src/false\.c$$' | sort > $@-1; \ + files=; \ + for file in $$($(VC_LIST_EXCEPT)) $(generated_files); do \ + test -r $$file || continue; \ + case $$file in \ + *.m4|*.mk) continue ;; \ + *.?|*.??) ;; \ + *) continue;; \ + esac; \ + case $$file in \ + *.[ch]) \ + base=`expr " $$file" : ' \(.*\)\..'`; \ + { test -f $$base.l || test -f $$base.y; } && continue;; \ + esac; \ + files="$$files $$file"; \ + done; \ + grep -E -l '\b(N?_|gettext *)\([^)"]*("|$$)' $$files \ + | sed 's|^$(_dot_escaped_srcdir)/||' | sort -u > $@-2; \ + diff -u -L $(po_file) -L $(po_file) $@-1 $@-2 \ + || { printf '$(ME): '$(fix_po_file_diag) 1>&2; exit 1; }; \ + rm -f $@-1 $@-2; \ + fi + +# Sometimes it is useful to change the PATH environment variable +# in Makefiles. When doing so, it's better not to use the Unix-centric +# path separator of `:', but rather the automake-provided `$(PATH_SEPARATOR)'. +msg = '$(ME): Do not use `:'\'' above; use $$(PATH_SEPARATOR) instead' +sc_makefile_path_separator_check: + @prohibit='PATH[=].*:' \ + in_vc_files='akefile|\.mk$$' \ + halt=$(msg) \ + $(_sc_search_regexp) + +# Check that `make alpha' will not fail at the end of the process, +# i.e., when pkg-M.N.tar.xz already exists (either in "." or in ../release) +# and is read-only. +writable-files: + if test -d $(release_archive_dir); then \ + for file in $(DIST_ARCHIVES); do \ + for p in ./ $(release_archive_dir)/; do \ + test -e $$p$$file || continue; \ + test -w $$p$$file \ + || { echo ERROR: $$p$$file is not writable; fail=1; }; \ + done; \ + done; \ + test "$$fail" && exit 1 || : ; \ + else :; \ + fi + +v_etc_file = $(gnulib_dir)/lib/version-etc.c +sample-test = tests/sample-test +texi = doc/$(PACKAGE).texi +# Make sure that the copyright date in $(v_etc_file) is up to date. +# Do the same for the $(sample-test) and the main doc/.texi file. +sc_copyright_check: + @require='enum { COPYRIGHT_YEAR = '$$(date +%Y)' };' \ + in_files=$(v_etc_file) \ + halt='out of date copyright in $(v_etc_file); update it' \ + $(_sc_search_regexp) + @require='# Copyright \(C\) '$$(date +%Y)' Free' \ + in_vc_files=$(sample-test) \ + halt='out of date copyright in $(sample-test); update it' \ + $(_sc_search_regexp) + @require='Copyright @copyright\{\} .*'$$(date +%Y)' Free' \ + in_vc_files=$(texi) \ + halt='out of date copyright in $(texi); update it' \ + $(_sc_search_regexp) + +# If tests/help-version exists and seems to be new enough, assume that its +# use of init.sh and path_prepend_ is correct, and ensure that every other +# use of init.sh is identical. +# This is useful because help-version cross-checks prog --version +# with $(VERSION), which verifies that its path_prepend_ invocation +# sets PATH correctly. This is an inexpensive way to ensure that +# the other init.sh-using tests also get it right. +_hv_file ?= $(srcdir)/tests/help-version +_hv_regex_weak ?= ^ *\. .*/init\.sh" +# Fix syntax-highlighters " +_hv_regex_strong ?= ^ *\. "\$${srcdir=\.}/init\.sh" +sc_cross_check_PATH_usage_in_tests: + @if test -f $(_hv_file); then \ + grep -l 'VERSION mismatch' $(_hv_file) >/dev/null \ + || { echo "$@: skipped: no such file: $(_hv_file)" 1>&2; \ + exit 0; }; \ + grep -lE '$(_hv_regex_strong)' $(_hv_file) >/dev/null \ + || { echo "$@: $(_hv_file) lacks conforming use of init.sh" 1>&2; \ + exit 1; }; \ + good=$$(grep -E '$(_hv_regex_strong)' $(_hv_file)); \ + grep -LFx "$$good" \ + $$(grep -lE '$(_hv_regex_weak)' $$($(VC_LIST_EXCEPT))) \ + | grep . && \ + { echo "$(ME): the above files use path_prepend_ inconsistently" \ + 1>&2; exit 1; } || :; \ + fi + +# #if HAVE_... will evaluate to false for any non numeric string. +# That would be flagged by using -Wundef, however gnulib currently +# tests many undefined macros, and so we can't enable that option. +# So at least preclude common boolean strings as macro values. +sc_Wundef_boolean: + @prohibit='^#define.*(yes|no|true|false)$$' \ + in_files='$(CONFIG_INCLUDE)' \ + halt='Use 0 or 1 for macro values' \ + $(_sc_search_regexp) + +# Even if you use pathmax.h to guarantee that PATH_MAX is defined, it might +# not be constant, or might overflow a stack. In general, use PATH_MAX as +# a limit, not an array or alloca size. +sc_prohibit_path_max_allocation: + @prohibit='(\balloca *\([^)]*|\[[^]]*)PATH_MAX' \ + halt='Avoid stack allocations of size PATH_MAX' \ + $(_sc_search_regexp) + +sc_vulnerable_makefile_CVE-2009-4029: + @prohibit='perm -777 -exec chmod a\+rwx|chmod 777 \$$\(distdir\)' \ + in_files=$$(find $(srcdir) -name Makefile.in) \ + halt=$$(printf '%s\n' \ + 'the above files are vulnerable; beware of running' \ + ' "make dist*" rules, and upgrade to fixed automake' \ + ' see http://bugzilla.redhat.com/542609 for details') \ + $(_sc_search_regexp) + +vc-diff-check: + (unset CDPATH; cd $(srcdir) && $(VC) diff) > vc-diffs || : + if test -s vc-diffs; then \ + cat vc-diffs; \ + echo "Some files are locally modified:" 1>&2; \ + exit 1; \ + else \ + rm vc-diffs; \ + fi + +rel-files = $(DIST_ARCHIVES) + +gnulib_dir ?= $(srcdir)/gnulib +gnulib-version = $$(cd $(gnulib_dir) && git describe) +bootstrap-tools ?= autoconf,automake,gnulib + +# If it's not already specified, derive the GPG key ID from +# the signed tag we've just applied to mark this release. +gpg_key_ID ?= \ + $$(git cat-file tag v$(VERSION) > .ann-sig \ + && gpgv .ann-sig - < /dev/null 2>&1 \ + | sed -n '/.*key ID \([0-9A-F]*\)/s//\1/p'; rm -f .ann-sig) + +translation_project_ ?= coordinator@translationproject.org + +# Make info-gnu the default only for a stable release. +ifeq ($(RELEASE_TYPE),stable) + announcement_Cc_ ?= $(translation_project_), $(PACKAGE_BUGREPORT) + announcement_mail_headers_ ?= \ + To: info-gnu@gnu.org \ + Cc: $(announcement_Cc_) \ + Mail-Followup-To: $(PACKAGE_BUGREPORT) +else + announcement_Cc_ ?= $(translation_project_) + announcement_mail_headers_ ?= \ + To: $(PACKAGE_BUGREPORT) \ + Cc: $(announcement_Cc_) +endif + +announcement: NEWS ChangeLog $(rel-files) + @$(srcdir)/$(_build-aux)/announce-gen \ + --mail-headers='$(announcement_mail_headers_)' \ + --release-type=$(RELEASE_TYPE) \ + --package=$(PACKAGE) \ + --prev=$(PREV_VERSION) \ + --curr=$(VERSION) \ + --gpg-key-id=$(gpg_key_ID) \ + --news=$(srcdir)/NEWS \ + --bootstrap-tools=$(bootstrap-tools) \ + --gnulib-version=$(gnulib-version) \ + --no-print-checksums \ + $(addprefix --url-dir=, $(url_dir_list)) + +## ---------------- ## +## Updating files. ## +## ---------------- ## + +ftp-gnu = ftp://ftp.gnu.org/gnu +www-gnu = http://www.gnu.org + +upload_dest_dir_ ?= $(PACKAGE) +emit_upload_commands: + @echo ===================================== + @echo ===================================== + @echo "$(srcdir)/$(_build-aux)/gnupload $(GNUPLOADFLAGS) \\" + @echo " --to $(gnu_rel_host):$(upload_dest_dir_) \\" + @echo " $(rel-files)" + @echo '# send the ~/announce-$(my_distdir) e-mail' + @echo ===================================== + @echo ===================================== + +define emit-commit-log + printf '%s\n' 'maint: post-release administrivia' '' \ + '* NEWS: Add header line for next release.' \ + '* .prev-version: Record previous version.' \ + '* cfg.mk (old_NEWS_hash): Auto-update.' +endef + +.PHONY: no-submodule-changes +no-submodule-changes: + if test -d $(srcdir)/.git; then \ + diff=$$(cd $(srcdir) && git submodule -q foreach \ + git diff-index --name-only HEAD) \ + || exit 1; \ + case $$diff in '') ;; \ + *) echo '$(ME): submodule files are locally modified:'; \ + echo "$$diff"; exit 1;; esac; \ + else \ + : ; \ + fi + +submodule-checks ?= no-submodule-changes public-submodule-commit + +# Ensure that each sub-module commit we're using is public. +# Without this, it is too easy to tag and release code that +# cannot be built from a fresh clone. +.PHONY: public-submodule-commit +public-submodule-commit: + $(AM_V_GEN)if test -d $(srcdir)/.git; then \ + cd $(srcdir) && \ + git submodule --quiet foreach test '$$(git rev-parse $$sha1)' \ + = '$$(git merge-base origin $$sha1)' \ + || { echo '$(ME): found non-public submodule commit' >&2; \ + exit 1; }; \ + else \ + : ; \ + fi +# This rule has a high enough utility/cost ratio that it should be a +# dependent of "check" by default. However, some of us do occasionally +# commit a temporary change that deliberately points to a non-public +# submodule commit, and want to be able to use rules like "make check". +# In that case, run e.g., "make check gl_public_submodule_commit=" +# to disable this test. +gl_public_submodule_commit ?= public-submodule-commit +check: $(gl_public_submodule_commit) + +.PHONY: alpha beta stable +ALL_RECURSIVE_TARGETS += alpha beta stable +alpha beta stable: $(local-check) writable-files $(submodule-checks) + test $@ = stable \ + && { echo $(VERSION) | grep -E '^[0-9]+(\.[0-9]+)+$$' \ + || { echo "invalid version string: $(VERSION)" 1>&2; exit 1;};}\ + || : + $(MAKE) vc-diff-check + $(MAKE) news-check + $(MAKE) distcheck + $(MAKE) dist XZ_OPT=-9ev + $(MAKE) $(release-prep-hook) RELEASE_TYPE=$@ + $(MAKE) -s emit_upload_commands RELEASE_TYPE=$@ + +# Override this in cfg.mk if you follow different procedures. +release-prep-hook ?= release-prep + +gl_noteworthy_news_ = * Noteworthy changes in release ?.? (????-??-??) [?] +.PHONY: release-prep +release-prep: + case $$RELEASE_TYPE in alpha|beta|stable) ;; \ + *) echo "invalid RELEASE_TYPE: $$RELEASE_TYPE" 1>&2; exit 1;; esac + $(MAKE) --no-print-directory -s announcement > ~/announce-$(my_distdir) + if test -d $(release_archive_dir); then \ + ln $(rel-files) $(release_archive_dir); \ + chmod a-w $(rel-files); \ + fi + echo $(VERSION) > $(prev_version_file) + $(MAKE) update-NEWS-hash + perl -pi -e '$$. == 3 and print "$(gl_noteworthy_news_)\n\n\n"' NEWS + $(emit-commit-log) > .ci-msg + $(VC) commit -F .ci-msg -a + rm .ci-msg + +# Override this with e.g., -s $(srcdir)/some_other_name.texi +# if the default $(PACKAGE)-derived name doesn't apply. +gendocs_options_ ?= + +.PHONY: web-manual +web-manual: + @test -z "$(manual_title)" \ + && { echo define manual_title in cfg.mk 1>&2; exit 1; } || : + @cd '$(srcdir)/doc'; \ + $(SHELL) ../$(_build-aux)/gendocs.sh $(gendocs_options_) \ + -o '$(abs_builddir)/doc/manual' \ + --email $(PACKAGE_BUGREPORT) $(PACKAGE) \ + "$(PACKAGE_NAME) - $(manual_title)" + @echo " *** Upload the doc/manual directory to web-cvs." + +# Code Coverage + +init-coverage: + $(MAKE) $(AM_MAKEFLAGS) clean + lcov --directory . --zerocounters + +COVERAGE_CCOPTS ?= "-g --coverage" +COVERAGE_OUT ?= doc/coverage + +build-coverage: + $(MAKE) $(AM_MAKEFLAGS) CFLAGS=$(COVERAGE_CCOPTS) CXXFLAGS=$(COVERAGE_CCOPTS) + $(MAKE) $(AM_MAKEFLAGS) CFLAGS=$(COVERAGE_CCOPTS) CXXFLAGS=$(COVERAGE_CCOPTS) check + mkdir -p $(COVERAGE_OUT) + lcov --directory . --output-file $(COVERAGE_OUT)/$(PACKAGE).info \ + --capture + +gen-coverage: + genhtml --output-directory $(COVERAGE_OUT) \ + $(COVERAGE_OUT)/$(PACKAGE).info \ + --highlight --frames --legend \ + --title "$(PACKAGE_NAME)" + +coverage: init-coverage build-coverage gen-coverage + +# Update gettext files. +PACKAGE ?= $(shell basename $(PWD)) +PO_DOMAIN ?= $(PACKAGE) +POURL = http://translationproject.org/latest/$(PO_DOMAIN)/ +PODIR ?= po +refresh-po: + rm -f $(PODIR)/*.po && \ + echo "$(ME): getting translations into po (please ignore the robots.txt ERROR 404)..." && \ + wget --no-verbose --directory-prefix $(PODIR) --no-directories --recursive --level 1 --accept .po --accept .po.1 $(POURL) && \ + echo 'en@boldquot' > $(PODIR)/LINGUAS && \ + echo 'en@quot' >> $(PODIR)/LINGUAS && \ + ls $(PODIR)/*.po | sed 's/\.po//' | sed 's,$(PODIR)/,,' | sort >> $(PODIR)/LINGUAS + + # Running indent once is not idempotent, but running it twice is. +INDENT_SOURCES ?= $(C_SOURCES) +.PHONY: indent +indent: + indent $(INDENT_SOURCES) + indent $(INDENT_SOURCES) + +# If you want to set UPDATE_COPYRIGHT_* environment variables, +# put the assignments in this variable. +update-copyright-env ?= + +# Run this rule once per year (usually early in January) +# to update all FSF copyright year lists in your project. +# If you have an additional project-specific rule, +# add it in cfg.mk along with a line 'update-copyright: prereq'. +# By default, exclude all variants of COPYING; you can also +# add exemptions (such as ChangeLog..* for rotated change logs) +# in the file .x-update-copyright. +.PHONY: update-copyright +update-copyright: + grep -l -w Copyright \ + $$(export VC_LIST_EXCEPT_DEFAULT=COPYING && $(VC_LIST_EXCEPT)) \ + | $(update-copyright-env) xargs $(srcdir)/$(_build-aux)/$@ + +# This tight_scope test is skipped with a warning if $(_gl_TS_headers) is not +# overridden and $(_gl_TS_dir)/Makefile.am does not mention noinst_HEADERS. + +# NOTE: to override any _gl_TS_* default value, you must +# define the variable(s) using "export" in cfg.mk. +_gl_TS_dir ?= src + +ALL_RECURSIVE_TARGETS += sc_tight_scope +sc_tight_scope: tight-scope.mk + @fail=0; \ + if ! grep '^ *export _gl_TS_headers *=' $(srcdir)/cfg.mk \ + > /dev/null \ + && ! grep -w noinst_HEADERS $(srcdir)/$(_gl_TS_dir)/Makefile.am \ + > /dev/null 2>&1; then \ + echo '$(ME): skipping $@'; \ + else \ + $(MAKE) -s -C $(_gl_TS_dir) \ + -f Makefile \ + -f $(abs_top_srcdir)/cfg.mk \ + -f $(abs_top_builddir)/$< \ + _gl_tight_scope \ + || fail=1; \ + fi; \ + rm -f $<; \ + exit $$fail + +tight-scope.mk: $(ME) + @rm -f $@ $@-t + @perl -ne '/^# TS-start/.../^# TS-end/ and print' $(ME) > $@-t + @chmod a=r $@-t && mv $@-t $@ + +ifeq (a,b) +# TS-start + +# Most functions should have static scope. +# Any that don't must be marked with `extern', but `main' +# and `usage' are exceptions: they're always extern, but +# do not need to be marked. Symbols matching `__.*' are +# reserved by the compiler, so are automatically excluded below. +_gl_TS_unmarked_extern_functions ?= main usage +_gl_TS_function_match ?= /^(?:$(_gl_TS_extern)) +.*?(\S+) *\(/ + +# If your project uses a macro like "XTERN", then put +# the following in cfg.mk to override this default: +# export _gl_TS_extern = extern|XTERN +_gl_TS_extern ?= extern + +# The second nm|grep checks for file-scope variables with `extern' scope. +# Without gnulib's progname module, you might put program_name here. +# Symbols matching `__.*' are reserved by the compiler, +# so are automatically excluded below. +_gl_TS_unmarked_extern_vars ?= + +# NOTE: the _match variables are perl expressions -- not mere regular +# expressions -- so that you can extend them to match other patterns +# and easily extract matched variable names. +# For example, if your project declares some global variables via +# a macro like this: GLOBAL(type, var_name, initializer), then you +# can override this definition to automatically extract those names: +# export _gl_TS_var_match = \ +# /^(?:$(_gl_TS_extern)) .*?\**(\w+)(\[.*?\])?;/ || /\bGLOBAL\(.*?,\s*(.*?),/ +_gl_TS_var_match ?= /^(?:$(_gl_TS_extern)) .*?(\w+)(\[.*?\])?;/ + +# The names of object files in (or relative to) $(_gl_TS_dir). +_gl_TS_obj_files ?= *.$(OBJEXT) + +# Files in which to search for the one-line style extern declarations. +# $(_gl_TS_dir)-relative. +_gl_TS_headers ?= $(noinst_HEADERS) + +.PHONY: _gl_tight_scope +_gl_tight_scope: $(bin_PROGRAMS) + t=exceptions-$$$$; \ + trap 's=$$?; rm -f $$t; exit $$s' 0; \ + for sig in 1 2 3 13 15; do \ + eval "trap 'v=`expr $$sig + 128`; (exit $$v); exit $$v' $$sig"; \ + done; \ + src=`for f in $(SOURCES); do \ + test -f $$f && d= || d=$(srcdir)/; echo $$d$$f; done`; \ + hdr=`for f in $(_gl_TS_headers); do \ + test -f $$f && d= || d=$(srcdir)/; echo $$d$$f; done`; \ + ( printf '^%s$$\n' '__.*' $(_gl_TS_unmarked_extern_functions); \ + grep -h -A1 '^extern .*[^;]$$' $$src \ + | grep -vE '^(extern |--)' | sed 's/ .*//'; \ + perl -lne \ + '$(_gl_TS_function_match) and print "^$$1\$$"' $$hdr; \ + ) | sort -u > $$t; \ + nm -e $(_gl_TS_obj_files) | sed -n 's/.* T //p'|grep -Ev -f $$t \ + && { echo the above functions should have static scope >&2; \ + exit 1; } || : ; \ + ( printf '^%s$$\n' '__.*' $(_gl_TS_unmarked_extern_vars); \ + perl -lne '$(_gl_TS_var_match) and print "^$$1\$$"' $$hdr *.h \ + ) | sort -u > $$t; \ + nm -e $(_gl_TS_obj_files) | sed -n 's/.* [BCDGRS] //p' \ + | sort -u | grep -Ev -f $$t \ + && { echo the above variables should have static scope >&2; \ + exit 1; } || : +# TS-end +endif -- cgit