ww build: honor output directories

This commit is contained in:
2026-08-21 02:32:56 +09:00
parent 71a9da2058
commit ce91f6662c
7 changed files with 1768 additions and 107 deletions

View File

@@ -24,6 +24,7 @@ type pkgfolder = struct {
type pkggroup = struct {
dir: str,
pkg: str,
basename: str,
testname: str,
publish: str,
prodpkg: str,
@@ -58,6 +59,11 @@ type pkgplan = struct {
buildonly: bool,
publish: bool,
emitasm: bool,
outputpatherror: bool,
defaultoutputdir: str,
outputcollisionbase: str,
outputcollisiondir: str,
suppressbuildreports: bool,
};
def PKG_COUNT_MAX: i32 = 2147483647;
@@ -1368,8 +1374,9 @@ fn pkgsetplanpaths(p: *pkgplan, groups: []pkggroup, root: str, index: i32,
return false;
};
if (buildonly) {
if (outputdir && strings.compare(g.pkg, "main") == 0) {
if (!pkgjoinpath(outname, pkgbase(g.dir), &g.bin)) { return false; };
if (outputdir && strings.compare(g.pkg, "main") == 0
&& !p.outputpatherror && !p.emitasm) {
if (!pkgjoinpath(outname, g.basename, &g.bin)) { return false; };
} else if (outname.len != 0 && !outputdir) { g.bin = outname; }
else if (!pkgstring(&g.bin, g.root, "/package.build")) { return false; };
} else {
@@ -1416,7 +1423,7 @@ fn pkgreportcommand(fd: i32, kind: str, g: *pkggroup,
fn pkgstartbuild(p: *pkgplan, groups: []pkggroup, builder: str, includes: []str,
libdirs: []str, libs: []str, h: *exec.process) bool = {
let nproducts: i32 = p.end - p.start;
let capacity: i32 = 16;
let capacity: i32 = 24;
if (nproducts < 0 || nproducts > (PKG_COUNT_MAX - capacity) / 10) {
pkgputln(os.STDERR_FILENO, "wwtest package: package graph is too large");
return false;
@@ -1457,6 +1464,18 @@ fn pkgstartbuild(p: *pkgplan, groups: []pkggroup, builder: str, includes: []str,
append(ba, "--ww-create-output-dir");
append(ba, p.outputdir);
};
if (p.outputpatherror) {
append(ba, "--ww-command-output-path-error");
};
if (p.defaultoutputdir.len != 0) {
append(ba, "--ww-default-output-dir");
append(ba, p.defaultoutputdir);
};
if (p.outputcollisionbase.len != 0) {
append(ba, "--ww-command-output-collision");
append(ba, p.outputcollisionbase);
append(ba, p.outputcollisiondir);
};
if (p.identity.len != 0) {
append(ba, "--ww-root-identity");
append(ba, p.identity);
@@ -1627,8 +1646,10 @@ fn pkgemitplan(p: *pkgplan, groups: []pkggroup,
let i: i32 = p.start;
for (i < p.end) {
if (!pkgproductbuilt(&groups[i], buildonly)) {
pkgreportcommand(os.STDERR_FILENO, "build", &groups[i],
&p.buildres);
if (!p.suppressbuildreports) {
pkgreportcommand(os.STDERR_FILENO, "build", &groups[i],
&p.buildres);
};
failed += 1;
} else if (buildonly) {
void;
@@ -2165,6 +2186,7 @@ export fn packagecommand(args: []str) int = {
g.dir = f.path;
g.pkg = family;
if (g.pkg.len == 0) { g.pkg = srcs[f.start].pkg; };
g.basename = "";
g.testname = "";
g.publish = "";
g.prodpkg = f.prodpkg;
@@ -2193,57 +2215,48 @@ export fn packagecommand(args: []str) int = {
return 1;
};
pkgsortgroups(groups);
i = 0;
for (i < groups.len) {
groups[i].basename = pkgbase(groups[i].dir);
if (roots.len == 1 && !anyrecurse && requestidentity.len != 0) {
groups[i].basename = pkgimportbase(requestidentity);
};
i += 1;
};
let defaultout: bool = false;
if (buildonly && !buildnull && outname.len == 0 && folders.len == 1
&& groups.len == 1 && strings.compare(groups[0].pkg, "main") == 0) {
outname = pkgbase(groups[0].dir);
outname = groups[0].basename;
defaultout = true;
};
let defaultoutputdir: str = "";
if (defaultout && pkgstatdir(outname)) {
pkgput(os.STDERR_FILENO, "ww: build output \"");
pkgput(os.STDERR_FILENO, outname);
pkgputln(os.STDERR_FILENO, "\" already exists and is a directory");
return 1;
defaultoutputdir = outname;
};
let outputdir: bool = buildonly && explicitout && !buildnull
&& pkgoutputdir(outname);
let outputpatherror: bool = false;
let outputcollisionbase: str = "";
let outputcollisiondir: str = "";
if (outputdir) {
let mainpackages: i32 = 0;
i = 0;
for (i < groups.len) {
if (strings.compare(groups[i].pkg, "main") == 0) {
mainpackages += 1;
};
i += 1;
};
if (mainpackages == 0) {
pkgputln(os.STDERR_FILENO, "ww: no main packages to build");
return 1;
};
i = 0;
for (i < groups.len) {
if (strings.compare(groups[i].pkg, "main") == 0) {
let slash: i64 = 1i64;
if (strings.hassuffix(outname, "/")) { slash = 0i64; };
let outputlen: i64 = outname.len: i64 + slash
+ pkgbase(groups[i].dir).len: i64;
+ groups[i].basename.len: i64;
if (outputlen + 1i64 > os.PATH_MAX: i64) {
pkgputln(os.STDERR_FILENO,
"ww: command output path is too long");
return 1;
outputpatherror = true;
};
let j: i32 = 0;
for (j < i) {
if (strings.compare(groups[j].pkg, "main") == 0
&& strings.compare(pkgbase(groups[j].dir),
pkgbase(groups[i].dir)) == 0) {
pkgput(os.STDERR_FILENO,
"ww: multiple commands produce output basename ");
pkgputquoted(os.STDERR_FILENO, pkgbase(groups[i].dir));
pkgput(os.STDERR_FILENO, " in directory ");
pkgputquoted(os.STDERR_FILENO, outname);
pkgputln(os.STDERR_FILENO, "");
return 1;
&& strings.compare(groups[j].basename,
groups[i].basename) == 0
&& outputcollisionbase.len == 0) {
outputcollisionbase = groups[i].basename;
outputcollisiondir = outname;
};
j += 1;
};
@@ -2273,11 +2286,9 @@ export fn packagecommand(args: []str) int = {
};
i = 0;
for (i < groups.len) {
let leaf: str = pkgbase(groups[i].dir);
if (roots.len == 1 && !anyrecurse && requestidentity.len != 0) {
leaf = pkgimportbase(requestidentity);
if (!pkgstring(&groups[i].testname, groups[i].basename, ".test")) {
return 1;
};
if (!pkgstring(&groups[i].testname, leaf, ".test")) { return 1; };
groups[i].publish = "";
if (testretain && !groups[i].notests && !testnull) {
if (!explicitout) {
@@ -2368,6 +2379,12 @@ export fn packagecommand(args: []str) int = {
&& groups.len == 1
&& strings.compare(groups[0].pkg, "main") != 0;
plan.emitasm = emitasm;
plan.outputpatherror = outputpatherror;
plan.defaultoutputdir = defaultoutputdir;
plan.outputcollisionbase = outputcollisionbase;
plan.outputcollisiondir = outputcollisiondir;
plan.suppressbuildreports = buildonly
&& (outputdir || defaultoutputdir.len != 0);
append(plans, plan);
let createdir: str = "";
if (buildonly && outputdir) {