build: pass direct exports to package compilers

This commit is contained in:
2026-08-12 18:42:22 +09:00
parent b373c445bd
commit edd3f4ee83
13 changed files with 678 additions and 611 deletions

View File

@@ -8,7 +8,8 @@ package wwi_test;
// 10): the `w6c -I <out.wwi>` producer IS the live import path, and
// `.wwi` is a cross-stage byte-id substrate pinned directly. POSITIVE:
// for ascii/strings/getopt (drew2-audited leak-free), drive the target
// as the PRIMARY module of a driver-combined unit, then (1) w6c -c -I and
// as the PRIMARY owner-only driver unit with separate direct exports, then
// (1) w6c -c -I and
// w6c_ww -c -I both succeed, (2) cs.wwi == ww.wwi byte-for-byte, (3) the
// emitted .wwi re-parses (wwdump -a exit 0). getopt is the recursion
// stressor. A synth fixture covers the decl-kinds + type-nodes no lib
@@ -28,10 +29,10 @@ package wwi_test;
// producer->importer flow on BOTH stages: (a) the dep `.wwi` package
// line equals the real leaf, (b) the dep `.wwi` is byte-identical
// across stages, (c) a root importing the dep RESOLVES on both stages
// and the two importer `.s` are byte-identical. The composed units are
// fed straight to w6c / w6c_ww (not `ww build`): the producer-unit
// shape `//ww:module-reset <path>` + body is exactly what the driver's
// sep_emit_body emits.
// and the two importer `.s` are byte-identical. The owner units and
// separate exports are fed straight to w6c / w6c_ww (not `ww build`):
// the producer-unit shape `//ww:module-reset <path>` + body is exactly
// what the driver's sep_emit_body emits.
import os;
import os.exec;
@@ -88,18 +89,40 @@ fn m2positive(pkg: str) void = {
let co: testenv.commandout;
testenv.runcommand(td, td, "drv", av, lifetime(), &co);
let comb: str = strings.concat(td, "/", pkg,
".sepwork/__root.unit.ww");
let work: str = strings.concat(td, "/", pkg, ".sepwork/");
let comb: str = strings.concat(work, "__root.unit.ww");
if (!testenv.exists(comb)) { fail(pkg, "no resolved unit"); };
let cs: str = strings.concat(td, "/cs.wwi");
let ws: str = strings.concat(td, "/ww.wwi");
// The driver-composed unit uses package separators and may contain the
// same compiler-owned origin fact through multiple direct interfaces;
// exact fact interning is intentionally tied to -c package mode.
let cav: []str = [testenv.driver("w6c"), "-c", "-I", cs, comb];
let deps: []str = [];
if (testenv.same(pkg, "ascii")) { append(deps, "strings"); };
if (testenv.same(pkg, "strings")) {
append(deps, "bytes"); append(deps, "encoding.utf8");
append(deps, "os"); append(deps, "types");
};
if (testenv.same(pkg, "getopt")) {
append(deps, "encoding.utf8"); append(deps, "fmt");
append(deps, "io"); append(deps, "os"); append(deps, "strings");
};
if (deps.len == 0) { abort("unknown m2 package"); };
let cav: []str = [testenv.driver("w6c"), "-c"];
let di: i32 = 0;
for (di < deps.len) {
append(cav, "--import"); append(cav, deps[di]);
append(cav, strings.concat(work, deps[di], ".wwi"));
di += 1;
};
append(cav, "-I"); append(cav, cs); append(cav, comb);
if (!runok(td, "w6c", cav)) { fail(pkg, "w6c -c -I rejected"); };
let wav: []str = [testenv.driver("w6c_ww"), "-c", "-I", ws, comb];
let wav: []str = [testenv.driver("w6c_ww"), "-c"];
di = 0;
for (di < deps.len) {
append(wav, "--import"); append(wav, deps[di]);
append(wav, strings.concat(work, deps[di], ".wwi"));
di += 1;
};
append(wav, "-I"); append(wav, ws); append(wav, comb);
if (!runok(td, "w6c_ww", wav)) { fail(pkg, "w6c_ww -c -I rejected"); };
if (!testenv.same(testenv.readfile(cs), testenv.readfile(ws))) {
@@ -318,22 +341,21 @@ fn leafrow(tag: str, path: str, leaf: str, body: str, want: str) void = {
fail(tag, "w6c vs w6c_ww .wwi differ (rule 10)");
};
// Leg c — a root importing the dep RESOLVES on both stages
// (pre-fix: "package main does not match import path" REJECT). The
// dep `.wwi` is prepended under //ww:module <path>, exactly as the
// driver composes an importer unit.
// Leg c — a root importing the dep RESOLVES from a separate export on
// both stages (pre-fix: "package main does not match import path"
// REJECT).
testenv.writefile(root, strings.concat(
"//ww:module ", path, "\n",
testenv.readfile(cswwi), "\n",
"//ww:module-reset\n",
"package main;\n",
"import ", path, ";\n",
"export fn main() i32 = { return 42; };\n"));
let rcav: []str = [testenv.driver("w6c"), "-c", "-o", rcss, root];
let rcav: []str = [testenv.driver("w6c"), "-c", "--import", path,
cswwi, "-o", rcss, root];
if (!runok(td, "csroot", rcav)) {
fail(tag, "w6c rejected the import (BUG-C)");
};
let rwav: []str = [testenv.driver("w6c_ww"), "-c", "-o", rwws, root];
let rwav: []str = [testenv.driver("w6c_ww"), "-c", "--import", path,
wwwwi, "-o", rwws, root];
if (!runok(td, "wsroot", rwav)) {
fail(tag, "w6c_ww rejected the import (BUG-C)");
};

View File

@@ -726,8 +726,9 @@ fn workescape(s: str) str = {
let prodwork: str = strings.concat(prodout, ".sepwork/");
let produnit: str = readfile(strings.concat(prodwork,
"pkg.unit.ww"));
assert(has(produnit, "//ww:module api\n"));
assert(!has(produnit, "//ww:module implementation\n"));
assert(has(produnit, "//ww:module-reset pkg\n"));
assert(!has(produnit, "//ww:module "));
assert(!has(produnit, "IMPLEMENTATION_SOURCE"));
assert(!has(produnit, "__same"));
assert(!has(produnit, "__external"));
assert(!os.exists(strings.concat(prodwork, "__same.unit.ww")));
@@ -807,30 +808,20 @@ fn workescape(s: str) str = {
let externalproduction: str = readfile(strings.concat(sharedwork,
"__ww-test-001-external-production.unit.ww"));
assert(!os.exists(strings.concat(externalbin, ".sepwork")));
assert(has(sameunit, "//ww:module api\n"));
assert(has(sameunit, "//ww:module __same\n"));
assert(has(sameunit, "//ww:module test\n"));
assert(!has(sameunit, "//ww:module implementation\n"));
assert(!has(sameunit, "//ww:module __external\n"));
assert(!has(sameunit, "//ww:module "));
assert(os.exists(strings.concat(sharedwork,
"__external.unit.ww")));
assert(has(sameunit, "PACKAGE_PRODUCTION_A"));
assert(has(sameunit, "PACKAGE_PRODUCTION_Z"));
assert(has(sameunit, "SAME_TEST_SOURCE"));
assert(!has(sameunit, "EXTERNAL_TEST_SOURCE"));
assert(has(externalunit, "//ww:module pkg\n"));
assert(has(externalunit, "//ww:module __external\n"));
assert(has(externalunit, "//ww:module test\n"));
assert(!has(externalunit, "//ww:module api\n"));
assert(!has(externalunit, "//ww:module implementation\n"));
assert(!has(externalunit, "//ww:module __same\n"));
assert(!has(externalunit, "//ww:module "));
assert(has(externalunit, "EXTERNAL_TEST_SOURCE"));
assert(!has(externalunit, "PACKAGE_PRODUCTION_A"));
assert(!has(externalunit, "PACKAGE_PRODUCTION_Z"));
assert(has(externalproduction, "PACKAGE_PRODUCTION_A"));
assert(has(externalproduction, "PACKAGE_PRODUCTION_Z"));
assert(has(externalproduction, "//ww:module api\n"));
assert(!has(externalproduction, "//ww:module implementation\n"));
assert(!has(externalproduction, "//ww:module "));
assert(!has(externalproduction, "SAME_TEST_SOURCE"));
assert(!has(externalproduction, "EXTERNAL_TEST_SOURCE"));
assert(!has(readfile(strings.concat(sharedwork, "api.unit.ww")),
@@ -872,6 +863,30 @@ fn workescape(s: str) str = {
"__ww-test-001-external.unit.ww") == 1);
assert(occurrences(ctrace,
"-T --test-support-module") == 2);
let samecompile: str = linecontaining(ctrace,
"__ww-test-000-same.unit.ww");
let externalcompile: str = linecontaining(ctrace,
"__ww-test-001-external.unit.ww");
let productioncompile: str = linecontaining(ctrace,
"__ww-test-001-external-production.unit.ww");
assert(same(samecompile, strings.concat(
"-T --test-support-module test -c --import __same ",
sharedwork, "__same.wwi --import api ", sharedwork,
"api.wwi --import test ", sharedwork, "test.wwi -o ",
sharedwork, "__ww-test-000-same.s ", sharedwork,
"__ww-test-000-same.unit.ww")));
assert(same(externalcompile, strings.concat(
"-T --test-support-module test -c --import __external ",
sharedwork, "__external.wwi --import pkg ", sharedwork,
"__ww-test-001-external-production.wwi --import test ",
sharedwork, "test.wwi -o ", sharedwork,
"__ww-test-001-external.s ", sharedwork,
"__ww-test-001-external.unit.ww")));
assert(same(productioncompile, strings.concat(
"-c --import api ", sharedwork, "api.wwi -I ", sharedwork,
"__ww-test-001-external-production.wwi -o ", sharedwork,
"__ww-test-001-external-production.s ", sharedwork,
"__ww-test-001-external-production.unit.ww")));
let ltrace: str = readfile(linkertrace);
assert(occurrences(ltrace, "\n") == 2);
let samelink: str = linecontaining(ltrace,
@@ -1204,43 +1219,33 @@ fn workescape(s: str) str = {
alphaartifact, ".unit.ww"));
let betaunit: str = readfile(strings.concat(sharedwork,
betaartifact, ".unit.ww"));
assert(has(commonunit, "//ww:module leaf\n"));
assert(!has(commonunit, "//ww:module test\n"));
assert(has(alphaunit, "//ww:module common\n"));
assert(!has(alphaunit, "//ww:module leaf\n"));
assert(has(commonunit, "//ww:module-reset common\n"));
assert(!has(commonunit, "//ww:module "));
assert(!has(alphaunit, "//ww:module "));
assert(has(alphaunit, "MULTIDIR_ALPHA_A"));
assert(has(alphaunit, "MULTIDIR_ALPHA_Z"));
assert(has(betaunit, "//ww:module common\n"));
assert(has(betaunit, "//ww:module alpha\n"));
assert(!has(betaunit, "//ww:module leaf\n"));
assert(!has(betaunit, "//ww:module "));
assert(has(betaunit, "MULTIDIR_BETA"));
assert(!has(commonunit, "DEPENDENCY_TEST_FILE_MUST_NOT_COMPILE"));
let roots: []str = [readfile(strings.concat(sharedwork,
rootkeys[0], ".unit.ww")), readfile(strings.concat(sharedwork,
rootkeys[1], ".unit.ww")), readfile(strings.concat(sharedwork,
rootkeys[2], ".unit.ww")), readfile(strings.concat(sharedwork,
rootkeys[3], ".unit.ww"))];
assert(has(roots[0], "//ww:module _alpha_same\n"));
assert(has(roots[0], "//ww:module common\n"));
assert(has(roots[0], "//ww:module test\n"));
assert(!has(roots[0], "//ww:module leaf\n"));
assert(!has(roots[0], "//ww:module alpha\n"));
assert(!has(roots[0], "//ww:module "));
assert(has(roots[0], "MULTIDIR_ALPHA_A"));
assert(has(roots[0], "MULTIDIR_ALPHA_Z"));
assert(has(roots[1], "//ww:module alpha\n"));
assert(has(roots[1], "//ww:module _alpha_external\n"));
assert(has(roots[1], "//ww:module test\n"));
assert(!has(roots[1], "//ww:module common\n"));
assert(!has(roots[1], "//ww:module _alpha_same\n"));
assert(has(roots[2], "//ww:module _beta_same\n"));
assert(has(roots[2], "//ww:module common\n"));
assert(has(roots[2], "//ww:module alpha\n"));
assert(has(roots[2], "//ww:module test\n"));
assert(!has(roots[2], "//ww:module leaf\n"));
assert(!has(roots[2], "//ww:module beta\n"));
assert(has(roots[3], "//ww:module beta\n"));
assert(has(roots[3], "//ww:module _beta_external\n"));
assert(has(roots[3], "//ww:module test\n"));
assert(!has(roots[3], "//ww:module common\n"));
assert(has(roots[0], "MULTIDIR_ALPHA_SAME"));
assert(!has(roots[0], "MULTIDIR_ALPHA_EXTERNAL"));
assert(!has(roots[1], "//ww:module "));
assert(has(roots[1], "MULTIDIR_ALPHA_EXTERNAL"));
assert(!has(roots[1], "MULTIDIR_ALPHA_A"));
assert(!has(roots[2], "//ww:module "));
assert(has(roots[2], "MULTIDIR_BETA"));
assert(has(roots[2], "MULTIDIR_BETA_SAME"));
assert(!has(roots[3], "//ww:module "));
assert(has(roots[3], "MULTIDIR_BETA_EXTERNAL"));
assert(!has(roots[3], "MULTIDIR_BETA_SAME"));
let products: []str = ["leaf", "common", alphaartifact, betaartifact,
"_alpha_same", "_alpha_external", "_beta_same",
"_beta_external", "test"];
@@ -1625,13 +1630,7 @@ fn workescape(s: str) str = {
let ri: i32 = 0;
for (ri < keys.len) {
let unit: str = readfile(strings.concat(work, keys[ri], ".unit.ww"));
assert(has(unit, "//ww:module __wwtest\n"));
if (ri == 1 || ri == 2) {
assert(has(unit, "//ww:module test\n"));
};
if (ri == 3) {
assert(has(unit, "//ww:module consumer\n"));
};
assert(!has(unit, "//ww:module "));
let runav: []str = [bins[ri]];
runcommand(root, strings.concat("mixed-run-", stages[si], "-",
keys[ri]), runav,
@@ -1748,8 +1747,8 @@ fn workescape(s: str) str = {
let cbin: str = readfile(bin);
let rootunit: str = readfile(strings.concat(work,
"__ww-test-000-same.unit.ww"));
assert(has(rootunit, "//ww:module p00\n"));
assert(!has(rootunit, "//ww:module p01\n"));
assert(has(rootunit, "//ww:module-reset\npackage target;"));
assert(!has(rootunit, "//ww:module "));
let linkargs: str = readfile(trace);
assert(linkargs.len > 8192);
assert(!has(linkargs, ".wwi\n"));
@@ -2075,8 +2074,7 @@ fn workescape(s: str) str = {
"__ww-test-000-external-production.unit.ww"));
let supportunit: str = readfile(strings.concat(work,
"__wwtest.unit.ww"));
assert(has(rootunit, "//ww:module test\n"));
assert(has(rootunit, "//ww:module __wwtest\n"));
assert(!has(rootunit, "//ww:module "));
assert(has(rootunit, "USER_TEST_EXTERNAL"));
assert(!has(rootunit, "USER_TEST_PACKAGE_A"));
assert(!has(rootunit, "USER_TEST_PACKAGE_Z"));
@@ -2115,121 +2113,52 @@ fn workescape(s: str) str = {
clean(root);
};
@test fn diamond_test_dependency_compiles_once() void = {
let root: str = fresh();
let shared: str = strings.concat(root, "/shared");
let left: str = strings.concat(root, "/left");
let right: str = strings.concat(root, "/right");
let target: str = strings.concat(root, "/diamond");
assert(os.mkdir(shared, 448i32) == 0);
assert(os.mkdir(left, 448i32) == 0);
assert(os.mkdir(right, 448i32) == 0);
assert(os.mkdir(target, 448i32) == 0);
writefile(strings.concat(shared, "/shared.ww"),
"package shared;\nexport fn value() i32 = { return 20; };\n");
writefile(strings.concat(left, "/left.ww"), strings.concat(
"package left;\nimport shared;\n",
"export fn value() i32 = { return shared.value(); };\n"));
writefile(strings.concat(right, "/right.ww"), strings.concat(
"package right;\nimport shared;\n",
"export fn value() i32 = { return shared.value() + 1; };\n"));
writefile(strings.concat(target, "/diamond.ww"),
"package diamond;\nfn local() i32 = { return 1; };\n");
writefile(strings.concat(target, "/diamond_test.ww"), strings.concat(
"package diamond;\nimport left;\nimport right;\n",
"@test fn one_shared_compile() void = {\n",
" assert(left.value() + right.value() + local() == 42);\n};\n"));
let trace: str = strings.concat(root, "/compiler.trace");
let wrapper: str = strings.concat(root, "/trace-w6c.sh");
writefile(trace, "");
writeexecutable(wrapper, strings.concat(
"#!/bin/sh\n",
"printf '%s\\n' \"$*\" >> \"$WW_PACKAGE_TRACE\"\n",
"exec \"$WW_PACKAGE_W6C\" \"$@\"\n"));
let baseenv: []str = os.getenvs();
let env: []str = alloc([], (baseenv.len + 3): u64)!;
let ei: i32 = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_PACKAGE_W6C=")) {
append(env, baseenv[ei]);
};
ei += 1;
};
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");
let av: []str = [driver("ww"), "test", "-c", "-o", bin,
"-I", root, target];
let out: commandout;
runcommandenv(root, "diamond-build", av, env,
(120i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(occurrences(readfile(trace), "shared.unit.ww") == 1);
let work: str = strings.concat(bin, ".sepwork/");
let unit: str = readfile(strings.concat(work,
"__ww-test-000-same.unit.ww"));
assert(has(unit, "//ww:module left\n"));
assert(has(unit, "//ww:module right\n"));
assert(!has(unit, "//ww:module shared\n"));
assert(has(readfile(strings.concat(work, "left.unit.ww")),
"//ww:module shared\n"));
assert(has(readfile(strings.concat(work, "right.unit.ww")),
"//ww:module shared\n"));
assert(os.exists(strings.concat(work, "shared.a")));
let runav: []str = [bin];
runcommand(root, "diamond-run", runav,
(60i64 * (time.second: i64)): time.duration, &out);
expectexit(&out, 0);
assert(has(out.stdout, "one_shared_compile ... ok\n"));
clean(root);
};
@test fn exact_package_tool_argv_stage_parity() void = {
let root: str = fresh();
let source: str = strings.concat(root, "/source tree");
let runtime: str = strings.concat(root, "/runtime library");
let leaf: str = strings.concat(source, "/ww_root_parity_leaf_7f3");
let dep: str = strings.concat(source, "/ww_root_parity_dep_7f3");
let base: str = strings.concat(source, "/ww_root_parity_base_7f3");
let left: str = strings.concat(source, "/ww_root_parity_left_7f3");
let right: str = strings.concat(source, "/ww_root_parity_right_7f3");
let target: str = strings.concat(source, "/ww_root_parity_target_7f3");
let tools: str = strings.concat(root, "/tool wrappers");
assert(os.mkdir(source, 448i32) == 0);
assert(os.mkdir(runtime, 448i32) == 0);
let copyav: []str = ["/bin/cp", "-R", strings.concat(repo(), "/lib/."),
source];
let copyout: commandout;
runcommand(root, "copy-source-library", copyav,
(30i64 * (time.second: i64)): time.duration, &copyout);
expectexit(&copyout, 0);
assert(copyout.stderr.len == 0);
let support: str = strings.concat(source, "/test/run.ww");
let supportbody: str = readfile(support);
assert(os.remove(support) == 0);
writefile(support, strings.concat("// WW_SRCLIB fixture marker\n",
supportbody));
writefile(strings.concat(runtime, "/libwwrt.a"),
readfile(strings.concat(repo(), "/out/lib/libwwrt.a")));
assert(os.mkdir(leaf, 448i32) == 0);
assert(os.mkdir(dep, 448i32) == 0);
assert(os.mkdir(base, 448i32) == 0);
assert(os.mkdir(left, 448i32) == 0);
assert(os.mkdir(right, 448i32) == 0);
assert(os.mkdir(target, 448i32) == 0);
assert(os.mkdir(tools, 448i32) == 0);
writefile(strings.concat(leaf, "/leaf.ww"), strings.concat(
"package ww_root_parity_leaf_7f3;\n",
"export fn value() i32 = { return 40; };\n"));
writefile(strings.concat(dep, "/dep.ww"), strings.concat(
"package ww_root_parity_dep_7f3;\n",
"import ww_root_parity_leaf_7f3;\n",
let basea: str = strings.concat(
"package ww_root_parity_base_7f3;\n",
"export fn value() i32 = { return 20; };\n");
let basez: str = strings.concat(
"package ww_root_parity_base_7f3;\n",
"fn private_value() i32 = { return 99; };\n");
let leftbody: str = strings.concat(
"package ww_root_parity_left_7f3;\n",
"import ww_root_parity_base_7f3;\n",
"import ww_root_parity_base_7f3;\n",
"export fn value() i32 = { return ",
"ww_root_parity_leaf_7f3.value() + 2; };\n"));
writefile(strings.concat(target, "/target.ww"), strings.concat(
"package ww_root_parity_target_7f3;\n",
"import ww_root_parity_dep_7f3;\n",
"fn value() i32 = { return ww_root_parity_dep_7f3.value(); };\n"));
writefile(strings.concat(target, "/target_test.ww"), strings.concat(
"package ww_root_parity_target_7f3;\n",
"@test fn exact_argv() void = { assert(value() == 42); };\n"));
"ww_root_parity_base_7f3.value(); };\n");
let rightbody: str = strings.concat(
"package ww_root_parity_right_7f3;\n",
"import ww_root_parity_base_7f3;\n",
"export fn value() i32 = { return ",
"ww_root_parity_base_7f3.value() + 1; };\n");
let rootbody: str = strings.concat(
"package main;\n",
"import ww_root_parity_right_7f3;\n",
"import ww_root_parity_left_7f3;\n",
"fn main() i32 = { return ww_root_parity_left_7f3.value() + ",
"ww_root_parity_right_7f3.value() + 1; };\n");
writefile(strings.concat(base, "/a.ww"), basea);
writefile(strings.concat(base, "/z.ww"), basez);
writefile(strings.concat(left, "/left.ww"), leftbody);
writefile(strings.concat(right, "/right.ww"), rightbody);
writefile(strings.concat(target, "/main.ww"), rootbody);
let compilerwrapper: str = strings.concat(tools, "/w6c wrapper.sh");
let assemblerwrapper: str = strings.concat(tools, "/w6a wrapper.sh");
@@ -2262,19 +2191,43 @@ fn workescape(s: str) str = {
"for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ",
"\"$WW_ARGV_FAILURE_TRACE\"; done\n",
"printf '\\n' >> \"$WW_ARGV_FAILURE_TRACE\"\n",
"exit 23\n"));
"owner=\n",
"for arg in \"$@\"; do if [ \"$arg\" = ",
"\"$WW_ARGV_MISSING_OWNER\" ]; then owner=1; fi; done\n",
"if [ -n \"$owner\" ]; then\n",
" mv -- \"$WW_ARGV_MISSING_EXPORT\" ",
"\"$WW_ARGV_MISSING_EXPORT.saved\" || exit 24\n",
" \"$WW_ARGV_REAL_COMPILER\" \"$@\"\n",
" rc=$?\n",
" mv -- \"$WW_ARGV_MISSING_EXPORT.saved\" ",
"\"$WW_ARGV_MISSING_EXPORT\" || exit 25\n",
" exit $rc\n",
"fi\n",
"exec \"$WW_ARGV_REAL_COMPILER\" \"$@\"\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 stages: []str = ["ww", "ww", "ww_ww", "ww_ww"];
let compilers: []str = ["w6c", "w6c", "w6c_ww", "w6c_ww"];
let assemblers: []str = ["w6a", "w6a", "w6a_ww", "w6a_ww"];
let linkers: []str = ["w6l", "w6l", "w6l_ww", "w6l_ww"];
let tags: []str = ["c1", "c2", "ww1", "ww2"];
let bin: str = strings.concat(root, "/published binary");
let workroot: str = strings.concat(bin, ".sepwork");
let work: str = strings.concat(workroot, "/");
let referenceunit: str = "";
let referencewwi: str = "";
let referencearchive: str = "";
let artifacts: []str = ["ww_root_parity_base_7f3",
"ww_root_parity_left_7f3", "ww_root_parity_right_7f3"];
let unitartifacts: []str = ["ww_root_parity_base_7f3",
"ww_root_parity_left_7f3", "ww_root_parity_right_7f3", "__root"];
let wantunits: []str = [strings.concat(
"//ww:module-reset ww_root_parity_base_7f3\n", basea,
"\n//ww:module-reset ww_root_parity_base_7f3\n", basez, "\n"),
strings.concat("//ww:module-reset ww_root_parity_left_7f3\n",
leftbody, "\n"),
strings.concat("//ww:module-reset ww_root_parity_right_7f3\n",
rightbody, "\n"),
strings.concat("//ww:module-reset\n", rootbody, "\n")];
let referenceunits: []str = ["", "", "", ""];
let referenceexports: []str = ["", "", ""];
let referencearchives: []str = ["", "", ""];
let referencebin: str = "";
let referencecompiler: str = "";
let referenceassembler: str = "";
@@ -2316,7 +2269,13 @@ fn workescape(s: str) str = {
&& !strings.hasprefix(baseenv[ei],
"WW_ARGV_REAL_ASSEMBLER=")
&& !strings.hasprefix(baseenv[ei],
"WW_ARGV_REAL_LINKER=")) {
"WW_ARGV_REAL_LINKER=")
&& !strings.hasprefix(baseenv[ei],
"WW_ARGV_FAILURE_TRACE=")
&& !strings.hasprefix(baseenv[ei],
"WW_ARGV_MISSING_EXPORT=")
&& !strings.hasprefix(baseenv[ei],
"WW_ARGV_MISSING_OWNER=")) {
append(env, baseenv[ei]);
};
ei += 1;
@@ -2336,72 +2295,89 @@ fn workescape(s: str) str = {
append(env, strings.concat("WW_ARGV_REAL_LINKER=",
driver(linkers[si])));
let av: []str = [driver(stages[si]), "test", "-c", "-o", bin,
let av: []str = [driver(stages[si]), "build", "-o", bin,
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,
"ww_root_parity_dep_7f3.unit.ww"));
assert(has(rootunit, "//ww:module ww_root_parity_dep_7f3\n"));
assert(!has(rootunit, "//ww:module ww_root_parity_leaf_7f3\n"));
assert(has(depunit, "//ww:module ww_root_parity_leaf_7f3\n"));
assert(os.exists(strings.concat(work,
"ww_root_parity_leaf_7f3.wwi")));
assert(os.exists(strings.concat(work,
"ww_root_parity_leaf_7f3.a")));
assert(os.exists(strings.concat(work,
"ww_root_parity_dep_7f3.wwi")));
assert(os.exists(strings.concat(work,
"ww_root_parity_dep_7f3.a")));
assert(has(readfile(strings.concat(work, "test.unit.ww")),
"// WW_SRCLIB fixture marker\n"));
assert(!os.exists(strings.concat(work,
"__ww-test-000-same.wwi")));
assert(!os.exists(strings.concat(work,
"__ww-test-000-same.a")));
let ui: i32 = 0;
for (ui < unitartifacts.len) {
let unit: str = readfile(strings.concat(work, unitartifacts[ui],
".unit.ww"));
assert(same(unit, wantunits[ui]));
assert(!has(unit, "//ww:module "));
if (si == 0) { referenceunits[ui] = strings.dup(unit); }
else { assert(same(referenceunits[ui], unit)); };
ui += 1;
};
let ai: i32 = 0;
for (ai < artifacts.len) {
let exportf: str = readfile(strings.concat(work, artifacts[ai],
".wwi"));
let archive: str = readfile(strings.concat(work, artifacts[ai],
".a"));
if (si == 0) {
referenceexports[ai] = strings.dup(exportf);
referencearchives[ai] = strings.dup(archive);
} else {
assert(same(referenceexports[ai], exportf));
assert(same(referencearchives[ai], archive));
};
ai += 1;
};
assert(!os.exists(strings.concat(work, "__root.wwi")));
assert(!os.exists(strings.concat(work, "__root.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,
"ww_root_parity_leaf_7f3.unit.ww>")) == 1);
assert(occurrences(ctrace, strings.concat("<", work,
"ww_root_parity_dep_7f3.unit.ww>")) == 1);
assert(occurrences(ctrace, strings.concat("<", work,
"__ww-test-000-same.unit.ww>")) == 1);
assert(pos(ctrace, strings.concat("<", work,
"ww_root_parity_leaf_7f3.unit.ww>"))
< pos(ctrace, strings.concat("<", work,
"ww_root_parity_dep_7f3.unit.ww>")));
assert(pos(ctrace, strings.concat("<", work,
"ww_root_parity_dep_7f3.unit.ww>"))
< pos(ctrace, strings.concat("<", work,
"__ww-test-000-same.unit.ww>")));
assert(has(ctrace, strings.concat("BEGIN<-c><-I><", work,
"ww_root_parity_dep_7f3.wwi><-o><", work,
"ww_root_parity_dep_7f3.s><", work,
"ww_root_parity_dep_7f3.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(occurrences(ctrace, "\n") == 4);
let baseline: str = strings.concat("BEGIN<-c><-I><", work,
"ww_root_parity_base_7f3.wwi><-o><", work,
"ww_root_parity_base_7f3.s><", work,
"ww_root_parity_base_7f3.unit.ww>");
let leftline: str = strings.concat("BEGIN<-c><--import>",
"<ww_root_parity_base_7f3><", work,
"ww_root_parity_base_7f3.wwi><-I><", work,
"ww_root_parity_left_7f3.wwi><-o><", work,
"ww_root_parity_left_7f3.s><", work,
"ww_root_parity_left_7f3.unit.ww>");
let rightline: str = strings.concat("BEGIN<-c><--import>",
"<ww_root_parity_base_7f3><", work,
"ww_root_parity_base_7f3.wwi><-I><", work,
"ww_root_parity_right_7f3.wwi><-o><", work,
"ww_root_parity_right_7f3.s><", work,
"ww_root_parity_right_7f3.unit.ww>");
let rootline: str = strings.concat("BEGIN<-c><--import>",
"<ww_root_parity_left_7f3><", work,
"ww_root_parity_left_7f3.wwi><--import>",
"<ww_root_parity_right_7f3><", work,
"ww_root_parity_right_7f3.wwi><-o><", work,
"__root.s><", work, "__root.unit.ww>");
assert(same(linecontaining(ctrace,
"ww_root_parity_base_7f3.unit.ww"), baseline));
assert(same(linecontaining(ctrace,
"ww_root_parity_left_7f3.unit.ww"), leftline));
assert(same(linecontaining(ctrace,
"ww_root_parity_right_7f3.unit.ww"), rightline));
assert(same(linecontaining(ctrace, "__root.unit.ww"), rootline));
assert(!has(rootline, "ww_root_parity_base_7f3.wwi"));
assert(occurrences(atrace, "\n") == 4);
assert(has(atrace, strings.concat("BEGIN<-o><", work,
"ww_root_parity_dep_7f3.o><", work,
"ww_root_parity_dep_7f3.s>")));
"ww_root_parity_left_7f3.o><", work,
"ww_root_parity_left_7f3.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,
"ww_root_parity_dep_7f3.a>")));
assert(has(ltrace, strings.concat("<", work,
"ww_root_parity_leaf_7f3.a>")));
assert(has(ltrace, strings.concat("<", work, "test.a>")));
"__root.o>")));
ai = 0;
for (ai < artifacts.len) {
assert(occurrences(ltrace, strings.concat("<", work, artifacts[ai],
".a>")) == 1);
ai += 1;
};
assert(has(ltrace, strings.concat("<", runtime, "/libwwrt.a>")));
assert(!has(ltrace, strings.concat("<", repo(),
"/out/lib/libwwrt.a>")));
@@ -2410,14 +2386,9 @@ fn workescape(s: str) str = {
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"));
expectexit(&out, 42);
assert(out.stdout.len == 0 && out.stderr.len == 0);
if (si == 0) {
referenceunit = strings.dup(rootunit);
referencewwi = strings.dup(readfile(strings.concat(work,
"ww_root_parity_dep_7f3.wwi")));
referencearchive = strings.dup(readfile(strings.concat(work,
"ww_root_parity_dep_7f3.a")));
referencebin = strings.dup(readfile(bin));
referencecompiler = strings.dup(ctrace);
referenceassembler = strings.dup(atrace);
@@ -2425,13 +2396,6 @@ fn workescape(s: str) str = {
referenceout = strings.dup(out.stdout);
referenceerr = strings.dup(out.stderr);
} else {
assert(same(referenceunit, rootunit));
assert(same(referencewwi,
readfile(strings.concat(work,
"ww_root_parity_dep_7f3.wwi"))));
assert(same(referencearchive,
readfile(strings.concat(work,
"ww_root_parity_dep_7f3.a"))));
assert(same(referencebin, readfile(bin)));
assert(same(referencecompiler, ctrace));
assert(same(referenceassembler, atrace));
@@ -2442,7 +2406,7 @@ fn workescape(s: str) str = {
clean(workroot);
clean(bin);
let failenv: []str = alloc([], (env.len + 2): u64)!;
let failenv: []str = alloc([], (env.len + 4): u64)!;
ei = 0;
for (ei < env.len) {
if (!strings.hasprefix(env[ei], "WW_W6C=")
@@ -2454,13 +2418,21 @@ fn workescape(s: str) str = {
};
append(failenv, strings.concat("WW_W6C=", failurewrapper));
append(failenv, strings.concat("WW_ARGV_FAILURE_TRACE=", failuretrace));
append(failenv, strings.concat("WW_ARGV_MISSING_EXPORT=", work,
"ww_root_parity_base_7f3.wwi"));
append(failenv, strings.concat("WW_ARGV_MISSING_OWNER=", work,
"ww_root_parity_left_7f3.unit.ww"));
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 ww_root_parity_leaf_7f3\n"));
assert(has(readfile(failuretrace), strings.concat("<-I><", work,
"ww_root_parity_leaf_7f3.wwi>")));
let wantfailure: str = strings.concat(
"w6c: import ww_root_parity_base_7f3: cannot read ", work,
"ww_root_parity_base_7f3.wwi\n",
"ww: w6c failed for ww_root_parity_left_7f3\n");
assert(same(out.stderr, wantfailure));
assert(has(readfile(failuretrace), strings.concat(
"<--import><ww_root_parity_base_7f3><", work,
"ww_root_parity_base_7f3.wwi>")));
if (si == 0) { referencefailure = strings.dup(out.stderr); }
else { assert(same(referencefailure, out.stderr)); };
clean(workroot);

View File

@@ -88,25 +88,22 @@ fn samefile(a: str, b: str, why: str) void = {
let cwork: str = strings.concat(stems[0], ".sepwork/");
let cwork2: str = strings.concat(stems[1], ".sepwork/");
let wwork: str = strings.concat(stems[2], ".sepwork/");
let bariface: str = testenv.readfile(strings.concat(cwork, "example.bar.wwi"));
let fooiface: str = testenv.readfile(strings.concat(cwork, "example.foo.wwi"));
let foounit: str = testenv.readfile(strings.concat(cwork,
"example.foo.unit.ww"));
let wantfoo: str = strings.concat("//ww:module example.bar\n", bariface,
"\n//ww:module-reset example.foo\n", afoosrc,
let wantfoo: str = strings.concat("//ww:module-reset example.foo\n", afoosrc,
"\n//ww:module-reset example.foo\n", zfoosrc, "\n");
if (!testenv.same(foounit, wantfoo)
|| testenv.has(foounit, "DECOY_FILE")) {
fail("foo unit is not its sorted, owned source set plus direct bar export");
|| testenv.has(foounit, "DECOY_FILE")
|| testenv.has(foounit, "//ww:module ")) {
fail("foo unit is not exactly its sorted, owned source set");
};
let wantroot: str = strings.concat("//ww:module example.foo\n", fooiface,
"\n//ww:module-reset\n", appsrc, "\n");
let wantroot: str = strings.concat("//ww:module-reset\n", appsrc, "\n");
if (!testenv.same(wantroot, testenv.readfile(strings.concat(cwork,
"__root.unit.ww")))) {
fail("root unit is not direct-foo-only");
fail("root unit is not exactly its owned source");
};
let keys: []str = ["example.base", "example.bar", "example.foo"];
let suffixes: []str = [".wwi", ".a"];
let suffixes: []str = [".unit.ww", ".wwi", ".a"];
i = 0;
for (i < keys.len) {
let j: i32 = 0;
@@ -120,6 +117,10 @@ fn samefile(a: str, b: str, why: str) void = {
};
i += 1;
};
samefile(strings.concat(cwork, "__root.unit.ww"), strings.concat(cwork2,
"__root.unit.ww"), "root unit changed across clean C builds");
samefile(strings.concat(cwork, "__root.unit.ww"), strings.concat(wwork,
"__root.unit.ww"), "root unit differs between stages");
samefile(stems[0], stems[1], "C executables are not deterministic");
samefile(stems[0], stems[2], "C/WW executables differ");

View File

@@ -286,12 +286,11 @@ fn rejectstable(dir: str, label: str, target: str, needle: str) void = {
|| testenv.has(apiiface, "hidden")) {
fail("self-contained", "api export leaked unrelated or private declarations");
};
let expectedunit: str = strings.concat("//ww:module api\n", apiiface,
"\n//ww:module-reset\n", mainsrc, "\n");
let expectedunit: str = strings.concat("//ww:module-reset\n", mainsrc, "\n");
if (!testenv.same(expectedunit, testenv.readfile(strings.concat(cwork,
"__root.unit.ww"))) || !testenv.same(expectedunit,
testenv.readfile(strings.concat(wwork, "__root.unit.ww")))) {
fail("self-contained", "consumer compiler input was not direct-api-only");
fail("self-contained", "consumer unit was not exactly its owned source");
};
if (!testenv.exists(strings.concat(cwork, "implementation.a"))
|| !testenv.exists(strings.concat(cwork, "dimensions.a"))) {
@@ -405,10 +404,12 @@ fn writediamond(td: str, reverse: bool) str = {
};
let unit: str = testenv.readfile(strings.concat(scratch,
"__root.unit.ww"));
let lp: i32 = testenv.pos(unit, "//ww:module left\n");
let rp: i32 = testenv.pos(unit, "//ww:module right\n");
if (lp < 0 || rp < 0 || lp >= rp) {
fail("diamond", "dependency traversal did not byte-sort imports");
let rootbody: str = testenv.readfile(strings.concat(main, "/main.ww"));
let wantroot: str = strings.concat("//ww:module-reset\n", rootbody,
"\n");
if (!testenv.same(unit, wantroot) || testenv.has(unit,
"//ww:module ")) {
fail("diamond", "root unit contains non-owned export text");
};
let sharedunit: str = testenv.readfile(strings.concat(scratch,
"shared.unit.ww"));
@@ -426,8 +427,7 @@ fn writediamond(td: str, reverse: bool) str = {
};
if (testenv.occurrences(leftiface, "export type token") != 1
|| testenv.occurrences(rightiface, "export type token") != 1
|| testenv.occurrences(unit, "export type token") != 2
|| testenv.occurrences(unit, "//ww:module shared\n") != 2) {
|| testenv.has(unit, "export type token")) {
fail("diamond", "origin fact closure did not merge deterministically");
};
i += 1;
@@ -452,43 +452,6 @@ fn writediamond(td: str, reverse: bool) str = {
fail("diamond", "shuffled enumeration changed package units");
};
// Count actual compiler actions, rather than inferring interning from
// artifact names. The wrapper is selected through the production
// driver's existing tool override and records one row per w6c process.
let trace: str = strings.concat(td, "/compiler.trace");
let wrapper: str = strings.concat(td, "/trace-w6c.sh");
testenv.writefile(trace, "");
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();
let env: []str = alloc([], (baseenv.len + 3): u64)!;
let ei: i32 = 0;
for (ei < baseenv.len) {
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
&& !strings.hasprefix(baseenv[ei], "WW_LOCALBUILD_TRACE=")
&& !strings.hasprefix(baseenv[ei], "WW_LOCALBUILD_W6C=")) {
append(env, baseenv[ei]);
};
ei += 1;
};
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")));
let countedout: str = strings.concat(td, "/diamond-counted");
let countedav: []str = [testenv.driver("ww"), "build", "-I", treea,
"-o", countedout, main];
let counted: testenv.commandout;
testenv.runcommandenv(td, td, "diamond_compile_count", countedav,
env, tmo(), &counted);
if (counted.termination != exec.termination.EXIT || counted.code != 0) {
fail("diamond", "instrumented build failed");
};
if (testenv.occurrences(testenv.readfile(trace), "shared.unit.ww") != 1) {
fail("diamond", "shared package was not compiled exactly once");
};
testenv.clean(td);
};
@@ -604,10 +567,11 @@ fn writediamond(td: str, reverse: bool) str = {
"__root.unit.ww"));
let depunit: str = testenv.readfile(strings.concat(work,
"dep.unit.ww"));
if (!testenv.has(rootunit, "//ww:module dep\n")
|| testenv.has(rootunit, "//ww:module leaf\n")
|| !testenv.has(depunit, "//ww:module leaf\n")) {
fail("library-roots", "compiler inputs crossed the direct-export boundary");
if (!testenv.has(rootunit, "//ww:module-reset\npackage main;")
|| testenv.has(rootunit, "//ww:module ")
|| !testenv.has(depunit, "//ww:module-reset dep\npackage dep;")
|| testenv.has(depunit, "//ww:module ")) {
fail("library-roots", "package units contain non-owned export text");
};
if (!testenv.exists(strings.concat(work, "leaf.wwi"))
|| !testenv.exists(strings.concat(work, "leaf.a"))
@@ -636,7 +600,8 @@ fn writediamond(td: str, reverse: bool) str = {
fail("library-roots", "compiler actions were not deterministic postorder");
};
if (!testenv.has(ctrace, strings.concat(
"BEGIN<-c><-I><", work, "dep.wwi><-o><", work,
"BEGIN<-c><--import><leaf><", work, "leaf.wwi><-I><", work,
"dep.wwi><-o><", work,
"dep.s><", work, "dep.unit.ww>"))
|| testenv.occurrences(atrace, "\n") != 3
|| !testenv.has(atrace, strings.concat("BEGIN<-o><", work,
@@ -758,7 +723,8 @@ fn writediamond(td: str, reverse: bool) str = {
runav) != 42) {
fail("library-roots", "empty override did not use default roots");
};
if (!testenv.has(rootunit, "//ww:module types\n")
if (!testenv.has(rootunit, "//ww:module-reset\npackage main;")
|| testenv.has(rootunit, "//ww:module ")
|| !testenv.exists(strings.concat(emptywork, "types.wwi"))
|| !testenv.exists(strings.concat(emptywork, "types.a"))
|| testenv.occurrences(ctrace, strings.concat("<", emptywork,
@@ -904,10 +870,11 @@ fn writediamond(td: str, reverse: bool) str = {
let depunitpath: str = strings.concat(work, "/dep.unit.ww");
let rootunit: str = testenv.readfile(rootunitpath);
let depunit: str = testenv.readfile(depunitpath);
if (!testenv.has(rootunit, "//ww:module dep\n")
|| testenv.has(rootunit, "//ww:module leaf\n")
|| !testenv.has(depunit, "//ww:module leaf\n")) {
fail("driver-identity", "warm units crossed the direct-export boundary");
if (!testenv.has(rootunit, "//ww:module-reset\npackage main;")
|| testenv.has(rootunit, "//ww:module ")
|| !testenv.has(depunit, "//ww:module-reset dep\npackage dep;")
|| testenv.has(depunit, "//ww:module ")) {
fail("driver-identity", "warm units contain non-owned export text");
};
if (!testenv.exists(strings.concat(work, "/leaf.wwi"))
|| !testenv.exists(strings.concat(work, "/leaf.a"))
@@ -923,7 +890,7 @@ fn writediamond(td: str, reverse: bool) str = {
"/.wwtool.w6a")), testenv.readfile(assembler))
|| !testenv.same(testenv.readfile(strings.concat(work,
"/.wwtool.stamp")),
"ww workdir fmt 5 mode build asm 0\n")) {
"ww workdir fmt 6 mode build asm 0\n")) {
fail("driver-identity", "persistent artifacts or identities are incomplete");
};
let coldwwi: str = testenv.readfile(strings.concat(work, "/dep.wwi"));
@@ -934,10 +901,12 @@ fn writediamond(td: str, reverse: bool) str = {
let coldlinker: str = testenv.readfile(linkertrace);
if (testenv.occurrences(coldcompiler, "\n") != 3
|| !testenv.has(coldcompiler, strings.concat(
"BEGIN<-c><-I><", work, "/dep.wwi.new><-o><", work,
"BEGIN<-c><--import><leaf><", work, "/leaf.wwi><-I><", work,
"/dep.wwi.new><-o><", work,
"/dep.s.new><", work, "/dep.unit.new>"))
|| !testenv.has(coldcompiler, strings.concat(
"BEGIN<-c><-o><", work, "/__root.s.new><", work,
"BEGIN<-c><--import><dep><", work, "/dep.wwi><-o><", work,
"/__root.s.new><", work,
"/__root.unit.new>"))
|| testenv.occurrences(coldassembler, "\n") != 3
|| !testenv.has(coldassembler, strings.concat(
@@ -964,21 +933,62 @@ fn writediamond(td: str, reverse: bool) str = {
fail("driver-identity", "cold binary returned the wrong value");
};
testenv.writefile(strings.concat(leaf, "/extra.ww"), strings.concat(
"package leaf;\n",
"export fn unchanged_api() i32 = { return 1; };\n"));
testenv.runcommandenv(cwd, td, strings.concat("driver-export-change-",
tags[si]), av, env, tmo(), &out);
if (out.termination != exec.termination.EXIT || out.code != 0
|| out.stderr.len != 0) {
fail("driver-identity", "dependency export-change build failed");
};
let changedexportcompiler: str = testenv.readfile(compilertrace);
let changedexportassembler: str = testenv.readfile(assemblertrace);
if (testenv.occurrences(changedexportcompiler, strings.concat("<", work,
"/leaf.unit.new>")) != 2
|| testenv.occurrences(changedexportcompiler, strings.concat("<", work,
"/dep.unit.new>")) != 2
|| testenv.occurrences(changedexportcompiler, strings.concat("<", work,
"/__root.unit.new>")) != 1
|| testenv.occurrences(changedexportcompiler, "\n") != 5
|| testenv.occurrences(changedexportassembler, "\n") != 5) {
fail("driver-identity", "changed export did not stop at an unchanged importer export");
};
if (code(cwd, strings.concat("driver-export-change-run-", tags[si]),
runav) != 42) {
fail("driver-identity", "export-change binary returned the wrong value");
};
let changedexportbin: str = testenv.readfile(bin);
let beforewarmcompiler: str = strings.dup(changedexportcompiler);
let beforewarmassembler: str = strings.dup(changedexportassembler);
testenv.runcommandenv(cwd, td, strings.concat("driver-warm-",
tags[si]), av, env, tmo(), &out);
if (out.termination != exec.termination.EXIT || out.code != 0
|| out.stderr.len != 0
|| !testenv.same(coldcompiler, testenv.readfile(compilertrace))
|| !testenv.same(coldassembler, testenv.readfile(assemblertrace))
|| testenv.occurrences(testenv.readfile(linkertrace), "\n") != 2
|| !testenv.same(beforewarmcompiler, testenv.readfile(compilertrace))
|| !testenv.same(beforewarmassembler, testenv.readfile(assemblertrace))
|| testenv.occurrences(testenv.readfile(linkertrace), "\n") != 3
|| !testenv.same(rootunit, testenv.readfile(rootunitpath))
|| !testenv.same(coldwwi, testenv.readfile(strings.concat(work,
"/dep.wwi")))
|| !testenv.same(coldarchive, testenv.readfile(strings.concat(work,
"/dep.a")))
|| !testenv.same(coldbin, testenv.readfile(bin))) {
|| !testenv.same(changedexportbin, testenv.readfile(bin))) {
fail("driver-identity", "unchanged warm build did not reuse packages");
};
assert(os.remove(strings.concat(leaf, "/extra.ww")) == 0);
testenv.runcommandenv(cwd, td, strings.concat("driver-export-restore-",
tags[si]), av, env, tmo(), &out);
if (out.termination != exec.termination.EXIT || out.code != 0
|| out.stderr.len != 0
|| testenv.occurrences(testenv.readfile(compilertrace), strings.concat(
"<", work, "/leaf.unit.new>")) != 3
|| testenv.occurrences(testenv.readfile(compilertrace), strings.concat(
"<", work, "/dep.unit.new>")) != 3
|| testenv.occurrences(testenv.readfile(compilertrace), strings.concat(
"<", work, "/__root.unit.new>")) != 1
|| testenv.occurrences(testenv.readfile(compilertrace), "\n") != 7
|| testenv.occurrences(testenv.readfile(assemblertrace), "\n") != 7
|| !testenv.same(coldbin, testenv.readfile(bin))) {
fail("driver-identity", "restored export did not rebuild only its direct importer");
};
assert(os.remove(copied[si]) == 0);
testenv.writeexecutable(copied[si], strings.concat(driverbytes,
@@ -994,14 +1004,14 @@ fn writediamond(td: str, reverse: bool) str = {
let changedassembler: str = testenv.readfile(assemblertrace);
let changedlinker: str = testenv.readfile(linkertrace);
if (testenv.occurrences(changedcompiler, strings.concat("<", work,
"/leaf.unit.new>")) != 2
"/leaf.unit.new>")) != 4
|| testenv.occurrences(changedcompiler, strings.concat("<", work,
"/dep.unit.new>")) != 2
"/dep.unit.new>")) != 4
|| testenv.occurrences(changedcompiler, strings.concat("<", work,
"/__root.unit.new>")) != 2
|| testenv.occurrences(changedcompiler, "\n") != 6
|| testenv.occurrences(changedassembler, "\n") != 6
|| testenv.occurrences(changedlinker, "\n") != 3) {
|| testenv.occurrences(changedcompiler, "\n") != 10
|| testenv.occurrences(changedassembler, "\n") != 10
|| testenv.occurrences(changedlinker, "\n") != 5) {
fail("driver-identity", "driver change reused stale package actions");
};
if (!testenv.same(testenv.readfile(strings.concat(work,

View File

@@ -3,26 +3,24 @@ package sepbuild_test;
// `ww build` sep-driver layout observers, both stages. Ports of the
// retired native carriers test/wcc/989_sepbuild_run.c,
// 989_seproot_export_run.c, 989_sepstructdef_run.c and
// 989_wwispread_sep.c; every assertion preserved.
// 989_wwispread_sep.c; assertions retained where their production boundary
// remains live.
//
// sepbuild (#46 commit-3) — build_one_sep END-TO-END on the real lib
// chain root -> os -> {rt,time} (transitive-closure discovery + topo):
// build+run exit 7 both stages; {time,rt,os}.wwi + __root.s
// materialize (#69: the root is compiled without -I, so no
// __root.wwi); per-package .s/.wwi/.unit.ww and the final binary
// byte-id cs vs ww; the KEYSTONE (spec 3.1) recompiles the driver's
// own non-leaf .unit.ww with each dep's .wwi section replaced by that
// dep's full directory bodies and requires byte-identical .s — the
// proof the .wwi conveys exactly the dep facts P's codegen needs;
// `ww run` routes through the same sole sep path (exit 7 both
// byte-id cs vs ww; every .unit.ww is the package's own sorted source
// set; `ww run` routes through the same sole sep path (exit 7 both
// stages).
//
// seproot (#69 BUG-1) — a ROOT whose `export fn use(a: *t)` names an
// unexported local `type t` builds (exit 37 both stages) because the
// root is compiled WITHOUT the -I .wwi-producer flag: __root.wwi must
// NOT exist; replaying the driver's own __root.unit.ww through
// w6c/w6c_ww with -I must REJECT (the isolated bug) while -c -o alone
// must accept; __root.s carries the exported fn.
// NOT exist; replaying the driver's own __root.unit.ww plus c.wwi
// through w6c/w6c_ww with -I must REJECT (the isolated bug) while -c
// -o alone must accept; __root.s carries the exported fn.
//
// sepstructdef (#70 BUG-2) — a dep exporting aggregate-init defs
// (struct-lit + array-lit) sep-builds and links (exit 20 both
@@ -69,80 +67,6 @@ fn samefile(label: str, what: str, a: str, b: str) void = {
};
};
// A package directory's *.ww bodies (less *test.ww), byte-sorted, each
// newline-terminated — mirrors the driver's body enumeration so the
// substituted bodies-unit matches the sep-unit structurally.
fn dirbodies(dir: str) str = {
let out: str = "";
let names: []str = testenv.listdir(dir);
let i: i32 = 0;
for (i < names.len) {
if (strings.hassuffix(names[i], ".ww")
&& !strings.hassuffix(names[i], "test.ww")) {
out = strings.concat(out,
testenv.readfile(strings.concat(dir, "/", names[i])),
"\n");
};
i += 1;
};
return out;
};
// Byte-offset borrow: strings.sub is rune-indexed, and the driver
// units embed lib comment bytes outside ASCII, so rune indices would
// mis-address the byte cursor below (readfile's borrow idiom).
fn bslice(s: str, start: i32, end: i32) str = {
assert(start <= end && end <= s.len);
let r: str;
r.ptr = s.ptr + (start: u64);
r.len = end - start;
return r;
};
// Transform a driver sep-unit into a bodies-unit: every `//ww:module
// <path>` dep section (its .wwi content) is replaced by <path>'s full
// directory bodies (dots -> slashes under libdir); the trailing
// `//ww:module-reset` primary body is copied verbatim. The keystone's
// other arm.
fn composebodies(unit: str, libdir: str) str = {
let out: str = "";
let n: i32 = unit.len;
let i: i32 = 0;
for (i < n) {
let j: i32 = i;
for (j < n && unit[j] != '\n') { j += 1; };
let line: str = bslice(unit, i, j);
if (strings.hasprefix(line, "//ww:module-reset")) {
out = strings.concat(out, bslice(unit, i, n));
return out;
};
if (strings.hasprefix(line, "//ww:module ")) {
out = strings.concat(out, line, "\n");
let path: str = bslice(line, 12, line.len);
let d: []u8 = alloc([], (path.len + 1): u64)!;
let k: i32 = 0;
for (k < path.len) {
if (path[k] == '.') { append(d, '/'); }
else { append(d, path[k]); };
k += 1;
};
out = strings.concat(out, dirbodies(strings.concat(libdir,
"/", strings.frombytes(d))));
i = j + 1;
for (i < n) {
let e: i32 = i;
for (e < n && unit[e] != '\n') { e += 1; };
if (strings.hasprefix(bslice(unit, i, e),
"//ww:module")) { break; };
i = e + 1;
};
continue;
};
i = j + 1;
};
return out;
};
@test fn sepbuild() void = {
let td: str = testenv.fresh();
let rootww: str = strings.concat(td, "/root.ww");
@@ -200,34 +124,6 @@ fn composebodies(unit: str, libdir: str) str = {
samefile("sepbuild", "the final binary",
strings.concat(td, "/prog.cs"), strings.concat(td, "/prog.ww"));
// KEYSTONE through the driver, non-leaf packages only (leaves have
// no dep sections, so their keystone is vacuous)
let libdir: str = strings.concat(testenv.repo(), "/lib");
let keypkgs: []str = ["os", "__root"];
let kp: i32 = 0;
for (kp < keypkgs.len) {
let unit: str = testenv.readfile(strings.concat(td,
"/prog.cs.sepwork/", keypkgs[kp], ".unit.ww"));
let bodiesf: str = strings.concat(td, "/", keypkgs[kp],
".bodies.ww");
testenv.writefile(bodiesf, composebodies(unit, libdir));
let bodiess: str = strings.concat(td, "/", keypkgs[kp],
".bodies.s");
let av: []str = [testenv.driver("w6c"), "-c", "-o", bodiess,
bodiesf];
if (runcode(td, strings.concat("key_", keypkgs[kp]), av) != 0) {
fail("sepbuild", strings.concat(keypkgs[kp], " bodies -c failed"));
};
if (!testenv.same(testenv.readfile(bodiess),
testenv.readfile(strings.concat(td, "/prog.cs.sepwork/",
keypkgs[kp], ".s")))) {
fail("sepbuild", strings.concat(keypkgs[kp],
" bodies.s != driver sep.s (the .wwi does not convey ",
"the dep facts P needs)"));
};
kp += 1;
};
// `ww run` routes through the sole sep path on both stages
let cav: []str = [testenv.driver("ww"), "run", rootww];
let rccs: i32 = runcode(td, "run_cs", cav);
@@ -309,19 +205,20 @@ fn composebodies(unit: str, libdir: str) str = {
// with -I the export-check FIRES (the isolated bug); without it the
// post-fix invocation accepts. Both compilers.
let unit: str = strings.concat(td, "/prog.cs.sepwork/__root.unit.ww");
let ciface: str = strings.concat(td, "/prog.cs.sepwork/c.wwi");
let comps: []str = ["w6c", "w6c_ww"];
let c: i32 = 0;
for (c < 2) {
let wwi: str = strings.concat(td, "/nv.", comps[c], ".wwi");
let asmf: str = strings.concat(td, "/nv.", comps[c], ".s");
let rav: []str = [testenv.driver(comps[c]), "-c", "-I", wwi,
"-o", asmf, unit];
let rav: []str = [testenv.driver(comps[c]), "-c", "--import", "c",
ciface, "-I", wwi, "-o", asmf, unit];
if (runcode(td, strings.concat("nvI_", comps[c]), rav) == 0) {
fail("seproot", strings.concat(comps[c], " -c -I accepted the ",
"root export-over-unexported-type (vacuous gate)"));
};
let aav: []str = [testenv.driver(comps[c]), "-c", "-o", asmf,
unit];
let aav: []str = [testenv.driver(comps[c]), "-c", "--import", "c",
ciface, "-o", asmf, unit];
if (runcode(td, strings.concat("nvO_", comps[c]), aav) != 0) {
fail("seproot", strings.concat(comps[c], " -c -o (no -I) ",
"rejected the root unit (post-fix invocation)"));

View File

@@ -18,8 +18,9 @@ package wwdump_test;
// wwdump_ww's exit code is deliberately NOT gated: the diagnostics
// land on stderr regardless, and the armed bail flips the exit code —
// the line count is the one signal stable across the fold sequence.
// #90 sep-feed: import-bearing fixtures feed their RESOLVED sep unit
// (`ww build -S` composes <stem>.sepwork/__root.unit.ww); the
// #90 sep-feed: `ww build -S` resolves import-bearing fixtures to an
// owner unit and direct exports; this raw wwdump-only gate explicitly
// composes those artifacts because wwdump has no package-input CLI. The
// import-free test/wcc/901_*.ww companions stay raw-fed.
//
// wwdumpgate (#52, F15 c4) — the -c and -r arms gate on parse-stage
@@ -93,11 +94,30 @@ fn countdiag(stderr: str) i32 = {
fail(classes[i], strings.concat(rels[i],
": no resolved sep unit (ww build -S failed)"));
};
src = strings.concat(stem, ".sepwork/__root.unit.ww");
if (!testenv.exists(src)) {
let work: str = strings.concat(stem, ".sepwork/");
let owner: str = strings.concat(work, "__root.unit.ww");
if (!testenv.exists(owner)) {
fail(classes[i], strings.concat(rels[i],
": __root.unit.ww missing after ww build -S"));
};
let deps: []str = [];
if (i == 0) { append(deps, "math.checked"); append(deps, "types"); };
if (i == 1) {
append(deps, "ascii"); append(deps, "os"); append(deps, "strconv");
};
if (i == 3) { append(deps, "fnmatch"); };
if (i == 4) { append(deps, "math.random"); append(deps, "test"); };
let composed: str = "";
let di: i32 = 0;
for (di < deps.len) {
composed = strings.concat(composed, "//ww:module ", deps[di],
"\n", testenv.readfile(strings.concat(work, deps[di],
".wwi")), "\n");
di += 1;
};
composed = strings.concat(composed, testenv.readfile(owner));
src = strings.concat(td, "/wwdump.raw.ww");
testenv.writefile(src, composed);
};
let co: testenv.commandout;
let av: []str = [testenv.driver("wwdump_ww"), "-c", src];