test: cover exact package tool invocation paths
This commit is contained in:
12
Makefile
12
Makefile
@@ -851,11 +851,11 @@ clean:
|
||||
# (it takes no -o/-I and writes asm to stdout), so the chainable sep
|
||||
# frontend w6c is the bootstrapped target (test 994 pins w6c ==
|
||||
# wwdump -c).
|
||||
# - The wwstage DRIVER (`ww_ww`) is NOT yet in this loop: it cannot
|
||||
# swap its frontend (it hardcodes <selfdir>/w6c_ww and honors no
|
||||
# WW_W6C override). Closing that — so `ww_ww` itself carries the
|
||||
# glue — is task #66. Until then cstage `ww` orchestrates and this
|
||||
# bootstrap does NOT claim a fully wwstage-driven self-host.
|
||||
# - The wwstage DRIVER (`ww_ww`) can now swap all three tools through
|
||||
# exact-path WW_W6C/WW_W6A/WW_W6L overrides. This loop deliberately
|
||||
# still keeps cstage `ww` as its fixed orchestrator, so the driver is
|
||||
# outside the compared artifacts and this target does NOT yet claim a
|
||||
# fully wwstage-driven self-host.
|
||||
#
|
||||
# Why a fourth stage? Stage 3 proves stage-1 w6c_ww and ww2 (which differ
|
||||
# in how they were built) emit the same machine code. Stage 4 proves ww3 is
|
||||
@@ -940,7 +940,7 @@ nocc:
|
||||
@rm -rf $(NOCC_OUT)
|
||||
@mkdir -p $(NOCC_BIN) $(NOCC_LIB) $(NOCC_OBJ)
|
||||
@# Stage 0: drop bootstrap binaries under both natural names and
|
||||
@# the _ww-suffixed names the driver expects when shelling out.
|
||||
@# the _ww-suffixed names used by the driver's default sibling lookup.
|
||||
@for f in ww w6c w6a w6l; do \
|
||||
cp $(STAGE0)/$$f $(NOCC_BIN)/$$f; \
|
||||
cp $(STAGE0)/$$f $(NOCC_BIN)/$${f}_ww; \
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* `path` is acceptable iff it's either an archive ("!<arch>\n") or
|
||||
* an ELF file ("\x7fELF"). Distros often ship lib<name>.so as a GNU
|
||||
@@ -128,10 +129,9 @@ main(int argc, char **argv)
|
||||
}
|
||||
int rc = l_emit_elf(&l, f, base, base + 0x1000 + entry->val);
|
||||
fclose(f);
|
||||
if (rc == 0) {
|
||||
char cmd[1024];
|
||||
snprintf(cmd, sizeof cmd, "chmod +x %s", out);
|
||||
(void)system(cmd);
|
||||
if (rc == 0 && chmod(out, 0755) != 0) {
|
||||
fprintf(stderr, "w6l: cannot make %s executable\n", out);
|
||||
rc = 1;
|
||||
}
|
||||
free(inputs);
|
||||
return rc;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1110,10 +1110,9 @@ fn workescape(s: str) str = {
|
||||
append(traceenv, strings.concat("WW_PACKAGE_LINKER_TRACE=", linkertrace));
|
||||
append(traceenv, strings.concat("WW_PACKAGE_W6C=", driver("w6c")));
|
||||
append(traceenv, strings.concat("WW_PACKAGE_W6L=", driver("w6l")));
|
||||
// The WW driver intentionally takes sibling tools rather than WW_W6C
|
||||
// overrides. Run an exact copied driver beside narrow tracing wrappers so
|
||||
// its real compiler/linker actions are observable without changing that
|
||||
// production contract.
|
||||
// Exercise default sibling discovery independently of the exact-path
|
||||
// override contract covered below: the copied driver sits beside narrow
|
||||
// tracing wrappers for its real compiler and linker actions.
|
||||
let wwtracebin: str = strings.concat(repo(), "/out/package-trace-",
|
||||
workescape(root));
|
||||
assert(os.mkdir(wwtracebin, 448i32) == 0);
|
||||
@@ -2143,7 +2142,8 @@ fn workescape(s: str) str = {
|
||||
let trace: str = strings.concat(root, "/compiler.trace");
|
||||
let wrapper: str = strings.concat(root, "/trace-w6c.sh");
|
||||
writefile(trace, "");
|
||||
writefile(wrapper, strings.concat(
|
||||
writeexecutable(wrapper, strings.concat(
|
||||
"#!/bin/sh\n",
|
||||
"printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_TRACE\"\n",
|
||||
"exec \"$WW_PACKAGE_W6C\" \"$@\"\n"));
|
||||
let baseenv: []str = os.getenvs();
|
||||
@@ -2157,7 +2157,7 @@ fn workescape(s: str) str = {
|
||||
};
|
||||
ei += 1;
|
||||
};
|
||||
append(env, strings.concat("WW_W6C=/bin/sh ", wrapper));
|
||||
append(env, strings.concat("WW_W6C=", wrapper));
|
||||
append(env, strings.concat("WW_PACKAGE_TRACE=", trace));
|
||||
append(env, strings.concat("WW_PACKAGE_W6C=", driver("w6c")));
|
||||
let bin: str = strings.concat(root, "/diamond.test");
|
||||
@@ -2187,6 +2187,245 @@ fn workescape(s: str) str = {
|
||||
clean(root);
|
||||
};
|
||||
|
||||
@test fn exact_package_tool_argv_stage_parity() void = {
|
||||
let root: str = fresh();
|
||||
let source: str = strings.concat(root, "/source tree");
|
||||
let leaf: str = strings.concat(source, "/leaf");
|
||||
let dep: str = strings.concat(source, "/dep");
|
||||
let target: str = strings.concat(source, "/target");
|
||||
let tools: str = strings.concat(root, "/tool wrappers");
|
||||
assert(os.mkdir(source, 448i32) == 0);
|
||||
assert(os.mkdir(leaf, 448i32) == 0);
|
||||
assert(os.mkdir(dep, 448i32) == 0);
|
||||
assert(os.mkdir(target, 448i32) == 0);
|
||||
assert(os.mkdir(tools, 448i32) == 0);
|
||||
writefile(strings.concat(leaf, "/leaf.ww"), strings.concat(
|
||||
"package leaf;\n",
|
||||
"export fn value() i32 = { return 40; };\n"));
|
||||
writefile(strings.concat(dep, "/dep.ww"), strings.concat(
|
||||
"package dep;\nimport leaf;\n",
|
||||
"export fn value() i32 = { return leaf.value() + 2; };\n"));
|
||||
writefile(strings.concat(target, "/target.ww"), strings.concat(
|
||||
"package target;\nimport dep;\n",
|
||||
"fn value() i32 = { return dep.value(); };\n"));
|
||||
writefile(strings.concat(target, "/target_test.ww"), strings.concat(
|
||||
"package target;\n",
|
||||
"@test fn exact_argv() void = { assert(value() == 42); };\n"));
|
||||
|
||||
let compilerwrapper: str = strings.concat(tools, "/w6c wrapper.sh");
|
||||
let assemblerwrapper: str = strings.concat(tools, "/w6a wrapper.sh");
|
||||
let linkerwrapper: str = strings.concat(tools, "/w6l wrapper.sh");
|
||||
let failurewrapper: str = strings.concat(tools, "/failing w6c wrapper.sh");
|
||||
writeexecutable(compilerwrapper, strings.concat(
|
||||
"#!/bin/sh\n",
|
||||
"printf 'BEGIN' >> \"$WW_ARGV_COMPILER_TRACE\"\n",
|
||||
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
|
||||
"\"$WW_ARGV_COMPILER_TRACE\"; done\n",
|
||||
"printf '\\n' >> \"$WW_ARGV_COMPILER_TRACE\"\n",
|
||||
"exec \"$WW_ARGV_REAL_COMPILER\" \"$@\"\n"));
|
||||
writeexecutable(assemblerwrapper, strings.concat(
|
||||
"#!/bin/sh\n",
|
||||
"printf 'BEGIN' >> \"$WW_ARGV_ASSEMBLER_TRACE\"\n",
|
||||
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
|
||||
"\"$WW_ARGV_ASSEMBLER_TRACE\"; done\n",
|
||||
"printf '\\n' >> \"$WW_ARGV_ASSEMBLER_TRACE\"\n",
|
||||
"exec \"$WW_ARGV_REAL_ASSEMBLER\" \"$@\"\n"));
|
||||
writeexecutable(linkerwrapper, strings.concat(
|
||||
"#!/bin/sh\n",
|
||||
"printf 'BEGIN' >> \"$WW_ARGV_LINKER_TRACE\"\n",
|
||||
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
|
||||
"\"$WW_ARGV_LINKER_TRACE\"; done\n",
|
||||
"printf '\\n' >> \"$WW_ARGV_LINKER_TRACE\"\n",
|
||||
"exec \"$WW_ARGV_REAL_LINKER\" \"$@\"\n"));
|
||||
writeexecutable(failurewrapper, strings.concat(
|
||||
"#!/bin/sh\n",
|
||||
"printf 'BEGIN' >> \"$WW_ARGV_FAILURE_TRACE\"\n",
|
||||
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
|
||||
"\"$WW_ARGV_FAILURE_TRACE\"; done\n",
|
||||
"printf '\\n' >> \"$WW_ARGV_FAILURE_TRACE\"\n",
|
||||
"exit 23\n"));
|
||||
|
||||
let stages: []str = ["ww", "ww_ww"];
|
||||
let compilers: []str = ["w6c", "w6c_ww"];
|
||||
let assemblers: []str = ["w6a", "w6a_ww"];
|
||||
let linkers: []str = ["w6l", "w6l_ww"];
|
||||
let tags: []str = ["c", "ww"];
|
||||
let bin: str = strings.concat(root, "/published test binary");
|
||||
let workroot: str = strings.concat(bin, ".sepwork");
|
||||
let work: str = strings.concat(workroot, "/");
|
||||
let referenceunit: str = "";
|
||||
let referencewwi: str = "";
|
||||
let referencearchive: str = "";
|
||||
let referencebin: str = "";
|
||||
let referencecompiler: str = "";
|
||||
let referenceassembler: str = "";
|
||||
let referencelinker: str = "";
|
||||
let referenceout: str = "";
|
||||
let referenceerr: str = "";
|
||||
let referencefailure: str = "";
|
||||
let baseenv: []str = os.getenvs();
|
||||
let si: i32 = 0;
|
||||
for (si < stages.len) {
|
||||
let compilertrace: str = strings.concat(root, "/", tags[si],
|
||||
" compiler trace");
|
||||
let assemblertrace: str = strings.concat(root, "/", tags[si],
|
||||
" assembler trace");
|
||||
let linkertrace: str = strings.concat(root, "/", tags[si],
|
||||
" linker trace");
|
||||
let failuretrace: str = strings.concat(root, "/", tags[si],
|
||||
" failure trace");
|
||||
writefile(compilertrace, "");
|
||||
writefile(assemblertrace, "");
|
||||
writefile(linkertrace, "");
|
||||
writefile(failuretrace, "");
|
||||
let env: []str = alloc([], (baseenv.len + 9): u64)!;
|
||||
let ei: i32 = 0;
|
||||
for (ei < baseenv.len) {
|
||||
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
|
||||
&& !strings.hasprefix(baseenv[ei], "WW_W6A=")
|
||||
&& !strings.hasprefix(baseenv[ei], "WW_W6L=")
|
||||
&& !strings.hasprefix(baseenv[ei],
|
||||
"WW_ARGV_COMPILER_TRACE=")
|
||||
&& !strings.hasprefix(baseenv[ei],
|
||||
"WW_ARGV_ASSEMBLER_TRACE=")
|
||||
&& !strings.hasprefix(baseenv[ei],
|
||||
"WW_ARGV_LINKER_TRACE=")
|
||||
&& !strings.hasprefix(baseenv[ei],
|
||||
"WW_ARGV_REAL_COMPILER=")
|
||||
&& !strings.hasprefix(baseenv[ei],
|
||||
"WW_ARGV_REAL_ASSEMBLER=")
|
||||
&& !strings.hasprefix(baseenv[ei],
|
||||
"WW_ARGV_REAL_LINKER=")) {
|
||||
append(env, baseenv[ei]);
|
||||
};
|
||||
ei += 1;
|
||||
};
|
||||
append(env, strings.concat("WW_W6C=", compilerwrapper));
|
||||
append(env, strings.concat("WW_W6A=", assemblerwrapper));
|
||||
append(env, strings.concat("WW_W6L=", linkerwrapper));
|
||||
append(env, strings.concat("WW_ARGV_COMPILER_TRACE=", compilertrace));
|
||||
append(env, strings.concat("WW_ARGV_ASSEMBLER_TRACE=", assemblertrace));
|
||||
append(env, strings.concat("WW_ARGV_LINKER_TRACE=", linkertrace));
|
||||
append(env, strings.concat("WW_ARGV_REAL_COMPILER=",
|
||||
driver(compilers[si])));
|
||||
append(env, strings.concat("WW_ARGV_REAL_ASSEMBLER=",
|
||||
driver(assemblers[si])));
|
||||
append(env, strings.concat("WW_ARGV_REAL_LINKER=",
|
||||
driver(linkers[si])));
|
||||
|
||||
let av: []str = [driver(stages[si]), "test", "-c", "-o", bin,
|
||||
"-I", source, target];
|
||||
let out: commandout;
|
||||
runcommandenv(root, strings.concat("exact-argv-", tags[si]), av, env,
|
||||
(120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(out.stderr.len == 0);
|
||||
let rootunit: str = readfile(strings.concat(work,
|
||||
"__ww-test-000-same.unit.ww"));
|
||||
let depunit: str = readfile(strings.concat(work, "dep.unit.ww"));
|
||||
assert(has(rootunit, "//ww:module dep\n"));
|
||||
assert(!has(rootunit, "//ww:module leaf\n"));
|
||||
assert(has(depunit, "//ww:module leaf\n"));
|
||||
assert(os.exists(strings.concat(work, "leaf.wwi")));
|
||||
assert(os.exists(strings.concat(work, "leaf.a")));
|
||||
assert(os.exists(strings.concat(work, "dep.wwi")));
|
||||
assert(os.exists(strings.concat(work, "dep.a")));
|
||||
assert(!os.exists(strings.concat(work,
|
||||
"__ww-test-000-same.wwi")));
|
||||
assert(!os.exists(strings.concat(work,
|
||||
"__ww-test-000-same.a")));
|
||||
assert(os.exists(bin));
|
||||
|
||||
let ctrace: str = readfile(compilertrace);
|
||||
let atrace: str = readfile(assemblertrace);
|
||||
let ltrace: str = readfile(linkertrace);
|
||||
assert(occurrences(ctrace, strings.concat("<", work,
|
||||
"leaf.unit.ww>")) == 1);
|
||||
assert(occurrences(ctrace, strings.concat("<", work,
|
||||
"dep.unit.ww>")) == 1);
|
||||
assert(occurrences(ctrace, strings.concat("<", work,
|
||||
"__ww-test-000-same.unit.ww>")) == 1);
|
||||
assert(pos(ctrace, strings.concat("<", work, "leaf.unit.ww>"))
|
||||
< pos(ctrace, strings.concat("<", work, "dep.unit.ww>")));
|
||||
assert(pos(ctrace, strings.concat("<", work, "dep.unit.ww>"))
|
||||
< pos(ctrace, strings.concat("<", work,
|
||||
"__ww-test-000-same.unit.ww>")));
|
||||
assert(has(ctrace, strings.concat("BEGIN<-c><-I><", work,
|
||||
"dep.wwi><-o><", work, "dep.s><", work, "dep.unit.ww>")));
|
||||
assert(has(ctrace, strings.concat(
|
||||
"BEGIN<-T><--test-support-module><test><-c><-o><", work,
|
||||
"__ww-test-000-same.s><", work,
|
||||
"__ww-test-000-same.unit.ww>")));
|
||||
assert(has(atrace, strings.concat("BEGIN<-o><", work,
|
||||
"dep.o><", work, "dep.s>")));
|
||||
assert(occurrences(ltrace, "\n") == 1);
|
||||
assert(has(ltrace, strings.concat("BEGIN<-o><", bin, "><", work,
|
||||
"__ww-test-000-same.o>")));
|
||||
assert(has(ltrace, strings.concat("<", work, "dep.a>")));
|
||||
assert(has(ltrace, strings.concat("<", work, "leaf.a>")));
|
||||
assert(has(ltrace, strings.concat("<", work, "test.a>")));
|
||||
assert(!has(ltrace, ".wwi>"));
|
||||
|
||||
let runav: []str = [bin];
|
||||
runcommand(root, strings.concat("exact-argv-run-", tags[si]), runav,
|
||||
(60i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 0);
|
||||
assert(has(out.stdout, "exact_argv ... ok\n"));
|
||||
if (si == 0) {
|
||||
referenceunit = strings.dup(rootunit);
|
||||
referencewwi = strings.dup(readfile(strings.concat(work,
|
||||
"dep.wwi")));
|
||||
referencearchive = strings.dup(readfile(strings.concat(work,
|
||||
"dep.a")));
|
||||
referencebin = strings.dup(readfile(bin));
|
||||
referencecompiler = strings.dup(ctrace);
|
||||
referenceassembler = strings.dup(atrace);
|
||||
referencelinker = strings.dup(ltrace);
|
||||
referenceout = strings.dup(out.stdout);
|
||||
referenceerr = strings.dup(out.stderr);
|
||||
} else {
|
||||
assert(same(referenceunit, rootunit));
|
||||
assert(same(referencewwi,
|
||||
readfile(strings.concat(work, "dep.wwi"))));
|
||||
assert(same(referencearchive,
|
||||
readfile(strings.concat(work, "dep.a"))));
|
||||
assert(same(referencebin, readfile(bin)));
|
||||
assert(same(referencecompiler, ctrace));
|
||||
assert(same(referenceassembler, atrace));
|
||||
assert(same(referencelinker, ltrace));
|
||||
assert(same(referenceout, out.stdout));
|
||||
assert(same(referenceerr, out.stderr));
|
||||
};
|
||||
clean(workroot);
|
||||
clean(bin);
|
||||
|
||||
let failenv: []str = alloc([], (env.len + 2): u64)!;
|
||||
ei = 0;
|
||||
for (ei < env.len) {
|
||||
if (!strings.hasprefix(env[ei], "WW_W6C=")
|
||||
&& !strings.hasprefix(env[ei],
|
||||
"WW_ARGV_FAILURE_TRACE=")) {
|
||||
append(failenv, env[ei]);
|
||||
};
|
||||
ei += 1;
|
||||
};
|
||||
append(failenv, strings.concat("WW_W6C=", failurewrapper));
|
||||
append(failenv, strings.concat("WW_ARGV_FAILURE_TRACE=", failuretrace));
|
||||
runcommandenv(root, strings.concat("exact-argv-fail-", tags[si]), av,
|
||||
failenv, (120i64 * (time.second: i64)): time.duration, &out);
|
||||
expectexit(&out, 1);
|
||||
assert(has(out.stderr, "ww: w6c failed for leaf\n"));
|
||||
assert(has(readfile(failuretrace), strings.concat("<-I><", work,
|
||||
"leaf.wwi>")));
|
||||
if (si == 0) { referencefailure = strings.dup(out.stderr); }
|
||||
else { assert(same(referencefailure, out.stderr)); };
|
||||
clean(workroot);
|
||||
if (os.exists(bin)) { clean(bin); };
|
||||
si += 1;
|
||||
};
|
||||
clean(root);
|
||||
};
|
||||
|
||||
@test fn package_graph_diagnostics_are_stable() void = {
|
||||
let root: str = fresh();
|
||||
let missing: str = strings.concat(root, "/missing");
|
||||
@@ -2640,9 +2879,9 @@ fn runtimepath(relative: str) str = {
|
||||
let ctraced: str = readfile(linktrace);
|
||||
assert(has(ctraced, strings.concat(" -L ", root, " -l extra")));
|
||||
|
||||
// WWstage intentionally locates sibling tools. Copy the real driver beside
|
||||
// a tracing linker and exact compiler/assembler siblings to inspect its
|
||||
// joined native-linker flag contract.
|
||||
// Keep this row on default sibling discovery: a copied driver beside a
|
||||
// tracing linker and exact compiler/assembler siblings exposes WWstage's
|
||||
// joined native-linker flag contract independently of tool overrides.
|
||||
let tracedir: str = strings.concat(repo(), "/out/link-flag-trace-",
|
||||
workescape(root));
|
||||
assert(os.mkdir(tracedir, 448i32) == 0);
|
||||
|
||||
@@ -421,7 +421,8 @@ fn writediamond(td: str, reverse: bool) str = {
|
||||
let trace: str = strings.concat(td, "/compiler.trace");
|
||||
let wrapper: str = strings.concat(td, "/trace-w6c.sh");
|
||||
testenv.writefile(trace, "");
|
||||
testenv.writefile(wrapper, strings.concat(
|
||||
testenv.writeexecutable(wrapper, strings.concat(
|
||||
"#!/bin/sh\n",
|
||||
"printf '%s\\n' \"$*\" >> \"$WW_LOCALBUILD_TRACE\"\n",
|
||||
"exec \"$WW_LOCALBUILD_W6C\" \"$@\"\n"));
|
||||
let baseenv: []str = os.getenvs();
|
||||
@@ -435,7 +436,7 @@ fn writediamond(td: str, reverse: bool) str = {
|
||||
};
|
||||
ei += 1;
|
||||
};
|
||||
append(env, strings.concat("WW_W6C=/bin/sh ", wrapper));
|
||||
append(env, strings.concat("WW_W6C=", wrapper));
|
||||
append(env, strings.concat("WW_LOCALBUILD_TRACE=", trace));
|
||||
append(env, strings.concat("WW_LOCALBUILD_W6C=",
|
||||
testenv.driver("w6c")));
|
||||
|
||||
@@ -76,6 +76,17 @@ export fn writefile(path: str, content: str) void = {
|
||||
assert(os.close(fd) == 0);
|
||||
};
|
||||
|
||||
export fn writeexecutable(path: str, content: str) void = {
|
||||
let fd: i32 = os.open(path,
|
||||
os.flag.WRONLY | os.flag.CREATE | os.flag.EXCL, 448i32);
|
||||
assert(fd >= 0);
|
||||
match (os.writeall(fd, content.ptr, content.len: u64)) {
|
||||
case let n: i64 => assert(n == content.len: i64);
|
||||
case let e: os.oserror => abort("write failed");
|
||||
};
|
||||
assert(os.close(fd) == 0);
|
||||
};
|
||||
|
||||
export fn exists(path: str) bool = {
|
||||
return os.access(path, 0i32) == 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user