ww: add -w persistent workdir builds with content-identity reuse
A -w DIR workdir replaces the fresh .sepwork scratch with a caller-owned persistent package-artifact tree. A package is reused only when its freshly composed unit byte-equals the committed unit and byte copies of the compiler/assembler recorded in the dir equal the live tools — pure content identity, no mtimes, no hashes, every decision reproducible with cmp against plain files. Recompiles stage at .new names and commit by rename, unit strictly last, so an interrupted build forces a recompile and can never leave a committed unit vouching for uncommitted artifacts; .o/.a additionally reject zero size (ELF/ar are never empty), while .s/.wwi accept legitimate empties (FFI-only rt). A mode stamp pins the -T/-S shape and the artifact protocol revision. Classic scratch keeps its exact acquire/refuse/cleanup contract; run rejects -w; dir-mode test rejects -w; both driver stages implement identical behavior and wording.
This commit is contained in:
@@ -201,6 +201,22 @@ beneath one freshly acquired directory, remove both after every build result,
|
||||
and make cleanup failure fail the command. Make recipes build driver-produced
|
||||
tools in invocation-owned directories and apply the same exact cleanup rule.
|
||||
|
||||
`ww build -w DIR` and single-file `ww test -w DIR` replace that scratch with a
|
||||
caller-owned persistent package-artifact workdir: the directory must already
|
||||
exist, is never cleaned by the driver, and holds one committed unit, `.wwi`,
|
||||
`.s`, `.o`, and dep `.a` per package plus byte copies of the compiler and
|
||||
assembler and a small mode stamp. A package is reused only when its freshly
|
||||
composed unit byte-equals the committed unit and the recorded tool copies
|
||||
byte-equal the live tools — content identity only, no mtimes, no hashes, every
|
||||
decision reproducible with `cmp` against plain files. Recompiled artifacts
|
||||
land at staged `.new` names and commit by rename with the unit renamed last,
|
||||
so an interrupted build forces a recompile rather than a false reuse; the
|
||||
link always reruns. One workdir serves one invocation at a time and one
|
||||
(root, mode) shape; both driver stages implement the identical contract.
|
||||
This is build staleness in the Make/mk/Go sense, not a result cache: tests
|
||||
always run, and the byte-identity and bootstrap gates keep building on fresh
|
||||
scratch. `make clean` reclaims every workdir under `out/`.
|
||||
|
||||
`test/lang` currently uses one package per source file, so its complete gate
|
||||
still performs independent package builds. That remaining source layout is not
|
||||
hidden behind caching or concurrency; it is outside the small `test` target.
|
||||
|
||||
Reference in New Issue
Block a user