Cross-Compilation of Packages

Updated

October 30, 2026

Cross-Compilation of Packages

When building an entire distribution from scratch, you have two choices: 1. Native Chroot Compilation: Compile software inside an emulated or native container using the target CPU architecture. (Slow if building ARM64 on x86 via QEMU user emulation). 2. True Cross-Compilation: Run cross-compilers (aarch64-linux-gnu-gcc) natively on high-powered x86_64 host hardware to emit target machine code directly.

+-------------------------------------------------------------+
|              Cross-Compilation Package Setup                |
|                                                             |
|  Host System (x86_64):                                      |
|  - Cross Compiler: aarch64-linux-gnu-gcc                    |
|  - Target Sysroot: /opt/sysroots/aarch64                    |
|       ├── usr/include (target C headers)                    |
|       └── usr/lib     (target shared libraries)             |
|                                                             |
|  pkg-config Configuration:                                  |
|  - PKG_CONFIG_SYSROOT_DIR=/opt/sysroots/aarch64             |
|  - PKG_CONFIG_LIBDIR=/opt/sysroots/aarch64/usr/lib/pkgconfig|
+-------------------------------------------------------------+

The Pitfall: pkg-config Poisoning

When building packages that depend on external libraries (e.g., compiling curl which depends on openssl), the build system invokes pkg-config to discover library paths and CFLAGS:

$ pkg-config --cflags --libs openssl
-I/usr/include -L/usr/lib -lssl -lcrypto # DANGER: Points to host libraries!

If your build system uses the host’s /usr/bin/pkg-config, it will return the host machine’s library paths! The linker will link against host x86_64 binaries, causing immediate cross-compilation linker errors.

The Solution: Cross-pkg-config Wrappers

Create an architecture-specific wrapper script at $TOOLS/bin/aarch64-linux-gnu-pkg-config:

#!/bin/sh
# aarch64-linux-gnu-pkg-config
export PKG_CONFIG_SYSROOT_DIR="/opt/sysroots/aarch64"
export PKG_CONFIG_LIBDIR="/opt/sysroots/aarch64/usr/lib/pkgconfig:/opt/sysroots/aarch64/usr/share/pkgconfig"
export PKG_CONFIG_SYSTEM_INCLUDE_PATH="/opt/sysroots/aarch64/usr/include"
export PKG_CONFIG_SYSTEM_LIBRARY_PATH="/opt/sysroots/aarch64/usr/lib"

exec /usr/bin/pkg-config "$@"

Cross-Compiling with Meson Cross-Files

Meson provides first-class support for cross-compilation via declarative INI files:

# /opt/cross/aarch64-linux.ini
[binaries]
c = 'aarch64-linux-gnu-gcc'
cpp = 'aarch64-linux-gnu-g++'
ar = 'aarch64-linux-gnu-ar'
strip = 'aarch64-linux-gnu-strip'
pkg-config = 'aarch64-linux-gnu-pkg-config'

[host_machine]
system = 'linux'
cpu_family = 'aarch64'
cpu = 'cortex-a72'
endian = 'little'

[properties]
sys_root = '/opt/sysroots/aarch64'

Invoking the build requires a single flag:

$ meson setup build --cross-file /opt/cross/aarch64-linux.ini
$ ninja -C build

The resulting binaries are guaranteed to run natively on the target architecture without host pollution.