You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(build): macOS test binaries link the toolchain's own libc++ (A1) + unpin llvm (#202)
* fix(build): macOS test binaries link the toolchain's own libc++ (A1 root fix)
TestBinary previously linked the SYSTEM -lc++ while compiling against the
toolchain's libc++ HEADERS — a header/dylib version split that detonated
when libc++ 22 moved string hashing out of line (__hash_memory undefined
against Apple's older dylib; every gtest link on macOS+llvm-22.1.8 failed).
Tests are host-only by definition, so an rpath into the toolchain registry
is acceptable for them in a way it isn't for distributables. ldStdlibTest
becomes: -nostdlib++ -L<llvm>/lib -lc++ -lc++abi -Wl,-rpath,<llvm>/lib
(when the toolchain ships a libc++ dylib; system -lc++ fallback otherwise).
Same-version headers and dylib by construction — future libc++
out-of-lining is self-consistent. Dynamic teardown also dissolves the
static-destruction SIGABRT that originally motivated the system-lib
exception. Distributables keep the static -load_hidden LLVM libc++.
ci-macos returns to latest-first llvm install (the 20.1.7 pin's exit
criterion): the job now PROVES each new llvm default self-consistent.
New e2e 94_macos_test_stdlib (requires: macos): unordered_map<string>
hashing under mcpp test + otool -L asserts no /usr/lib/libc++ reference.
Design: .agents/docs/2026-07-08-root-cause-remediation-design.md A1.
* fix(build): drop explicit -lc++abi from the test stdlib link
libc++.1.dylib reexports its abi; linking libc++abi.dylib explicitly
alongside the system abi (loaded transitively via macOS frameworks)
doubled the __cxa_* runtime state — every test binary aborted before
main (exit 6) on the first macOS CI round.
* fix(build): restore -lc++abi (this llvm's libc++ doesn't reexport abi); add macOS failure forensics
Round 2 proved the abi symbols are NOT reexported by this distribution's
libc++.dylib (undefined __cxa_*/operator new at link). Round 1's
runtime SIGABRT therefore has a different cause — the new forensics step
captures otool -L, LC_RPATHs and a direct binary run on failure so the
next round names it.
* ci(macos): sandbox uses LLVM_ROOT's exact version; forensics captures crash reports
The version-glob pick chose a stale cached 20.1.7 beside the freshly
installed 22.1.8 — rounds 1-3 never actually tested the new llvm. Also
capture the newest .ips crash report after a direct failing run (the
SIGABRT is silent on stderr).
* build(macos): toolchain pin llvm@20.1.7 -> 22.1.8; forensics extracts crash termination
Rounds 1-4 never tested llvm 22: mcpp.toml's macos pin kept resolving
20.1.7 (whose lib/ dylibs silently SIGABRT at load — they were never
exercised in the static-archive era). Pin the current llvm so mcpp's own
macOS build+tests run on it; forensics now parses the .ips crash report
(termination + triggered-thread frames) instead of dumping raw JSON.
* fix(build): link the toolchain libc++/abi dylibs by path (round-5 crash: dual libc++ states)
Crash report named it: exit-time locale::~locale freeing a pointer
malloc never allocated — two libc++ copies in one process, from -l
resolution mixing the sibling libc++.a into the link. By-path dylib
linking removes the ambiguity. Forensics now also counts statically
embedded libc++ text symbols (nm) to prove the binary is archive-free.
* fix(build): test binaries use the same static -load_hidden libc++ as distributables
Forensics rounds 5-6 closed the dynamic route: this llvm distribution's
libc++abi/libunwind dylibs upward-link /usr/lib/libc++, so the system
libc++ ALWAYS loads beside the toolchain's — gtest's static initializers
then construct a stringstream in one copy and destroy it in the other
(BUG_IN_CLIENT_OF_LIBMALLOC_POINTER_BEING_FREED in locale::~locale).
Static hidden archives keep exactly one libc++ inside the binary — the
shape mcpp's own shipped binaries have used green for months. If the
historical gtest exit-teardown SIGABRT resurfaces it will now be caught
by this same CI lane with forensics in place.
* docs(remediation): A1 addendum — forensics-driven revision + xim llvm dylib self-containment item
* test(e2e): 94 asserts 'N passed; 0 failed' — mcpp new's template adds test_smoke (2 passed)
0 commit comments