test: cover exact package tool invocation paths

This commit is contained in:
2026-08-12 14:29:17 +09:00
parent d78020baf7
commit bb71b31f81
6 changed files with 321 additions and 31 deletions

View File

@@ -2651,11 +2651,13 @@ Other accidental constraints include fixed 256/1024-byte name/path buffers. The
compiler parser silently truncates dotted full imports beyond 255 bytes, while
the C driver scanner can stop advancing and hang on an import identifier at that
limit; the dynamically sized WWstage scanner differs. There is no regression
test for this stage divergence. Other defects include unquoted Cstage `system()` command
construction, and dependence on `/bin/sh`. Cstage honors `WW_W6C`, `WW_W6A`,
`WW_W6L`, `WW_LIB`, and source-library fallbacks; the self-hosted driver instead
hardcodes sibling tools and relative libraries. The two implementations are
therefore similar algorithms, not one protocol implementation.
test for this stage divergence. Compiler, assembler, and linker launches now use
structured argument vectors in both stages. Both drivers honor exact executable
paths in `WW_W6C`, `WW_W6A`, and `WW_W6L` and otherwise select their
stage-specific sibling tools. Cstage additionally honors `WW_LIB` and
source-library fallbacks; the self-hosted driver still uses relative source and
runtime libraries. The two implementations remain parallel production
algorithms rather than one protocol implementation.
Build and test disagree about source symlinks. External package tests are built
from a generated single-file root plus `-I`; an external import of a multi-file
@@ -2689,8 +2691,8 @@ The observed invalidation rules are:
content is not rehashed.
Hidden or incompletely modeled inputs include `CC`, `AR`, `PATH`, `ccache`, Make
flags, shell quoting/behavior, compiler built-ins, assembler/linker defaults,
inferred `argv[0]` library locations, current working directory, `chmod`, runtime
flags, compiler built-ins, assembler/linker defaults,
inferred `argv[0]` library locations, current working directory, file mode, runtime
archive, linker binary, native-library resolution, host libc/CRT/loader, SDK,
CPU, target, and environment. Make does not invalidate existing C objects when
the host compiler or C flags change. Workdir reuse also omits the driver binary/
@@ -2736,9 +2738,10 @@ holds for measured WW artifacts, not for the complete build.
Cstage and WWstage drivers building the same eight-package graph produced a
byte-identical final executable and all 38 non-tool artifacts, but took 0.138 s
and 0.356 s respectively. Under `env -i PATH=/nonexistent`, Cstage returned
success after ambient `chmod` failed and left mode 0644; WWstage returned success
with mode 0755. This exposes implementation asymmetry and an undeclared host tool.
and 0.356 s respectively. The audit also found that Cstage formerly returned
success after an ambient `chmod` lookup failed and left mode 0644, while WWstage
created mode 0755 directly. Cstage now calls `chmod(2)` on the exact output path
and reports failure, removing that host-tool and path-splitting asymmetry.
### 11.5 What survives and what is deleted
@@ -2985,6 +2988,42 @@ boundary in
with compiler and linker import configurations emitted separately in
[`cmd/go/internal/work/exec.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/exec.go).
### 11.8 Implemented exact package-tool invocation slice
The local package builder now launches the compiler, assembler, and linker as
an executable plus an argument vector in both Cstage and WWstage. No package
source path, work-directory artifact path, output path, test-support qualifier,
or link-closure member is flattened into a shell command. Paths containing
spaces therefore retain one argument boundary from the package coordinator
through compilation, assembly, and final executable linking.
`WW_W6C`, `WW_W6A`, and `WW_W6L` each name one exact executable path. They are
not shell fragments and are not searched through `PATH`. With no override,
Cstage keeps its `w6c`/`w6a`/`w6l` siblings and WWstage keeps its
`w6c_ww`/`w6a_ww`/`w6l_ww` siblings. The coordinator preserves these variables
when it starts the one command-scoped package build, so the same contract covers
ordinary directory builds, same-package tests, external tests, recursive test
requests, and persistent-workdir tool identity. A failed overridden compiler or
assembler remains attributed to its owning package in both stages. The Cstage
linker also sets executable mode with `chmod(2)` on the exact output path rather
than invoking an ambient command.
This changes only process invocation and publication. Source imports still own
the graph, each directory is still one production package, compiler actions
still consume direct dependency export data through `.unit.ww`, and links still
receive the complete per-root `.a` closure. Repository-native coverage wraps
all three real stage tools at executable paths containing spaces, records every
argument boundary, inspects `.unit.ww`, `.wwi`, `.a`, and root object placement,
runs the published test binary, compares Cstage/WWstage artifacts and traces,
and injects a compiler failure to compare package attribution.
Go 1.26.5 keeps the same responsibility boundary: its work executor passes the
selected compiler or linker tool and a constructed argument slice to the
builder, while package loading and action construction remain separate
([`cmd/go/internal/work/exec.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/exec.go)).
WW adopts that exact-tool boundary without adding a command schema, generalized
action graph, scheduler, manifest, cache protocol, or package-manager behavior.
## 12. Candidate architectures and hard-gate decision
Five candidates were developed as coherent systems, not as feature bins.