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

@@ -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)"));