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

@@ -69,6 +69,11 @@ export fn main(argc: i32, argv: **u8) i32 = {
let sepmode: i32 = 0i32; // -c: #22 M3 separate-compile / primary-
// only codegen (emit imported==0 decls
// only; treat `.wwi` deps as external)
let importpaths: []*u8 = alloc([], argc: u64)!;
importpaths.len = argc;
let importfiles: []*u8 = alloc([], argc: u64)!;
importfiles.len = argc;
let nimports: i32 = 0;
let i: i32 = 1;
for (i < argc) {
@@ -101,6 +106,16 @@ export fn main(argc: i32, argv: **u8) i32 = {
testsupport = argv[i];
} else { if (cstreq(a, "-c")) {
sepmode = 1i32;
} else { if (cstreq(a, "--import")) {
if (i + 2 >= argc) {
let m: str = "w6c: --import requires path and file\n";
os.write(2, m.ptr, m.len: u64);
return 2;
};
importpaths[nimports] = argv[i + 1];
importfiles[nimports] = argv[i + 2];
nimports += 1;
i += 2;
} else { if (a[0u64] == 45u8) {
let m: str = "w6c: unknown flag\n";
os.write(2, m.ptr, m.len: u64);
@@ -112,15 +127,35 @@ export fn main(argc: i32, argv: **u8) i32 = {
return 2;
};
src = a;
}; }; }; }; }; };
}; }; }; }; }; }; };
i += 1;
};
if (src == nil) {
let m: str = "usage: w6c_ww [-T] [-o out.s] file.ww\n";
let m: str = "usage: w6c_ww [-T] [-c] [-I out.wwi] [--import path dep.wwi]... [-o out.s] file.ww\n";
os.write(2, m.ptr, m.len: u64);
return 2;
};
if (nimports > 0 && sepmode == 0) {
let m: str = "w6c: --import requires -c\n";
os.write(2, m.ptr, m.len: u64);
return 2;
};
let importi: i32 = 0;
for (importi < nimports) {
if (importpaths[importi][0u64] == 0u8) {
let m: str = "w6c: --import path is empty\n";
os.write(2, m.ptr, m.len: u64);
return 2;
};
if (importi > 0 && strings.compare(pathstr(importpaths[importi - 1]),
pathstr(importpaths[importi])) >= 0) {
let m: str = "w6c: --import paths must be sorted and unique\n";
os.write(2, m.ptr, m.len: u64);
return 2;
};
importi += 1;
};
if (testsupport != nil && (sepmode == 0
|| (!cstreq(testsupport, "test")
&& !cstreq(testsupport, "__wwtest")))) {
@@ -129,6 +164,46 @@ export fn main(argc: i32, argv: **u8) i32 = {
return 2;
};
let importhead: *node = nil;
let importtail: *node = nil;
importi = 0;
for (importi < nimports) {
let ibuf: *u8;
let ilen: u64;
ibuf, ilen = slurp(importfiles[importi]);
if (ibuf == nil) {
let pre: str = "w6c: import ";
let mid: str = ": cannot read ";
let nl: str = "\n";
let ipath: str = pathstr(importpaths[importi]);
let ifile: str = pathstr(importfiles[importi]);
os.write(2, pre.ptr, pre.len: u64);
os.write(2, ipath.ptr, ipath.len: u64);
os.write(2, mid.ptr, mid.len: u64);
os.write(2, ifile.ptr, ifile.len: u64);
os.write(2, nl.ptr, nl.len: u64);
return 1;
};
let il: lex;
lexinit(&il, strings.dup(pathstr(importfiles[importi])), ibuf, ilen);
let ips: parser;
parserinit(&ips, &il);
let imod: str = pathstr(importpaths[importi]);
ips.pathmod = imod;
ips.curmod = imod;
if (testsupport != nil) { ips.testmodule = pathstr(testsupport); };
let imported: *node = parsefile(&ips);
if (il.errs > 0 || ips.errs > 0) { return 1; };
let d: *node = imported.list;
if (d != nil) {
if (importhead == nil) { importhead = d; }
else { importtail.next = d; };
for (d.next != nil) { d = d.next; };
importtail = d;
};
importi += 1;
};
let buf: *u8;
let blen: u64;
buf, blen = slurp(src);
@@ -137,10 +212,22 @@ export fn main(argc: i32, argv: **u8) i32 = {
os.write(2, m.ptr, m.len: u64);
return 1;
};
let l: lex;
lexinit(&l, strings.dup(pathstr(src)), buf, blen);
let ps: parser;
parserinit(&ps, &l);
if (testsupport != nil) { ps.testmodule = pathstr(testsupport); };
let f: *node = parsefile(&ps);
// Gate cgen on parse-stage errors. Mirrors cmd/w6c/main.c's
// `if (l.errs || p.errs) return 1;` — broken AST otherwise reaches
// cgen and emits junk asm with a zero exit (silent miscompile).
if (l.errs > 0 || ps.errs > 0) { return 1; };
if (importhead != nil) {
importtail.next = f.list;
f.list = importhead;
};
// Redirect fd 1 to the output file before any cgen emit runs.
// cgen.ww writes directly to fd 1; dup2 lets us reuse it without
// threading a file descriptor through the emit helpers.
// cgen writes directly to fd 1; dup2 keeps that implementation private.
if (out != nil) {
let ofd: i32 = os.open(pathstr(out),
os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC, 420i32); // 0o644
@@ -158,24 +245,6 @@ export fn main(argc: i32, argv: **u8) i32 = {
os.close(ofd);
};
let nlen: u64 = cstrlen(src);
let view: str;
view.ptr = src;
view.len = nlen: i32;
let fname: str = strings.dup(view);
let l: lex;
lexinit(&l, fname, buf, blen);
let ps: parser;
parserinit(&ps, &l);
if (testsupport != nil) { ps.testmodule = pathstr(testsupport); };
let f: *node = parsefile(&ps);
// Gate cgen on parse-stage errors. Mirrors cmd/w6c/main.c's
// `if (l.errs || p.errs) return 1;` — broken AST otherwise reaches
// cgen and emits junk asm with a zero exit (silent miscompile).
if (l.errs > 0 || ps.errs > 0) { return 1; };
let testmodule: str;
if (testsupport != nil) { testmodule = pathstr(testsupport); };
let interfaceout: str;