package archive_test; // Archive-driven w6l observers (host ar). Ports of the retired native // carriers test/wcc/610_arch.c and 632_w6l_manyflags.c; every // assertion preserved. // // selectivity (610) — libfoo.a holds a needed member and a member // referencing an undefined extern; the link succeeds (exit 0) because // w6l pulls ONLY the needed member — pulling lib_bad would fail with // an undefined reference to this_symbol_does_not_exist — and the // binary runs with exit 7. The bad member's @symbol extern is the // discriminator; keep it verbatim. // // manyflags (632, drain F-C) — -L/-l arrays must be sized by argc, // not a fixed 64-slot cap. -lfoo resolves only through the FINAL real // -L placed after N-1 junk dirs, so a successful link (exit 0 + // ELF64 ET_EXEC output) proves the Nth -L was honoured. N table // {1, 64, 65, 100, 128}; N=65 is the exact pre-fix overflow slot. // Both w6l and w6l_ww are driven (the w6l_ww leg was ungated in the // carrier too). // // Dropped C machinery, not assertions: wwtestpkg.h package-clause // injection, the 16KB shell-command buffer (argv is a real vector // here), and per-file unlink accounting (testenv.clean). import os; import os.exec; import strconv; import strings; import testenv; import time; fn fail(label: str, why: str) void = { let m: str = strings.concat("archive FAIL: ", label, " -- ", why, "\n"); os.write(2, m.ptr, m.len: u64); assert(false); }; fn tmo() time.duration = { return (240i64 * (time.second: i64)): time.duration; }; // -1 encodes an abnormal (non-EXIT) termination, never a valid code. fn runcode(dir: str, name: str, argv: []str) i32 = { let co: testenv.commandout; testenv.runcommand(dir, dir, name, argv, tmo(), &co); if (co.termination != exec.termination.EXIT) { return -1; }; return co.code; }; // itos returns a view into a static buffer; dup materializes it. fn dec(n: i32) str = { return strings.dup(strconv.itos(n: int, strconv.base.DEC)); }; // w6c + w6a on one package-main source; leaves .o next to it. fn compile(td: str, stem: str, body: str) void = { let src: str = strings.concat(td, "/", stem, ".ww"); let asmf: str = strings.concat(td, "/", stem, ".s"); let obj: str = strings.concat(td, "/", stem, ".o"); testenv.writefile(src, body); let cav: []str = [testenv.driver("w6c"), "-o", asmf, src]; if (runcode(td, strings.concat("c_", stem), cav) != 0) { fail(stem, "w6c failed"); }; let aav: []str = [testenv.driver("w6a"), "-o", obj, asmf]; if (runcode(td, strings.concat("a_", stem), aav) != 0) { fail(stem, "w6a failed"); }; }; // ---- selectivity (610) ------------------------------------------------- @test fn selectivity() void = { let td: str = testenv.fresh(); compile(td, "lib_good", strings.concat("package main;\n", "export fn f1() i32 = { return 7; };\n")); // defines f2 but also references an undefined extern — the // discriminator: pulling this member makes the link fail compile(td, "lib_bad", strings.concat("package main;\n", "@symbol(\"this_symbol_does_not_exist\") fn bogus() i32;\n", "export fn f2() i32 = { return bogus(); };\n")); // the plain prototype declares f1 in the same (main) module, so // the call resolves to main.f1 — matching lib_good's definition compile(td, "m", strings.concat("package main;\n", "fn f1() i32;\n", "fn main() i32 = { return f1(); };\n")); let lib: str = strings.concat(td, "/libfoo.a"); let arav: []str = ["/usr/bin/ar", "rcs", lib, strings.concat(td, "/lib_good.o"), strings.concat(td, "/lib_bad.o")]; if (runcode(td, "ar", arav) != 0) { fail("selectivity", "ar failed"); }; let exe: str = strings.concat(td, "/m"); let start: str = strings.concat(testenv.repo(), "/out/obj/rt/start.o"); let lav: []str = [testenv.driver("w6l"), "-o", exe, strings.concat(td, "/m.o"), start, lib]; let co: testenv.commandout; testenv.runcommand(td, td, "link", lav, tmo(), &co); if (co.termination != exec.termination.EXIT || co.code != 0) { fail("selectivity", strings.concat( "link failed (bad member pulled?): ", co.stderr)); }; let rav: []str = [exe]; if (runcode(td, "run_m", rav) != 7) { fail("selectivity", "exit != 7"); }; testenv.clean(td); }; // ---- manyflags (632) --------------------------------------------------- fn linkwith(td: str, lnk: str, n: i32) void = { let tag: str = strings.concat(lnk, "_", dec(n)); let exe: str = strings.concat(td, "/x_", tag); let av: []str = alloc([], 8u64)!; append(av, testenv.driver(lnk)); append(av, "-o"); append(av, exe); append(av, strings.concat(td, "/m.o")); let i: i32 = 1; for (i < n) { append(av, strings.concat("-L/nonexist/wwfc_d", dec(i))); i += 1; }; append(av, strings.concat("-L", td)); append(av, "-lfoo"); if (runcode(td, strings.concat("lnk_", tag), av) != 0) { fail("manyflags", strings.concat(lnk, " nflags=", dec(n), " link failed (Nth -L not honoured)")); }; let o: str = testenv.readfile(exe); if (o.len < 64 || o[0] != 0x7fu8 || o[1] != 0x45u8 || o[2] != 0x4cu8 || o[3] != 0x46u8) { fail("manyflags", strings.concat(lnk, " nflags=", dec(n), " output not an ELF")); }; // ET_EXEC == 2 (Ehdr e_type at 16, LE u16) if (testenv.leu16(o, 16) != 2u64) { fail("manyflags", strings.concat(lnk, " nflags=", dec(n), " output not ET_EXEC")); }; }; @test fn manyflags() void = { let td: str = testenv.fresh(); // a standalone main.o (no undefs) + an unrelated archived foo.o compile(td, "m", strings.concat("package main;\n", "fn main() i32 = { return 42; };\n")); compile(td, "f", strings.concat("package main;\n", "export fn foo() i32 = { return 7; };\n")); let arav: []str = ["/usr/bin/ar", "rcs", strings.concat(td, "/libfoo.a"), strings.concat(td, "/f.o")]; if (runcode(td, "ar", arav) != 0) { fail("manyflags", "ar failed"); }; let counts: []i32 = [1, 64, 65, 100, 128]; let i: i32 = 0; for (i < 5) { linkwith(td, "w6l_ww", counts[i]); linkwith(td, "w6l", counts[i]); i += 1; }; testenv.clean(td); };