build: pass direct exports to package compilers
This commit is contained in:
@@ -741,16 +741,12 @@ type lflags = struct {
|
||||
// every package on its own (`w6c -c`), then flat-links the `.o` set.
|
||||
// Separate compilation is the SOLE build path (E3-C1 flip, task #87).
|
||||
//
|
||||
// Each w6c pass is BOTH consumer (reads dep `.wwi` as import scope) AND
|
||||
// producer (writes this package's `.wwi` via -I). Reverse-topo order
|
||||
// guarantees a package's deps' `.wwi` exist before it compiles.
|
||||
//
|
||||
// Every direct dep is tagged by its FULL DOTTED import path on prepend
|
||||
// (`//ww:module <path>`), so the definer's qualified symbol equals the
|
||||
// consumer's qualified reference and the sep `.o`s link. A dependency's
|
||||
// compiler-owned `.wwi` carries its reachable public foreign type facts;
|
||||
// separately prepending transitive interfaces is neither necessary nor
|
||||
// allowed. The unit composition is byte-identical to the cstage driver.
|
||||
// Each w6c pass is BOTH consumer (reads each direct dep `.wwi` through a
|
||||
// separate --import argument) AND producer (writes this package's `.wwi`
|
||||
// via -I). Reverse-topo order guarantees a package's deps' `.wwi` exist.
|
||||
// The canonical import path paired with each self-contained export preserves
|
||||
// qualified symbol identity; transitive exports remain outside the compile
|
||||
// action. Unit composition is byte-identical to the cstage driver.
|
||||
|
||||
def SEP_MAXPKG: i32 = 256;
|
||||
|
||||
@@ -775,6 +771,7 @@ type seppkg = struct {
|
||||
failed: bool,
|
||||
testsupport: bool,
|
||||
loaded: bool,
|
||||
exportchanged: bool,
|
||||
emitcontext: i32,
|
||||
contextstate: []u8,
|
||||
bindings: []sepbind,
|
||||
@@ -929,6 +926,7 @@ fn sepfindoraddvariant(g: *sepgraph, path: *u8, entry: *u8,
|
||||
g.pkg[g.n].failed = false;
|
||||
g.pkg[g.n].testsupport = false;
|
||||
g.pkg[g.n].loaded = false;
|
||||
g.pkg[g.n].exportchanged = false;
|
||||
g.pkg[g.n].emitcontext = -1;
|
||||
let cslot: []u8 = alloc([], SEP_MAXCONTEXT: u64)!;
|
||||
cslot.len = SEP_MAXCONTEXT;
|
||||
@@ -1546,8 +1544,8 @@ fn sepvalidatemoduleclosure(g: *sepgraph, order: []i32, n: i32,
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Imported source never enters this body: its direct export data was
|
||||
// prepended above, while this package owns exactly its sorted source set.
|
||||
// No imported source or export enters this body: the package owns exactly its
|
||||
// sorted source set.
|
||||
fn sepwriteall(fd: i32, buf: *u8, n: u64) bool = {
|
||||
match (os.writeall(fd, buf, n)) {
|
||||
case let wrote: i64 => return wrote == n: i64;
|
||||
@@ -1589,12 +1587,9 @@ fn sepemitbody(fd: i32, path: *u8, modpath: *u8) i32 = {
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Compose pi's sep-unit at `unitf`: its byte-sorted DIRECT dependency
|
||||
// `.wwi`s, each tagged by its dotted path, then pi's own body under
|
||||
// //ww:module-reset. Compiler exports are self-contained for public type
|
||||
// facts; the linker separately retains the reachable archive closure.
|
||||
fn sepcomposeunit(g: *sepgraph, pi: i32, scratch: *u8,
|
||||
unitf: *u8) i32 = {
|
||||
// Compose pi's sep-unit from only pi's byte-sorted sources. Direct exports are
|
||||
// separate compiler inputs; the linker retains the reachable archive closure.
|
||||
fn sepcomposeunit(g: *sepgraph, pi: i32, unitf: *u8) i32 = {
|
||||
if (g.pkg[pi].emitcontext < 0
|
||||
|| g.pkg[pi].emitcontext >= g.ncontext) { return -1; };
|
||||
let u: i32 = os.open(pathstr(unitf), os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC, 420i32); // 0o644
|
||||
@@ -1602,31 +1597,6 @@ fn sepcomposeunit(g: *sepgraph, pi: i32, scratch: *u8,
|
||||
cerr("ww: cannot open unit\n");
|
||||
return -1;
|
||||
};
|
||||
let k: i32 = 0;
|
||||
for (k < g.pkg[pi].ndeps) {
|
||||
let dj: i32 = g.pkg[pi].deps[k];
|
||||
let wwi: *u8 = sepfname(g, dj, scratch, ".wwi");
|
||||
let wb: *u8;
|
||||
let wn: u64;
|
||||
wb, wn = slurp(wwi);
|
||||
if (wb == nil) {
|
||||
cerr("ww: missing wwi\n");
|
||||
os.close(u);
|
||||
return -1;
|
||||
};
|
||||
let dm: str = "//ww:module ";
|
||||
if (!sepwriteall(u, dm.ptr, dm.len: u64)
|
||||
|| !sepwriteall(u, g.pkg[dj].path,
|
||||
cstrlen(g.pkg[dj].path))
|
||||
|| !sepwriteall(u, "\n".ptr, 1u64)
|
||||
|| !sepwriteall(u, wb, wn)
|
||||
|| !sepwriteall(u, "\n".ptr, 1u64)) {
|
||||
cerr("ww: cannot compose package unit\n");
|
||||
os.close(u);
|
||||
return -1;
|
||||
};
|
||||
k += 1;
|
||||
};
|
||||
let bodyrc: i32 = 0;
|
||||
if (g.pkg[pi].isdir != 0) {
|
||||
let i: i32 = 0;
|
||||
@@ -1720,7 +1690,7 @@ fn archiveo(objpath: *u8, apath: *u8) i32 = {
|
||||
};
|
||||
|
||||
// buildonesep — discover deps, reverse-topo,
|
||||
// the transitive producer loop (one `w6c -c -I` per package, dep-first,
|
||||
// the dependency-first producer loop (one `w6c -c -I` per package,
|
||||
// each dependency `.o` wrapped in its own deterministic per-package `.a`), then a
|
||||
// reverse-topo `w6l` of the root `.o` + dependency `.a` set + libwwrt.a.
|
||||
// Side files land in a cold `<stem>.sepwork` scratch dir. Twin of cstage
|
||||
@@ -1728,9 +1698,10 @@ fn archiveo(objpath: *u8, apath: *u8) i32 = {
|
||||
|
||||
// A `-w DIR` workdir is a caller-owned persistent package-artifact tree
|
||||
// that replaces the fresh `.sepwork` scratch. Staleness is pure content
|
||||
// identity, never mtime: a package is reused only when its freshly
|
||||
// composed unit byte-equals the committed unit AND the driver/tool copies
|
||||
// recorded in the dir byte-equal the live executables — every decision is
|
||||
// identity, never mtime: a package is reused only when its freshly composed
|
||||
// unit byte-equals the committed unit, no direct dependency emitted a changed
|
||||
// export, AND the driver/tool copies recorded in the dir byte-equal the live
|
||||
// executables — every decision is
|
||||
// reproducible by hand with cmp(1) against plain files. Artifacts commit
|
||||
// via temp + rename with the unit renamed last, so a killed build can
|
||||
// never leave a committed unit vouching for uncommitted artifacts. The
|
||||
@@ -1840,14 +1811,14 @@ fn copyfileatomic(src: *u8, dst: *u8) i32 = {
|
||||
fn workdirstamptext(istest: i32, emitasm: i32) str = {
|
||||
if (istest != 0) {
|
||||
if (emitasm != 0) {
|
||||
return "ww workdir fmt 6 mode test asm 1\n";
|
||||
return "ww workdir fmt 7 mode test asm 1\n";
|
||||
};
|
||||
return "ww workdir fmt 6 mode test asm 0\n";
|
||||
return "ww workdir fmt 7 mode test asm 0\n";
|
||||
};
|
||||
if (emitasm != 0) {
|
||||
return "ww workdir fmt 5 mode build asm 1\n";
|
||||
return "ww workdir fmt 6 mode build asm 1\n";
|
||||
};
|
||||
return "ww workdir fmt 5 mode build asm 0\n";
|
||||
return "ww workdir fmt 6 mode build asm 0\n";
|
||||
};
|
||||
|
||||
fn stampmatches(path: *u8, want: str) bool = {
|
||||
@@ -2338,15 +2309,23 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
};
|
||||
let needsexport: bool = !g.pkg[pi].root || rootpackage;
|
||||
let needsarchive: bool = !g.pkg[pi].root || rootpackage;
|
||||
if (sepcomposeunit(g, pi, scratch, cu) < 0) {
|
||||
if (sepcomposeunit(g, pi, cu) < 0) {
|
||||
g.pkg[pi].failed = true;
|
||||
anyfailed = true;
|
||||
oi += 1;
|
||||
continue;
|
||||
};
|
||||
let depschanged: bool = false;
|
||||
let changedk: i32 = 0;
|
||||
for (changedk < g.pkg[pi].ndeps) {
|
||||
if (g.pkg[g.pkg[pi].deps[changedk]].exportchanged) {
|
||||
depschanged = true;
|
||||
};
|
||||
changedk += 1;
|
||||
};
|
||||
let fresh: bool = false;
|
||||
if (warm) {
|
||||
if (!staleall) {
|
||||
if (!staleall && !depschanged) {
|
||||
fresh = fileequal(unitnew, unitf);
|
||||
if (fresh) { fresh = fileisreg(asmf); };
|
||||
if (fresh) {
|
||||
@@ -2390,6 +2369,7 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
let alen: u64 = 8u64;
|
||||
if (!needsexport) { alen = 6u64; if (roott) { alen = 9u64; }; };
|
||||
if (supportt) { alen += 2u64; };
|
||||
alen += (g.pkg[pi].ndeps: u64) * 3u64;
|
||||
let argv: []str = alloc([], alen)!;
|
||||
append(argv, "w6c");
|
||||
if (roott) {
|
||||
@@ -2402,6 +2382,14 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
append(argv, testsupportmodule);
|
||||
};
|
||||
append(argv, "-c");
|
||||
let importk: i32 = 0;
|
||||
for (importk < g.pkg[pi].ndeps) {
|
||||
let dj: i32 = g.pkg[pi].deps[importk];
|
||||
append(argv, "--import");
|
||||
append(argv, pathstr(g.pkg[dj].path));
|
||||
append(argv, pathstr(sepfname(g, dj, scratch, ".wwi")));
|
||||
importk += 1;
|
||||
};
|
||||
if (needsexport) {
|
||||
append(argv, "-I");
|
||||
append(argv, pathstr(cw));
|
||||
@@ -2430,6 +2418,11 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
continue;
|
||||
};
|
||||
};
|
||||
if (needsexport) {
|
||||
if (!warm || !fileequal(wwinew, wwi)) {
|
||||
g.pkg[pi].exportchanged = true;
|
||||
};
|
||||
};
|
||||
if (emitasm == 0) {
|
||||
let argv: []str = alloc([], 4u64)!;
|
||||
append(argv, "w6a");
|
||||
|
||||
Reference in New Issue
Block a user