ww: build intermediates follow -o output stem, not the source dir (test-perf T3a)
build_one/buildone gain an explicit objstem: 'ww build -o X' derives
main.{combined.ww,s,o} beside X; 'ww run' uses its per-pid /tmp stem;
default no--o stays next-to-source (load-bearing for the make regen of
tracked combined.ww and the freshness gate). Realizes the redirect TODO
in 995_self_rebuild.c. Kills the concurrent-test torn-read race on
selfhost/cmd/<tool>/main.* (the 991 transient). 993/995/949 pass -o
into their per-pid workdirs; 949's '-o /dev/null' relied on the old
driver ignoring -o (audited: the only live driver case). Atomic
combined write (os.rename) deferred to its own commit - lib/os lacks
rename and that addition is an import-floor regen.
This commit is contained in:
@@ -3581,8 +3581,11 @@ fn appendlit(stem: *u8, suffix: str) *u8 = {
|
||||
return buf.ptr;
|
||||
};
|
||||
|
||||
// linker flags bundled as a struct so buildone stays at the wwstage
|
||||
// w6c's 6-argument calling-convention limit.
|
||||
// linker flags (-L<dir>, -l<name>) grouped as one struct so buildone's
|
||||
// param list stays readable. (The earlier note here claimed a 6-argument
|
||||
// wwstage calling-convention cap; that is stale — emittuplerowrelocs in
|
||||
// cgen.ww takes 7 params and self-compiles green, and buildone itself now
|
||||
// takes 7.)
|
||||
type lflags = struct {
|
||||
libdirs: **u8,
|
||||
nlibdirs: i32,
|
||||
@@ -3597,6 +3600,13 @@ type lflags = struct {
|
||||
// src: NUL-terminated entry path (file or directory).
|
||||
// entryisdir: non-zero when src is a module directory.
|
||||
// out: NUL-terminated desired output path
|
||||
// objstem: when non-nil, redirects the .s/.o/.combined.ww side
|
||||
// files to live beside this stem instead of next to the
|
||||
// source (T3 / task #15). `ww run` and `ww build -o` pass
|
||||
// it so concurrent builds never share next-to-source fixed
|
||||
// paths; nil keeps the old next-to-source layout (the make
|
||||
// tracked-combined.ww regen + #110 gate depend on it). Twin
|
||||
// of cmd/ww/main.c build_one's objstem.
|
||||
// incs: NUL-terminated colon-list of -I dirs (may be empty)
|
||||
// lf: extra linker flags (-L<dir>, -l<name>); may be nil
|
||||
//
|
||||
@@ -3604,7 +3614,7 @@ type lflags = struct {
|
||||
// touches no C-built code at runtime. The C `ww` driver in cmd/ww/
|
||||
// still drives the C-built w6c/w6a/w6l. Test 993 pins the two
|
||||
// pipelines to byte-identical output on a corpus.
|
||||
fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *lflags) i32 = {
|
||||
fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, objstem: *u8, incs: *u8, lf: *lflags) i32 = {
|
||||
let c6: *u8 = joinpathlit(selfdir, "w6c_ww");
|
||||
let a6: *u8 = joinpathlit(selfdir, "w6a_ww");
|
||||
let l6: *u8 = joinpathlit(selfdir, "w6l_ww");
|
||||
@@ -3687,9 +3697,11 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
||||
} else {
|
||||
makestem(stem.ptr, src);
|
||||
};
|
||||
let asmf: *u8 = appendlit(stem.ptr, ".s");
|
||||
let objf: *u8 = appendlit(stem.ptr, ".o");
|
||||
let combined: *u8 = appendlit(stem.ptr, ".combined.ww");
|
||||
let effstem: *u8 = stem.ptr;
|
||||
if (objstem != nil) { effstem = objstem; };
|
||||
let asmf: *u8 = appendlit(effstem, ".s");
|
||||
let objf: *u8 = appendlit(effstem, ".o");
|
||||
let combined: *u8 = appendlit(effstem, ".combined.ww");
|
||||
|
||||
// libwwrt.a path: <selfdir>/../lib/libwwrt.a
|
||||
let libwwrt: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
@@ -3934,6 +3946,7 @@ fn defaultoutpath(src: *u8) *u8 = {
|
||||
|
||||
fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
let src: *u8 = nil;
|
||||
let outflag: *u8 = nil; // -o target (binary + intermediate stem); T3
|
||||
let incs: []u8 = alloc([], (os.PATH_MAX: u64) * 2u64)!;
|
||||
incs.len = ((os.PATH_MAX: u64) * 2u64): i32;
|
||||
let incoff: u64 = 0u64;
|
||||
@@ -4005,10 +4018,21 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
};
|
||||
libs[nlibs] = nm;
|
||||
nlibs += 1;
|
||||
} else { if (p[1u64] == 111u8) { // '-o'
|
||||
if (p[2u64] != 0u8) {
|
||||
outflag = p + 2u64;
|
||||
} else {
|
||||
if (i + 1 >= argc) {
|
||||
cerr("ww build: -o needs an argument\n");
|
||||
return 2;
|
||||
};
|
||||
i += 1;
|
||||
outflag = argv[i];
|
||||
};
|
||||
} else {
|
||||
cerr("ww build: unknown flag\n");
|
||||
return 2;
|
||||
}; }; };
|
||||
}; }; }; };
|
||||
} else {
|
||||
if (src == nil) { src = p; };
|
||||
};
|
||||
@@ -4027,7 +4051,13 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
return 1;
|
||||
};
|
||||
let out: *u8 = nil;
|
||||
if (isdir != 0) {
|
||||
let objstem: *u8 = nil;
|
||||
if (outflag != nil) {
|
||||
// -o sets both the binary path and the intermediate stem so
|
||||
// artifacts land beside the requested output (T3).
|
||||
out = outflag;
|
||||
objstem = outflag;
|
||||
} else { if (isdir != 0) {
|
||||
let rlen: u64 = cstrlen(resolved);
|
||||
for (rlen > 1u64) {
|
||||
if (resolved[rlen - 1u64] != 47u8) { break; };
|
||||
@@ -4043,13 +4073,13 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
cstrseal(out, off);
|
||||
} else {
|
||||
out = defaultoutpath(resolved);
|
||||
};
|
||||
}; };
|
||||
let lf: lflags;
|
||||
lf.libdirs = libdirs.ptr;
|
||||
lf.nlibdirs = nlibdirs;
|
||||
lf.libs = libs.ptr;
|
||||
lf.nlibs = nlibs;
|
||||
return buildone(selfdir, resolved, isdir, out, incs.ptr, &lf);
|
||||
return buildone(selfdir, resolved, isdir, out, objstem, incs.ptr, &lf);
|
||||
};
|
||||
|
||||
// Format the scratch path /tmp/ww_run_<pid> into buf. Returns NUL-
|
||||
@@ -4158,10 +4188,20 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
};
|
||||
libs[nlibs] = nm;
|
||||
nlibs += 1;
|
||||
} else { if (p[1u64] == 111u8) { // '-o'
|
||||
// run always execs the temp binary; -o is accepted+
|
||||
// ignored, mirroring the C driver's shared flag parser.
|
||||
if (p[2u64] == 0u8) {
|
||||
if (i + 1 >= argc) {
|
||||
cerr("ww run: -o needs an argument\n");
|
||||
return 2;
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
} else {
|
||||
cerr("ww run: unknown flag\n");
|
||||
return 2;
|
||||
}; }; };
|
||||
}; }; }; };
|
||||
i += 1;
|
||||
} else {
|
||||
if (src == nil) {
|
||||
@@ -4193,7 +4233,9 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
lf.nlibdirs = nlibdirs;
|
||||
lf.libs = libs.ptr;
|
||||
lf.nlibs = nlibs;
|
||||
if (buildone(selfdir, resolved, isdir, tmp.ptr, incs.ptr, &lf) != 0) {
|
||||
// objstem = tmp → intermediates at /tmp/ww_run_<pid>.{s,o,combined.ww},
|
||||
// never next to the source (T3).
|
||||
if (buildone(selfdir, resolved, isdir, tmp.ptr, tmp.ptr, incs.ptr, &lf) != 0) {
|
||||
os.remove(pathstr(tmp.ptr));
|
||||
return 1;
|
||||
};
|
||||
@@ -4227,7 +4269,7 @@ fn runsingletest(selfdir: *u8, src: *u8) i32 = {
|
||||
let tmp: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
tmp.len = os.PATH_MAX;
|
||||
makeruntmp(tmp.ptr);
|
||||
if (buildone(selfdir, src, 0, tmp.ptr, "\0".ptr, nil) != 0) {
|
||||
if (buildone(selfdir, src, 0, tmp.ptr, nil, "\0".ptr, nil) != 0) {
|
||||
os.remove(pathstr(tmp.ptr));
|
||||
return 1;
|
||||
};
|
||||
@@ -4282,7 +4324,7 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
|
||||
let tmp: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
tmp.len = os.PATH_MAX;
|
||||
makeruntmp(tmp.ptr);
|
||||
let bres: i32 = buildone(selfdir, path.ptr, 0, tmp.ptr, tincs.ptr, nil);
|
||||
let bres: i32 = buildone(selfdir, path.ptr, 0, tmp.ptr, nil, tincs.ptr, nil);
|
||||
if (bres != 0) {
|
||||
fail += 1;
|
||||
cerr("FAIL ");
|
||||
|
||||
@@ -795,8 +795,11 @@ fn appendlit(stem: *u8, suffix: str) *u8 = {
|
||||
return buf.ptr;
|
||||
};
|
||||
|
||||
// linker flags bundled as a struct so buildone stays at the wwstage
|
||||
// w6c's 6-argument calling-convention limit.
|
||||
// linker flags (-L<dir>, -l<name>) grouped as one struct so buildone's
|
||||
// param list stays readable. (The earlier note here claimed a 6-argument
|
||||
// wwstage calling-convention cap; that is stale — emittuplerowrelocs in
|
||||
// cgen.ww takes 7 params and self-compiles green, and buildone itself now
|
||||
// takes 7.)
|
||||
type lflags = struct {
|
||||
libdirs: **u8,
|
||||
nlibdirs: i32,
|
||||
@@ -811,6 +814,13 @@ type lflags = struct {
|
||||
// src: NUL-terminated entry path (file or directory).
|
||||
// entryisdir: non-zero when src is a module directory.
|
||||
// out: NUL-terminated desired output path
|
||||
// objstem: when non-nil, redirects the .s/.o/.combined.ww side
|
||||
// files to live beside this stem instead of next to the
|
||||
// source (T3 / task #15). `ww run` and `ww build -o` pass
|
||||
// it so concurrent builds never share next-to-source fixed
|
||||
// paths; nil keeps the old next-to-source layout (the make
|
||||
// tracked-combined.ww regen + #110 gate depend on it). Twin
|
||||
// of cmd/ww/main.c build_one's objstem.
|
||||
// incs: NUL-terminated colon-list of -I dirs (may be empty)
|
||||
// lf: extra linker flags (-L<dir>, -l<name>); may be nil
|
||||
//
|
||||
@@ -818,7 +828,7 @@ type lflags = struct {
|
||||
// touches no C-built code at runtime. The C `ww` driver in cmd/ww/
|
||||
// still drives the C-built w6c/w6a/w6l. Test 993 pins the two
|
||||
// pipelines to byte-identical output on a corpus.
|
||||
fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *lflags) i32 = {
|
||||
fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, objstem: *u8, incs: *u8, lf: *lflags) i32 = {
|
||||
let c6: *u8 = joinpathlit(selfdir, "w6c_ww");
|
||||
let a6: *u8 = joinpathlit(selfdir, "w6a_ww");
|
||||
let l6: *u8 = joinpathlit(selfdir, "w6l_ww");
|
||||
@@ -901,9 +911,11 @@ fn buildone(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8, incs: *u8, lf: *l
|
||||
} else {
|
||||
makestem(stem.ptr, src);
|
||||
};
|
||||
let asmf: *u8 = appendlit(stem.ptr, ".s");
|
||||
let objf: *u8 = appendlit(stem.ptr, ".o");
|
||||
let combined: *u8 = appendlit(stem.ptr, ".combined.ww");
|
||||
let effstem: *u8 = stem.ptr;
|
||||
if (objstem != nil) { effstem = objstem; };
|
||||
let asmf: *u8 = appendlit(effstem, ".s");
|
||||
let objf: *u8 = appendlit(effstem, ".o");
|
||||
let combined: *u8 = appendlit(effstem, ".combined.ww");
|
||||
|
||||
// libwwrt.a path: <selfdir>/../lib/libwwrt.a
|
||||
let libwwrt: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
@@ -1148,6 +1160,7 @@ fn defaultoutpath(src: *u8) *u8 = {
|
||||
|
||||
fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
let src: *u8 = nil;
|
||||
let outflag: *u8 = nil; // -o target (binary + intermediate stem); T3
|
||||
let incs: []u8 = alloc([], (os.PATH_MAX: u64) * 2u64)!;
|
||||
incs.len = ((os.PATH_MAX: u64) * 2u64): i32;
|
||||
let incoff: u64 = 0u64;
|
||||
@@ -1219,10 +1232,21 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
};
|
||||
libs[nlibs] = nm;
|
||||
nlibs += 1;
|
||||
} else { if (p[1u64] == 111u8) { // '-o'
|
||||
if (p[2u64] != 0u8) {
|
||||
outflag = p + 2u64;
|
||||
} else {
|
||||
if (i + 1 >= argc) {
|
||||
cerr("ww build: -o needs an argument\n");
|
||||
return 2;
|
||||
};
|
||||
i += 1;
|
||||
outflag = argv[i];
|
||||
};
|
||||
} else {
|
||||
cerr("ww build: unknown flag\n");
|
||||
return 2;
|
||||
}; }; };
|
||||
}; }; }; };
|
||||
} else {
|
||||
if (src == nil) { src = p; };
|
||||
};
|
||||
@@ -1241,7 +1265,13 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
return 1;
|
||||
};
|
||||
let out: *u8 = nil;
|
||||
if (isdir != 0) {
|
||||
let objstem: *u8 = nil;
|
||||
if (outflag != nil) {
|
||||
// -o sets both the binary path and the intermediate stem so
|
||||
// artifacts land beside the requested output (T3).
|
||||
out = outflag;
|
||||
objstem = outflag;
|
||||
} else { if (isdir != 0) {
|
||||
let rlen: u64 = cstrlen(resolved);
|
||||
for (rlen > 1u64) {
|
||||
if (resolved[rlen - 1u64] != 47u8) { break; };
|
||||
@@ -1257,13 +1287,13 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
cstrseal(out, off);
|
||||
} else {
|
||||
out = defaultoutpath(resolved);
|
||||
};
|
||||
}; };
|
||||
let lf: lflags;
|
||||
lf.libdirs = libdirs.ptr;
|
||||
lf.nlibdirs = nlibdirs;
|
||||
lf.libs = libs.ptr;
|
||||
lf.nlibs = nlibs;
|
||||
return buildone(selfdir, resolved, isdir, out, incs.ptr, &lf);
|
||||
return buildone(selfdir, resolved, isdir, out, objstem, incs.ptr, &lf);
|
||||
};
|
||||
|
||||
// Format the scratch path /tmp/ww_run_<pid> into buf. Returns NUL-
|
||||
@@ -1372,10 +1402,20 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
};
|
||||
libs[nlibs] = nm;
|
||||
nlibs += 1;
|
||||
} else { if (p[1u64] == 111u8) { // '-o'
|
||||
// run always execs the temp binary; -o is accepted+
|
||||
// ignored, mirroring the C driver's shared flag parser.
|
||||
if (p[2u64] == 0u8) {
|
||||
if (i + 1 >= argc) {
|
||||
cerr("ww run: -o needs an argument\n");
|
||||
return 2;
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
} else {
|
||||
cerr("ww run: unknown flag\n");
|
||||
return 2;
|
||||
}; }; };
|
||||
}; }; }; };
|
||||
i += 1;
|
||||
} else {
|
||||
if (src == nil) {
|
||||
@@ -1407,7 +1447,9 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
lf.nlibdirs = nlibdirs;
|
||||
lf.libs = libs.ptr;
|
||||
lf.nlibs = nlibs;
|
||||
if (buildone(selfdir, resolved, isdir, tmp.ptr, incs.ptr, &lf) != 0) {
|
||||
// objstem = tmp → intermediates at /tmp/ww_run_<pid>.{s,o,combined.ww},
|
||||
// never next to the source (T3).
|
||||
if (buildone(selfdir, resolved, isdir, tmp.ptr, tmp.ptr, incs.ptr, &lf) != 0) {
|
||||
os.remove(pathstr(tmp.ptr));
|
||||
return 1;
|
||||
};
|
||||
@@ -1441,7 +1483,7 @@ fn runsingletest(selfdir: *u8, src: *u8) i32 = {
|
||||
let tmp: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
tmp.len = os.PATH_MAX;
|
||||
makeruntmp(tmp.ptr);
|
||||
if (buildone(selfdir, src, 0, tmp.ptr, "\0".ptr, nil) != 0) {
|
||||
if (buildone(selfdir, src, 0, tmp.ptr, nil, "\0".ptr, nil) != 0) {
|
||||
os.remove(pathstr(tmp.ptr));
|
||||
return 1;
|
||||
};
|
||||
@@ -1496,7 +1538,7 @@ fn rundirtests(selfdir: *u8, dir: *u8) i32 = {
|
||||
let tmp: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
tmp.len = os.PATH_MAX;
|
||||
makeruntmp(tmp.ptr);
|
||||
let bres: i32 = buildone(selfdir, path.ptr, 0, tmp.ptr, tincs.ptr, nil);
|
||||
let bres: i32 = buildone(selfdir, path.ptr, 0, tmp.ptr, nil, tincs.ptr, nil);
|
||||
if (bres != 0) {
|
||||
fail += 1;
|
||||
cerr("FAIL ");
|
||||
|
||||
Reference in New Issue
Block a user