diff --git a/.github/workflows/update_tccbin.yml b/.github/workflows/update_tccbin.yml index 529c6de6dbf42a..291209bcba02be 100644 --- a/.github/workflows/update_tccbin.yml +++ b/.github/workflows/update_tccbin.yml @@ -698,13 +698,18 @@ jobs: exit 1 fi - # Deliverable A (this PR) does not include the V selector change - # (deliverable C, vlib/builtin/builtin_d_gcboehm.c.v) - it merges - # separately, only after this pair is published and vlang/tccbin's - # gate is confirmed green under it. To actually exercise the - # dylib pairing here, apply that selector collapse to an entirely - # separate, freshly-cloned vlang/v workspace, in memory only - - # never written back to this checkout, never committed anywhere. + # Build ./v in an entirely separate, freshly-cloned workspace so the + # smoke test below runs a real V against the staged bundle. + # + # This step used to patch vlib/builtin/builtin_d_gcboehm.c.v in memory + # to make macOS amd64 select libgc.dylib, because the selector still + # chose the static libgc.a and the smoke test would otherwise not have + # exercised the dylib pairing at all. That patch is gone: the selector + # itself now links the dylib on both macOS arches, so this clone needs + # no modification to test the right thing. (Leaving the patch in place + # would in fact have broken this job outright - it asserted its search + # text occurred exactly once, and that text no longer exists.) + # # This clone's own thirdparty/tcc has nothing to do with the # bundle staged above (a brand new clone doesn't have one yet), # so letting `make`'s default target bootstrap it normally here @@ -733,30 +738,6 @@ jobs: git clone --quiet "https://github.com/${{ github.repository }}" /tmp/v-bootstrap-workspace git -C /tmp/v-bootstrap-workspace checkout --quiet "${{ github.sha }}" - python3 - <<'PYEOF' - path = "/tmp/v-bootstrap-workspace/vlib/builtin/builtin_d_gcboehm.c.v" - with open(path, "r", encoding="utf-8", newline="") as f: - content = f.read() - old = ('\t\t\t\t\t\t$if arm64 {\n' - '\t\t\t\t\t\t\t// tcc on macOS arm64 can leave the bundled GC archive symbols unresolved.\n' - '\t\t\t\t\t\t\t#flag @VEXEROOT/thirdparty/tcc/lib/libgc.dylib\n' - '\t\t\t\t\t\t\t#flag -Wl,-rpath,"@VEXEROOT/thirdparty/tcc/lib"\n' - '\t\t\t\t\t\t} $else {\n' - '\t\t\t\t\t\t\t// macOS amd64 tccbin only ships libgc.a (no .dylib).\n' - '\t\t\t\t\t\t\t#flag @VEXEROOT/thirdparty/tcc/lib/libgc.a\n' - '\t\t\t\t\t\t}\n') - new = ('\t\t\t\t\t\t// SMOKE-TEST-ONLY PATCH (thirdparty-macos-amd64_bdwgc_validate.sh\n' - '\t\t\t\t\t\t// caller) - never committed. Deliverable C applies this for real.\n' - '\t\t\t\t\t\t#flag @VEXEROOT/thirdparty/tcc/lib/libgc.dylib\n' - '\t\t\t\t\t\t#flag -Wl,-rpath,"@VEXEROOT/thirdparty/tcc/lib"\n') - count = content.count(old) - assert count == 1, f"expected exactly 1 occurrence of the selector block to patch, found {count}" - content = content.replace(old, new) - with open(path, "w", encoding="utf-8", newline="") as f: - f.write(content) - print("smoke-test-only selector patch applied in isolated workspace") - PYEOF - (cd /tmp/v-bootstrap-workspace && make -j4) - name: Prove a failing TCC cannot fall back to another compiler diff --git a/vlib/builtin/builtin_d_gcboehm.c.v b/vlib/builtin/builtin_d_gcboehm.c.v index 816fbe41f31b22..603da53965f44b 100644 --- a/vlib/builtin/builtin_d_gcboehm.c.v +++ b/vlib/builtin/builtin_d_gcboehm.c.v @@ -74,14 +74,15 @@ $if dynamic_boehm ? { $if !use_bundled_libgc ? { $if macos { $if tinyc { - $if arm64 { - // tcc on macOS arm64 can leave the bundled GC archive symbols unresolved. - #flag @VEXEROOT/thirdparty/tcc/lib/libgc.dylib - #flag -Wl,-rpath,"@VEXEROOT/thirdparty/tcc/lib" - } $else { - // macOS amd64 tccbin only ships libgc.a (no .dylib). - #flag @VEXEROOT/thirdparty/tcc/lib/libgc.a - } + // tcc cannot reliably link the bundled *static* GC archive on + // either macOS arch: its Mach-O archive reader leaves the GC + // symbols unresolved against an archive built by a modern + // toolchain, even though `nm -g` shows them defined. arm64 has + // always used the dynamic library for that reason; amd64 now + // does too, because tccbin ships a libgc.dylib rebuilt in + // lockstep with each tcc.exe for it as of vlang/v#27982. + #flag @VEXEROOT/thirdparty/tcc/lib/libgc.dylib + #flag -Wl,-rpath,"@VEXEROOT/thirdparty/tcc/lib" } $else { #flag -L@VEXEROOT/thirdparty/tcc/lib #flag -lgc diff --git a/vlib/v/builder/gc_flags_test.v b/vlib/v/builder/gc_flags_test.v index 51c5b654e2648e..81cca033115d45 100644 --- a/vlib/v/builder/gc_flags_test.v +++ b/vlib/v/builder/gc_flags_test.v @@ -29,9 +29,17 @@ fn test_macos_tcc_boehm_uses_bundled_libgc() { defer { os.rm(exe_path) or {} } - assert res.exit_code == 0 - // macOS amd64 tccbin only ships libgc.a (no .dylib). - assert res.output.contains('thirdparty/tcc/lib/libgc.a') + assert res.exit_code == 0, res.output + normalized := res.output.replace('\\', '/') + // tcc cannot reliably link the bundled static archive on macOS, so both + // arches link the paired libgc.dylib with an rpath instead. tccbin ships + // one for amd64 as of vlang/v#27982; arm64 already did. + assert normalized.contains('thirdparty/tcc/lib/libgc.dylib'), res.output + assert normalized.contains('-rpath'), res.output + // The static archive must be gone from the link line entirely - this is + // what actually proves the selector collapsed, rather than the dylib + // merely being present alongside it. + assert !normalized.contains('thirdparty/tcc/lib/libgc.a'), res.output assert !res.output.contains(' -lgc') }