Subject: bug#8365: 3 of 657 tests failed

From: Stefano Lattarini <[email-masked]>
Date: Wed, 30 Mar 2011 18:10:23 +0200

Reference:
  <http://debbugs.gnu.org/cgi/bugreport.cgi?bug=8365>

Hi Sam, and thanks for the report.

> FAIL: aclocal6.test (exit: 1)
> =============================
> 
> /home/sds/src/automake-1.11.1/tests:/home/sds/src/top/bin:/usr/lib6
> 4/qt-3.3/bin:/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/usr/NX
> /bin:/home/sds/bin:/sbin:/usr/sbin:/usr/NX/bin:/usr/NX/bin:/home/sd
> s/bin:/sbin:/usr/sbin:/usr/NX/bin:/home/sds/bin:/sbin:/usr/sbin
> aclocal6: running make --version -v | grep GNU
> GNU Make 3.81
> === Running test ./aclocal6.test
> ++ pwd
> /home/sds/src/automake-1.11.1/tests/aclocal6.dir
> + set -e
> + cat
> + cat
> + mkdir sub
> + :
> + mkdir m4
> + echo 'AC_DEFUN([SOME_DEFS], [])'
> + echo 'AC_DEFUN([MORE_DEFS], [AC_SUBST([GREPME])])'
> + aclocal-1.11 -Werror -I m4
> + autoconf
> + automake-1.11 --foreign -Werror -Wall --copy --add-missing
> + test -d autom4te.cache
> + test_cache='test -d'
> + mkdir build
> + cd build
> + ../configure
> checking for a BSD-compatible install... /usr/bin/install -c
> checking whether build environment is sane... yes
> checking for a thread-safe mkdir -p... /bin/mkdir -p
> checking for gawk... gawk
> checking whether make sets $(MAKE)... yes
> configure: creating ./config.status
> config.status: creating Makefile
> config.status: creating sub/Makefile
> + make
> Making all in sub
> make[1]: Entering directory `/home2/sds/src/automake-1.11.1/tests/aclocal6.dir/build/sub'
> make[1]: Nothing to be done for `all'.
> make[1]: Leaving directory `/home2/sds/src/automake-1.11.1/tests/aclocal6.dir/build/sub'
> make[1]: Entering directory `/home2/sds/src/automake-1.11.1/tests/aclocal6.dir/build'
> make[1]: Nothing to be done for `all-am'.
> make[1]: Leaving directory `/home2/sds/src/automake-1.11.1/tests/aclocal6.dir/build'
> + echo 'AC_DEFUN([SOME_DEFS], [MORE_DEFS])'
> + echo 'AC_SUBST([METOO])'
> + cd sub
> + make
> cd .. && make  am--refresh
> make[1]: Entering directory `/home2/sds/src/automake-1.11.1/tests/aclocal6.dir/build'
>  CDPATH="${ZSH_VERSION+.}:" && cd .. && /bin/sh /home/sds/src/automake-1.11.1/tests/aclocal6.dir/missing --run aclocal-1.11 -I m4
>  cd .. && /bin/sh /home/sds/src/automake-1.11.1/tests/aclocal6.dir/missing --run automake-1.11 --foreign
>  CDPATH="${ZSH_VERSION+.}:" && cd .. && /bin/sh /home/sds/src/automake-1.11.1/tests/aclocal6.dir/missing --run autoconf
>
Correct so far: aclocal.m4 dependencies are modified, so the
Automake-generated Makefile re-runs aclocal, autoconf and automake ...

> make[1]: Leaving directory `/home2/sds/src/automake-1.11.1/tests/aclocal6.dir/build'
>
... but then it doesn't re-run configure!  So that the Makefile(s) are not
updated, and consequently ...

> make[1]: Entering directory `/home2/sds/src/automake-1.11.1/tests/aclocal6.dir/build'
> make[1]: Leaving directory `/home2/sds/src/automake-1.11.1/tests/aclocal6.dir/build'
> make: Nothing to be done for `all'.
> + cd ..
> + grep GREPME Makefile
> + exit_status=1
>
... this check fails.

-*-*-

Now, why is configure not re-run?  Here is my (longish) tentative explanation,
step by step. In what follows, I'll use the abbraviation `TS(f)' to indicate
the timestamp (i.e. last modification time) of the file `f'.

 01. configure is run for the first time; it concludes its execution creating
     the `config.status' script and the `Makefile' and `sub/Makefile' files,
     which are all assured to be created older than configure (see code in
     sanity.m4:AM_SANITY_CHECK).

 02. Since the creations of `config.status', `Makefile' and `sub/Makefile'
     take place very near, it's quite likely they'll have the same timestamp;
     let's assume this is indeed the case:
       [E1] TS(config.status) = TS(Makefile) = TS(sub/Makefile)

 03. make is run for the first time; all is up-to-date at this point, so that
     nothing gets rebuilt -- basically a no-op;

 04. the test script modifies the aclocal dependencies `m4/somedef.m4' and
     `acinclude.m4', *without sleeping* before doing this modification (this
     lack of a `sleep' is very important; see point 7 below).

 05. make is called again right away *from the `sub' subdirectory*; it sees
     that `m4/somedef.m4' and `acinclude.m4' are newer than `sub/Makefile.in'
     (which depends on them), and it knows that `sub/Makefile' depends on
     `sub/Makefile.in'.  So a recursive make call is issued, to run the
     special target `am--refresh' *in the top-level directory*, in order to
     bring `sub/Makefile.in' up-to-date.

 06. This "recursive" make, running in the top-level directory, similarly
     sees that `m4/somedef.m4' and `acinclude.m4' are newer than `Makefile.in'
     (which depends on them), and that `Makefile' depends on `Makefile.in'.
     It also sees that `Makefile' depends on `config.status', which in turn
     depends on `configure', which in turn depends on `aclocal.m4'.

 07. At this point, make issues calls to aclocal, autoconf and automake in
     order to bring up-to-date the various files that `Makefile' depends on.
     After the autotools have run, we have:
      [E3] for each x in { Makefile.in, sub/Makefile.in, configure, aclocal.m4 }
           for each y in { config.status, sub/Makefile, Makefile, m4/somedef.m4,
                           acinclude.m4 }
           it is TS(x) >= TS(y)

 08. Now, since no explicit call to `sleep' has been issued in any of the
     preceding steps (from (2) to (7)), it's very well possible (assuming
     those steps have been executed fast enough, as would mayhap be possible
     on a fast, lighlty loaded system) that all the files updated until now
     still have the *same* timestamp of `config.status'.  Let's assume this
     is indeed the case; so we have:
       [E4] TS(Makefile.in) = TS(sub/Makefile.in) = TS(configure) =
            = TS(aclocal.m4) = TS(m4/somedef.m4) = TS(acinclude.m4) =
            = TS(config.status) = TS(Makefile) = TS(sub/Makefile).

 09. Reprising the dependency analysis of pass (6), make (in top-level
     directory) now sees that `config.status' is *not* older than `configure';
     so `config.status --recheck' (which would be responsible to re-run
     configure, and regenerate an updated `config.status') won't be called.
     Similarly, both `config.status' and `Makefile.in' are *not* older than
     `Makefile', so Makefile won't be regenerated either (it would have been
     if .`config.status --recheck' had been run).
     At this point, the work in the top-level directory is concluded.

 10. Back in the `sub' subdirectory, a similar situation arises: now
     `config.status' and `sub/Makefile.in' are fully up-to-date *for what
     concerns the timestamps*, thanks to the work done by the top-level
     Makefile; yet, they are *not* newer than `sub/Makefile' (see [E4]),
     which consequently doesn't get rebuilt.

 11. Failure ensues. D'oh!

-*-*-

Ralf, does the above explanation sounds sensible to you?  If yes, OK to
apply the attached trivial patch (to maint) to fix this failure?

Sam, have you by chance kept the content of the *.dir directories for the
failed tests?  If yes, could you please send them to me? (Notice that you
might have to send them off-list, as I'm not sure how the policy about size
and format of attachements on the automake-patches list is).  This way I
could verify whether my explanation is correct.

Thanks,
   Stefano
From 2dff1fdaf0f2cf37980307b7413984dfb6ac155b Mon Sep 17 00:00:00 2001
From: Stefano Lattarini <[email-masked]>
Date: Wed, 30 Mar 2011 18:06:29 +0200
Subject: [PATCH] tests: fix timestamp-related spurious failure in aclocal6.test

Related to automake bug#8365.

* tests/aclocal6.test: Sleep before modifying m4 files that should
trigger remake rules.  This fixes an hard-to-hit timestamp-related
race condition.

Report from Sam Steingold.
---
 ChangeLog           |    9 +++++++++
 tests/aclocal6.test |    2 ++
 2 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index dae2a48..bafedb1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2011-03-30  Stefano Lattarini  <[email-masked]>
+
+	tests: fix timestamp-related spurious failure in aclocal6.test
+	Related to automake bug#8365.
+	* tests/aclocal6.test: Sleep before modifying m4 files that should
+	trigger remake rules.  This fixes an hard-to-hit timestamp-related
+	race condition.
+	Report from Sam Steingold.
+
 2011-03-21  Ralf Wildenhues  <[email-masked]>
 
 	tests: fix unindent to use printf not echo for script.
diff --git a/tests/aclocal6.test b/tests/aclocal6.test
index ea6bac3..fb3842c 100755
--- a/tests/aclocal6.test
+++ b/tests/aclocal6.test
@@ -57,6 +57,8 @@ cd build
 ../configure
 $MAKE
 
+# Modified configure dependencies must be newer than config.status.
+$sleep
 # Update an aclocal.m4 dependency, then make sure all Makefiles
 # are updated, even from a sub-directory.
 echo 'AC_DEFUN([SOME_DEFS], [MORE_DEFS])' > ../m4/somedefs.m4
-- 
1.7.2.3