@platforms repo, for example:
- Dev: machine where the code is cloned
- Host: machine where Bazel is running
- Exec: machine where tools like compilers run
- Target: machine where the built program will run
Requirements of cross compilation
- Compiler toolchain that supports the particular combination of exec → target platform. eg llvm/clang.
- A sysroot that matches the target platform
Why cross-compile?
- You can compile code for any target platform regardless of where Bazel runs
- Fully reproducible and repeatable, eg: any update the developer machine does not break the build
- No glibc version skews that surface later during deployment
Sysroot
A sysroot contains all the linkable libraries and headers needed for compilation and linking. Typical contents include/usr/lib[64] and /usr/include .
Here is a list of sysroot generators we know of:
- https://github.com/scasagrande/toolchains_llvm_sysroot
- https://github.com/keith/bazel-cc-sysroot-generator
- https://github.com/malt3/sysroots
- https://github.com/f0rmiga/gcc-toolchain
- https://github.com/lukasoyen/bazel_linux_packages
Example: Targeting GNU/Linux arm64
For the following example, we will not build our own sysroot, instead we will use an existing sysroot for Linuxaarch64 CPU architecture. We’ll just use the first one in the list above, but don’t have a strong reason to prefer one over another.
We can run the llvm/clang compiler to compile a simple C binary for a target platform.
Add this to MODULE.bazel
BUILD file
bazel build :main --platforms=//tools/platforms:linux_aarch64
Now let’s put this binary into a Docker container with a newer glibc version than the sysroot, which ought to work since glibc releases are backwards-compatible.
Append to MODULE.bazel:
BUILD.bazel
bazel run :load_into_docker --platforms=//tools/platforms:linux_aarch64 which will build your binary and put it into a container and load onto the docker daemon running locally.
Once it loads, run docker run app:latest, you should see the following output.
Transitions
By default Bazel will compile your code for the platform that you are running on and in order to tell it to compile for a specific target platform, we have to use the--platforms flag.
However this doesn’t work for more than one platform simultaneously, even though the flag signifies plurality. In addition to this limitation, it’s not always easy to remember what flags you are supposed to pass. Instead, we can use transitions.
Transitions define configuration changes between rules.
For example, a request like “compile my dependency for a different CPU than its parent” is handled by a transition.
platform_transition_binary to transition our binary to be built for a specific platform.
bazel build :main_aarch64

