diff --git a/test/package/package_test.ww b/test/package/package_test.ww index 20b43588..4b107aaa 100644 --- a/test/package/package_test.ww +++ b/test/package/package_test.ww @@ -2190,26 +2190,45 @@ fn workescape(s: str) str = { @test fn exact_package_tool_argv_stage_parity() void = { let root: str = fresh(); let source: str = strings.concat(root, "/source tree"); - let leaf: str = strings.concat(source, "/leaf"); - let dep: str = strings.concat(source, "/dep"); - let target: str = strings.concat(source, "/target"); + let runtime: str = strings.concat(root, "/runtime library"); + let leaf: str = strings.concat(source, "/ww_root_parity_leaf_7f3"); + let dep: str = strings.concat(source, "/ww_root_parity_dep_7f3"); + let target: str = strings.concat(source, "/ww_root_parity_target_7f3"); let tools: str = strings.concat(root, "/tool wrappers"); assert(os.mkdir(source, 448i32) == 0); + assert(os.mkdir(runtime, 448i32) == 0); + let copyav: []str = ["/bin/cp", "-R", strings.concat(repo(), "/lib/."), + source]; + let copyout: commandout; + runcommand(root, "copy-source-library", copyav, + (30i64 * (time.second: i64)): time.duration, ©out); + expectexit(©out, 0); + assert(copyout.stderr.len == 0); + let support: str = strings.concat(source, "/test/run.ww"); + let supportbody: str = readfile(support); + assert(os.remove(support) == 0); + writefile(support, strings.concat("// WW_SRCLIB fixture marker\n", + supportbody)); + writefile(strings.concat(runtime, "/libwwrt.a"), + readfile(strings.concat(repo(), "/out/lib/libwwrt.a"))); assert(os.mkdir(leaf, 448i32) == 0); assert(os.mkdir(dep, 448i32) == 0); assert(os.mkdir(target, 448i32) == 0); assert(os.mkdir(tools, 448i32) == 0); writefile(strings.concat(leaf, "/leaf.ww"), strings.concat( - "package leaf;\n", + "package ww_root_parity_leaf_7f3;\n", "export fn value() i32 = { return 40; };\n")); writefile(strings.concat(dep, "/dep.ww"), strings.concat( - "package dep;\nimport leaf;\n", - "export fn value() i32 = { return leaf.value() + 2; };\n")); + "package ww_root_parity_dep_7f3;\n", + "import ww_root_parity_leaf_7f3;\n", + "export fn value() i32 = { return ", + "ww_root_parity_leaf_7f3.value() + 2; };\n")); writefile(strings.concat(target, "/target.ww"), strings.concat( - "package target;\nimport dep;\n", - "fn value() i32 = { return dep.value(); };\n")); + "package ww_root_parity_target_7f3;\n", + "import ww_root_parity_dep_7f3;\n", + "fn value() i32 = { return ww_root_parity_dep_7f3.value(); };\n")); writefile(strings.concat(target, "/target_test.ww"), strings.concat( - "package target;\n", + "package ww_root_parity_target_7f3;\n", "@test fn exact_argv() void = { assert(value() == 42); };\n")); let compilerwrapper: str = strings.concat(tools, "/w6c wrapper.sh"); @@ -2278,10 +2297,12 @@ fn workescape(s: str) str = { writefile(assemblertrace, ""); writefile(linkertrace, ""); writefile(failuretrace, ""); - let env: []str = alloc([], (baseenv.len + 9): u64)!; + let env: []str = alloc([], (baseenv.len + 11): u64)!; let ei: i32 = 0; for (ei < baseenv.len) { - if (!strings.hasprefix(baseenv[ei], "WW_W6C=") + if (!strings.hasprefix(baseenv[ei], "WW_SRCLIB=") + && !strings.hasprefix(baseenv[ei], "WW_LIB=") + && !strings.hasprefix(baseenv[ei], "WW_W6C=") && !strings.hasprefix(baseenv[ei], "WW_W6A=") && !strings.hasprefix(baseenv[ei], "WW_W6L=") && !strings.hasprefix(baseenv[ei], @@ -2300,6 +2321,8 @@ fn workescape(s: str) str = { }; ei += 1; }; + append(env, strings.concat("WW_SRCLIB=", source)); + append(env, strings.concat("WW_LIB=", runtime)); append(env, strings.concat("WW_W6C=", compilerwrapper)); append(env, strings.concat("WW_W6A=", assemblerwrapper)); append(env, strings.concat("WW_W6L=", linkerwrapper)); @@ -2314,7 +2337,7 @@ fn workescape(s: str) str = { driver(linkers[si]))); let av: []str = [driver(stages[si]), "test", "-c", "-o", bin, - "-I", source, target]; + target]; let out: commandout; runcommandenv(root, strings.concat("exact-argv-", tags[si]), av, env, (120i64 * (time.second: i64)): time.duration, &out); @@ -2322,14 +2345,21 @@ fn workescape(s: str) str = { assert(out.stderr.len == 0); let rootunit: str = readfile(strings.concat(work, "__ww-test-000-same.unit.ww")); - let depunit: str = readfile(strings.concat(work, "dep.unit.ww")); - assert(has(rootunit, "//ww:module dep\n")); - assert(!has(rootunit, "//ww:module leaf\n")); - assert(has(depunit, "//ww:module leaf\n")); - assert(os.exists(strings.concat(work, "leaf.wwi"))); - assert(os.exists(strings.concat(work, "leaf.a"))); - assert(os.exists(strings.concat(work, "dep.wwi"))); - assert(os.exists(strings.concat(work, "dep.a"))); + let depunit: str = readfile(strings.concat(work, + "ww_root_parity_dep_7f3.unit.ww")); + assert(has(rootunit, "//ww:module ww_root_parity_dep_7f3\n")); + assert(!has(rootunit, "//ww:module ww_root_parity_leaf_7f3\n")); + assert(has(depunit, "//ww:module ww_root_parity_leaf_7f3\n")); + assert(os.exists(strings.concat(work, + "ww_root_parity_leaf_7f3.wwi"))); + assert(os.exists(strings.concat(work, + "ww_root_parity_leaf_7f3.a"))); + assert(os.exists(strings.concat(work, + "ww_root_parity_dep_7f3.wwi"))); + assert(os.exists(strings.concat(work, + "ww_root_parity_dep_7f3.a"))); + assert(has(readfile(strings.concat(work, "test.unit.ww")), + "// WW_SRCLIB fixture marker\n")); assert(!os.exists(strings.concat(work, "__ww-test-000-same.wwi"))); assert(!os.exists(strings.concat(work, @@ -2340,30 +2370,41 @@ fn workescape(s: str) str = { let atrace: str = readfile(assemblertrace); let ltrace: str = readfile(linkertrace); assert(occurrences(ctrace, strings.concat("<", work, - "leaf.unit.ww>")) == 1); + "ww_root_parity_leaf_7f3.unit.ww>")) == 1); assert(occurrences(ctrace, strings.concat("<", work, - "dep.unit.ww>")) == 1); + "ww_root_parity_dep_7f3.unit.ww>")) == 1); assert(occurrences(ctrace, strings.concat("<", work, "__ww-test-000-same.unit.ww>")) == 1); - assert(pos(ctrace, strings.concat("<", work, "leaf.unit.ww>")) - < pos(ctrace, strings.concat("<", work, "dep.unit.ww>"))); - assert(pos(ctrace, strings.concat("<", work, "dep.unit.ww>")) + assert(pos(ctrace, strings.concat("<", work, + "ww_root_parity_leaf_7f3.unit.ww>")) + < pos(ctrace, strings.concat("<", work, + "ww_root_parity_dep_7f3.unit.ww>"))); + assert(pos(ctrace, strings.concat("<", work, + "ww_root_parity_dep_7f3.unit.ww>")) < pos(ctrace, strings.concat("<", work, "__ww-test-000-same.unit.ww>"))); assert(has(ctrace, strings.concat("BEGIN<-c><-I><", work, - "dep.wwi><-o><", work, "dep.s><", work, "dep.unit.ww>"))); + "ww_root_parity_dep_7f3.wwi><-o><", work, + "ww_root_parity_dep_7f3.s><", work, + "ww_root_parity_dep_7f3.unit.ww>"))); assert(has(ctrace, strings.concat( "BEGIN<-T><--test-support-module><-c><-o><", work, "__ww-test-000-same.s><", work, "__ww-test-000-same.unit.ww>"))); assert(has(atrace, strings.concat("BEGIN<-o><", work, - "dep.o><", work, "dep.s>"))); + "ww_root_parity_dep_7f3.o><", work, + "ww_root_parity_dep_7f3.s>"))); assert(occurrences(ltrace, "\n") == 1); assert(has(ltrace, strings.concat("BEGIN<-o><", bin, "><", work, "__ww-test-000-same.o>"))); - assert(has(ltrace, strings.concat("<", work, "dep.a>"))); - assert(has(ltrace, strings.concat("<", work, "leaf.a>"))); + assert(has(ltrace, strings.concat("<", work, + "ww_root_parity_dep_7f3.a>"))); + assert(has(ltrace, strings.concat("<", work, + "ww_root_parity_leaf_7f3.a>"))); assert(has(ltrace, strings.concat("<", work, "test.a>"))); + assert(has(ltrace, strings.concat("<", runtime, "/libwwrt.a>"))); + assert(!has(ltrace, strings.concat("<", repo(), + "/out/lib/libwwrt.a>"))); assert(!has(ltrace, ".wwi>")); let runav: []str = [bin]; @@ -2374,9 +2415,9 @@ fn workescape(s: str) str = { if (si == 0) { referenceunit = strings.dup(rootunit); referencewwi = strings.dup(readfile(strings.concat(work, - "dep.wwi"))); + "ww_root_parity_dep_7f3.wwi"))); referencearchive = strings.dup(readfile(strings.concat(work, - "dep.a"))); + "ww_root_parity_dep_7f3.a"))); referencebin = strings.dup(readfile(bin)); referencecompiler = strings.dup(ctrace); referenceassembler = strings.dup(atrace); @@ -2386,9 +2427,11 @@ fn workescape(s: str) str = { } else { assert(same(referenceunit, rootunit)); assert(same(referencewwi, - readfile(strings.concat(work, "dep.wwi")))); + readfile(strings.concat(work, + "ww_root_parity_dep_7f3.wwi")))); assert(same(referencearchive, - readfile(strings.concat(work, "dep.a")))); + readfile(strings.concat(work, + "ww_root_parity_dep_7f3.a")))); assert(same(referencebin, readfile(bin))); assert(same(referencecompiler, ctrace)); assert(same(referenceassembler, atrace)); @@ -2414,9 +2457,10 @@ fn workescape(s: str) str = { runcommandenv(root, strings.concat("exact-argv-fail-", tags[si]), av, failenv, (120i64 * (time.second: i64)): time.duration, &out); expectexit(&out, 1); - assert(has(out.stderr, "ww: w6c failed for leaf\n")); + assert(has(out.stderr, + "ww: w6c failed for ww_root_parity_leaf_7f3\n")); assert(has(readfile(failuretrace), strings.concat("<-I><", work, - "leaf.wwi>"))); + "ww_root_parity_leaf_7f3.wwi>"))); if (si == 0) { referencefailure = strings.dup(out.stderr); } else { assert(same(referencefailure, out.stderr)); }; clean(workroot); diff --git a/test/sep/localbuild_test.ww b/test/sep/localbuild_test.ww index 93241bfd..e1f703ba 100644 --- a/test/sep/localbuild_test.ww +++ b/test/sep/localbuild_test.ww @@ -41,6 +41,43 @@ fn build(dir: str, driver: str, tag: str, target: str, out: str) i32 = { return code(dir, strings.concat("build_", tag), av); }; +fn roottraceenv(source: str, runtime: str, + compiler: str, assembler: str, linker: str, + compilertrace: str, assemblertrace: str, linkertrace: str, + realcompiler: str, realassembler: str, reallinker: str) []str = { + let base: []str = os.getenvs(); + let env: []str = alloc([], (base.len + 11): u64)!; + let i: i32 = 0; + for (i < base.len) { + if (!strings.hasprefix(base[i], "WW_SRCLIB=") + && !strings.hasprefix(base[i], "WW_LIB=") + && !strings.hasprefix(base[i], "WW_W6C=") + && !strings.hasprefix(base[i], "WW_W6A=") + && !strings.hasprefix(base[i], "WW_W6L=") + && !strings.hasprefix(base[i], "WW_ROOT_COMPILER_TRACE=") + && !strings.hasprefix(base[i], "WW_ROOT_ASSEMBLER_TRACE=") + && !strings.hasprefix(base[i], "WW_ROOT_LINKER_TRACE=") + && !strings.hasprefix(base[i], "WW_ROOT_REAL_COMPILER=") + && !strings.hasprefix(base[i], "WW_ROOT_REAL_ASSEMBLER=") + && !strings.hasprefix(base[i], "WW_ROOT_REAL_LINKER=")) { + append(env, base[i]); + }; + i += 1; + }; + append(env, strings.concat("WW_SRCLIB=", source)); + append(env, strings.concat("WW_LIB=", runtime)); + append(env, strings.concat("WW_W6C=", compiler)); + append(env, strings.concat("WW_W6A=", assembler)); + append(env, strings.concat("WW_W6L=", linker)); + append(env, strings.concat("WW_ROOT_COMPILER_TRACE=", compilertrace)); + append(env, strings.concat("WW_ROOT_ASSEMBLER_TRACE=", assemblertrace)); + append(env, strings.concat("WW_ROOT_LINKER_TRACE=", linkertrace)); + append(env, strings.concat("WW_ROOT_REAL_COMPILER=", realcompiler)); + append(env, strings.concat("WW_ROOT_REAL_ASSEMBLER=", realassembler)); + append(env, strings.concat("WW_ROOT_REAL_LINKER=", reallinker)); + return env; +}; + fn diagnosticbody(s: str) str = { let p: i32 = testenv.pos(s, ": error: "); // Driver-owned graph diagnostics have no source-location prefix. Compare @@ -455,6 +492,316 @@ fn writediamond(td: str, reverse: bool) str = { testenv.clean(td); }; +@test fn toolchain_library_root_stage_parity() void = { + let td: str = testenv.fresh(); + let source: str = strings.concat(td, "/source library"); + let app: str = strings.concat(source, "/app"); + let dep: str = strings.concat(source, "/dep"); + let leaf: str = strings.concat(source, "/leaf"); + let runtime: str = strings.concat(td, "/runtime library"); + let decoy: str = strings.concat(runtime, "/app"); + let tools: str = strings.concat(td, "/tool wrappers"); + let cwd: str = strings.concat(td, "/isolated cwd"); + let defaultapp: str = strings.concat(td, "/default app"); + let fallbackbuf: []u8 = alloc([], os.PATH_MAX: u64)!; + fallbackbuf.len = os.PATH_MAX; + let fi: i32 = 0; + for (fi < fallbackbuf.len) { fallbackbuf[fi] = 120u8; fi += 1; }; + let fallback: str = strings.frombytes(fallbackbuf); + mkdir(source); mkdir(app); mkdir(dep); mkdir(leaf); + mkdir(runtime); mkdir(decoy); mkdir(tools); mkdir(cwd); mkdir(defaultapp); + testenv.writefile(strings.concat(leaf, "/leaf.ww"), strings.concat( + "package leaf;\n", + "export fn value() i32 = { return 40; };\n")); + testenv.writefile(strings.concat(dep, "/dep.ww"), strings.concat( + "package dep;\nimport leaf;\n", + "export fn value() i32 = { return leaf.value() + 2; };\n")); + testenv.writefile(strings.concat(app, "/app.ww"), strings.concat( + "package main;\nimport dep;\n", + "fn main() i32 = { return dep.value(); };\n")); + testenv.writefile(strings.concat(decoy, "/app.ww"), + "package main;\nfn main() i32 = { return 7; };\n"); + testenv.writefile(strings.concat(defaultapp, "/main.ww"), strings.concat( + "package main;\nimport types;\n", + "fn main() i32 = { return (types.I8_MAX: i32) - 85; };\n")); + testenv.writefile(strings.concat(runtime, "/libwwrt.a"), + testenv.readfile(strings.concat(testenv.repo(), "/out/lib/libwwrt.a"))); + + let compiler: str = strings.concat(tools, "/w6c wrapper.sh"); + let assembler: str = strings.concat(tools, "/w6a wrapper.sh"); + let linker: str = strings.concat(tools, "/w6l wrapper.sh"); + testenv.writeexecutable(compiler, strings.concat( + "#!/bin/sh\n", + "printf 'BEGIN' >> \"$WW_ROOT_COMPILER_TRACE\"\n", + "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", + "\"$WW_ROOT_COMPILER_TRACE\"; done\n", + "printf '\\n' >> \"$WW_ROOT_COMPILER_TRACE\"\n", + "exec \"$WW_ROOT_REAL_COMPILER\" \"$@\"\n")); + testenv.writeexecutable(assembler, strings.concat( + "#!/bin/sh\n", + "printf 'BEGIN' >> \"$WW_ROOT_ASSEMBLER_TRACE\"\n", + "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", + "\"$WW_ROOT_ASSEMBLER_TRACE\"; done\n", + "printf '\\n' >> \"$WW_ROOT_ASSEMBLER_TRACE\"\n", + "exec \"$WW_ROOT_REAL_ASSEMBLER\" \"$@\"\n")); + testenv.writeexecutable(linker, strings.concat( + "#!/bin/sh\n", + "printf 'BEGIN' >> \"$WW_ROOT_LINKER_TRACE\"\n", + "for arg in \"$@\"; do printf '<%s>' \"$arg\" >> ", + "\"$WW_ROOT_LINKER_TRACE\"; done\n", + "printf '\\n' >> \"$WW_ROOT_LINKER_TRACE\"\n", + "exec \"$WW_ROOT_REAL_LINKER\" \"$@\"\n")); + + let stages: []str = ["ww", "ww_ww"]; + let compilers: []str = ["w6c", "w6c_ww"]; + let assemblers: []str = ["w6a", "w6a_ww"]; + let linkers: []str = ["w6l", "w6l_ww"]; + let tags: []str = ["c", "ww"]; + let modes: []str = ["archive", "overlong-fallback"]; + let runtimes: []str = [runtime, fallback]; + let bin: str = strings.concat(td, "/published binary"); + let workroot: str = strings.concat(bin, ".sepwork"); + let work: str = strings.concat(workroot, "/"); + let mi: i32 = 0; + for (mi < modes.len) { + let referenceunit: str = ""; + let referencewwi: str = ""; + let referencearchive: str = ""; + let referencebin: str = ""; + let referencecompiler: str = ""; + let referenceassembler: str = ""; + let referencelinker: str = ""; + let si: i32 = 0; + for (si < stages.len) { + let prefix: str = strings.concat(modes[mi], "-", tags[si]); + let compilertrace: str = strings.concat(td, "/", prefix, + " compiler trace"); + let assemblertrace: str = strings.concat(td, "/", prefix, + " assembler trace"); + let linkertrace: str = strings.concat(td, "/", prefix, + " linker trace"); + testenv.writefile(compilertrace, ""); + testenv.writefile(assemblertrace, ""); + testenv.writefile(linkertrace, ""); + let env: []str = roottraceenv(source, runtimes[mi], + compiler, assembler, linker, + compilertrace, assemblertrace, linkertrace, + testenv.driver(compilers[si]), + testenv.driver(assemblers[si]), + testenv.driver(linkers[si])); + let av: []str = [testenv.driver(stages[si]), "build", "-o", bin, + "app"]; + let out: testenv.commandout; + testenv.runcommandenv(cwd, td, strings.concat("library-root-", prefix), + av, env, tmo(), &out); + if (out.termination != exec.termination.EXIT || out.code != 0 + || out.stderr.len != 0) { + fail("library-roots", strings.concat(prefix, " build failed: ", + out.stderr)); + }; + + let rootunit: str = testenv.readfile(strings.concat(work, + "__root.unit.ww")); + let depunit: str = testenv.readfile(strings.concat(work, + "dep.unit.ww")); + if (!testenv.has(rootunit, "//ww:module dep\n") + || testenv.has(rootunit, "//ww:module leaf\n") + || !testenv.has(depunit, "//ww:module leaf\n")) { + fail("library-roots", "compiler inputs crossed the direct-export boundary"); + }; + if (!testenv.exists(strings.concat(work, "leaf.wwi")) + || !testenv.exists(strings.concat(work, "leaf.a")) + || !testenv.exists(strings.concat(work, "dep.wwi")) + || !testenv.exists(strings.concat(work, "dep.a")) + || !testenv.exists(strings.concat(work, "__root.o")) + || testenv.exists(strings.concat(work, "__root.wwi")) + || testenv.exists(strings.concat(work, "__root.a"))) { + fail("library-roots", "package artifacts do not match root ownership"); + }; + let ctrace: str = testenv.readfile(compilertrace); + let atrace: str = testenv.readfile(assemblertrace); + let ltrace: str = testenv.readfile(linkertrace); + if (testenv.occurrences(ctrace, strings.concat("<", work, + "leaf.unit.ww>")) != 1 + || testenv.occurrences(ctrace, strings.concat("<", work, + "dep.unit.ww>")) != 1 + || testenv.occurrences(ctrace, strings.concat("<", work, + "__root.unit.ww>")) != 1 + || testenv.pos(ctrace, strings.concat("<", work, + "leaf.unit.ww>")) >= testenv.pos(ctrace, strings.concat("<", + work, "dep.unit.ww>")) + || testenv.pos(ctrace, strings.concat("<", work, + "dep.unit.ww>")) >= testenv.pos(ctrace, strings.concat("<", + work, "__root.unit.ww>"))) { + fail("library-roots", "compiler actions were not deterministic postorder"); + }; + if (!testenv.has(ctrace, strings.concat( + "BEGIN<-c><-I><", work, "dep.wwi><-o><", work, + "dep.s><", work, "dep.unit.ww>")) + || testenv.occurrences(atrace, "\n") != 3 + || !testenv.has(atrace, strings.concat("BEGIN<-o><", work, + "dep.o><", work, "dep.s>"))) { + fail("library-roots", "compiler or assembler argv changed"); + }; + if (testenv.occurrences(ltrace, "\n") != 1 + || !testenv.has(ltrace, strings.concat("BEGIN<-o><", bin, "><", + work, "__root.o>")) + || testenv.pos(ltrace, strings.concat("<", work, "dep.a>")) < 0 + || testenv.pos(ltrace, strings.concat("<", work, "leaf.a>")) + < testenv.pos(ltrace, strings.concat("<", work, "dep.a>")) + || testenv.has(ltrace, ".wwi>")) { + fail("library-roots", "linker did not receive the reachable archive closure"); + }; + if (mi == 0) { + if (!testenv.has(ltrace, strings.concat("<", runtime, + "/libwwrt.a>")) + || testenv.has(ltrace, strings.concat("<", testenv.repo(), + "/out/lib/libwwrt.a>"))) { + fail("library-roots", "WW_LIB did not select the runtime archive"); + }; + } else { + if (!testenv.has(ltrace, strings.concat("<", testenv.repo(), + "/out/bin/../obj/rt/start.o>")) + || !testenv.has(ltrace, strings.concat("<", testenv.repo(), + "/out/bin/../obj/rt/syscall.o>"))) { + fail("library-roots", "missing runtime archive did not use object fallback"); + }; + }; + let runav: []str = [bin]; + if (code(cwd, strings.concat("run-library-root-", prefix), runav) + != 42) { + fail("library-roots", "WW_SRCLIB did not win over the WW_LIB decoy"); + }; + if (si == 0) { + referenceunit = strings.dup(rootunit); + referencewwi = strings.dup(testenv.readfile(strings.concat(work, + "dep.wwi"))); + referencearchive = strings.dup(testenv.readfile(strings.concat(work, + "dep.a"))); + referencebin = strings.dup(testenv.readfile(bin)); + referencecompiler = strings.dup(ctrace); + referenceassembler = strings.dup(atrace); + referencelinker = strings.dup(ltrace); + } else { + if (!testenv.same(referenceunit, rootunit) + || !testenv.same(referencewwi, testenv.readfile(strings.concat( + work, "dep.wwi"))) + || !testenv.same(referencearchive, testenv.readfile(strings.concat( + work, "dep.a"))) + || !testenv.same(referencebin, testenv.readfile(bin)) + || !testenv.same(referencecompiler, ctrace) + || !testenv.same(referenceassembler, atrace) + || !testenv.same(referencelinker, ltrace)) { + fail("library-roots", "Cstage and WWstage products or argv differ"); + }; + }; + if (mi == 0) { + let missing: []str = [testenv.driver(stages[si]), "build", "-o", + strings.concat(td, "/missing binary"), "absent"]; + testenv.runcommandenv(cwd, td, strings.concat("library-missing-", + tags[si]), missing, env, tmo(), &out); + if (out.termination != exec.termination.EXIT || out.code != 1 + || !testenv.same(out.stderr, + "ww build: cannot find module absent\n")) { + fail("library-roots", "bare-target diagnostic differs by stage"); + }; + }; + testenv.clean(workroot); + assert(os.remove(bin) == 0); + si += 1; + }; + mi += 1; + }; + + let emptyunitreference: str = ""; + let emptywwireference: str = ""; + let emptyarchivereference: str = ""; + let emptybinreference: str = ""; + let emptycompilerreference: str = ""; + let emptyassemblerreference: str = ""; + let emptylinkerreference: str = ""; + let emptyout: str = strings.concat(td, "/empty published binary"); + let si: i32 = 0; + for (si < stages.len) { + let outpath: str = emptyout; + let emptyworkroot: str = strings.concat(outpath, ".sepwork"); + let emptywork: str = strings.concat(emptyworkroot, "/"); + let compilertrace: str = strings.concat(td, "/empty-", tags[si], + " compiler trace"); + let assemblertrace: str = strings.concat(td, "/empty-", tags[si], + " assembler trace"); + let linkertrace: str = strings.concat(td, "/empty-", tags[si], + " linker trace"); + testenv.writefile(compilertrace, ""); + testenv.writefile(assemblertrace, ""); + testenv.writefile(linkertrace, ""); + let emptyenv: []str = roottraceenv("", "", + compiler, assembler, linker, + compilertrace, assemblertrace, linkertrace, + testenv.driver(compilers[si]), + testenv.driver(assemblers[si]), + testenv.driver(linkers[si])); + let av: []str = [testenv.driver(stages[si]), "build", "-o", outpath, + defaultapp]; + let out: testenv.commandout; + testenv.runcommandenv(cwd, td, strings.concat("empty-library-", + tags[si]), av, emptyenv, tmo(), &out); + let rootunit: str = testenv.readfile(strings.concat(emptywork, + "__root.unit.ww")); + let ctrace: str = testenv.readfile(compilertrace); + let atrace: str = testenv.readfile(assemblertrace); + let ltrace: str = testenv.readfile(linkertrace); + let runav: []str = [outpath]; + if (out.termination != exec.termination.EXIT || out.code != 0 + || out.stderr.len != 0 + || code(cwd, strings.concat("run-empty-library-", tags[si]), + runav) != 42) { + fail("library-roots", "empty override did not use default roots"); + }; + if (!testenv.has(rootunit, "//ww:module types\n") + || !testenv.exists(strings.concat(emptywork, "types.wwi")) + || !testenv.exists(strings.concat(emptywork, "types.a")) + || testenv.occurrences(ctrace, strings.concat("<", emptywork, + "types.unit.ww>")) != 1 + || testenv.occurrences(atrace, "\n") != 2) { + fail("library-roots", "empty WW_SRCLIB did not use the default source root"); + }; + if (testenv.occurrences(ltrace, "\n") != 1 + || !testenv.has(ltrace, strings.concat("<", emptywork, "types.a>")) + || !testenv.has(ltrace, strings.concat("<", testenv.repo(), + "/out/bin/../lib/libwwrt.a>")) + || testenv.has(ltrace, "/../obj/rt/start.o>") + || testenv.has(ltrace, "/../obj/rt/syscall.o>")) { + fail("library-roots", "empty WW_LIB did not use the default runtime archive"); + }; + if (si == 0) { + emptyunitreference = strings.dup(rootunit); + emptywwireference = strings.dup(testenv.readfile(strings.concat( + emptywork, "types.wwi"))); + emptyarchivereference = strings.dup(testenv.readfile(strings.concat( + emptywork, "types.a"))); + emptybinreference = strings.dup(testenv.readfile(outpath)); + emptycompilerreference = strings.dup(ctrace); + emptyassemblerreference = strings.dup(atrace); + emptylinkerreference = strings.dup(ltrace); + } else { if (!testenv.same(emptyunitreference, rootunit) + || !testenv.same(emptywwireference, testenv.readfile(strings.concat( + emptywork, "types.wwi"))) + || !testenv.same(emptyarchivereference, testenv.readfile( + strings.concat(emptywork, "types.a"))) + || !testenv.same(emptybinreference, testenv.readfile(outpath)) + || !testenv.same(emptycompilerreference, ctrace) + || !testenv.same(emptyassemblerreference, atrace) + || !testenv.same(emptylinkerreference, ltrace)) { + fail("library-roots", "empty-root fallback changed stage output or argv"); + }; }; + testenv.clean(emptyworkroot); + assert(os.remove(outpath) == 0); + si += 1; + }; + testenv.clean(td); +}; + @test fn builtin_type_precedence() void = { let td: str = testenv.fresh(); let dep: str = strings.concat(td, "/builtinshadow"); mkdir(dep);