make: build driver-produced binaries in persistent -w workdirs

The five wwstage tools, wwtest, wwfixture, both exec-test binaries, and
the package-test binary move off the per-invocation mktemp workspace to
one persistent ww-build workdir per target under out/wwbuild/, publishing
into out/bin by one atomic mv. Package artifacts now survive across
rebuilds and reuse on exact content identity, so a toolchain-source
touch rebuilds in seconds instead of five from-scratch sep builds; the
per-target split keeps -jN recipe concurrency race-free. Rebuilt
binaries verified byte-identical to the mktemp-path builds for all ten
targets.
This commit is contained in:
2026-08-08 03:54:29 +09:00
parent e06b871ab9
commit 7bb31f8cb3

167
Makefile
View File

@@ -109,6 +109,14 @@ CSTAGE_BINS = $(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l $(BIN)/wwdump
# (tests 990-994).
WWSTAGE_BINS = $(BIN)/wwdump_ww $(BIN)/w6c_ww $(BIN)/w6a_ww $(BIN)/w6l_ww $(BIN)/ww_ww
# Driver-produced binaries build in persistent per-target `ww build -w`
# workdirs: package artifacts are reused across rebuilds on exact content
# identity (see docs/test-system-v2.md), and the finished binary is
# published into $(BIN) by one atomic mv. One workdir per target keeps
# `make -jN` recipe concurrency race-free. test-incremental proves the
# reuse path byte-identical to a from-scratch build.
WWBUILD = $(OUT)/wwbuild
BINS = $(CSTAGE_BINS) $(WWSTAGE_BINS) $(WWTEST_BIN)
LIBS = $(LIB)/libwcc.a $(LIB)/libwwrt.a
@@ -174,17 +182,12 @@ $(BIN)/wwdump_ww: selfhost/cmd/wwdump/main.ww \
lib/os/os.ww lib/rt/malloc.ww lib/time/time.ww lib/strconv/strconv.ww lib/strconv/stof_data.ww lib/strconv/decimal.ww lib/strconv/stof.ww lib/strconv/ftos_data.ww lib/strconv/ftos.ww lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww lib/ascii/ascii.ww lib/errors/errors.ww lib/io/io.ww lib/io/stream.ww lib/io/types.ww lib/memio/memio.ww lib/fmt/fmt.ww \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
$(LIB)/libwwrt.a | $(BIN)
@mkdir -p $(BIN)/wwdump_ww.d
@d=$$(mktemp -d "$(CURDIR)/$(BIN)/wwdump_ww.d/build.XXXXXX") || exit 1; \
rc=0; published=0; \
(cd "$$d" && $(CURDIR)/$(BIN)/ww build -o main \
-I $(CURDIR)/lib/ww -I $(CURDIR)/selfhost/cmd/wcc \
$(CURDIR)/selfhost/cmd/wwdump/main.ww) || rc=$$?; \
rm -rf -- "$$d/main.sepwork" || { echo "$@: scratch cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; \
if [ $$rc -eq 0 ]; then mv "$$d/main" "$(CURDIR)/$@" && published=1 || rc=$$?; fi; \
if [ $$published -eq 0 ]; then rm -f -- "$$d/main" || { echo "$@: output cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; fi; \
if ! rmdir "$$d"; then echo "$@: workspace cleanup failed" >&2; if [ $$published -eq 1 ]; then rm -f -- "$(CURDIR)/$@" || echo "$@: published-output cleanup failed" >&2; fi; if [ $$rc -eq 0 ]; then rc=1; fi; fi; \
exit $$rc
@mkdir -p $(WWBUILD)/wwdump_ww
@$(CURDIR)/$(BIN)/ww build -w $(WWBUILD)/wwdump_ww \
-o $(WWBUILD)/wwdump_ww/main \
-I $(CURDIR)/lib/ww -I $(CURDIR)/selfhost/cmd/wcc \
$(CURDIR)/selfhost/cmd/wwdump/main.ww
@mv $(WWBUILD)/wwdump_ww/main $@
# ---- ww-side w6c (compiler port, exercised by 994_w6c_ww) -------------
# Thin driver: parse + cgen. The frontend (lex/parse/ast/...) is the
@@ -199,17 +202,12 @@ $(BIN)/w6c_ww: selfhost/cmd/w6c/main.ww \
lib/os/os.ww lib/rt/malloc.ww lib/time/time.ww lib/strconv/strconv.ww lib/strconv/stof_data.ww lib/strconv/decimal.ww lib/strconv/stof.ww lib/strconv/ftos_data.ww lib/strconv/ftos.ww lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww lib/ascii/ascii.ww lib/errors/errors.ww lib/io/io.ww lib/io/stream.ww lib/io/types.ww lib/memio/memio.ww lib/fmt/fmt.ww \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
$(LIB)/libwwrt.a | $(BIN)
@mkdir -p $(BIN)/w6c_ww.d
@d=$$(mktemp -d "$(CURDIR)/$(BIN)/w6c_ww.d/build.XXXXXX") || exit 1; \
rc=0; published=0; \
(cd "$$d" && $(CURDIR)/$(BIN)/ww build -o main \
-I $(CURDIR)/lib/ww -I $(CURDIR)/selfhost/cmd/wcc \
$(CURDIR)/selfhost/cmd/w6c/main.ww) || rc=$$?; \
rm -rf -- "$$d/main.sepwork" || { echo "$@: scratch cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; \
if [ $$rc -eq 0 ]; then mv "$$d/main" "$(CURDIR)/$@" && published=1 || rc=$$?; fi; \
if [ $$published -eq 0 ]; then rm -f -- "$$d/main" || { echo "$@: output cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; fi; \
if ! rmdir "$$d"; then echo "$@: workspace cleanup failed" >&2; if [ $$published -eq 1 ]; then rm -f -- "$(CURDIR)/$@" || echo "$@: published-output cleanup failed" >&2; fi; if [ $$rc -eq 0 ]; then rc=1; fi; fi; \
exit $$rc
@mkdir -p $(WWBUILD)/w6c_ww
@$(CURDIR)/$(BIN)/ww build -w $(WWBUILD)/w6c_ww \
-o $(WWBUILD)/w6c_ww/main \
-I $(CURDIR)/lib/ww -I $(CURDIR)/selfhost/cmd/wcc \
$(CURDIR)/selfhost/cmd/w6c/main.ww
@mv $(WWBUILD)/w6c_ww/main $@
# ---- ww-side w6a (assembler port, exercised by 991_w6a_ww) ------------
# Built like wwdump_ww. Needs -I selfhost/cmd/w6a for the local types/lex/
@@ -221,17 +219,12 @@ $(BIN)/w6a_ww: selfhost/cmd/w6a/main.ww selfhost/cmd/w6a/opcodes.ww \
lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
$(LIB)/libwwrt.a | $(BIN)
@mkdir -p $(BIN)/w6a_ww.d
@d=$$(mktemp -d "$(CURDIR)/$(BIN)/w6a_ww.d/build.XXXXXX") || exit 1; \
rc=0; published=0; \
(cd "$$d" && $(CURDIR)/$(BIN)/ww build -o main \
-I $(CURDIR)/selfhost/cmd/w6a \
$(CURDIR)/selfhost/cmd/w6a/main.ww) || rc=$$?; \
rm -rf -- "$$d/main.sepwork" || { echo "$@: scratch cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; \
if [ $$rc -eq 0 ]; then mv "$$d/main" "$(CURDIR)/$@" && published=1 || rc=$$?; fi; \
if [ $$published -eq 0 ]; then rm -f -- "$$d/main" || { echo "$@: output cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; fi; \
if ! rmdir "$$d"; then echo "$@: workspace cleanup failed" >&2; if [ $$published -eq 1 ]; then rm -f -- "$(CURDIR)/$@" || echo "$@: published-output cleanup failed" >&2; fi; if [ $$rc -eq 0 ]; then rc=1; fi; fi; \
exit $$rc
@mkdir -p $(WWBUILD)/w6a_ww
@$(CURDIR)/$(BIN)/ww build -w $(WWBUILD)/w6a_ww \
-o $(WWBUILD)/w6a_ww/main \
-I $(CURDIR)/selfhost/cmd/w6a \
$(CURDIR)/selfhost/cmd/w6a/main.ww
@mv $(WWBUILD)/w6a_ww/main $@
# ---- ww-side w6l (linker port, exercised by 992_w6l_ww) ---------------
# Built like 6a_ww. Needs -I selfhost/cmd/w6l for the local sym/obj/pass/
@@ -244,17 +237,12 @@ $(BIN)/w6l_ww: selfhost/cmd/w6l/main.ww selfhost/cmd/w6l/sym.ww \
lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
$(LIB)/libwwrt.a | $(BIN)
@mkdir -p $(BIN)/w6l_ww.d
@d=$$(mktemp -d "$(CURDIR)/$(BIN)/w6l_ww.d/build.XXXXXX") || exit 1; \
rc=0; published=0; \
(cd "$$d" && $(CURDIR)/$(BIN)/ww build -o main \
-I $(CURDIR)/selfhost/cmd/w6l \
$(CURDIR)/selfhost/cmd/w6l/main.ww) || rc=$$?; \
rm -rf -- "$$d/main.sepwork" || { echo "$@: scratch cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; \
if [ $$rc -eq 0 ]; then mv "$$d/main" "$(CURDIR)/$@" && published=1 || rc=$$?; fi; \
if [ $$published -eq 0 ]; then rm -f -- "$$d/main" || { echo "$@: output cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; fi; \
if ! rmdir "$$d"; then echo "$@: workspace cleanup failed" >&2; if [ $$published -eq 1 ]; then rm -f -- "$(CURDIR)/$@" || echo "$@: published-output cleanup failed" >&2; fi; if [ $$rc -eq 0 ]; then rc=1; fi; fi; \
exit $$rc
@mkdir -p $(WWBUILD)/w6l_ww
@$(CURDIR)/$(BIN)/ww build -w $(WWBUILD)/w6l_ww \
-o $(WWBUILD)/w6l_ww/main \
-I $(CURDIR)/selfhost/cmd/w6l \
$(CURDIR)/selfhost/cmd/w6l/main.ww
@mv $(WWBUILD)/w6l_ww/main $@
# ---- ww-side ww driver (exercised by 993_ww_ww) ------------------------
# The driver pulls in lib/os (default search path) and orchestrates
@@ -265,16 +253,11 @@ $(BIN)/ww_ww: selfhost/cmd/ww/main.ww lib/os/exec/exec.ww \
lib/strings/strings.ww lib/bytes/bytes.ww lib/encoding/utf8/utf8.ww \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
$(LIB)/libwwrt.a | $(BIN)
@mkdir -p $(BIN)/ww_ww.d
@d=$$(mktemp -d "$(CURDIR)/$(BIN)/ww_ww.d/build.XXXXXX") || exit 1; \
rc=0; published=0; \
(cd "$$d" && $(CURDIR)/$(BIN)/ww build -o main \
$(CURDIR)/selfhost/cmd/ww/main.ww) || rc=$$?; \
rm -rf -- "$$d/main.sepwork" || { echo "$@: scratch cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; \
if [ $$rc -eq 0 ]; then mv "$$d/main" "$(CURDIR)/$@" && published=1 || rc=$$?; fi; \
if [ $$published -eq 0 ]; then rm -f -- "$$d/main" || { echo "$@: output cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; fi; \
if ! rmdir "$$d"; then echo "$@: workspace cleanup failed" >&2; if [ $$published -eq 1 ]; then rm -f -- "$(CURDIR)/$@" || echo "$@: published-output cleanup failed" >&2; fi; if [ $$rc -eq 0 ]; then rc=1; fi; fi; \
exit $$rc
@mkdir -p $(WWBUILD)/ww_ww
@$(CURDIR)/$(BIN)/ww build -w $(WWBUILD)/ww_ww \
-o $(WWBUILD)/ww_ww/main \
$(CURDIR)/selfhost/cmd/ww/main.ww
@mv $(WWBUILD)/ww_ww/main $@
# ---- runtime (libwwrt.a, assembled by our own w6a) ---------------------
$(OBJ)/rt/%.o: rt/%.s $(BIN)/w6a | $(OBJ)/rt
@@ -293,16 +276,11 @@ $(LIB)/libwwrt.a: $(RT_OBJ) | $(LIB)
$(WWTEST_BIN): $(WWTEST_SRC) $(BIN)/ww $(BIN)/w6c $(BIN)/w6a \
$(BIN)/w6l $(LIB)/libwwrt.a | $(BIN)
@mkdir -p $(BIN)/wwtest.d
@d=$$(mktemp -d "$(CURDIR)/$(BIN)/wwtest.d/build.XXXXXX") || exit 1; \
rc=0; published=0; \
(cd "$$d" && $(CURDIR)/$(BIN)/ww build -o main \
-I $(CURDIR)/internal $(CURDIR)/cmd/wwtest/wwtest.ww) || rc=$$?; \
rm -rf -- "$$d/main.sepwork" || { echo "$@: scratch cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; \
if [ $$rc -eq 0 ]; then mv "$$d/main" "$(CURDIR)/$@" && published=1 || rc=$$?; fi; \
if [ $$published -eq 0 ]; then rm -f -- "$$d/main" || { echo "$@: output cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; fi; \
if ! rmdir "$$d"; then echo "$@: workspace cleanup failed" >&2; if [ $$published -eq 1 ]; then rm -f -- "$(CURDIR)/$@" || echo "$@: published-output cleanup failed" >&2; fi; if [ $$rc -eq 0 ]; then rc=1; fi; fi; \
exit $$rc
@mkdir -p $(WWBUILD)/wwtest
@$(CURDIR)/$(BIN)/ww build -w $(WWBUILD)/wwtest \
-o $(WWBUILD)/wwtest/main \
-I $(CURDIR)/internal $(CURDIR)/cmd/wwtest/wwtest.ww
@mv $(WWBUILD)/wwtest/main $@
wwfixture: $(WWFIXTURE_BIN)
@@ -314,54 +292,35 @@ test-wwfixture: wwfixture test-wwfixture-process
sh test/wwfixture/integration.sh
$(WWFIXTURE_BIN): $(WWFIXTURE_SRC) $(WWFIXTURE_BUILD_TOOLS) | $(BIN)
@mkdir -p $(BIN)/wwfixture.d
@d=$$(mktemp -d "$(CURDIR)/$(BIN)/wwfixture.d/build.XXXXXX") || exit 1; \
rc=0; published=0; \
(cd "$$d" && $(CURDIR)/$(BIN)/ww build -o main \
-I $(CURDIR)/internal $(CURDIR)/cmd/wwfixture/wwfixture.ww) || rc=$$?; \
rm -rf -- "$$d/main.sepwork" || { echo "$@: scratch cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; \
if [ $$rc -eq 0 ]; then mv "$$d/main" "$(CURDIR)/$@" && published=1 || rc=$$?; fi; \
if [ $$published -eq 0 ]; then rm -f -- "$$d/main" || { echo "$@: output cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; fi; \
if ! rmdir "$$d"; then echo "$@: workspace cleanup failed" >&2; if [ $$published -eq 1 ]; then rm -f -- "$(CURDIR)/$@" || echo "$@: published-output cleanup failed" >&2; fi; if [ $$rc -eq 0 ]; then rc=1; fi; fi; \
exit $$rc
@mkdir -p $(WWBUILD)/wwfixture
@$(CURDIR)/$(BIN)/ww build -w $(WWBUILD)/wwfixture \
-o $(WWBUILD)/wwfixture/main \
-I $(CURDIR)/internal $(CURDIR)/cmd/wwfixture/wwfixture.ww
@mv $(WWBUILD)/wwfixture/main $@
$(EXEC_TEST_C): $(EXEC_TEST_SRC) $(WWFIXTURE_TOOLS) | $(BIN)
@mkdir -p $(BIN)/test_exec.d
@d=$$(mktemp -d "$(CURDIR)/$(BIN)/test_exec.d/build.XXXXXX") || exit 1; \
rc=0; published=0; \
(cd "$$d" && $(CURDIR)/$(BIN)/ww build -o main \
-I $(CURDIR)/internal $(CURDIR)/test/wwfixture/process/main.ww) || rc=$$?; \
rm -rf -- "$$d/main.sepwork" || { echo "$@: scratch cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; \
if [ $$rc -eq 0 ]; then mv "$$d/main" "$(CURDIR)/$@" && published=1 || rc=$$?; fi; \
if [ $$published -eq 0 ]; then rm -f -- "$$d/main" || { echo "$@: output cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; fi; \
if ! rmdir "$$d"; then echo "$@: workspace cleanup failed" >&2; if [ $$published -eq 1 ]; then rm -f -- "$(CURDIR)/$@" || echo "$@: published-output cleanup failed" >&2; fi; if [ $$rc -eq 0 ]; then rc=1; fi; fi; \
exit $$rc
@mkdir -p $(WWBUILD)/test_exec
@$(CURDIR)/$(BIN)/ww build -w $(WWBUILD)/test_exec \
-o $(WWBUILD)/test_exec/main \
-I $(CURDIR)/internal $(CURDIR)/test/wwfixture/process/main.ww
@mv $(WWBUILD)/test_exec/main $@
# Built by the wwstage driver: the ordinary Make path exercises
# ww_ww's -w implementation, not only the cstage twin's.
$(EXEC_TEST_WW): $(EXEC_TEST_SRC) $(WWFIXTURE_TOOLS) | $(BIN)
@mkdir -p $(BIN)/test_exec_ww.d
@d=$$(mktemp -d "$(CURDIR)/$(BIN)/test_exec_ww.d/build.XXXXXX") || exit 1; \
rc=0; published=0; \
(cd "$$d" && $(CURDIR)/$(BIN)/ww_ww build -o main \
-I $(CURDIR)/internal $(CURDIR)/test/wwfixture/process/main.ww) || rc=$$?; \
rm -rf -- "$$d/main.sepwork" || { echo "$@: scratch cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; \
if [ $$rc -eq 0 ]; then mv "$$d/main" "$(CURDIR)/$@" && published=1 || rc=$$?; fi; \
if [ $$published -eq 0 ]; then rm -f -- "$$d/main" || { echo "$@: output cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; fi; \
if ! rmdir "$$d"; then echo "$@: workspace cleanup failed" >&2; if [ $$published -eq 1 ]; then rm -f -- "$(CURDIR)/$@" || echo "$@: published-output cleanup failed" >&2; fi; if [ $$rc -eq 0 ]; then rc=1; fi; fi; \
exit $$rc
@mkdir -p $(WWBUILD)/test_exec_ww
@$(CURDIR)/$(BIN)/ww_ww build -w $(WWBUILD)/test_exec_ww \
-o $(WWBUILD)/test_exec_ww/main \
-I $(CURDIR)/internal $(CURDIR)/test/wwfixture/process/main.ww
@mv $(WWBUILD)/test_exec_ww/main $@
$(PACKAGE_TEST_BIN): $(PACKAGE_TEST_SRC) $(WWTEST_BIN) \
$(BIN)/ww $(BIN)/ww_ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
$(LIB)/libwwrt.a | $(BIN)
@mkdir -p $(BIN)/test_package.d
@d=$$(mktemp -d "$(CURDIR)/$(BIN)/test_package.d/build.XXXXXX") || exit 1; \
rc=0; published=0; \
(cd "$$d" && $(CURDIR)/$(BIN)/ww test -c -o main \
-I $(CURDIR)/internal $(CURDIR)/test/package/package_test.ww) || rc=$$?; \
rm -rf -- "$$d/main.sepwork" || { echo "$@: scratch cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; \
if [ $$rc -eq 0 ]; then mv "$$d/main" "$(CURDIR)/$@" && published=1 || rc=$$?; fi; \
if [ $$published -eq 0 ]; then rm -f -- "$$d/main" || { echo "$@: output cleanup failed" >&2; if [ $$rc -eq 0 ]; then rc=1; fi; }; fi; \
if ! rmdir "$$d"; then echo "$@: workspace cleanup failed" >&2; if [ $$published -eq 1 ]; then rm -f -- "$(CURDIR)/$@" || echo "$@: published-output cleanup failed" >&2; fi; if [ $$rc -eq 0 ]; then rc=1; fi; fi; \
exit $$rc
@mkdir -p $(WWBUILD)/test_package
@$(CURDIR)/$(BIN)/ww test -c -w $(WWBUILD)/test_package \
-I $(CURDIR)/internal $(CURDIR)/test/package/package_test.ww
@mv $(WWBUILD)/test_package/main $@
test-package: all $(PACKAGE_TEST_BIN)
@WW_PACKAGE_REPO=$(CURDIR) $(CURDIR)/$(PACKAGE_TEST_BIN)