Hello.
Thank you for reporting the issue.
The attached patch should fix the problem. It may be a bit of an
overkill, perhaps just one of the fixes would suffice, but it seems to
work at least.
I've re-made your useful script into an Automake test. Since
non-deterministic defects may be hard to find and fix, and certainly
harder to test if they're fixed, the new version simply runs parallel
'make recheck' a few times "just in case". Without the fix, the test
failed in the first or the second run. With the fix, the test (which
runs 'make recheck' 5 times) passed 5 times in a row. This *should* be
a decent sample.
All tests with "check" in the name pass.
The test and my patch can, of course, be adapted and further changed.
--
Regards - Bogdan ('bogdro') D. (GNU/Linux & FreeDOS)
X86 assembly (DOS, GNU/Linux): http://bogdro.evai.pl/index-en.php
Soft(EN): http://bogdro.evai.pl/soft http://bogdro.evai.pl/soft4asm
www.Xiph.org www.TorProject.org www.LibreOffice.org www.GnuPG.org
From eb64fc56f13955a0b05b89492f48df886311191f Mon Sep 17 00:00:00 2001
From: Bogdan Drozdowski <>
Date: Sat, 17 Aug 2024 00:17:35 +0200
Subject: [PATCH] Bug#68860 Fix race condition in recheck
---
bin/automake.in | 6 +-
lib/am/check.am | 2 +-
t/list-of-tests.mk | 1 +
t/recheck-race.sh | 135 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 141 insertions(+), 3 deletions(-)
create mode 100644 t/recheck-race.sh
diff --git a/bin/automake.in b/bin/automake.in
index a17f45236..1d6c29d1c 100644
--- a/bin/automake.in
+++ b/bin/automake.in
@@ -4705,12 +4705,14 @@ sub do_check_merge_target ()
# The check target must depend on the local equivalent of
# 'all', to ensure all the primary targets are built. Then it
# must build the local check rules.
- $output_rules .= "check-am: all-am\n";
+ $output_rules .= "check-am: all-am";
if (@check)
{
- pretty_print_rule ("\t\$(MAKE) \$(AM_MAKEFLAGS)", "\t ", @check);
+ $output_rules .= " @check";
+ #pretty_print_rule ("\t\$(MAKE) \$(AM_MAKEFLAGS)", "\t ", @check);
depend ('.MAKE', 'check-am');
}
+ $output_rules .= "\n";
if (@check_tests)
{
diff --git a/lib/am/check.am b/lib/am/check.am
index e51a771bf..72c71a0f4 100644
--- a/lib/am/check.am
+++ b/lib/am/check.am
@@ -480,7 +480,7 @@ check-TESTS: %CHECK_DEPS%
## Recheck must depend on $(check_SCRIPTS), $(check_PROGRAMS), etc.
## It must also depend on the 'all' target. See automake bug#11252.
-recheck: all %CHECK_DEPS%
+recheck: all-am %CHECK_DEPS%
## See comments above in the check-TESTS recipe for why remove
## $(TEST_SUITE_LOG) here.
@$(am__rm_f) $(TEST_SUITE_LOG)
diff --git a/t/list-of-tests.mk b/t/list-of-tests.mk
index e80ace470..f359ba8a1 100644
--- a/t/list-of-tests.mk
+++ b/t/list-of-tests.mk
@@ -824,6 +824,7 @@ t/parallel-tests-no-spurious-summary.sh \
t/parallel-tests-exit-statuses.sh \
t/parallel-tests-console-output.sh \
t/parallel-tests-once.sh \
+t/recheck-race.sh \
t/tests-environment.sh \
t/am-tests-environment.sh \
t/tests-environment-backcompat.sh \
diff --git a/t/recheck-race.sh b/t/recheck-race.sh
new file mode 100644
index 000000000..abeb8c441
--- /dev/null
+++ b/t/recheck-race.sh
@@ -0,0 +1,135 @@
+#! /bin/sh
+# Copyright (C) 2024 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 2, 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 <https://www.gnu.org/licenses/>.
+
+# Test for race conditions in 'make recheck'.
+
+. test-init.sh
+
+cat > configure.ac <<EOF
+AC_INIT([foo], [2])
+AC_CONFIG_SRCDIR([config.h.in])
+AC_CONFIG_HEADERS([config.h])
+AM_INIT_AUTOMAKE([foreign silent-rules parallel-tests])
+AC_LANG([C++])
+AC_PROG_CXX
+AC_PROG_CXXCPP
+AC_PROG_RANLIB
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
+EOF
+
+cat > Makefile.am <<EOF
+lib_LIBRARIES = libfoo.a
+libfoo_a_SOURCES = foo.cc
+
+check_LIBRARIES = libtest.a
+libtest_a_SOURCES = test.cc
+
+TESTS = one.test two.test
+TEST_EXTENSIONS = .test
+AM_DEFAULT_SOURCE_EXT = .cc
+EXTRA_PROGRAMS = \$(TESTS)
+
+libtest_a_LIBADD = libfoo.a
+LDADD = libtest.a libfoo.a
+EOF
+
+cat > foo.h <<EOF
+#ifndef my_foo_h
+#define my_foo_h
+#include <string>
+std::string foo(void);
+#endif
+EOF
+
+cat > foo.cc <<EOF
+#include <config.h>
+#include "foo.h"
+std::string foo(void) { return "fu"; }
+
+EOF
+
+cat > one.cc <<EOF
+#include <config.h>
+#include "foo.h"
+#include "test.h"
+#include <iostream>
+#include <string>
+int main(int argc, char* argv[])
+{
+ init(argc, argv);
+ std::cout << "Hello World!\n" << foo() << "\n";
+ return 0;
+}
+EOF
+
+cat > two.cc <<EOF
+#include <config.h>
+#include "foo.h"
+#include "test.h"
+#include <iostream>
+#include <string>
+int main(int argc, char* argv[])
+{
+ init(argc, argv);
+ std::string str = foo();
+ if (str != "foo") {
+ std::cerr << "error: foo(): " << str << "\n";
+ return 1;
+ }
+ return 0;
+}
+EOF
+
+cat > test.h <<EOF
+#ifndef my_test_h
+#define my_test_h
+void init(int argc, char* argv[]);
+#endif
+EOF
+
+cat > test.cc <<EOF
+#include <config.h>
+#include "test.h"
+#include "foo.h"
+#include <iostream>
+void init(int argc, char* argv[])
+{
+ std::cout << "init test for " << foo() << "\n";
+}
+EOF
+
+$ACLOCAL
+$AUTOCONF
+$AUTOHEADER
+$AUTOMAKE -a
+./configure --enable-silent-rules
+$MAKE all -j8
+run_make -M -e FAIL check -j8
+
+sed 's,"fu","foo",' < foo.cc > foo.cc-t && mv foo.cc-t foo.cc
+
+$MAKE recheck -j16
+$MAKE clean all
+$MAKE recheck -j16
+$MAKE clean all
+$MAKE recheck -j16
+$MAKE clean all
+$MAKE recheck -j16
+$MAKE clean all
+$MAKE recheck -j16
+
+:
--
2.35.1