From 6d9a197588ef725da1e4a37dc2277e03e3e1cd65 Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Wed, 10 Jun 2026 11:21:37 +0000 Subject: [PATCH] [recipes] Ship libLLVM and libclang-cpp dylibs alongside the static libs. The recipes link clang as a fully-static binary, so the linker drops any TU that no in-tree caller references. clang::TypeName functions (QualTypeNames.o) are the canonical victim: nothing inside clang itself calls them, but plugins (clad, CppInterOp, ...) do, and the plugin's symbol lookup then fails at load time. apt's distribution clang doesn't have the problem because it ships the umbrella dylib. Add a small llvm_build.dylib_flags() helper that returns LLVM_BUILD_LLVM_DYLIB / LLVM_LINK_LLVM_DYLIB / CLANG_LINK_CLANG_DYLIB on Linux and macOS, and an empty list on Windows -- where LLVM_LINK_LLVM_DYLIB is force-OFF and setting CLANG_LINK_CLANG_DYLIB=ON then trips clang's consistency check. Call it from llvm-release, llvm-asan, and llvm-msan. Static archives stay in install/lib; the dylibs are shipped beside them, and clang is linked against the dylib so its full symbol surface is loaded at startup. This is the layout Debian and Fedora use. llvm-root and llvm-wasm intentionally untouched: cling expects to link statically against LLVM/Clang, and the wasm path is its own emscripten-driven shape -- both can opt in separately if needed. --- actions/lib/llvm_build.py | 28 ++++++++++++++++++++++++++++ recipes/llvm-asan/build.py | 1 + recipes/llvm-msan/build.py | 1 + recipes/llvm-release/build.py | 1 + 4 files changed, 31 insertions(+) diff --git a/actions/lib/llvm_build.py b/actions/lib/llvm_build.py index e04cbfe..23377fa 100644 --- a/actions/lib/llvm_build.py +++ b/actions/lib/llvm_build.py @@ -104,6 +104,20 @@ def record_src_commit(repo_path: Path) -> str: return sha +def dylib_flags() -> List[str]: + """Ship libLLVM-N + libclang-cpp-N alongside the static archives so + plugins resolve the full symbol surface at load time. Returns [] on + Windows -- LLVM_LINK_LLVM_DYLIB is force-OFF there and setting + CLANG_LINK_CLANG_DYLIB=ON then trips clang's consistency check.""" + if sys.platform == "win32": + return [] + return [ + "-DLLVM_BUILD_LLVM_DYLIB=ON", + "-DLLVM_LINK_LLVM_DYLIB=ON", + "-DCLANG_LINK_CLANG_DYLIB=ON", + ] + + def cmake_extra() -> List[str]: """Return cmake -D flags derived from CC/CXX/launcher env vars.""" flags: List[str] = [] @@ -197,6 +211,20 @@ def install_distribution(extras: Optional[Sequence[str]] = None) -> None: base = base[:-2] if base.endswith(".a") else base[:-4] if base.startswith("clang") or base.startswith("LLVM"): dist.append(base) + # Pick up umbrella dylibs when the recipe set LLVM_BUILD_LLVM_DYLIB / + # CLANG_LINK_CLANG_DYLIB. Their install components are the bare + # names 'LLVM' / 'clang-cpp'. Without them, every clangX/LLVMX export + # rule above references the aggregate target and cmake errors with + # "target LLVM is not in any export set". Read the cache rather than + # globbing lib/ -- dylib filenames vary across LLVM majors and + # platforms; the cmake variable is the source of truth. + cache = Path("CMakeCache.txt") + if cache.is_file(): + text = cache.read_text() + if "LLVM_BUILD_LLVM_DYLIB:BOOL=ON" in text: + dist.append("LLVM") + if "CLANG_LINK_CLANG_DYLIB:BOOL=ON" in text: + dist.append("clang-cpp") if extras: dist.extend(extras) run_install_distribution(";".join(dist)) diff --git a/recipes/llvm-asan/build.py b/recipes/llvm-asan/build.py index 90c37fa..42d05a6 100644 --- a/recipes/llvm-asan/build.py +++ b/recipes/llvm-asan/build.py @@ -140,6 +140,7 @@ def main() -> int: '-DCOMPILER_RT_BUILD_GWP_ASAN=OFF', '-DCOMPILER_RT_BUILD_CTX_PROFILE=OFF', ] + + llvm_build.dylib_flags() + llvm_build.cmake_extra() + ["../llvm"] ) diff --git a/recipes/llvm-msan/build.py b/recipes/llvm-msan/build.py index a218077..2a9eb5e 100755 --- a/recipes/llvm-msan/build.py +++ b/recipes/llvm-msan/build.py @@ -382,6 +382,7 @@ def main() -> int: "-DCOMPILER_RT_BUILD_GWP_ASAN=OFF", "-DCOMPILER_RT_BUILD_CTX_PROFILE=OFF", ] + + llvm_build.dylib_flags() + llvm_build.cmake_extra() + ["../llvm"] ) diff --git a/recipes/llvm-release/build.py b/recipes/llvm-release/build.py index 65028b4..230d02e 100755 --- a/recipes/llvm-release/build.py +++ b/recipes/llvm-release/build.py @@ -129,6 +129,7 @@ def main() -> int: cmake_args = ( llvm_build.base_cmake_args(str(out_dir / "install")) + [f"-DLLVM_ENABLE_PROJECTS={projects}"] + + llvm_build.dylib_flags() + compiler_rt_flags + llvm_build.cmake_extra() + ["../llvm"]