https://lists.gnu.org/archive/html/bug-bash/2011-10/msg00036.html
the current yacc rules allow multiple runs to generate the same files. usually
this doesn't come up as the generated files are shipped in the tarball, but
when you modify parse.y (applying a patch or developing or whatever), you can
hit this problem.
simple way of showing this:
make -j y.tab.{c,h}
a correct system would not show the yacc parser running twice :)
simple patch is to have the .h file depend on the .c file, and have the .h file
itself issue a dummy rule (to avoid make thinking things changed).
--- a/Makefile.in
+++ b/Makefile.in
@@ -579,16 +579,17 @@
# old rules
GRAM_H = parser-built
-y.tab.o: y.tab.c ${GRAM_H} command.h ${BASHINCDIR}/stdc.h input.h
+y.tab.o: y.tab.h y.tab.c ${GRAM_H} command.h ${BASHINCDIR}/stdc.h input.h
${GRAM_H}: y.tab.h
@-if test -f y.tab.h ; then \
cmp -s $@ y.tab.h 2>/dev/null || cp -p y.tab.h $@; \
fi
-y.tab.c y.tab.h: parse.y
+y.tab.c: parse.y
# -if test -f y.tab.h; then mv -f y.tab.h old-y.tab.h; fi
$(YACC) -d $(srcdir)/parse.y
touch parser-built
# -if cmp -s old-y.tab.h y.tab.h; then mv old-y.tab.h y.tab.h; else cp -p y.tab.h ${GRAM_H}; fi
+y.tab.h: y.tab.c ; @true
# experimental new rules - work with GNU make but not BSD (or OSF) make
#y.tab.o: y.tab.c y.tab.h
https://lists.gnu.org/archive/html/bug-bash/2011-10/msg00037.html
the current code generates a bunch of local libraries in subdirs and then
links bash against that. those subdirs sometimes need version.h. so they
have a rule to change back up to the parent dir and build version.h (which is
fine). the trouble is that the top level objects and the subdirs are allowed
to build in parallel, so it's possible for multiple children to see that
version.h is not available and that it needs to be created, so they all do.
there is even more trouble is that version.h depends on all the top level
sources, some of which are compiled (like syntax.c). so these parallel
children all kick off a job to generate syntax.c which in turn requires the
mksyntax helper executable. obviously multiple processes rm-ing, compiling,
and linking the same files quickly falls apart.
so tweak the subdirs to all depend on the .build target which in turn depends
on all of these top level files being generated. now the subdirs won't try and
recursively enter the top level.
(noticed by David James)
--- a/Makefile.in
+++ b/Makefile.in
@@ -597,6 +598,11 @@
# $(YACC) -d $(srcdir)/parse.y
# -if cmp -s old-y.tab.h y.tab.h; then mv old-y.tab.h y.tab.h; fi
+# Subdirs will often times want version.h, so they'll change back up to
+# the top level and try to create it. This causes parallel build issues
+# so just force top level sanity before we descend.
+$(LIBDEP): .build
+
$(READLINE_LIBRARY): config.h $(READLINE_SOURCE)
@echo making $@ in ${RL_LIBDIR}
@( { test "${RL_LIBDIR}" = "${libdir}" && exit 0; } || \
http://lists.gnu.org/archive/html/bug-bash/2011-10/msg00107.html
the top level Makefile will recurse into the defdir for multiple targets
(libbuiltins.a, common.o, bashgetopt.o, builtext.h), and since these do
not have any declared interdependencies, parallel makes will recurse into
the subdir and build the respective targets.
nothing depends on common.o or bashgetopt.o, so those targets don't get
used normally. this leaves libbuiltins.a and builtext.h. at a glance,
this shouldn't be a big deal, but when we look closer, there's a subtle
failure lurking.
most of the objects in the defdir need to be generated which means they
need to build+link the local mkbuiltins helper. the builtext.h header
also needs to be generated by the mkbuiltins helper. so when the top
level launches a child for libbuiltins.a and a child for builtext.h, we
can hit a race condition where the two try to generate mkbuiltins, and
the build randomly fails.
so update libbuiltins.a to depend on builtext.h. this should be fairly
simple since it's only a single target.
--- a/Makefile.in
+++ b/Makefile.in
@@ -674,7 +674,7 @@
$(RM) $@
./mksyntax$(EXEEXT) -o $@
-$(BUILTINS_LIBRARY): $(BUILTIN_DEFS) $(BUILTIN_C_SRC) config.h ${BASHINCDIR}/memalloc.h version.h
+$(BUILTINS_LIBRARY): $(BUILTIN_DEFS) $(BUILTIN_C_SRC) config.h ${BASHINCDIR}/memalloc.h ${DEFDIR}/builtext.h version.h
@(cd $(DEFDIR) && $(MAKE) $(MFLAGS) DEBUG=${DEBUG} libbuiltins.a ) || exit 1
# these require special rules to circumvent make builtin rules