LLM-generated hermetic llvm#3045
Open
AlexanderViand wants to merge 16 commits into
Open
Conversation
The llvm 0.7.8 module defines its cc_toolchain/toolchain() rules under
@llvm//toolchain, not the root package. register_toolchains("@llvm//:all")
therefore matched zero toolchains, so builds silently fell back to the
autodetected host clang. Point the registration at @llvm//toolchain:all.
LLVM's llvm:Support pulls zlib/zstd headers via @llvm-project//third-party cc_library_wrapper targets that propagate the includes field (-I) but not system_includes (-isystem). zstd uses strip_include_prefix='lib' (propagating -I); zlib-ng uses strip_include_prefix='.' (a no-op), so zlib.h only reached the -iquote path. On a normal host '#include <zlib.h>' resolved via /usr/include; under the hermetic clang toolchain (no system include dirs) it failed with: 'zlib.h' file not found with <angled> include. Add a HEIR-local zlib-ng.BUILD that relocates zlib.h/zconf.h into include/ with strip_include_prefix='include' (mirroring zstd) and point @llvm_zlib at it so a propagating -I reaches llvm:Support.
fmt 11.1.3's include/fmt/format.h uses the unqualified C functions malloc/free in detail::allocator but only includes C++ headers. The file defines _LIBCPP_REMOVE_TRANSITIVE_INCLUDES, so libc++ strips the transitive includes that would otherwise declare malloc/free. Under HEIR's hermetic clang+libc++ toolchain this leaves them undeclared and breaks the build of fmt (pulled in transitively via SCIP/SoPlex). Pin fmt as a direct bazel_dep and apply a single_version_override patch that backports the upstream fix (explicit #include <stdlib.h>). Drop the override once HEIR moves to an fmt release containing the fix.
bison vendors gnulib, whose generated replacement headers (lib/stdio.h / lib/stdio-safer.h) leave fopen_safer & friends undeclared under HEIR's hermetic clang+libc++ toolchain (explicit -isystem search), failing with 'expected function body after function declarator'. Pin bison via single_version_override and apply patches/bison.patch so it builds.
rustc's default link args for x86_64-unknown-linux-gnu unconditionally inject -lgcc_s for unwinding, but the bootstrapped LLVM toolchain ships compiler-rt + libunwind and has no libgcc_s, so every Rust link (starting with rules_rust's process_wrapper) fails with 'unable to find library -lgcc_s'. Enable the toolchain's documented escape hatch --@llvm//config:experimental_stub_libgcc_s=True (Linux only) which provides a stub libgcc_s to satisfy the flag while still linking libunwind statically.
…hain The bootstrapped clang distribution ships no OpenMP runtime / omp.h, so OpenFHE's '#include <omp.h>' + -fopenmp -lomp (enabled by @openfhe//:enable_openmp, default True) could not be satisfied. Build libomp from the pinned LLVM openmp sources (@openmp//:libomp), expose its omp.h, and patch OpenFHE to link it instead of a nonexistent system libomp -- so the hermetic build keeps OpenMP enabled.
The Python frontend's OpenFHE backend JIT-compiles the emitted C++ into a .so at runtime. Under the hermetic LLVM toolchain, @openfhe//:libopenfhe is built against libc++, so its exported symbols use libc++'s std::__1::... mangling and the library statically embeds (and weakly re-exports) libc++. The JIT previously used the host compiler with no -stdlib pin, which on Linux defaults to libstdc++ (std::...). The mismatched mangling left the OpenFHE symbols unresolved -> "undefined symbol" ImportError at module load. Thread a stdlib-matching option through the JIT path: - config.py (OpenFHEConfig): new optional cxx_compiler / extra_compiler_flags / extra_linker_search_paths / extra_link_libs fields, populated from new OPENFHE_CXX_* env vars (runfiles-resolved like the existing OPENFHE_* vars). Add _discover_hermetic_toolchain_clang(): when handed hermetic libc++ headers but no explicit compiler, locate the toolchain's clang next to them (the host clang/g++ is too old to parse the toolchain's libc++ headers -- "libc++ only supports Clang 20 and later"). - backend.py: use OpenFHEConfig.cxx_compiler for the JIT compiler and append the extra flags / search paths / libs to both compile invocations. - testing.bzl: depend on the toolchain's libc++ / libc++abi -isystem header dirs and pass them plus -stdlib=libc++ -nostdinc++ to the JIT. - MODULE.bazel: use_repo the llvm_source libcxx / libcxxabi repos so the frontend tests can reference their header search dirs.
The libc++/libc++abi -isystem dirs were passed via $(rootpath ...), which for a cross-repo target yields a ../<repo>/... path; joined onto RUNFILES_DIR in config.py it escaped the runfiles tree, so clang found no libc++ headers (manifesting as '<initializer_list> file not found'). Use $(rlocationpath ...) so it resolves to runfiles/<repo>/... NOTE: the raw-clang JIT still needs the rest of the toolchain hermetic include set (clang builtins, glibc, kernel, compiler-rt).
The prebuilt @openfhe//:libopenfhe is built by the hermetic LLVM toolchain against libc++, so the runtime JIT step must compile the emitted OpenFHE C++ against the same libc++ to match its std::__1 symbol mangling. Hand the JIT the toolchain's libc++/libc++abi/glibc/kernel/builtin include set plus -stdlib=libc++ -nostdinc++ --sysroot=/dev/null -nostdlibinc so the libc++ headers parse with no host include leakage. Those flags are compile-only: the link must use the host C runtime (crt*.o, libc, libm, libgcc_s) and let libopenfhe.so supply the libc++ symbols at load, so --sysroot=/dev/null/-stdlib=libc++/-lc++ must not reach the linker. Split compile_to_shared_object into a -c compile (with the libc++ compile-only flags) and a separate -shared link (without them) whenever compile_only_flags are supplied.
…rule, re-enable sandboxing, and gate hermetic config to linux
This was referenced Jun 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.