Back to list

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.