Cross-Compiling Chromium for ARM64 on x86_64 Linux Hosts
This article provides a quick overview of how the Chromium build system cross-compiles ARM64 binaries on an x86_64 Linux host machine. It covers how Chromium leverages a hermetic LLVM/Clang toolchain, isolated target sysroots, the GN meta-build system, and an integrated CPU simulator to compile complex target binaries while simultaneously building and running necessary host utilities.
1. The Hermetic Clang Toolchain
Chromium does not rely on the host system’s default compiler (such as
a locally installed GCC). Instead, during the initial source checkout,
Chromium's gclient tool downloads a pre-built, hermetic
version of the LLVM toolchain (Clang and the LLD linker) that runs
natively on x86_64.
Because Clang is inherently a cross-compiler by design, Chromium does
not need a separate toolchain binary to build for ARM64. The exact same
x86_64 Clang binary emits ARM64 machine code simply by receiving the
--target=aarch64-linux-gnu flag during the build
process.
2. Managing Target Dependencies with Sysroots
Compiling software for ARM64 requires ARM64-specific system headers
and shared libraries (such as glibc,
libstdc++, GTK, and X11). An
x86_64 host machine only possesses x86_64 versions of these files in its
/usr/include and /usr/lib directories.
Chromium solves this by using a sysroot—a directory containing a
minimal root filesystem of an ARM64 Linux distribution (typically
Debian). During the gclient runhooks step, Chromium
executes a script
(build/linux/sysroot_scripts/install-sysroot.py --arch=arm64)
that downloads a pre-packaged ARM64 sysroot archive from Google Cloud
Storage into the local source tree.
When compiling, the build system passes the
--sysroot=<path_to_arm64_sysroot> flag to Clang and
LLD. This forces the compiler and linker to ignore the x86_64 host
environment and strictly use the headers and libraries inside the ARM64
sysroot.
3. Configuring the Build with GN
Chromium uses GN (Generate Ninja) to generate its build files. To
initiate a cross-compile, the developer specifies the target
architecture in the args.gn configuration file located in
the output directory:
target_cpu = "arm64"When GN runs, it detects the host architecture automatically
(host_cpu = "x64") and reads the desired target
(target_cpu = "arm64"). GN then generates the
.ninja build manifests, setting up the correct compiler
flags, include paths, and sysroot directories for an ARM64 build.
4. Dual Toolchains: Host Tools vs. Target Binaries
The most complex part of cross-compiling Chromium is that the build process requires compiling helper executables and running them immediately to generate code for the rest of the build. Because an x86_64 Linux machine cannot natively execute ARM64 binaries (without QEMU setup), these helper tools must be compiled for x86_64, while the browser itself is compiled for ARM64.
GN handles this by maintaining two active toolchains in the same
build graph: the host toolchain
(//build/toolchain/linux:clang_x64) and the target
toolchain
(//build/toolchain/linux:clang_arm64).
- Code Generators: Tools like
protoc(the Protocol Buffers compiler) and Mojo interface generators are assigned to the host toolchain. Ninja compiles these tools into x86_64 binaries using the host's x86_64 sysroot. Ninja then runs these binaries on the host CPU to output C++ source and header files. Finally, those generated C++ files are compiled into ARM64 object files using the target toolchain. - The V8 Snapshot Generator: Chromium’s V8 JavaScript
engine uses a build-time tool called
mksnapshotto initialize the JavaScript heap and dump it into a binary snapshot file, which drastically reduces browser startup time. Because the memory layout of the snapshot is architecture-specific,mksnapshotmust generate an ARM64 memory layout. To do this on an x86_64 machine, GN compilesmksnapshotas an x86_64 binary, but configures V8 to use its built-in ARM64 simulator. When Ninja runsmksnapshoton the host, the x86_64 binary simulates an ARM64 CPU in software, executes the initialization code, and outputs a valid ARM64 binary snapshot to be linked into the final browser.
5. Linking with LLD
In the final phase of the build, the Ninja build system invokes the
LLVM linker (ld.lld). Like Clang, the x86_64 LLD binary is
natively capable of cross-linking. It takes the compiled ARM64 object
files (.o), links them against the ARM64 shared objects
(.so) located in the downloaded sysroot, embeds the ARM64
V8 snapshot, and outputs the final chrome executable as an
ELF 64-bit AArch64 binary.