Cross compiling zen-internals with Zig and Rust for older glibc versions on GitHub actions
November 10, 2024
At Aikido, we needed zen-internals
to work on Linux systems with older glibc versions, such as Amazon Linux. By default, Rust links against the glibc installed on the OS it builds on. In GitHub Actions, this means using the version provided by ubuntu-latest
, which is currently Ubuntu 22.04. We tried using an older build environment with Ubuntu 20.04, but even those glibc versions were too new for our target systems.
Why we use Zig
Zig lets us link with an older glibc version without needing it installed on the build machine. Zig provides its own headers and link libraries, allowing us to specify the version we need, ensuring compatibility across different systems.
In this setup, Zig is used solely as a linker for Rust, not for compiling the Rust code itself. Rust handles the code compilation, but by using Zig as the linker, we gain Zig’s advanced cross-compilation capabilities, which simplify linking with specific glibc versions. This is especially useful when targeting environments with varying glibc versions.
If we were building a standalone binary, we could use Rust’s musl target to avoid dependencies on glibc entirely. However, zen-internals is a library that Zen calls through FFI, so using musl isn’t suitable here.
We first tried Cross for cross-compilation, which runs builds inside a container. However, the required glibc version was still to high for some reason. cargo-zigbuild did the trick for us.
GitHub Actions Setup
Here’s our GitHub Actions setup to cross-compile zen-internals
as a dynamic library. This configuration uses cargo-zigbuild
to link against an older glibc (e.g. 2.17) and compiles for both x86_64 and ARM64 architectures.
jobs:
build-linux:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Zig
uses: mlugg/setup-zig@v1
- name: Install Rust and cargo-zigbuild
run: |
rustup update --no-self-update stable
rustup default stable
cargo install --locked cargo-zigbuild
- name: Build for Linux
run: |
cargo zigbuild --target x86_64-unknown-linux-gnu.2.17 --release
build-linux-arm64:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Zig
uses: mlugg/setup-zig@v1
- name: Install Rust and cargo-zigbuild
run: |
rustup update --no-self-update stable
rustup default stable
rustup target add aarch64-unknown-linux-gnu
cargo install --locked cargo-zigbuild
- name: Build for Linux ARM64
run: |
cargo zigbuild --target aarch64-unknown-linux-gnu.2.17 --release
Using cargo-zigbuild with Zig provides a simple way to cross-compile Rust code. This approach lets us control glibc compatibility and ensures our binaries run on both new and old Linux systems.