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.
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,
)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.0To 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.
target_arch names the architecture a toolchain produces code FOR. host_arch names the one its
binaries RUN on, and defaults to whatever architecture Bazel itself is running on, so building
natively on either x86_64 or aarch64 needs no configuration at all:
# On an x86_64 machine this is an x86_64-hosted cross toolchain; on an aarch64 machine it is a
# native one. Either way it targets aarch64.
gcc_toolchains.toolchain(
name = "gcc_toolchain_aarch64",
target_arch = "aarch64",
)It drives exec_compatible_with on the generated toolchain(), so toolchain resolution picks the
toolchain whose binaries the execution platform can actually run.
Set it explicitly only to fetch a toolchain for a host you are not on — for example to declare an aarch64-hosted toolchain from x86_64:
gcc_toolchains.toolchain(
name = "gcc_toolchain_aarch64_host",
host_arch = "aarch64",
target_arch = "aarch64",
)gcc-builds publishes aarch64-hosted archives from the 08072026 release on, which covers GCC
14.3.0 and newer. Asking for a version with no build for that host fails at fetch time, naming the
hosts it does have. armv7 is a target only.
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.
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.
)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"],
)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.
)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=remoteBy 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-lldThen build with:
bazel build --config lld //<your_binary>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.
Add the following to your .bazelrc:
build:asan --features asan
build:asan --strip never
build:asan --action_env ASAN_OPTIONS=detect_leaks=0:color=alwaysThen run:
bazel run --config asan //<your_binary>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=1Then run:
bazel run --config lsan //<your_binary>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=1Then run:
bazel run --config tsan //<your_binary>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=1Then run:
bazel run --config ubsan //<your_binary>