autoconf-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Avoid certain spurious `testsuite' rebuilds


From: Noah Misch
Subject: Avoid certain spurious `testsuite' rebuilds
Date: Fri, 31 Mar 2006 08:09:06 -0800
User-agent: Mutt/1.5.6i

If you change a lib/autoconf/*.m4 and then `make check', mktests.sh touches
every ac*.at (the generated test cases), forcing a rebuild of `testsuite'.  Only
adding new public macros actually changes the generated test cases, so that
rebuild is usually superfluous.

With this patch, mktests.sh runs for each edit in lib/autoconf/*.m4 but only
touches output files that have changed.  This eliminates the spurious rebuilds.

`make distcheck' passes on GNU.  This affected `make' behaviors also work with
GNU make on FreeBSD and the native `make' on Tru64 Unix.

FreeBSD `make' does not conform to POSIX in its handling of modification times:

$ cat >Makefile
a: b
        : a
b: c
        : b
$ for f in b a c; do touch $f; sleep 1; done
$ make
: b
: a
$ gmake
: b
$ make -dm
Examining c...modified 21:11:38 Feb 07, 2005...up-to-date.
Examining b...modified 21:11:36 Feb 07, 2005...modified before
source...out-of-date.
: b
update time: 21:11:38 Feb 07, 2005
Examining a...modified 21:11:37 Feb 07, 2005...modified before
source...out-of-date.
: a
update time: 21:11:38 Feb 07, 2005

Consequently, this patch does not help users of FreeBSD `make'.  They do not
seem to lose anything, though.

Does the large comment add anything?

I am no Makefile hacker, so comments especially appreciated on this one.


2006-03-31  Noah Misch  <address@hidden>

        Do not rebuild `testsuite' when a lib/autoconf/*.m4 edit does not affect
        the generated test cases.

        * tests/Makefile.am (stamp_tgat, stamp_acm4): New macros.  Distribute.
        (TESTSUITE): Depend on $(stamp_tgat).  Split $(TESTSUITE_AT) dependency
        into $(TESTSUITE_HAND_AT) and $(TESTSUITE_GENERATED_AT) and reorder.
        (do_update): New macro, from old TESTSUITE_GENERATED_AT commands.
        (stamp_tgat, stamp_acm4): New rules.
        (TESTSUITE_GENERATED_AT): Remove prerequisites; adjust commands.
        * tests/mktests: Only touch the products if they would change.  Exit
        with status 55 if some product changes or 0 if none change.
        * tests/.cvsignore: Update.

diff -urp -X dontdiff ac-clean/tests/.cvsignore 
ac-test_ifchanged/tests/.cvsignore
--- ac-clean/tests/.cvsignore   2004-12-10 02:08:52.000000000 -0500
+++ ac-test_ifchanged/tests/.cvsignore  2006-03-31 10:31:27.000000000 -0500
@@ -14,4 +14,6 @@ autoreconf
 autom4te
 autoheader
 autoconf
+stamp-tgat
+stamp-acm4
 wrapper.in
diff -urp -X dontdiff ac-clean/tests/Makefile.am 
ac-test_ifchanged/tests/Makefile.am
--- ac-clean/tests/Makefile.am  2006-03-06 16:13:22.000000000 -0500
+++ ac-test_ifchanged/tests/Makefile.am 2006-03-31 10:51:20.000000000 -0500
@@ -1,7 +1,7 @@
 ## Process this file with automake to create Makefile.in. -*-Makefile-*-
 
 ## Makefile for Autoconf testsuite.
-## Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
+## Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006
 ## Free Software Foundation, Inc.
 
 ## This program is free software; you can redistribute it and/or modify
@@ -79,6 +79,10 @@ $(wrappers): wrapper.in
 ## Test suite.  ##
 ## ------------ ##
 
+stamp_tgat = $(srcdir)/stamp-tgat
+stamp_acm4 = $(srcdir)/stamp-acm4
+EXTRA_DIST += $(stamp_tgat) $(stamp_acm4)
+
 TESTSUITE_GENERATED_AT = \
        $(srcdir)/aclang.at \
        $(srcdir)/acc.at \
@@ -112,7 +116,8 @@ TESTSUITE = ./testsuite
 AUTOTEST = ./autom4te --language=autotest
 $(TESTSUITE): $(srcdir)/package.m4 \
              local.at \
-             $(TESTSUITE_AT) \
+             $(TESTSUITE_HAND_AT) \
+             $(stamp_tgat) $(TESTSUITE_GENERATED_AT) \
              $(autotest_m4f_dependencies)
        cd $(top_builddir)/lib/autotest && $(MAKE) $(AM_MAKEFLAGS) autotest.m4f
        $(AUTOTEST) -I $(srcdir) suite.at -o address@hidden
@@ -161,9 +166,54 @@ AUTOCONF_FILES = $(autoconfdir)/general.
                 $(autoconfdir)/types.m4 \
                 $(autoconfdir)/programs.m4
 
-$(TESTSUITE_GENERATED_AT): mktests.sh $(AUTOCONF_FILES)
-       cd $(srcdir) && ./mktests.sh \
-         `echo " "$(AUTOCONF_FILES) | sed 's, [^ ]*/, ../lib/autoconf/,g'`
+# In this discussion, TGAT is short for $(TESTSUITE_GENERATED_AT) and ACM4 for
+# $(AUTOCONF_FILES).  A colon represents a Make dependency from left to right.
+#
+# testsuite : TGAT : ACM4 is natural, but it needlessly rebuilds `testsuite'
+# much of the time.  Only ACM4 changes that introduce a new public macro
+# actually affect TGAT.
+#
+# As a second try, one can keep the same dependencies but only touch the TGAT
+# that change.  One can then edit and test ACM4 without rebuilding testsuite,
+# but as soon as a TGAT is older than an ACM4, every `make check' will run
+# `mktests.sh' to possibly update TGAT.  That cost adds up.
+#
+# In this implementation, we use testsuite : stamp-tgat : stamp-acm4 : ACM4.
+# stamp-acm4 stands for the greatest mtime among ACM4 and stamp-tgat for the
+# greatest mtime among TGAT.  The stamp-tgat rules always run, but they simply
+# check a sentinel that the stamp-acm4 rules set when a TGAT changes.
+#
+# `testsuite' separately depends on TGAT, and TGAT depends on nothing but has
+# the same rebuild rule as stamp-acm4.  That serves to rebuild members of TGAT
+# if the user deletes one of them.
+#
+# This timing diagram shows the implementation in action.  Natural numbers
+# represent abstract time stamps.
+# COMMAND                    TIMESTAMP OF: testsuite stamp-tgat stamp-acm4 ACM4
+# $ rm testsuite stamp-tgat stamp-acm4  |                                     0
+# $ make check                          |  3          1           2           0
+# $ touch lib/autoconf/c.m4; make check |  3          1           5           4
+# $ rm acc.at; make check               |  8          6           7           4
+
+# Command to update TESTSUITE_GENERATED_AT from AUTOCONF_FILEs.  It should not
+# touch files that need no change.  It should return zero if it changed nothing
+# and 55 if it changed something.  Other exit values signify errors.
+do_update = cd $(srcdir) && ./mktests.sh \
+           `echo " "$(AUTOCONF_FILES) | sed 's, [^ ]*/, ../lib/autoconf/,g'`
+
+## Rebuild TESTSUITE_GENERATED_AT when their sources change.
+$(stamp_tgat): $(stamp_acm4)
+       test -f updated && mv -f updated $@; :
+$(stamp_acm4): mktests.sh $(AUTOCONF_FILES)
+       touch updated
+       { ($(do_update)) && \
+           if test -f $(stamp_tgat); then rm -f updated; fi; } \
+         || test $$? -eq 55
+       touch $@
+
+## Rebuild TESTSUITE_GENERATED_AT when the developer deletes one of them.
+$(TESTSUITE_GENERATED_AT):
+       $(do_update) || :
 
 
 ## maintainer-check ##
diff -urp -X dontdiff ac-clean/tests/mktests.sh 
ac-test_ifchanged/tests/mktests.sh
--- ac-clean/tests/mktests.sh   2006-03-06 16:13:22.000000000 -0500
+++ ac-test_ifchanged/tests/mktests.sh  2006-03-31 10:31:27.000000000 -0500
@@ -202,6 +202,7 @@ fi
 ## Creating the test files.  ##
 ## ------------------------- ##
 
+exit_val=0
 for file in $src
 do
   base=`echo "$file" | sed 's,.*[\\/],,;s/\..*//'`
@@ -256,18 +257,27 @@ MK_EOF
   # preserves the old version of the file.  If there is nothing to
   # check, output /rien du tout/[1].
   if grep AT_CHECK ac$base.tat >/dev/null 2>&1; then
-    mv -f ac$base.tat ac$base.at
-    # Help people not to update these files by hand.
-    chmod a-w ac$base.at
+    if diff ac$base.at ac$base.tat >/dev/null 2>&1; then
+       rm -f ac$base.tat
+    else
+       mv -f ac$base.tat ac$base.at
+       # Help people not to update these files by hand.
+       chmod a-w ac$base.at
+       exit_val=55
+    fi
   else
-    rm -f ac$base.tat ac$base.at
-    touch ac$base.at
+    rm -f ac$base.tat
+    if test -s ac$base.at; then
+       rm -f ac$base.at
+       touch ac$base.at
+       exit_val=55
+    fi
   fi
 done
 
 rm -f acdefuns audefuns requires
 
 trap 0
-exit 0
+exit $exit_val
 
 # [1] En franc,ais dans le texte.
Only in ac-test_ifchanged/tests: stamp-tgat




reply via email to

[Prev in Thread] Current Thread [Next in Thread]