ww: select build action from package declaration
This commit is contained in:
@@ -1402,6 +1402,14 @@ fn sepcommanddeclaredname(p: *seppkg) bool = {
|
||||
return cstreqlit(p.name, "main");
|
||||
};
|
||||
|
||||
// Directory-package action kind comes only from the loaded declaration. An
|
||||
// explicit package-less file is the retained raw-unit compatibility path and
|
||||
// remains a command unit.
|
||||
fn seprootiscommand(p: *seppkg) bool = {
|
||||
if (p.name == nil) { return p.isdir == 0; };
|
||||
return cstreqlit(p.name, "main");
|
||||
};
|
||||
|
||||
fn sepforbiddencommandimport(g: *sepgraph, importer: i32, dep: i32) bool = {
|
||||
let from: *seppkg = &g.pkg[importer];
|
||||
let to: *seppkg = &g.pkg[dep];
|
||||
@@ -3324,8 +3332,20 @@ fn copyfileatomic(src: *u8, dst: *u8) i32 = {
|
||||
return os.rename(pathstr(tmpp), pathstr(dst));
|
||||
};
|
||||
|
||||
// Package publication writes OUT, OUT.new, OUT.wwi, and OUT.wwi.new. Check
|
||||
// the longest spelling before any producer tool can run.
|
||||
fn validatepackageoutputpath(out: *u8) i32 = {
|
||||
let suffix: u64 = ".wwi.new".len: u64 + 1u64;
|
||||
let limit: u64 = os.PATH_MAX: u64;
|
||||
if (suffix > limit || cstrlen(out) > limit - suffix) {
|
||||
cerr("ww: package output path is too long\n");
|
||||
return -1;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
|
||||
// The stamp pins the non-content build inputs a unit compare cannot see:
|
||||
// the -T/-S shape of the producer pass and the artifact protocol
|
||||
// the -T/-S/root-action shape of the producer pass and the artifact protocol
|
||||
// revision (bump "fmt" when the unit/archive/commit format changes).
|
||||
fn workdirstamptext(istest: i32, emitasm: i32) str = {
|
||||
if (istest != 0) {
|
||||
@@ -3335,9 +3355,9 @@ fn workdirstamptext(istest: i32, emitasm: i32) str = {
|
||||
return "ww workdir fmt 11 mode test asm 0\n";
|
||||
};
|
||||
if (emitasm != 0) {
|
||||
return "ww workdir fmt 10 mode build asm 1\n";
|
||||
return "ww workdir fmt 12 mode build asm 1\n";
|
||||
};
|
||||
return "ww workdir fmt 10 mode build asm 0\n";
|
||||
return "ww workdir fmt 12 mode build asm 0\n";
|
||||
};
|
||||
|
||||
fn stampmatches(path: *u8, want: str) bool = {
|
||||
@@ -3444,7 +3464,7 @@ fn cerrpath(head: str, path: *u8, tail: str) void = {
|
||||
|
||||
fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
out: *u8, objstem: *u8, incs: *u8, lf: *lflags,
|
||||
packageonly: i32, istest: i32,
|
||||
publishpackage: i32, requirecommand: i32, istest: i32,
|
||||
products: *sepproduct, nproducts: i32, emitasm: i32,
|
||||
workdir: *u8, scratchout: **u8,
|
||||
graphout: **sepgraph) i32 = {
|
||||
@@ -3663,9 +3683,6 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
SEP_ROLE_NORMAL, products[producti].artifact, true);
|
||||
if (products[producti].root < 0) { return 1; };
|
||||
products[producti].variantroot = products[producti].root;
|
||||
if (istest == 0 && packageonly == 0) {
|
||||
g.pkg[products[producti].root].linkentry = true;
|
||||
};
|
||||
producti += 1;
|
||||
};
|
||||
let testsupportmodule: str = "test";
|
||||
@@ -3785,6 +3802,17 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
};
|
||||
if (g.identityfailed) { return 1; };
|
||||
if (sepfinalizedirectoryidentities(g) < 0) { return 1; };
|
||||
if (istest == 0) {
|
||||
producti = 0;
|
||||
for (producti < nproducts) {
|
||||
let root: i32 = products[producti].variantroot;
|
||||
if (!g.pkg[root].failed) {
|
||||
g.pkg[root].linkentry =
|
||||
seprootiscommand(&g.pkg[root]);
|
||||
};
|
||||
producti += 1;
|
||||
};
|
||||
};
|
||||
if (istest != 0 && entryisdir != 0) {
|
||||
producti = 0;
|
||||
for (producti < nproducts) {
|
||||
@@ -3803,16 +3831,12 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
producti += 1;
|
||||
};
|
||||
};
|
||||
let rootpackage: bool = istest == 0
|
||||
&& !g.pkg[products[0].root].failed
|
||||
&& !seprootiscommand(&g.pkg[products[0].root]);
|
||||
if (sepvalidateartifactpaths(g, scratch) < 0) { return 1; };
|
||||
if (warm && sepvalidateworkdirowners(g, scratch) < 0) { return 1; };
|
||||
if (warm && staleall && invalidateworkdirunits(scratch) != 0) { return 1; };
|
||||
let rootpackage: bool = packageonly != 0;
|
||||
if (rootpackage && !g.pkg[products[0].root].failed
|
||||
&& cstreqlit(g.pkg[products[0].root].name, "main")) {
|
||||
cerr("ww: -p requires a non-main package\n");
|
||||
return 1;
|
||||
};
|
||||
|
||||
let ci: i32 = 0;
|
||||
let order: []i32;
|
||||
let stack: []i32;
|
||||
@@ -3839,6 +3863,21 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
};
|
||||
producti += 1;
|
||||
};
|
||||
if (istest == 0 && requirecommand != 0) {
|
||||
let root: i32 = products[0].root;
|
||||
if (!g.pkg[root].failed && !seprootiscommand(&g.pkg[root])) {
|
||||
let identity: *u8 = g.pkg[root].canon;
|
||||
if (g.pkg[root].path[0u64] != 0u8) {
|
||||
identity = g.pkg[root].path;
|
||||
};
|
||||
cerrpath("ww: package ", identity,
|
||||
" is not a main package\n");
|
||||
return 1;
|
||||
};
|
||||
};
|
||||
if (!g.pkg[products[0].root].failed
|
||||
&& rootpackage && publishpackage != 0 && emitasm == 0
|
||||
&& validatepackageoutputpath(out) < 0) { return 1; };
|
||||
ci = 0;
|
||||
for (ci < g.n) { g.pkg[ci].color = 0; ci += 1; };
|
||||
producti = 0;
|
||||
@@ -4149,14 +4188,18 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
if (rootpackage) {
|
||||
let root: i32 = products[0].root;
|
||||
if (g.pkg[root].failed) { return 1; };
|
||||
let archive: *u8 = sepfname(g, root, scratch, ".a");
|
||||
let iface: *u8 = sepfname(g, root, scratch, ".wwi");
|
||||
let outiface: *u8 = sepappendlit(out, ".wwi");
|
||||
if (archive == nil || iface == nil || outiface == nil) { return 1; };
|
||||
if (copyfileatomic(archive, out) != 0
|
||||
|| copyfileatomic(iface, outiface) != 0) {
|
||||
cerrpath("ww: cannot write package artifact ", out, "\n");
|
||||
return 1;
|
||||
if (publishpackage != 0) {
|
||||
let archive: *u8 = sepfname(g, root, scratch, ".a");
|
||||
let iface: *u8 = sepfname(g, root, scratch, ".wwi");
|
||||
let outiface: *u8 = sepappendlit(out, ".wwi");
|
||||
if (archive == nil || iface == nil || outiface == nil) {
|
||||
return 1;
|
||||
};
|
||||
if (copyfileatomic(archive, out) != 0
|
||||
|| copyfileatomic(iface, outiface) != 0) {
|
||||
cerrpath("ww: cannot write package artifact ", out, "\n");
|
||||
return 1;
|
||||
};
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
@@ -4305,7 +4348,8 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
// exact tree. Twin of the cstage build_one_sep wrapper.
|
||||
fn buildonesep(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
rootidentity: *u8, out: *u8,
|
||||
objstem: *u8, incs: *u8, lf: *lflags, packageonly: i32, istest: i32,
|
||||
objstem: *u8, incs: *u8, lf: *lflags, publishpackage: i32,
|
||||
requirecommand: i32, istest: i32,
|
||||
rootvariant: i32, testpackage: *u8, emitasm: i32,
|
||||
keepscratch: i32, workdir: *u8) i32 = {
|
||||
let scratch: *u8 = nil;
|
||||
@@ -4317,7 +4361,7 @@ fn buildonesep(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
product.testpackage = testpackage;
|
||||
product.status = nil;
|
||||
product.artifact = nil;
|
||||
if (packageonly == 0 && entryisdir == 0) {
|
||||
if (entryisdir == 0) {
|
||||
product.artifact = "__root\0".ptr;
|
||||
};
|
||||
product.variant = rootvariant;
|
||||
@@ -4325,7 +4369,7 @@ fn buildonesep(selfdir: *u8, src: *u8, entryisdir: i32,
|
||||
product.variantroot = -1;
|
||||
product.support = -1;
|
||||
let r: i32 = buildonesepimpl(selfdir, src, entryisdir, out, objstem,
|
||||
incs, lf, packageonly, istest, &product, 1,
|
||||
incs, lf, publishpackage, requirecommand, istest, &product, 1,
|
||||
emitasm, workdir, &scratch, &g);
|
||||
sepgraphfree(g);
|
||||
if (keepscratch == 0 && scratch != nil) {
|
||||
@@ -4367,7 +4411,7 @@ fn buildpackagetests(selfdir: *u8, src: *u8, rootidentity: *u8,
|
||||
i += 1;
|
||||
};
|
||||
let r: i32 = buildonesepimpl(selfdir, src, 1,
|
||||
products[0].out, products[0].out, incs, &lf, 0, 1,
|
||||
products[0].out, products[0].out, incs, &lf, 0, 0, 1,
|
||||
products, nproducts, 0, workdir, &scratch, &g);
|
||||
sepgraphfree(g);
|
||||
return r;
|
||||
@@ -4464,7 +4508,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 [-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";
|
||||
let s: str = "usage: ww [-V] <subcommand> [args...]\n -V print version and exit\n build [-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 -o publishes 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);
|
||||
};
|
||||
|
||||
@@ -4508,7 +4552,6 @@ 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 inccap: u64 = 1u64;
|
||||
let capi: i32 = start;
|
||||
for (capi < argc) {
|
||||
@@ -4535,8 +4578,6 @@ 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) {
|
||||
@@ -4616,7 +4657,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; };
|
||||
};
|
||||
@@ -4627,10 +4668,6 @@ 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))) {
|
||||
@@ -4643,13 +4680,9 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
cerrpath("ww build: cannot find module ", src, "\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) {
|
||||
if (outflag != nil && outflag[0u64] != 0u8) {
|
||||
// -o sets both the binary path and the intermediate stem so
|
||||
// artifacts land beside the requested output (T3).
|
||||
out = outflag;
|
||||
@@ -4678,9 +4711,11 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
lf.nlibs = nlibs;
|
||||
let rootidentity: *u8 = nil;
|
||||
if (!requestedliteral && isdir != 0) { rootidentity = src; };
|
||||
let publishpackage: i32 = 0;
|
||||
if (outflag != nil && outflag[0u64] != 0u8) { publishpackage = 1; };
|
||||
return buildonesep(selfdir, resolved, isdir, rootidentity,
|
||||
out, objstem, incs.ptr, &lf,
|
||||
packageonly, 0i32, SEP_VARIANT_PRODUCTION, nil,
|
||||
publishpackage, 0i32, 0i32, SEP_VARIANT_PRODUCTION, nil,
|
||||
emitasm, 1i32, workdir);
|
||||
};
|
||||
|
||||
@@ -4862,7 +4897,8 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
if (!requestedliteral && isdir != 0) { rootidentity = src; };
|
||||
if (buildonesep(selfdir, resolved, isdir, rootidentity,
|
||||
outp, outp, incs.ptr, &lf,
|
||||
0i32, 0i32, SEP_VARIANT_PRODUCTION, nil, 0i32, 0i32, nil) != 0) {
|
||||
0i32, 1i32, 0i32, SEP_VARIANT_PRODUCTION, nil,
|
||||
0i32, 0i32, nil) != 0) {
|
||||
let cleanrc: i32 = os.remove(pathstr(outp));
|
||||
if (cleanrc != 0 && cleanrc != -2i32) {
|
||||
cerr("ww: cannot remove temporary output\n");
|
||||
@@ -4952,7 +4988,8 @@ fn runsingletest(selfdir: *u8, src: *u8, incs: *u8, compileonly: i32,
|
||||
let keep: i32 = 0;
|
||||
if (outstem != nil) { keep = 1; };
|
||||
let bres: i32 = buildonesep(selfdir, src, 0, nil, outp, objstem, incs, &lf,
|
||||
0i32, 1i32, SEP_VARIANT_PRODUCTION, nil, emitasm, keep, workdir);
|
||||
0i32, 0i32, 1i32, SEP_VARIANT_PRODUCTION, nil,
|
||||
emitasm, keep, workdir);
|
||||
if (bres != 0) {
|
||||
if (owntmp) {
|
||||
let cleanrc: i32 = os.remove(pathstr(outp));
|
||||
|
||||
Reference in New Issue
Block a user