A fully hermetic Clang/LLVM
toolchain for Bazel
that produces completely
self-contained, statically linked binaries with zero host system dependencies.
- hermetic: Produces statically linked binaries with no host dependencies
musl libc
:c/c++
standard libraries fetched from Alpine repolibstdc++ 14.2.0
: Alpine's C++ standard library built formusl
- statically linked: All binaries are statically linked (no dynamic dependencies)
- Compiling
- Uses
-nostdinc
and-nostdinc++
flags to prevent host header inclusion - All headers come from the toolchain's
sysroot
(musl
and Alpinelibstdc++
) - No host system headers are used during compilation
- Linking
- Uses
-nostdlib
flag to prevent host library linking - Uses
-static
flag to force static linking - All libraries (
musl libc
,libstdc++
,libunwind
) come from the toolchain'ssysroot
- Produces completely statically linked binaries with no dynamic dependencies
- Execution/Runtime
- The produced binaries are statically linked
- No dynamic loader or shared library dependencies
- Binaries can run on any Linux
x86-64
system without requiring any host libraries
Supported versions with prebuilt binaries:
- 21.1.0 (default - latest)
- 20.1.8
- 19.1.7
- 18.1.8
- 17.0.6
The clang compiler binary does require host libraries to run, but this only
affects the build environment, not the produced binaries. The toolchain
provides libtinfo5
to minimize host dependencies for the compiler.
The toolchain achieves hermeticity through several mechanisms:
- Separate Library Paths:
lib/
: Contains libraries needed by Clang itself to run (Ubuntu
/LLVM
libraries)sysroot/
: Containsmusl
,libstdc++
libraries used for compiling
- Compiler Flags:
-nostdinc
and-nostdinc++
: Prevents using host system headers-nostdlib
: Prevents linking against host system libraries-static
: Forces static linking of all dependencies
- Library Stack:
- C Library:
musl
from Alpine Linux (for static linking) - C++ Library:
libstdc++
from Alpine Linux (built againstmusl
) - Unwinding:
libunwind
fromLLVM
(for exception handling) - Linker:
LLD
fromLLVM
- C Library:
Add this to your MODULE.bazel
:
bazel_dep(name = "hermetic_clang_toolchain", version = "1.0.0")
hermetic_clang = use_extension("@hermetic_clang_toolchain//clang_toolchain:hermetic_clang.bzl", "hermetic_clang_extension")
hermetic_clang.use(version = "21.1.0")
use_repo(hermetic_clang, "hermetic_clang")
register_toolchains("@hermetic_clang_toolchain//clang_toolchain:hermetic_clang_toolchain")
Add this to your .bazelrc
:
# Disable default C++ toolchain detection
build --incompatible_enable_cc_toolchain_resolution
build --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1
# Use hermetic clang toolchain
build --extra_toolchains=@hermetic_clang//:toolchain
See the example/
directory for a working example:
bazel build //example:simple_test
# Run the test
./bazel-bin/example/simple_test
# Verify it's hermetic (should show "not a dynamic executable")
ldd bazel-bin/example/simple_test
# Check the binary info
file bazel-bin/example/simple_test
# Output: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked
readelf -p .comment bazel-bin/example/simple_test
# String dump of section '.comment':
# [ 0] clang version 18.1.8
# [ 16] Linker: LLD 18.1.8
# [ 29] GCC: (Alpine 14.2.0) 14.2.0
LLVM/Clang 18.1.8
: Pre-built compiler toolchain fromLLVM
project- Provides:
clang
,clang++
,lld
,llvm-ar
, and otherLLVM
tools - Source: GitHub releases
- Provides:
- Alpine Packages:
musl-dev
: C standard librarylibstdc++
: C++ standard librarylibstdc++-dev
: C++ headers- Source: Alpine Linux v3.22 repository
- Ubuntu Packages (for
Clang
runtime only):libtinfo5
: Terminal info library needed byClang
- Compilation: Uses
Clang
with hermetic headers fromsysroot
- Linking: Statically links all libraries (
musl
,libstdc++
,libunwind
) - Result: Self-contained binary with no external dependencies