build: serialize module@X/lib@X per directory to fix a -j race
main@ depends on both `modules` and `libs`, so `module@X` (`make -C X module`) and `lib@X` (`make -C X lib`) could run in the same directory concurrently under -j and race on X's shared objects -- each %.o recipe does `rm $*.o; cc -c`, so one make would delete/rebuild an object while the other was linking it, e.g. `ld: cannot find touchtypes.o` while linking libutils.o. It was rare (timing dependent) but real; it surfaced on a --without-tcl --disable-readline -j12 build. Make `lib@%` depend on its own `module@%`: module@X builds the objects, lib@X then only archives them, so the two never touch X's *.o at the same time. Cross-directory parallelism is unchanged (lib@X waits only on module@X, not the whole modules phase). Verified: 4/4 clean --without-tcl -j12 builds pass (previously intermittently failed); Tcl -j12 still builds 375 files. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c05ac60851
commit
5d6c9899d4
|
|
@ -106,7 +106,13 @@ LIB_TARGETS := $(addprefix lib@,${MODULES})
|
|||
.PHONY: $(MODULE_TARGETS) $(LIB_TARGETS)
|
||||
$(MODULE_TARGETS): module@%: ${DATABASE_H}
|
||||
@$(call submake,$*,module)
|
||||
$(LIB_TARGETS): lib@%: ${DATABASE_H}
|
||||
# lib@X depends on module@X (its OWN module): main@ pulls both `modules` and
|
||||
# `libs`, so without this `make -C X module` and `make -C X lib` can run in the
|
||||
# same directory at once under -j and race on X's shared *.o (each recipe does
|
||||
# `rm $*.o; cc -c $*.o`). Serializing them per-dir removes the race; module@X
|
||||
# builds the objects and lib@X then just archives them. Cross-dir parallelism is
|
||||
# unaffected (lib@X only waits on module@X, not the whole modules phase).
|
||||
$(LIB_TARGETS): lib@%: ${DATABASE_H} module@%
|
||||
@$(call submake,$*,lib)
|
||||
|
||||
# Cross-module archive edge (-j correctness): libdatabase.a physically archives
|
||||
|
|
|
|||
Loading…
Reference in New Issue