From: Kyrylo Tkachov <[email protected]>
This is an attempt to fix bootstrap comparison on Darwin and Solaris.
Rainer, Iain, could you help with testing it?
The comparison writes a makefile and runs it under $(MAKE). Building and
running that makefile assumed GNU sed, and assumed more of the shell than
several hosts provide. Four defects, all from 54c3bdc8ad6.
The comparison command was escaped for the generated makefile with
printf '%s' "$cmp_raw" | sed 's,\$,$$,g'
whose input carries no trailing newline. GNU sed passes that through
unchanged, a POSIX sed terminates the last line, and Solaris /usr/bin/sed
drops it. The first splits the recipe in two, and the sub-make stops with
compare.42895.mk:5: *** missing separator. Stop.
The second leaves a bare redirection where the comparison should be, so every
object is judged equal and the bootstrap reports "Comparison successful"
having compared nothing. Double the '$' characters with $(subst), which make
can do on its own.
The exit traps use "trap - 0", which Solaris 10 /bin/sh takes for a command
named '-', and recover the status with "$?", which Zsh and Solaris 10 /bin/sh
answer with the status of the command before the "exit" rather than its
argument. The recipe reports a comparison failure with "exit 1" right after
a successful "mv", so on those shells the trap recovers zero and lets the
failure through as success. A trap that only removes files needs neither.
Let the shell exit with the status it already has.
The comparator fallback installs its trap in a subshell that ends in "cmp",
and several shells do not run an exit trap from a subshell whose last command
is not a builtin. Now that the temporaries are process specific, a trap that
does not run leaks a pair of files per object. End the subshell with a
builtin.
The generated makefile did not name the shell. make neither exports SHELL
nor lets a sub-make inherit it, so the comparisons ran under /bin/sh rather
than the shell configure chose.
The serial comparison removed .bad_compare before starting. That file is now
written only by a comparison that completes and finds a difference, so a
sub-make that fails first leaves the previous run's result in place, still
named in the failure message. Shards from a run killed with SIGKILL survive
too, keyed on a pid a later comparison can draw. Remove both up front.
Ok for trunk?
Thanks,
Kyrill
ChangeLog:
PR bootstrap/126875
* Makefile.tpl ([+compare-target+]): Escape the comparison command
with $(subst) rather than a sed pipe. Clean up from the exit trap
without resetting it or re-deriving the exit status. Name the shell
in the generated makefile. Remove any previous result file and
result shards before comparing.
* Makefile.in: Regenerate.
* configure: Regenerate.
config/ChangeLog:
PR other/126875
* acx.m4 (ACX_PROG_CMP_IGNORE_INITIAL): Clean up from the exit trap
without resetting it, and end the fallback subshell with a builtin so
that the trap runs.
Signed-off-by: Kyrylo Tkachov <[email protected]>
---
Makefile.in | 30 ++++++++++++++++++++----------
Makefile.tpl | 15 ++++++++++-----
config/acx.m4 | 7 +++----
configure | 7 +++----
4 files changed, 36 insertions(+), 23 deletions(-)
diff --git a/Makefile.in b/Makefile.in
index 5cca69c3f52..24374257381 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -66024,7 +66024,10 @@ do-clean: clean-stage3
# Run the comparisons in parallel through a generated sub-makefile under
# the jobserver. Each failing recipe writes a separate result shard that
-# is collected after the sub-make finishes.
+# is collected after the sub-make finishes. The comparison command is
+# written into that makefile, so double its '$' characters to survive the
+# expansion the sub-make performs when it reads them back, and name the
+# shell there, which a sub-make does not inherit.
compare:
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
@@ -66036,22 +66039,24 @@ compare:
compare_id=$$$$; \
bad_compare=.bad_compare.$$compare_id; export bad_compare; \
compare_makefile=compare.$$compare_id.mk; \
- trap 'st=$$?; rm -f "$$compare_makefile" "$$bad_compare" \
- "$$bad_compare".*; trap - 0; exit $$st' 0; \
+ trap ':; rm -f "$$compare_makefile" "$$bad_compare" \
+ "$$bad_compare".*' 0; \
trap 'exit 1' 1 2 3 15; \
+ rm -f .bad_compare "$$bad_compare" "$$bad_compare".*; \
echo Comparing stages 2 and 3; \
sed=`echo stage3 | sed 's,^stage,,;s,.,.,g'`; \
files=`find stage3-* -name "*$(objext)" -print | \
sed -n s,^stage$$sed-,,p`; \
- cmp_raw='$(do-compare)'; \
+ cmp_cmd='$(subst $$,$$$$,$(do-compare))'; \
{ \
+ echo 'SHELL = $(SHELL)'; \
echo 'all:'; \
echo '.PHONY: all FORCE'; \
echo 'FORCE:'; \
printf 'compare/%%: FORCE ; @'; \
printf 'f1=$$$$r/stage2-$$*; '; \
printf 'f2=$$$$r/stage3-$$*; '; \
- printf '%s' "$$cmp_raw" | sed 's,\$$,$$$$,g'; \
+ printf '%s' "$$cmp_cmd"; \
printf ' > /dev/null 2>&1; st=$$$$?; '; \
printf 'if test $$$$st -eq 1; then '; \
printf 'case $$* in '; \
@@ -66484,7 +66489,10 @@ do-clean: clean-stage4
# Run the comparisons in parallel through a generated sub-makefile under
# the jobserver. Each failing recipe writes a separate result shard that
-# is collected after the sub-make finishes.
+# is collected after the sub-make finishes. The comparison command is
+# written into that makefile, so double its '$' characters to survive the
+# expansion the sub-make performs when it reads them back, and name the
+# shell there, which a sub-make does not inherit.
compare3:
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
@@ -66496,22 +66504,24 @@ compare3:
compare_id=$$$$; \
bad_compare=.bad_compare.$$compare_id; export bad_compare; \
compare_makefile=compare3.$$compare_id.mk; \
- trap 'st=$$?; rm -f "$$compare_makefile" "$$bad_compare" \
- "$$bad_compare".*; trap - 0; exit $$st' 0; \
+ trap ':; rm -f "$$compare_makefile" "$$bad_compare" \
+ "$$bad_compare".*' 0; \
trap 'exit 1' 1 2 3 15; \
+ rm -f .bad_compare "$$bad_compare" "$$bad_compare".*; \
echo Comparing stages 3 and 4; \
sed=`echo stage4 | sed 's,^stage,,;s,.,.,g'`; \
files=`find stage4-* -name "*$(objext)" -print | \
sed -n s,^stage$$sed-,,p`; \
- cmp_raw='$(do-compare3)'; \
+ cmp_cmd='$(subst $$,$$$$,$(do-compare3))'; \
{ \
+ echo 'SHELL = $(SHELL)'; \
echo 'all:'; \
echo '.PHONY: all FORCE'; \
echo 'FORCE:'; \
printf 'compare3/%%: FORCE ; @'; \
printf 'f1=$$$$r/stage3-$$*; '; \
printf 'f2=$$$$r/stage4-$$*; '; \
- printf '%s' "$$cmp_raw" | sed 's,\$$,$$$$,g'; \
+ printf '%s' "$$cmp_cmd"; \
printf ' > /dev/null 2>&1; st=$$$$?; '; \
printf 'if test $$$$st -eq 1; then '; \
printf 'case $$* in '; \
diff --git a/Makefile.tpl b/Makefile.tpl
index 98bd03e9a33..3123c21eab3 100644
--- a/Makefile.tpl
+++ b/Makefile.tpl
@@ -1823,7 +1823,10 @@ do-clean: clean-stage[+id+]
[+ IF compare-target +]
# Run the comparisons in parallel through a generated sub-makefile under
# the jobserver. Each failing recipe writes a separate result shard that
-# is collected after the sub-make finishes.
+# is collected after the sub-make finishes. The comparison command is
+# written into that makefile, so double its '$' characters to survive the
+# expansion the sub-make performs when it reads them back, and name the
+# shell there, which a sub-make does not inherit.
[+compare-target+]:
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
@@ -1835,22 +1838,24 @@ do-clean: clean-stage[+id+]
compare_id=$$$$; \
bad_compare=.bad_compare.$$compare_id; export bad_compare; \
compare_makefile=[+compare-target+].$$compare_id.mk; \
- trap 'st=$$?; rm -f "$$compare_makefile" "$$bad_compare" \
- "$$bad_compare".*; trap - 0; exit $$st' 0; \
+ trap ':; rm -f "$$compare_makefile" "$$bad_compare" \
+ "$$bad_compare".*' 0; \
trap 'exit 1' 1 2 3 15; \
+ rm -f .bad_compare "$$bad_compare" "$$bad_compare".*; \
echo Comparing stages [+prev+] and [+id+]; \
sed=`echo stage[+id+] | sed 's,^stage,,;s,.,.,g'`; \
files=`find stage[+id+]-* -name "*$(objext)" -print | \
sed -n s,^stage$$sed-,,p`; \
- cmp_raw='$(do-[+compare-target+])'; \
+ cmp_cmd='$(subst $$,$$$$,$(do-[+compare-target+]))'; \
{ \
+ echo 'SHELL = $(SHELL)'; \
echo 'all:'; \
echo '.PHONY: all FORCE'; \
echo 'FORCE:'; \
printf '[+compare-target+]/%%: FORCE ; @'; \
printf 'f1=$$$$r/stage[+prev+]-$$*; '; \
printf 'f2=$$$$r/stage[+id+]-$$*; '; \
- printf '%s' "$$cmp_raw" | sed 's,\$$,$$$$,g'; \
+ printf '%s' "$$cmp_cmd"; \
printf ' > /dev/null 2>&1; st=$$$$?; '; \
printf 'if test $$$$st -eq 1; then '; \
printf 'case $$* in '; \
diff --git a/config/acx.m4 b/config/acx.m4
index 5547cbeb9b8..0af0b371bf2 100644
--- a/config/acx.m4
+++ b/config/acx.m4
@@ -477,16 +477,15 @@ AC_DEFUN([ACX_PROG_CMP_IGNORE_INITIAL],
[AC_CACHE_CHECK([how to compare bootstrapped objects], gcc_cv_prog_cmp_skip,
[ echo abfoo >t1
echo cdfoo >t2
- gcc_cv_prog_cmp_skip='(trap "st=\$$?; rm -f tmp-foo1.$$$$ '
- gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tmp-foo2.$$$$; '
- gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'trap - 0; exit \$$st" 0; '
+ gcc_cv_prog_cmp_skip='(trap ":; rm -f tmp-foo1.$$$$ '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tmp-foo2.$$$$" 0; '
gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'trap "exit 2" 1 2 3 15; '
gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tail -c +17 $$f1 '
gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'> tmp-foo1.$$$$ || exit 2; '
gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tail -c +17 $$f2 '
gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'> tmp-foo2.$$$$ || exit 2; '
gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'cmp tmp-foo1.$$$$ '
- gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tmp-foo2.$$$$)'
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tmp-foo2.$$$$; exit $$?)'
if cmp t1 t2 2 2 > /dev/null 2>&1; then
if cmp t1 t2 1 1 > /dev/null 2>&1; then
:
diff --git a/configure b/configure
index 4db0edbdccd..fc27b526f78 100755
--- a/configure
+++ b/configure
@@ -6123,16 +6123,15 @@ if ${gcc_cv_prog_cmp_skip+:} false; then :
else
echo abfoo >t1
echo cdfoo >t2
- gcc_cv_prog_cmp_skip='(trap "st=\$$?; rm -f tmp-foo1.$$$$ '
- gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tmp-foo2.$$$$; '
- gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'trap - 0; exit \$$st" 0; '
+ gcc_cv_prog_cmp_skip='(trap ":; rm -f tmp-foo1.$$$$ '
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tmp-foo2.$$$$" 0; '
gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'trap "exit 2" 1 2 3 15; '
gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tail -c +17 $$f1 '
gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'> tmp-foo1.$$$$ || exit 2; '
gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tail -c +17 $$f2 '
gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'> tmp-foo2.$$$$ || exit 2; '
gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'cmp tmp-foo1.$$$$ '
- gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tmp-foo2.$$$$)'
+ gcc_cv_prog_cmp_skip="$gcc_cv_prog_cmp_skip"'tmp-foo2.$$$$; exit $$?)'
if cmp t1 t2 2 2 > /dev/null 2>&1; then
if cmp t1 t2 1 1 > /dev/null 2>&1; then
:
--
2.50.1 (Apple Git-155)