maint.mk: add a syntax-check rule to ensure tightly-scoped symbols
authorJim Meyering <meyering@redhat.com>
Mon, 9 May 2011 10:30:55 +0000 (12:30 +0200)
committerJim Meyering <meyering@redhat.com>
Mon, 9 May 2011 10:30:55 +0000 (12:30 +0200)
* top/maint.mk (sc_tight_scope): New rule.
(sc_tight_scope-0): New rule, ifdef'd out.
(_gl_TS_dir): Default.
(_gl_TS_unmarked_extern_functions, _gl_TS_function_regex): Define.
(_gl_TS_unmarked_extern_vars, _gl_TS_var_regex): Define.

ChangeLog
top/maint.mk

index f7e0a330bd7963061e0caf8505ce3a2727031b26..7feeba08dd539cbce3de1e03e9d47a3b8a530add 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2011-05-09  Jim Meyering  <meyering@redhat.com>
+
+       maint.mk: add a syntax-check rule to ensure tightly-scoped symbols
+       * top/maint.mk (sc_tight_scope): New rule.
+       (sc_tight_scope-0): New rule, ifdef'd out.
+       (_gl_TS_dir): Default.
+       (_gl_TS_unmarked_extern_functions, _gl_TS_function_regex): Define.
+       (_gl_TS_unmarked_extern_vars, _gl_TS_var_regex): Define.
+
 2011-05-09  Simon Josefsson  <simon@josefsson.org>
 
        * m4/gc.m4: Remove gl_PREREQ_GC (not used).  Reported by Bruno
index 03a9036752d6974f08934aaed06c67a2a99da3ee..793915cc7f036930373cde8f1ed88082afd36472 100644 (file)
@@ -1325,3 +1325,65 @@ update-copyright:
        grep -l -w Copyright                                             \
          $$(export VC_LIST_EXCEPT_DEFAULT=COPYING && $(VC_LIST_EXCEPT)) \
          | $(update-copyright-env) xargs $(build_aux)/$@
+
+# NOTE: This test is silently skipped if $(_gl_TS_dir)/Makefile.am
+# does not mention noinst_HEADERS.
+# NOTE: to override these _gl_TS_* default values, 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
+       @grep noinst_HEADERS $(_gl_TS_dir)/Makefile.am > /dev/null 2>&1 \
+         && $(MAKE) -s -C $(_gl_TS_dir)                                \
+             -f Makefile -f '$(abs_srcdir)/tight-scope.mk' $@-0        \
+         || :
+       @rm -f $<
+
+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.
+_gl_TS_unmarked_extern_functions ?= main usage
+_gl_TS_function_regex ?= \
+  ^(?:extern|XTERN) +(?:void|(?:struct |const |enum )?\S+) +\**(\S+) +\(
+
+# The second nm|grep checks for file-scope variables with `extern' scope.
+# Without gnulib's progname module, you might put program_name here.
+_gl_TS_unmarked_extern_vars ?=
+_gl_TS_var_regex ?= ^(?:extern|XTERN) .*?\**(\w+)(\[.*?\])?;
+.PHONY: sc_tight_scope-0
+sc_tight_scope-0: $(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 $(noinst_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_regex)/'                        \
+                 -e 'and print $$1' $$hdr;                             \
+       ) | sort -u | sed 's/^/^/;s/$$/$$/' > $$t;                      \
+       nm -e *.$(OBJEXT) | 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_regex)/ and print "^$$1\$$"'         \
+           $$hdr *.h ) | sort -u > $$t;                                \
+       nm -e *.$(OBJEXT) | 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