diff --git a/Makefile b/Makefile index 8bae0073..fb25e9d8 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,21 @@ PREFIX ?= /usr/local CC ?= cc AR ?= ar + +# Parallelise the build by default. The C-compile DAG and the five +# wwstage builds write disjoint outputs (each .o is distinct; each +# wwstage tool's side files land at its own selfhost/cmd//main.* +# stem), so -j is order-independent. test/run's Phase-2 byte-id gates +# (950/990-997) are a single serial recipe — MAKEFLAGS -j does not +# reach inside them. Override with `make -j1` if needed. +NPROC ?= $(shell nproc 2>/dev/null || echo 4) +MAKEFLAGS += -j$(NPROC) + +# Wrap the C compiler with ccache when present — content-addressed, so +# byte-identical to plain cc; just skips recompiling unchanged TUs. +# Falls back cleanly to bare $(CC) when ccache is absent. A command-line +# CC= override wins and is left unwrapped. +CC := $(shell command -v ccache >/dev/null 2>&1 && echo "ccache $(CC)" || echo "$(CC)") CFLAGS ?= -O0 -g -Wall -Wextra -Wpedantic -Wno-unused-parameter CFLAGS += -std=c99 -fno-strict-aliasing -D_POSIX_C_SOURCE=200809L INCS = -Icmd/wcc @@ -1675,6 +1690,28 @@ test: all sizelint $(TESTS) test-unit: all sizelint $(TESTS) @WW=$(BIN)/ww BIN=$(BIN) UNIT=1 sh test/run +# ---- smoke: inner-loop cross-stage byte-id check on a SMALL input ------ +# Compiles one self-contained fixture through cstage w6c AND wwstage +# w6c_ww and diffs the emitted .s. Catches a cs!=ww emission divergence +# (rule 10) in seconds — the per-fold inner-loop check Rob's cadence +# calls for. NOT a substitute for the full 990-997 byte-id gate, which +# self-compiles main.combined.ww: ALWAYS run `make test` before landing +# a cgen/ABI/compiler-lib fold. w6c consumes a flat unit (no import +# resolution), so FIXTURE must be import-free or a pre-built .combined.ww. +# make smoke # default: rt/malloc.ww +# make smoke FIXTURE=rt/ensure.ww # any self-contained .ww +FIXTURE ?= rt/malloc.ww +smoke: $(BIN)/w6c $(BIN)/w6c_ww + @$(BIN)/w6c $(FIXTURE) > $(OUT)/smoke.cs.s || { echo "smoke: cstage w6c failed on $(FIXTURE)"; exit 1; } + @$(BIN)/w6c_ww $(FIXTURE) > $(OUT)/smoke.ww.s || { echo "smoke: wwstage w6c_ww failed on $(FIXTURE)"; exit 1; } + @if cmp -s $(OUT)/smoke.cs.s $(OUT)/smoke.ww.s; then \ + echo "smoke OK: cs == ww .s for $(FIXTURE) (`wc -l < $(OUT)/smoke.cs.s` lines)"; \ + else \ + echo "smoke FAIL: cs != ww .s for $(FIXTURE)"; \ + diff -u $(OUT)/smoke.cs.s $(OUT)/smoke.ww.s | head -40; \ + exit 1; \ + fi + install: all mkdir -p $(PREFIX)/bin $(PREFIX)/lib cp $(BIN)/ww $(PREFIX)/bin/ @@ -1820,4 +1857,4 @@ nocc: @echo @echo "NOCC OK: $(STAGE0)/* reproduces itself from source. cc not invoked." -.PHONY: all cstage wwstage test test-unit sizelint install clean bootstrap nocc bootstrap-snapshot +.PHONY: all cstage wwstage test test-unit smoke sizelint install clean bootstrap nocc bootstrap-snapshot diff --git a/test/wcc/990_selfhost.c b/test/wcc/990_selfhost.c index cc180f04..3708ee53 100644 --- a/test/wcc/990_selfhost.c +++ b/test/wcc/990_selfhost.c @@ -709,60 +709,6 @@ cleanup: return fail ? -1 : 0; } -/* Probe 8: ww1 → ww2 ladder. wwdump_ww (= ww1, built by C tools) - * compiles its own concatenated source. The output assembles + links - * via w6a/w6l into ww2 (a fresh ww-built compiler binary). Confirms - * the full ww-cgen pipeline is functionally correct end-to-end on - * the entire frontend (lex+parse+check+cgen+ast+typ+sym+mem+err+ - * driver). Pre-fix-set this segfaulted at 5919 lines of asm; post- - * fix-set it produces 43K+ lines that assemble/link cleanly. */ -static int -probe_ww1_to_ww2(const char *bin) -{ - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return -1; - char tmpdir[64]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/ww12_%d", getpid()); - mkdir(tmpdir, 0755); - char asm_p[512], obj_p[512], exe_p[512], cmd[4096]; - snprintf(asm_p, sizeof asm_p, "%s/ww2.s", tmpdir); - snprintf(obj_p, sizeof obj_p, "%s/ww2.o", tmpdir); - snprintf(exe_p, sizeof exe_p, "%s/ww2", tmpdir); - int fail = 0; - snprintf(cmd, sizeof cmd, - "timeout 180 %s/wwdump_ww -c %s/selfhost/cmd/wwdump/main.combined.ww > %s 2>/dev/null", - bin, cwd, asm_p); - if (runwait(cmd) != 0) { - fprintf(stderr, "ww1->ww2 FAIL: wwdump_ww segfaulted on its own source\n"); - fail++; - goto cleanup; - } - snprintf(cmd, sizeof cmd, "timeout 180 %s/w6a -o %s %s 2>/dev/null", bin, obj_p, asm_p); - if (runwait(cmd) != 0) { - fprintf(stderr, "ww1->ww2 FAIL: w6a errored on ww1 output\n"); - fail++; - goto cleanup; - } - char rt[1024]; - snprintf(rt, sizeof rt, "%s/../lib/libwwrt.a", bin); - snprintf(cmd, sizeof cmd, "timeout 180 %s/w6l -o %s %s %s 2>/dev/null", - bin, exe_p, obj_p, rt); - if (runwait(cmd) != 0) { - fprintf(stderr, "ww1->ww2 FAIL: w6l errored\n"); - fail++; - goto cleanup; - } - struct stat st; - if (stat(exe_p, &st) != 0 || !(st.st_mode & 0111)) { - fprintf(stderr, "ww1->ww2 FAIL: ww2 binary not executable\n"); - fail++; - } -cleanup: - snprintf(cmd, sizeof cmd, "rm -rf %s", tmpdir); - runwait(cmd); - return fail ? -1 : 0; -} - /* Probe 7: end-to-end via wwdump_ww. Use `ww build` to produce the * concatenated source as a side effect, then drive ww-cgen → w6a → * w6l → run, comparing the binary's exit code to the fixture's @@ -930,7 +876,6 @@ main(void) if (probe_ww_compile(bin) != 0) fail++; if (probe_cgen_match(bin) != 0) fail++; if (probe_ww_links(bin) != 0) fail++; - if (probe_ww1_to_ww2(bin) != 0) fail++; if (probe_bootstrap_fixed_point(bin) != 0) fail++; if (fail) {