cmd: build local package graphs
This commit is contained in:
@@ -17,6 +17,7 @@ import os;
|
||||
import os.exec;
|
||||
import rt;
|
||||
import strings;
|
||||
import syntax;
|
||||
|
||||
// All path/string scratch buffers go on the runtime page allocator.
|
||||
// One page is plenty for any path we build. PATH_MAX lives in lib/os
|
||||
@@ -33,6 +34,25 @@ fn cerr(m: str) void = {
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
};
|
||||
|
||||
fn cerrnum(v: i32) void = {
|
||||
let digits: [16]u8;
|
||||
let n: i32 = 0;
|
||||
let x: i32 = v;
|
||||
if (x <= 0) { digits[n] = '0'; n += 1; }
|
||||
else {
|
||||
for (x > 0) {
|
||||
digits[n] = ((x % 10) + ('0': i32)): u8;
|
||||
n += 1;
|
||||
x = x / 10;
|
||||
};
|
||||
};
|
||||
for (n > 0) { n -= 1; os.write(2, &digits[n], 1u64); };
|
||||
};
|
||||
|
||||
fn cerrpos(file: str, line: i32, col: i32) void = {
|
||||
cerr(file); cerr(":"); cerrnum(line); cerr(":"); cerrnum(col);
|
||||
};
|
||||
|
||||
fn cstrlen(p: *u8) u64 = {
|
||||
let n: u64 = 0u64;
|
||||
for (p[n] != 0u8) { n += 1u64; };
|
||||
@@ -386,6 +406,22 @@ fn dirfileclass(dirpath: *u8, name: *u8, nlen: u64) i32 = {
|
||||
s.len = nlen: i32;
|
||||
if (!strings.hassuffix(s, ".ww")) { return 0; };
|
||||
if (strings.hassuffix(s, "_test.ww")) { return 0; };
|
||||
let source: *u8 = joinpath(dirpath, name);
|
||||
let fi: os.filestat;
|
||||
let sr: (void | os.oserror) = os.lstat(&fi, pathstr(source));
|
||||
let regular: bool = false;
|
||||
match (sr) {
|
||||
case void => {
|
||||
let t: u32 = (fi.mode: u32) & 61440u32;
|
||||
if (t == os.mode.REG: u32) { regular = true; };
|
||||
};
|
||||
case let e: os.oserror => void;
|
||||
};
|
||||
if (!regular) {
|
||||
cerr("ww: "); cerr(pathstr(source));
|
||||
cerr(": package source is not a regular file\n");
|
||||
return -2;
|
||||
};
|
||||
if (dirfileattest(dirpath, name)) { return -1; };
|
||||
return 1;
|
||||
};
|
||||
@@ -438,13 +474,17 @@ fn enumeratedir(dirpath: *u8) (**u8, i32) = {
|
||||
let nm: *u8 = buf.ptr + off + 19u64;
|
||||
let nl: u64 = cstrlen(nm);
|
||||
let cls: i32 = dirfileclass(dirpath, nm, nl);
|
||||
if (cls < 0) {
|
||||
if (cls == -1) {
|
||||
cerr("ww: ");
|
||||
cerr(pathstr(joinpath(dirpath, nm)));
|
||||
cerr(": @test declaration outside *_test.ww\n");
|
||||
os.close(fd);
|
||||
return nil: **u8, -2;
|
||||
};
|
||||
if (cls == -2) {
|
||||
os.close(fd);
|
||||
return nil: **u8, -2;
|
||||
};
|
||||
if (cls > 0) {
|
||||
if (n >= cap) {
|
||||
let ncap: i32 = cap * 2;
|
||||
@@ -527,59 +567,17 @@ fn slurp(pathcs: *u8) (*u8, u64) = {
|
||||
let buf: []u8 = alloc([], nu + 1u64)!;
|
||||
buf.len = (nu + 1u64): i32;
|
||||
let rr: (i64 | os.oserror) = os.readall(fd, buf.ptr, nu);
|
||||
os.close(fd);
|
||||
let closed: i32 = os.close(fd);
|
||||
let got: i64 = 0i64;
|
||||
match (rr) {
|
||||
case let v: i64 => got = v;
|
||||
case let e: os.oserror => return nil, 0u64;
|
||||
};
|
||||
if (got != n) { return nil, 0u64; };
|
||||
if (got != n || closed != 0) { return nil, 0u64; };
|
||||
buf[nu] = 0u8;
|
||||
return buf.ptr, nu;
|
||||
};
|
||||
|
||||
fn isidentbyte(c: u8) bool = {
|
||||
if (c >= 'a' && c <= 'z') { return true; };
|
||||
if (c >= 'A' && c <= 'Z') { return true; };
|
||||
if (c >= '0' && c <= '9') { return true; };
|
||||
if (c == '_') { return true; };
|
||||
if (c == '.') { return true; };
|
||||
return false;
|
||||
};
|
||||
|
||||
// Scan one `import IDENT;` line out of [start, end). Returns the start
|
||||
// of the ident and its length, or (nil, 0) if no `import` here. The
|
||||
// caller passes a slice of the source: src points at the line start.
|
||||
fn scanuse(src: *u8, len: u64) (*u8, u64) = {
|
||||
let i: u64 = 0u64;
|
||||
for (i < len) {
|
||||
if (src[i] != 32u8) { if (src[i] != 9u8) { break; }; };
|
||||
i += 1u64;
|
||||
};
|
||||
// i+7>len guard kept: hasprefix("import") covers the 6 spell-out
|
||||
// bytes, but the sep read at src[i+6] still needs i+6 < len.
|
||||
if (i + 7u64 > len) { return nil, 0u64; };
|
||||
let rest: str;
|
||||
rest.ptr = src + i;
|
||||
rest.len = (len - i): i32;
|
||||
if (!strings.hasprefix(rest, "import")) { return nil, 0u64; };
|
||||
let sep: u8 = src[i + 6u64];
|
||||
if (sep != 32u8) { if (sep != 9u8) { return nil, 0u64; }; };
|
||||
i += 7u64;
|
||||
for (i < len) {
|
||||
if (src[i] != 32u8) { if (src[i] != 9u8) { break; }; };
|
||||
i += 1u64;
|
||||
};
|
||||
let idstart: u64 = i;
|
||||
for (i < len) {
|
||||
if (!isidentbyte(src[i])) { break; };
|
||||
i += 1u64;
|
||||
};
|
||||
let idlen: u64 = i - idstart;
|
||||
if (idlen == 0u64) { return nil, 0u64; };
|
||||
return src + idstart, idlen;
|
||||
};
|
||||
|
||||
fn makestem(stem: *u8, src: *u8) void = {
|
||||
let n: u64 = cstrlen(src);
|
||||
let stop: u64 = n;
|
||||
@@ -632,8 +630,10 @@ type lflags = struct {
|
||||
// reference (#40) and the sep `.o`s link. The prepend is the TRANSITIVE
|
||||
// closure of a package's deps (lead-ratified): a dep's interface can
|
||||
// name a transitive dep's type, so the consuming unit needs the whole
|
||||
// closure for resolution. The unit composition is byte-identical to the
|
||||
// cstage driver (rule 10) so w6c/w6c_ww emit identical `.s`.
|
||||
// closure for resolution. Qualifier lookup remains scoped to the direct
|
||||
// imports owned by each source package, so those type facts do not expose
|
||||
// a transitive package. The unit composition is byte-identical to the cstage
|
||||
// driver (rule 10) so w6c/w6c_ww emit identical `.s`.
|
||||
|
||||
def SEP_MAXPKG: i32 = 256;
|
||||
|
||||
@@ -655,9 +655,30 @@ type sepgraph = struct {
|
||||
};
|
||||
|
||||
fn sepfindoradd(g: *sepgraph, path: *u8, entry: *u8, isdir: i32) i32 = {
|
||||
if (cstrlen(path) >= 256u64) {
|
||||
cerr("ww: package path is too long (limit 255 bytes)\n");
|
||||
return -1;
|
||||
};
|
||||
let i: i32 = 0;
|
||||
for (i < g.n) {
|
||||
if (cstreq(g.pkg[i].path, path)) { return i; };
|
||||
if (cstreq(g.pkg[i].path, path)) {
|
||||
if (!os.samefile(pathstr(g.pkg[i].entry), pathstr(entry))) {
|
||||
cerr("ww: package "); cerr(pathstr(path));
|
||||
cerr(" resolves to more than one location\n");
|
||||
return -1;
|
||||
};
|
||||
return i;
|
||||
};
|
||||
if (os.samefile(pathstr(g.pkg[i].entry), pathstr(entry))) {
|
||||
cerr("ww: one package directory has identities ");
|
||||
if (g.pkg[i].path[0u64] == 0u8) { cerr("(root)"); }
|
||||
else { cerr(pathstr(g.pkg[i].path)); };
|
||||
cerr(" and ");
|
||||
if (path[0u64] == 0u8) { cerr("(root)"); }
|
||||
else { cerr(pathstr(path)); };
|
||||
cerr("\n");
|
||||
return -1;
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
if (g.n >= SEP_MAXPKG) {
|
||||
@@ -723,140 +744,6 @@ fn sepfname(g: *sepgraph, pi: i32, scratch: *u8, suffix: str) *u8 = {
|
||||
return buf.ptr;
|
||||
};
|
||||
|
||||
// unithaspackage — does the unit buffer declare `package <leaf>;` ANYWHERE?
|
||||
// #16 ENFORCE-driver (rob A) cstage unit_has_package twin: distinguishes a
|
||||
// genuinely-missing import from one satisfied by an INLINE package in the
|
||||
// same single-file multi-package unit (`package aa; ... package main;
|
||||
// import aa;`). Scans EVERY line (comment-skip) — not just the first
|
||||
// package decl. Decision byte-identical to
|
||||
// cstage so the skip/fatal choice + driver output match (rule 10).
|
||||
fn unithaspackage(buf: *u8, buflen: u64, leafp: *u8, leafn: u64) bool = {
|
||||
let p: u64 = 0u64;
|
||||
for (p < buflen) {
|
||||
let q: u64 = p;
|
||||
for (q < buflen) { if (buf[q] == 10u8) { break; }; q += 1u64; };
|
||||
let s: u64 = p;
|
||||
for (s < q) {
|
||||
if (buf[s] != 32u8) { if (buf[s] != 9u8) { break; }; };
|
||||
s += 1u64;
|
||||
};
|
||||
if (s < q) {
|
||||
let line: str;
|
||||
line.ptr = buf + s;
|
||||
line.len = (q - s): i32;
|
||||
if (strings.hasprefix(line, "//")) { p = q + 1u64; continue; };
|
||||
if (s + 8u64 <= q) {
|
||||
if (strings.hasprefix(line, "package")) {
|
||||
let sep: u8 = buf[s + 7u64];
|
||||
let oksep: bool = false;
|
||||
if (sep == 32u8) { oksep = true; }
|
||||
else { if (sep == 9u8) { oksep = true; }; };
|
||||
if (oksep) {
|
||||
let t: u64 = s + 8u64;
|
||||
for (t < q) {
|
||||
if (buf[t] != 32u8) { if (buf[t] != 9u8) { break; }; };
|
||||
t += 1u64;
|
||||
};
|
||||
let m: u64 = 0u64;
|
||||
let eq: bool = true;
|
||||
for (m < leafn) {
|
||||
if (t + m >= q) { eq = false; break; };
|
||||
if (buf[t + m] != leafp[m]) { eq = false; break; };
|
||||
m += 1u64;
|
||||
};
|
||||
if (eq) {
|
||||
let after: u64 = t + leafn;
|
||||
let term: bool = false;
|
||||
if (after >= q) { term = true; }
|
||||
else {
|
||||
let c: u8 = buf[after];
|
||||
if (c == 59u8) { term = true; } // ';'
|
||||
else { if (c == 32u8) { term = true; }
|
||||
else { if (c == 9u8) { term = true; }; }; };
|
||||
};
|
||||
if (term) { return true; };
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
p = q + 1u64;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
fn sepidentstart(c: u8) bool = {
|
||||
if (c >= 'a' && c <= 'z') { return true; };
|
||||
if (c >= 'A' && c <= 'Z') { return true; };
|
||||
return c == '_';
|
||||
};
|
||||
|
||||
fn sepidentcontinue(c: u8) bool = {
|
||||
if (sepidentstart(c)) { return true; };
|
||||
return c >= '0' && c <= '9';
|
||||
};
|
||||
|
||||
// Skip the whitespace and comments accepted before and within the leading
|
||||
// package clause. This is deliberately only the loader's small header
|
||||
// grammar, not a second compiler lexer.
|
||||
fn sepskipspace(src: *u8, n: u64, start: u64, ok: *bool) u64 = {
|
||||
let i: u64 = start;
|
||||
*ok = true;
|
||||
for (true) {
|
||||
for (i < n && (src[i] == ' ' || src[i] == '\t'
|
||||
|| src[i] == '\r' || src[i] == '\n')) { i += 1u64; };
|
||||
if (i + 1u64 < n && src[i] == '/' && src[i + 1u64] == '/') {
|
||||
i += 2u64;
|
||||
for (i < n && src[i] != '\n') { i += 1u64; };
|
||||
continue;
|
||||
};
|
||||
if (i + 1u64 < n && src[i] == '/' && src[i + 1u64] == '*') {
|
||||
i += 2u64;
|
||||
let closed: bool = false;
|
||||
for (i + 1u64 < n) {
|
||||
if (src[i] == '*' && src[i + 1u64] == '/') {
|
||||
i += 2u64;
|
||||
closed = true;
|
||||
break;
|
||||
};
|
||||
i += 1u64;
|
||||
};
|
||||
if (!closed) { *ok = false; return i; };
|
||||
continue;
|
||||
};
|
||||
break;
|
||||
};
|
||||
return i;
|
||||
};
|
||||
|
||||
// Parse exactly the leading loader grammar `package ident;`.
|
||||
fn seppackageclause(src: *u8, n: u64, outp: **u8, outn: *u64) bool = {
|
||||
let ok: bool = true;
|
||||
let i: u64 = sepskipspace(src, n, 0u64, &ok);
|
||||
if (!ok || i + 7u64 >= n) { return false; };
|
||||
let word: str = "package";
|
||||
let j: i32 = 0;
|
||||
for (j < word.len) {
|
||||
let ju: u64 = j: u64;
|
||||
if (src[i + ju] != word[j]) { return false; };
|
||||
j += 1;
|
||||
};
|
||||
i += 7u64;
|
||||
if (i >= n || !(src[i] == ' ' || src[i] == '\t'
|
||||
|| src[i] == '\r' || src[i] == '\n')) { return false; };
|
||||
i = sepskipspace(src, n, i, &ok);
|
||||
if (!ok || i >= n || !sepidentstart(src[i])) { return false; };
|
||||
let begin: u64 = i;
|
||||
i += 1u64;
|
||||
for (i < n && sepidentcontinue(src[i])) { i += 1u64; };
|
||||
let end: u64 = i;
|
||||
i = sepskipspace(src, n, i, &ok);
|
||||
if (!ok || i >= n || src[i] != ';') { return false; };
|
||||
*outp = src + begin;
|
||||
*outn = end - begin;
|
||||
return true;
|
||||
};
|
||||
|
||||
// Scan one already-selected source file for its leading package clause
|
||||
// (when it is an owned directory source) and top-level imports. A DIRECTORY
|
||||
// import is a package boundary: add as a direct dep of pi. A FILE import is an
|
||||
@@ -877,44 +764,109 @@ fn sepscanfile(g: *sepgraph, pi: i32, file: *u8, searchpath: *u8,
|
||||
cerr("ww: cannot read source\n");
|
||||
return -1;
|
||||
};
|
||||
if (ownedsource != 0) {
|
||||
let declared: *u8 = nil;
|
||||
let declaredn: u64 = 0u64;
|
||||
if (!seppackageclause(bufp, blen, &declared, &declaredn)) {
|
||||
cerr("ww: ");
|
||||
cerr(pathstr(file));
|
||||
cerr(": invalid or missing package clause\n");
|
||||
return -1;
|
||||
};
|
||||
let l: syntax.lex;
|
||||
syntax.lexinit(&l, fdup, bufp, blen);
|
||||
let ps: syntax.parser;
|
||||
syntax.parserinit(&ps, &l);
|
||||
let imports: *syntax.node = syntax.parseimports(&ps);
|
||||
if (l.errs > 0 || ps.errs > 0) { return -1; };
|
||||
if (imports.nmod.len == 0 && ownedsource != 0) {
|
||||
cerrpos(fdup, 1, 1);
|
||||
cerr(": error: invalid or missing package clause\n");
|
||||
return -1;
|
||||
};
|
||||
if (imports.nmod.len != 0
|
||||
&& (ownedsource != 0 || g.pkg[pi].name == nil)) {
|
||||
let declared: *u8 = imports.nmod.ptr;
|
||||
let declaredn: u64 = imports.nmod.len: u64;
|
||||
if (g.pkg[pi].name == nil) {
|
||||
g.pkg[pi].name = arenadupcstr(declared, declaredn);
|
||||
} else { if (bytecmp(g.pkg[pi].name, cstrlen(g.pkg[pi].name),
|
||||
declared, declaredn) != 0) {
|
||||
cerr("ww: ");
|
||||
cerr(pathstr(g.pkg[pi].entry));
|
||||
cerr(": conflicting package names ");
|
||||
cerrpos(imports.file, imports.line, imports.col);
|
||||
cerr(": error: conflicting package names ");
|
||||
cerr(pathstr(g.pkg[pi].name));
|
||||
cerr(" and ");
|
||||
os.write(2, declared, declaredn);
|
||||
cerr("\n");
|
||||
cerr(" in "); cerr(pathstr(g.pkg[pi].entry)); cerr("\n");
|
||||
return -1;
|
||||
}; };
|
||||
};
|
||||
let i: u64 = 0u64;
|
||||
for (i < blen) {
|
||||
let j: u64 = i;
|
||||
for (j < blen) {
|
||||
if (bufp[j] == 10u8) { break; }; // '\n'
|
||||
j += 1u64;
|
||||
if (ownedsource != 0 && g.pkg[pi].isdir != 0) {
|
||||
let pm: *syntax.node = imports.body;
|
||||
for (pm != nil) {
|
||||
if (!syntax.streq(pm.nmod, pathstr(g.pkg[pi].name))) {
|
||||
cerrpos(pm.file, pm.line, pm.col);
|
||||
cerr(": error: conflicting package names ");
|
||||
cerr(pathstr(g.pkg[pi].name)); cerr(" and ");
|
||||
cerr(pm.nmod); cerr(" in ");
|
||||
cerr(pathstr(g.pkg[pi].entry)); cerr("\n");
|
||||
return -1;
|
||||
};
|
||||
pm = pm.next;
|
||||
};
|
||||
let idp: *u8;
|
||||
let idn: u64;
|
||||
idp, idn = scanuse(bufp + i, j - i);
|
||||
if (idp != nil) {
|
||||
};
|
||||
let nuse: i32 = 0;
|
||||
let u: *syntax.node = imports.list;
|
||||
for (u != nil) {
|
||||
if (u.kind == syntax.nkind.N_USE) { nuse += 1; };
|
||||
u = u.next;
|
||||
};
|
||||
let uses: []*syntax.node = [];
|
||||
if (nuse > 0) {
|
||||
let allocated: []*syntax.node = alloc([], nuse: u64)!;
|
||||
uses = allocated;
|
||||
uses.len = nuse;
|
||||
};
|
||||
let ui: i32 = 0;
|
||||
u = imports.list;
|
||||
for (u != nil) {
|
||||
if (u.kind == syntax.nkind.N_USE) { uses[ui] = u; ui += 1; };
|
||||
u = u.next;
|
||||
};
|
||||
let si: i32 = 1;
|
||||
for (si < nuse) {
|
||||
let sj: i32 = si;
|
||||
for (sj > 0) {
|
||||
if (strings.compare(uses[sj - 1].usepath,
|
||||
uses[sj].usepath) <= 0) { sj = 0; }
|
||||
else {
|
||||
let t: *syntax.node = uses[sj];
|
||||
uses[sj] = uses[sj - 1];
|
||||
uses[sj - 1] = t;
|
||||
sj -= 1;
|
||||
};
|
||||
};
|
||||
si += 1;
|
||||
};
|
||||
let previous: str = "";
|
||||
ui = 0;
|
||||
for (ui < nuse) {
|
||||
u = uses[ui];
|
||||
let duplicate: bool = previous.len > 0
|
||||
&& syntax.streq(previous, u.usepath);
|
||||
if (!duplicate) {
|
||||
previous = u.usepath;
|
||||
let idp: *u8 = u.usepath.ptr;
|
||||
let idn: u64 = u.usepath.len: u64;
|
||||
if (idn >= 256u64) {
|
||||
cerrpos(u.file, u.line, u.col);
|
||||
cerr(": error: import path is too long (limit 255 bytes)\n");
|
||||
return -1;
|
||||
};
|
||||
let isdir: i32 = 0;
|
||||
let ipath: *u8 = locateimport(searchpath, idp, idn, &isdir);
|
||||
if (ipath != nil) {
|
||||
if (isdir != 0) {
|
||||
if (os.samefile(pathstr(ipath), pathstr(g.pkg[pi].entry))) {
|
||||
cerrpos(u.file, u.line, u.col);
|
||||
cerr(": error: self-import: package '");
|
||||
if (g.pkg[pi].path[0u64] != 0u8) {
|
||||
cerr(pathstr(g.pkg[pi].path));
|
||||
} else { cerr(pathstr(g.pkg[pi].name)); };
|
||||
cerr("' cannot import itself\n");
|
||||
return -1;
|
||||
};
|
||||
let nm: []u8 = alloc([], idn + 1u64)!;
|
||||
let k: u64 = 0u64;
|
||||
for (k < idn) { nm[k] = idp[k]; k += 1u64; };
|
||||
@@ -938,14 +890,6 @@ fn sepscanfile(g: *sepgraph, pi: i32, file: *u8, searchpath: *u8,
|
||||
};
|
||||
};
|
||||
} else {
|
||||
// #16 ENFORCE-driver (rob A): a locate-miss is legal
|
||||
// when the package is defined INLINE in the same unit
|
||||
// (single-file multi-package). leaf = last dotted
|
||||
// component; inline `package <leaf>` -> skip (the
|
||||
// checker binds it), else fatal. E3-C1 (#87): the
|
||||
// legacy amalgamator that owned the genuine-missing
|
||||
// case is gone, so the sep producer enforces it here
|
||||
// (INV-2). cstage twin; fatal text identical.
|
||||
let lstart: u64 = 0u64;
|
||||
let lk: u64 = 0u64;
|
||||
for (lk < idn) {
|
||||
@@ -954,15 +898,23 @@ fn sepscanfile(g: *sepgraph, pi: i32, file: *u8, searchpath: *u8,
|
||||
};
|
||||
let leafp: *u8 = idp + lstart;
|
||||
let leafn: u64 = idn - lstart;
|
||||
if (!unithaspackage(bufp, blen, leafp, leafn)) {
|
||||
cerr("ww: cannot find package ");
|
||||
let inlinepackage: bool = false;
|
||||
let pm: *syntax.node = imports.body;
|
||||
for (pm != nil) {
|
||||
if (bytecmp(pm.nmod.ptr, pm.nmod.len: u64,
|
||||
leafp, leafn) == 0) { inlinepackage = true; };
|
||||
pm = pm.next;
|
||||
};
|
||||
if (!inlinepackage) {
|
||||
cerrpos(u.file, u.line, u.col);
|
||||
cerr(": error: cannot find package ");
|
||||
os.write(2, idp, idn);
|
||||
cerr("\n");
|
||||
return -1;
|
||||
};
|
||||
};
|
||||
};
|
||||
i = j + 1u64;
|
||||
ui += 1;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
@@ -1028,6 +980,24 @@ fn seploadpkg(g: *sepgraph, pi: i32, searchpath: *u8) i32 = {
|
||||
rc = sepscanfile(g, pi, g.pkg[pi].entry, searchpath, &fv, 0);
|
||||
};
|
||||
if (rc < 0) { return rc; };
|
||||
if (pi == 0 && g.pkg[pi].path[0u64] == 0u8
|
||||
&& g.pkg[pi].name != nil) {
|
||||
g.pkg[pi].path = arenadupcstr(g.pkg[pi].name,
|
||||
cstrlen(g.pkg[pi].name));
|
||||
};
|
||||
let si: i32 = 1;
|
||||
for (si < g.pkg[pi].ndeps) {
|
||||
let v: i32 = g.pkg[pi].deps[si];
|
||||
let sj: i32 = si;
|
||||
for (sj > 0 && strings.compare(
|
||||
pathstr(g.pkg[g.pkg[pi].deps[sj - 1]].path),
|
||||
pathstr(g.pkg[v].path)) > 0) {
|
||||
g.pkg[pi].deps[sj] = g.pkg[pi].deps[sj - 1];
|
||||
sj -= 1;
|
||||
};
|
||||
g.pkg[pi].deps[sj] = v;
|
||||
si += 1;
|
||||
};
|
||||
let k: i32 = 0;
|
||||
for (k < g.pkg[pi].ndeps) {
|
||||
if (seploadpkg(g, g.pkg[pi].deps[k], searchpath) < 0) { return -1; };
|
||||
@@ -1093,55 +1063,106 @@ fn sepmarkdeps(g: *sepgraph, pi: i32, inset: []u8) void = {
|
||||
// //ww:module-reset primary boundary (so -c emits its decls, imported
|
||||
// ==0). DIRECTORY imports are skipped (provided as `.wwi` ahead);
|
||||
// FILE imports fold in (intra-package split).
|
||||
fn sepemitbody(fd: i32, path: *u8, visit: *expctx, searchpath: *u8, modpath: *u8) void = {
|
||||
fn sepwriteall(fd: i32, buf: *u8, n: u64) bool = {
|
||||
match (os.writeall(fd, buf, n)) {
|
||||
case let wrote: i64 => return wrote == n: i64;
|
||||
case let e: os.oserror => return false;
|
||||
};
|
||||
};
|
||||
|
||||
fn sepemitbody(fd: i32, path: *u8, visit: *expctx, searchpath: *u8,
|
||||
modpath: *u8) i32 = {
|
||||
let pview: str;
|
||||
pview.ptr = path;
|
||||
pview.len = cstrlen(path): i32;
|
||||
let pdup: str = strings.dup(pview);
|
||||
if (visitseen(visit, pdup)) { return; };
|
||||
if (visitseen(visit, pdup)) { return 0; };
|
||||
visitadd(visit, pdup);
|
||||
let bufp: *u8;
|
||||
let blen: u64;
|
||||
bufp, blen = slurp(path);
|
||||
if (bufp == nil) {
|
||||
cerr("ww: cannot read source\n");
|
||||
return;
|
||||
return -1;
|
||||
};
|
||||
let i: u64 = 0u64;
|
||||
for (i < blen) {
|
||||
let j: u64 = i;
|
||||
for (j < blen) {
|
||||
if (bufp[j] == 10u8) { break; }; // '\n'
|
||||
j += 1u64;
|
||||
let l: syntax.lex;
|
||||
syntax.lexinit(&l, pdup, bufp, blen);
|
||||
let ps: syntax.parser;
|
||||
syntax.parserinit(&ps, &l);
|
||||
let imports: *syntax.node = syntax.parseimports(&ps);
|
||||
if (l.errs > 0 || ps.errs > 0) { return -1; };
|
||||
let nuse: i32 = 0;
|
||||
let u: *syntax.node = imports.list;
|
||||
for (u != nil) {
|
||||
if (u.kind == syntax.nkind.N_USE) { nuse += 1; };
|
||||
u = u.next;
|
||||
};
|
||||
let uses: []*syntax.node = [];
|
||||
if (nuse > 0) {
|
||||
let allocated: []*syntax.node = alloc([], nuse: u64)!;
|
||||
uses = allocated;
|
||||
uses.len = nuse;
|
||||
};
|
||||
let ui: i32 = 0;
|
||||
u = imports.list;
|
||||
for (u != nil) {
|
||||
if (u.kind == syntax.nkind.N_USE) { uses[ui] = u; ui += 1; };
|
||||
u = u.next;
|
||||
};
|
||||
let si: i32 = 1;
|
||||
for (si < nuse) {
|
||||
let sj: i32 = si;
|
||||
for (sj > 0) {
|
||||
if (strings.compare(uses[sj - 1].usepath,
|
||||
uses[sj].usepath) <= 0) { sj = 0; }
|
||||
else {
|
||||
let t: *syntax.node = uses[sj];
|
||||
uses[sj] = uses[sj - 1];
|
||||
uses[sj - 1] = t;
|
||||
sj -= 1;
|
||||
};
|
||||
};
|
||||
let idp: *u8;
|
||||
let idn: u64;
|
||||
idp, idn = scanuse(bufp + i, j - i);
|
||||
if (idp != nil) {
|
||||
si += 1;
|
||||
};
|
||||
ui = 0;
|
||||
for (ui < nuse) {
|
||||
u = uses[ui];
|
||||
let idp: *u8 = u.usepath.ptr;
|
||||
let idn: u64 = u.usepath.len: u64;
|
||||
let isdir: i32 = 0;
|
||||
let ipath: *u8 = locateimport(searchpath, idp, idn, &isdir);
|
||||
if (ipath != nil) {
|
||||
if (isdir == 0) {
|
||||
sepemitbody(fd, ipath, visit, searchpath, modpath);
|
||||
if (sepemitbody(fd, ipath, visit, searchpath,
|
||||
modpath) < 0) { return -1; };
|
||||
};
|
||||
};
|
||||
};
|
||||
i = j + 1u64;
|
||||
ui += 1;
|
||||
};
|
||||
// #57: tag the primary body by its full dotted import path so the
|
||||
// definer mangles == the importer reference; a root build (path "")
|
||||
// stays a bare reset (keeps bare main).
|
||||
if (modpath != nil && modpath[0u64] != 0u8) {
|
||||
let dm: str = "//ww:module-reset ";
|
||||
os.writeall(fd, dm.ptr, dm.len: u64);
|
||||
os.writeall(fd, modpath, cstrlen(modpath));
|
||||
os.writeall(fd, "\n".ptr, 1u64);
|
||||
if (!sepwriteall(fd, dm.ptr, dm.len: u64)
|
||||
|| !sepwriteall(fd, modpath, cstrlen(modpath))
|
||||
|| !sepwriteall(fd, "\n".ptr, 1u64)) {
|
||||
cerr("ww: cannot write package unit\n");
|
||||
return -1;
|
||||
};
|
||||
} else {
|
||||
let d: str = "//ww:module-reset\n";
|
||||
os.writeall(fd, d.ptr, d.len: u64);
|
||||
if (!sepwriteall(fd, d.ptr, d.len: u64)) {
|
||||
cerr("ww: cannot write package unit\n");
|
||||
return -1;
|
||||
};
|
||||
};
|
||||
os.writeall(fd, bufp, blen);
|
||||
os.writeall(fd, "\n".ptr, 1u64);
|
||||
if (!sepwriteall(fd, bufp, blen)
|
||||
|| !sepwriteall(fd, "\n".ptr, 1u64)) {
|
||||
cerr("ww: cannot write package unit\n");
|
||||
return -1;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Compose pi's sep-unit at `unitf`: the transitive-closure `.wwi`s
|
||||
@@ -1175,11 +1196,16 @@ fn sepcomposeunit(g: *sepgraph, pi: i32, scratch: *u8, order: []i32,
|
||||
return -1;
|
||||
};
|
||||
let dm: str = "//ww:module ";
|
||||
os.writeall(u, dm.ptr, dm.len: u64);
|
||||
os.writeall(u, g.pkg[dj].path, cstrlen(g.pkg[dj].path));
|
||||
os.writeall(u, "\n".ptr, 1u64);
|
||||
os.writeall(u, wb, wn);
|
||||
os.writeall(u, "\n".ptr, 1u64);
|
||||
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;
|
||||
};
|
||||
};
|
||||
};
|
||||
oi += 1;
|
||||
@@ -1188,18 +1214,23 @@ fn sepcomposeunit(g: *sepgraph, pi: i32, scratch: *u8, order: []i32,
|
||||
bv.out = u;
|
||||
bv.dirs = searchpath;
|
||||
bv.visit = nil;
|
||||
let bodyrc: i32 = 0;
|
||||
if (g.pkg[pi].isdir != 0) {
|
||||
let i: i32 = 0;
|
||||
for (i < g.pkg[pi].nsources) {
|
||||
sepemitbody(u, g.pkg[pi].sources[i], &bv, searchpath,
|
||||
for (i < g.pkg[pi].nsources && bodyrc == 0) {
|
||||
bodyrc = sepemitbody(u, g.pkg[pi].sources[i], &bv, searchpath,
|
||||
g.pkg[pi].path);
|
||||
i += 1;
|
||||
};
|
||||
} else {
|
||||
sepemitbody(u, g.pkg[pi].entry, &bv, searchpath, g.pkg[pi].path);
|
||||
bodyrc = sepemitbody(u, g.pkg[pi].entry, &bv, searchpath,
|
||||
g.pkg[pi].path);
|
||||
};
|
||||
os.close(u);
|
||||
return 0;
|
||||
if (os.close(u) != 0) {
|
||||
cerr("ww: cannot close package unit\n");
|
||||
return -1;
|
||||
};
|
||||
return bodyrc;
|
||||
};
|
||||
|
||||
// archiveo — twin of cmd/ww/main.c archive_o. Writes a deterministic
|
||||
@@ -1268,8 +1299,12 @@ fn archiveo(objpath: *u8, apath: *u8) i32 = {
|
||||
cerr("ww: cannot open archive\n");
|
||||
return -1;
|
||||
};
|
||||
os.writeall(fd, out, total);
|
||||
os.close(fd);
|
||||
let bad: bool = !sepwriteall(fd, out, total);
|
||||
if (os.close(fd) != 0) { bad = true; };
|
||||
if (bad) {
|
||||
cerr("ww: cannot write archive\n");
|
||||
return -1;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -1375,12 +1410,14 @@ fn copyfileatomic(src: *u8, dst: *u8) i32 = {
|
||||
else { if (n == 0) { done = true; }
|
||||
else {
|
||||
match (os.writeall(out, buf.ptr, n: u64)) {
|
||||
case let w: i64 => void;
|
||||
case let w: i64 => {
|
||||
if (w != n) { bad = true; done = true; };
|
||||
};
|
||||
case let e: os.oserror => { bad = true; done = true; };
|
||||
};
|
||||
}; };
|
||||
};
|
||||
os.close(in);
|
||||
if (os.close(in) != 0) { bad = true; };
|
||||
if (os.close(out) != 0) { bad = true; };
|
||||
if (bad) { return -1; };
|
||||
return os.rename(pathstr(tmpp), pathstr(dst));
|
||||
@@ -1427,7 +1464,7 @@ fn writestampatomic(path: *u8, want: str) i32 = {
|
||||
if (fd < 0) { return -1; };
|
||||
let bad: bool = false;
|
||||
match (os.writeall(fd, want.ptr, want.len: u64)) {
|
||||
case let w: i64 => void;
|
||||
case let w: i64 => { if (w != want.len: i64) { bad = true; }; };
|
||||
case let e: os.oserror => { bad = true; };
|
||||
};
|
||||
if (os.close(fd) != 0) { bad = true; };
|
||||
@@ -1444,9 +1481,11 @@ fn cerrpath(head: str, path: *u8, tail: str) void = {
|
||||
cerr(tail);
|
||||
};
|
||||
|
||||
fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
objstem: *u8, incs: *u8, lf: *lflags, istest: i32, emitasm: i32,
|
||||
workdir: *u8, scratchout: **u8, graphout: **sepgraph) i32 = {
|
||||
fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
rootidentity: *u8, out: *u8,
|
||||
objstem: *u8, incs: *u8, lf: *lflags, packageonly: i32, istest: i32,
|
||||
emitasm: i32, workdir: *u8, scratchout: **u8,
|
||||
graphout: **sepgraph) i32 = {
|
||||
let c6: *u8 = joinpathlit(selfdir, "w6c_ww");
|
||||
let a6: *u8 = joinpathlit(selfdir, "w6a_ww");
|
||||
let l6: *u8 = joinpathlit(selfdir, "w6l_ww");
|
||||
@@ -1588,7 +1627,9 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
pkgslot.len = SEP_MAXPKG;
|
||||
let g: *sepgraph = alloc(sepgraph{pkg = pkgslot, n = 0})!;
|
||||
if (graphout != nil) { *graphout = g; };
|
||||
let root: i32 = sepfindoradd(g, "\0".ptr, src, entryisdir);
|
||||
let rootpath: *u8 = "\0".ptr;
|
||||
if (packageonly != 0 && rootidentity != nil) { rootpath = rootidentity; };
|
||||
let root: i32 = sepfindoradd(g, rootpath, src, entryisdir);
|
||||
if (root < 0) { return 1; };
|
||||
// #79 (-T): lib/test is the synth main's `test.run` callee but @test
|
||||
// files never `import test;`. Inject it as a direct dep of the root so
|
||||
@@ -1616,6 +1657,11 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
};
|
||||
};
|
||||
if (seploadpkg(g, root, searchpath.ptr) < 0) { return 1; };
|
||||
let rootpackage: bool = packageonly != 0;
|
||||
if (rootpackage && cstreqlit(g.pkg[root].name, "main")) {
|
||||
cerr("ww: -p requires a non-main package\n");
|
||||
return 1;
|
||||
};
|
||||
|
||||
let ci: i32 = 0;
|
||||
for (ci < g.n) { g.pkg[ci].color = 0; ci += 1; };
|
||||
@@ -1625,6 +1671,7 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
stack.len = g.n;
|
||||
let norder: i32 = 0;
|
||||
if (septopovisit(g, root, order, &norder, stack, 0) < 0) { return 1; };
|
||||
if (!rootpackage) { g.pkg[root].path = "\0".ptr; };
|
||||
|
||||
let oi: i32 = 0;
|
||||
for (oi < norder) {
|
||||
@@ -1650,6 +1697,8 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
cu = unitnew; cw = wwinew; cs = asmnew;
|
||||
co = objnew; ca = anew;
|
||||
};
|
||||
let needsexport: bool = (pi != root) || rootpackage;
|
||||
let needsarchive: bool = (pi != root) || rootpackage;
|
||||
if (sepcomposeunit(g, pi, scratch, order, norder, searchpath.ptr, cu) < 0) {
|
||||
return 1;
|
||||
};
|
||||
@@ -1659,7 +1708,7 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
fresh = fileequal(unitnew, unitf);
|
||||
if (fresh) { fresh = fileisreg(asmf); };
|
||||
if (fresh) {
|
||||
if (pi != root) {
|
||||
if (needsexport) {
|
||||
fresh = fileisreg(wwi);
|
||||
};
|
||||
};
|
||||
@@ -1669,7 +1718,7 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
};
|
||||
};
|
||||
if (fresh) {
|
||||
if (emitasm == 0 && pi != root) {
|
||||
if (emitasm == 0 && needsarchive) {
|
||||
fresh = filesizenonzero(apath);
|
||||
};
|
||||
};
|
||||
@@ -1695,12 +1744,12 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
// synthesizes the test main; deps never get -T.
|
||||
let roott: bool = (pi == root) && (istest != 0);
|
||||
let alen: u64 = 8u64;
|
||||
if (pi == root) { alen = 6u64; if (roott) { alen = 7u64; }; };
|
||||
if (!needsexport) { alen = 6u64; if (roott) { alen = 7u64; }; };
|
||||
let argv: []str = alloc([], alen)!;
|
||||
append(argv, "w6c");
|
||||
if (roott) { append(argv, "-T"); };
|
||||
append(argv, "-c");
|
||||
if (pi != root) {
|
||||
if (needsexport) {
|
||||
append(argv, "-I");
|
||||
append(argv, pathstr(cw));
|
||||
};
|
||||
@@ -1744,7 +1793,7 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
// the build target), so `main` is defined before any archive is
|
||||
// processed. The link
|
||||
// consumes `.o`/`.a`, never `.wwi`.
|
||||
if (emitasm == 0 && pi != root) {
|
||||
if (emitasm == 0 && needsarchive) {
|
||||
if (archiveo(co, ca) != 0) {
|
||||
cerr("ww: archive failed\n");
|
||||
return 1;
|
||||
@@ -1754,7 +1803,7 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
// them, unit strictly last.
|
||||
if (warm) {
|
||||
let bad: bool = false;
|
||||
if (pi != root) {
|
||||
if (needsexport) {
|
||||
if (os.rename(pathstr(wwinew), pathstr(wwi)) != 0) {
|
||||
bad = true;
|
||||
};
|
||||
@@ -1772,7 +1821,7 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
};
|
||||
};
|
||||
if (!bad) {
|
||||
if (emitasm == 0 && pi != root) {
|
||||
if (emitasm == 0 && needsarchive) {
|
||||
if (os.rename(pathstr(anew), pathstr(apath)) != 0) {
|
||||
bad = true;
|
||||
};
|
||||
@@ -1821,6 +1870,17 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
};
|
||||
};
|
||||
if (emitasm != 0) { return 0; };
|
||||
if (rootpackage) {
|
||||
let archive: *u8 = sepfname(g, root, scratch, ".a");
|
||||
let iface: *u8 = sepfname(g, root, scratch, ".wwi");
|
||||
let outiface: *u8 = appendlit(out, ".wwi");
|
||||
if (copyfileatomic(archive, out) != 0
|
||||
|| copyfileatomic(iface, outiface) != 0) {
|
||||
cerrpath("ww: cannot write package artifact ", out, "\n");
|
||||
return 1;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Reverse-topo link: root `.o` first (order[norder-1]), dependency `.a`
|
||||
// files after, then libwwrt.a (which still
|
||||
@@ -1895,13 +1955,15 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
// no-output single-file test remove internal scratch on success and failure.
|
||||
// The path is non-nil only after this invocation successfully created the
|
||||
// exact tree. Twin of the cstage build_one_sep wrapper.
|
||||
fn buildonesep(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
objstem: *u8, incs: *u8, lf: *lflags, istest: i32, emitasm: i32,
|
||||
keepscratch: i32, workdir: *u8) i32 = {
|
||||
fn buildonesep(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
rootidentity: *u8, out: *u8,
|
||||
objstem: *u8, incs: *u8, lf: *lflags, packageonly: i32, istest: i32,
|
||||
emitasm: i32, keepscratch: i32, workdir: *u8) i32 = {
|
||||
let scratch: *u8 = nil;
|
||||
let g: *sepgraph = nil;
|
||||
let r: i32 = buildonesepimpl(selfdir, src, entryisdir, out, objstem,
|
||||
incs, lf, istest, emitasm, workdir, &scratch, &g);
|
||||
let r: i32 = buildonesepimpl(selfdir, src, entryisdir, rootidentity,
|
||||
out, objstem,
|
||||
incs, lf, packageonly, istest, emitasm, workdir, &scratch, &g);
|
||||
sepgraphfree(g);
|
||||
if (keepscratch == 0 && scratch != nil) {
|
||||
if (cstrendswithlit(scratch, ".sepwork")) {
|
||||
@@ -2001,7 +2063,7 @@ fn resolvemodule(selfdir: *u8, name: *u8, incs: *u8, isdir: *i32) *u8 = {
|
||||
};
|
||||
|
||||
fn writeusage(fd: i32) void = {
|
||||
let s: str = "usage: ww [-V] <subcommand> [args...]\n -V print version and exit\n build [-S] [-w DIR] [-o FILE] [path] compile module; -S stops after package asm\n run [path] ... build then exec, passing extra args to the program\n test [-S -o STEM] [-w DIR] [options] [path] build/run tests; -S emits package asm\n version print version and exit\n\n path forms:\n foo.ww literal file\n foo search cwd, -I dirs, then the source library for foo.ww or foo/\n lib/foo directory: build its package sources\n lib/... every package under lib, recursively (test only)\n . build the cwd's <basename>.ww\n";
|
||||
let s: str = "usage: ww [-V] <subcommand> [args...]\n -V print version and exit\n build [-p] [-S] [-w DIR] [-I DIR] [-o FILE] [path] build a local package graph\n run [path] ... build then exec, passing extra args to the program\n test [-S -o STEM] [-w DIR] [options] [path] build/run tests; -S emits package asm\n version print version and exit\n\n path forms:\n foo.ww literal file\n foo search cwd, -I dirs, then the source library for foo.ww or foo/\n lib/foo directory: build its package sources\n -p emits a non-main archive FILE + FILE.wwi\n lib/... every package under lib, recursively (test only)\n . build the cwd's <basename>.ww\n";
|
||||
os.write(fd, s.ptr, s.len: u64);
|
||||
};
|
||||
|
||||
@@ -2045,6 +2107,7 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
let outflag: *u8 = nil; // -o target (binary + intermediate stem); T3
|
||||
let workdir: *u8 = nil; // -w persistent package-artifact workdir
|
||||
let emitasm: i32 = 0;
|
||||
let packageonly: i32 = 0;
|
||||
let incs: []u8 = alloc([], (os.PATH_MAX: u64) * 2u64)!;
|
||||
incs.len = ((os.PATH_MAX: u64) * 2u64): i32;
|
||||
let incoff: u64 = 0u64;
|
||||
@@ -2064,6 +2127,8 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
if (p[0u64] == 45u8) { // '-'
|
||||
if (cstreqlit(p, "-S")) {
|
||||
emitasm = 1;
|
||||
} else { if (cstreqlit(p, "-p")) {
|
||||
packageonly = 1;
|
||||
} else { if (p[1u64] == 73u8) { // '-I'
|
||||
let dir: *u8 = nil;
|
||||
if (p[2u64] != 0u8) {
|
||||
@@ -2143,7 +2208,7 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
} else {
|
||||
cerr("ww build: unknown flag\n");
|
||||
return 2;
|
||||
}; }; }; }; }; };
|
||||
}; }; }; }; }; }; };
|
||||
} else {
|
||||
if (src == nil) { src = p; };
|
||||
};
|
||||
@@ -2154,12 +2219,26 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
let dot: [2]u8 = ['.': u8, 0u8];
|
||||
src = &dot[0];
|
||||
};
|
||||
if (packageonly != 0 && emitasm != 0) {
|
||||
cerr("ww build: -p and -S cannot be combined\n");
|
||||
return 2;
|
||||
};
|
||||
let requestedliteral: bool = false;
|
||||
let requestedstat: os.filestat;
|
||||
match (os.stat(&requestedstat, pathstr(src))) {
|
||||
case void => requestedliteral = true;
|
||||
case let e: os.oserror => void;
|
||||
};
|
||||
let isdir: i32 = 0;
|
||||
let resolved: *u8 = resolvemodule(selfdir, src, incs.ptr, &isdir);
|
||||
if (resolved == nil) {
|
||||
cerr("ww build: cannot find module\n");
|
||||
return 1;
|
||||
};
|
||||
if (packageonly != 0 && isdir == 0) {
|
||||
cerr("ww build: -p needs a package directory\n");
|
||||
return 2;
|
||||
};
|
||||
let out: *u8 = nil;
|
||||
let objstem: *u8 = nil;
|
||||
if (outflag != nil) {
|
||||
@@ -2189,8 +2268,11 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
lf.nlibdirs = nlibdirs;
|
||||
lf.libs = libs.ptr;
|
||||
lf.nlibs = nlibs;
|
||||
return buildonesep(selfdir, resolved, isdir, out, objstem, incs.ptr, &lf,
|
||||
0i32, emitasm, 1i32, workdir);
|
||||
let rootidentity: *u8 = nil;
|
||||
if (packageonly != 0 && !requestedliteral) { rootidentity = src; };
|
||||
return buildonesep(selfdir, resolved, isdir, rootidentity,
|
||||
out, objstem, incs.ptr, &lf,
|
||||
packageonly, 0i32, emitasm, 1i32, workdir);
|
||||
};
|
||||
|
||||
// Format the owned driver workspace /tmp/<prefix><pid> into buf. Pid is
|
||||
@@ -2354,8 +2436,8 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
lf.libs = libs.ptr;
|
||||
lf.nlibs = nlibs;
|
||||
// The freshly acquired directory owns both main and main.sepwork.
|
||||
if (buildonesep(selfdir, resolved, isdir, outp, outp, incs.ptr, &lf,
|
||||
0i32, 0i32, 0i32, nil) != 0) {
|
||||
if (buildonesep(selfdir, resolved, isdir, nil, outp, outp, incs.ptr, &lf,
|
||||
0i32, 0i32, 0i32, 0i32, nil) != 0) {
|
||||
let cleanrc: i32 = os.remove(pathstr(outp));
|
||||
if (cleanrc != 0 && cleanrc != -2i32) {
|
||||
cerr("ww: cannot remove temporary output\n");
|
||||
@@ -2444,8 +2526,8 @@ fn runsingletest(selfdir: *u8, src: *u8, incs: *u8, compileonly: i32,
|
||||
lf.nlibs = 0;
|
||||
let keep: i32 = 0;
|
||||
if (outstem != nil) { keep = 1; };
|
||||
let bres: i32 = buildonesep(selfdir, src, 0, outp, objstem, incs, &lf,
|
||||
1i32, emitasm, keep, workdir);
|
||||
let bres: i32 = buildonesep(selfdir, src, 0, nil, outp, objstem, incs, &lf,
|
||||
0i32, 1i32, emitasm, keep, workdir);
|
||||
if (bres != 0) {
|
||||
if (owntmp) {
|
||||
let cleanrc: i32 = os.remove(pathstr(outp));
|
||||
|
||||
Reference in New Issue
Block a user