Documentation
August 10, 2026 ยท View on GitHub
For the rules definitions, see defs.md.
For examples on how to use this repository, see the examples.
For how to bump the pinned toolchain tarballs, see updating-gcc-builds.md.
Getting Started
Basic Setup
Add the following to your WORKSPACE file:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "gcc_toolchain",
# Add appropriate URL and SHA for your desired version
)
load("@gcc_toolchain//toolchain:repositories.bzl", "gcc_toolchain_dependencies")
gcc_toolchain_dependencies()
load("@gcc_toolchain//toolchain:defs.bzl", "gcc_register_toolchain", "ARCHS")
# Register toolchains for desired architectures
gcc_register_toolchain(
name = "gcc_toolchain_x86_64",
target_arch = ARCHS.x86_64,
)
gcc_register_toolchain(
name = "gcc_toolchain_aarch64",
target_arch = ARCHS.aarch64,
)
gcc_register_toolchain(
name = "gcc_toolchain_armv7",
target_arch = ARCHS.armv7,
)
Selecting the GCC version
Every GCC version listed in AVAILABLE_GCC_VERSIONS is registered as a toolchain, and the
@gcc_toolchain//toolchain:gcc_version flag picks which one resolves:
bazel build --@gcc_toolchain//toolchain:gcc_version=15.2.0 //...
Leaving the flag unset uses the gcc_version the toolchain was declared with, which defaults to
the newest available version. Only the selected version is downloaded โ the others are declared but
never fetched.
Because it is an ordinary build flag, it can be bound to a .bazelrc config:
build:gcc15 --@gcc_toolchain//toolchain:gcc_version=15.2.0
To change which version is used while the flag is unset, set it when declaring the toolchain. An
explicit --@gcc_toolchain//toolchain:gcc_version still overrides it:
gcc_toolchains.toolchain(
name = "gcc_toolchain_x86_64",
gcc_version = "15.2.0",
target_arch = "x86_64",
)
Each version also gets a config_setting, so build rules can branch on the selected compiler:
copts = select({
"@gcc_toolchain//toolchain:gcc_version_12_5_0": ["-Wno-maybe-uninitialized"],
"//conditions:default": [],
})
Note that these settings only match when the flag is set explicitly, so a select() over them
needs a //conditions:default branch to cover the unset case.
Language Support
Pure C
For C-only code, no additional configuration is needed. The toolchain does not automatically link
libstdc++, allowing for clean C compilation without C++ standard library dependencies.
C++
Full C++ support with modern standards (C++17 by default). The toolchain includes optimized include paths and flags for improved compilation performance. C++ programs that need the standard library should explicitly link it:
cc_binary(
name = "my_cpp_program",
srcs = ["main.cpp"],
linkopts = ["-lstdc++"], # Add when using C++ standard library.
)
Fortran
Complete Fortran support including:
- Modern Fortran standards.
- OpenMP support for parallel computing.
- Integration with C/C++ code.
Example Fortran target with OpenMP:
fortran_library(
name = "my_fortran_lib",
srcs = ["source.f90"],
copts = ["-fopenmp"],
linkopts = ["-fopenmp"],
)
Advanced Configuration
Linking C++ Standard Library
The toolchain does not automatically link the C++ standard library, giving you full control over the linking behavior:
Dynamic linking (default for C++):
cc_binary(
name = "my_program",
srcs = ["main.cpp"],
linkopts = ["-lstdc++"],
)
Static linking:
cc_binary(
name = "my_program",
srcs = ["main.cpp"],
linkopts = ["-l:libstdc++.a"],
)
No C++ standard library (for C code or custom implementations):
cc_binary(
name = "my_c_program",
srcs = ["main.c"],
# No additional linkopts needed.
)
Remote Build Execution (RBE)
The toolchain has been optimized for remote execution with improved performance and macOS host
compatibility. Add the following to your .bazelrc, replacing @<gcc_toolchain_workspace> with the
name given to the http_archive when importing this repository:
build --host_platform=@<gcc_toolchain_workspace>//platforms:x86_64_linux_remote
build --extra_execution_platforms=@<gcc_toolchain_workspace>//platforms:x86_64_linux_remote
build --cpu k8 # Force host platforms other than Linux to use this configuration.
build --crosstool_top=@gcc_toolchain_x86_64//:_cc_toolchain # Allows the toolchain resolution for --cpu k8.
build --strategy=remote
build --genrule_strategy=remote
build --spawn_strategy=remote
Linking with lld
By default the toolchain links with the GNU BFD linker (ld). The toolchain also ships LLVM's
lld, which you can opt into through the linker-lld feature. lld is generally faster than BFD
and is a drop-in replacement for most use cases.
Enable it for an individual target with the features attribute:
cc_binary(
name = "my_program",
srcs = ["main.c"],
features = ["linker-lld"],
)
Or enable it for an entire build. Add the following to your .bazelrc:
build:lld --features linker-lld
Then build with:
bazel build --config lld //<your_binary>
Running sanitizers
If you want to run automated tests with the sanitizers enabled, see how we do testing under
//tests/sanitizers, and how we call them from CI.
For running the binaries with the sanitizers enabled, check the following topics.
Address Sanitizer (asan)
Add the following to your .bazelrc:
build:asan --features asan
build:asan --strip never
build:asan --action_env ASAN_OPTIONS=detect_leaks=0:color=always
Then run:
bazel run --config asan //<your_binary>
Leak Sanitizer (lsan)
Add the following to your .bazelrc:
build:lsan --features lsan
build:lsan --strip never
build:lsan --action_env LSAN_OPTIONS=verbosity=1:log_threads=1:report_objects=1
Then run:
bazel run --config lsan //<your_binary>
Thread Sanitizer (tsan)
Add the following to your .bazelrc:
build:tsan --features tsan
build:tsan --strip never
build:tsan --action_env TSAN_OPTIONS=halt_on_error=1:second_deadlock_stack=1
Then run:
bazel run --config tsan //<your_binary>
Undefined Behaviour Sanitizer (ubsan)
Add the following to your .bazelrc:
build:ubsan --features ubsan
build:ubsan --strip never
build:ubsan --action_env UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1
Then run:
bazel run --config ubsan //<your_binary>