Cross-compilation

A single Docker image — the same one the Jenkins pipeline builds in (tools/build-env/Dockerfile_ubuntu_2404) — cross-compiles Delta for the main targets and is easy to extend. It carries musl cross toolchains that produce static, tiny binaries for every Linux arch in the matrix.

make cross                      # build image + cross-compile -> dist/
make build_min_static MUSL_TARGET=aarch64-linux-musl   # one target, no Docker

The image bundles cmake/ninja/git plus musl cross toolchains (from musl.cc, mirror overridable via --build-arg MUSL_MIRROR=). The matrix covers, by family:

  • x86 — x86_64;

  • ARM — aarch64 (arm64), armv7l (hard-float), arm hard-float and soft-float EABI;

  • RISC-V — riscv64 and riscv32;

  • MIPS — 32-bit o32 big-/little-endian in hard- and soft-float, and 64-bit big-/little-endian in n64 and n32 ABIs.

A toolchain missing from the mirror is skipped at image-build time (and its target then simply fails in the cross-build), so an unavailable triple — e.g. riscv32 on some mirrors — never breaks the whole image.

The target matrix

Targets are declarative — one line each in tools/targets.txt:

<name> | <cmake toolchain file> | <extra cmake flags>
linux-x86_64-musl     | toolchain/linux-musl.cmake | -DMUSL_TARGET=x86_64-linux-musl
linux-aarch64-musl    | toolchain/linux-musl.cmake | -DMUSL_TARGET=aarch64-linux-musl
linux-armv7-musl      | toolchain/linux-musl.cmake | -DMUSL_TARGET=armv7l-linux-musleabihf
linux-armhf-musl      | toolchain/linux-musl.cmake | -DMUSL_TARGET=arm-linux-musleabihf
linux-arm-musl        | toolchain/linux-musl.cmake | -DMUSL_TARGET=arm-linux-musleabi
linux-riscv64-musl    | toolchain/linux-musl.cmake | -DMUSL_TARGET=riscv64-linux-musl
linux-riscv32-musl    | toolchain/linux-musl.cmake | -DMUSL_TARGET=riscv32-linux-musl
linux-mips32-musl     | toolchain/linux-musl.cmake | -DMUSL_TARGET=mips-linux-musl
linux-mips32el-musl   | toolchain/linux-musl.cmake | -DMUSL_TARGET=mipsel-linux-musl
linux-mips32sf-musl   | toolchain/linux-musl.cmake | -DMUSL_TARGET=mips-linux-muslsf
linux-mips32elsf-musl | toolchain/linux-musl.cmake | -DMUSL_TARGET=mipsel-linux-muslsf
linux-mips64-musl     | toolchain/linux-musl.cmake | -DMUSL_TARGET=mips64-linux-musl
linux-mips64el-musl   | toolchain/linux-musl.cmake | -DMUSL_TARGET=mips64el-linux-musl
linux-mips64n32-musl  | toolchain/linux-musl.cmake | -DMUSL_TARGET=mips64-linux-musln32
linux-mips64eln32-musl| toolchain/linux-musl.cmake | -DMUSL_TARGET=mips64el-linux-musln32

tools/cross-build.sh reads the file, builds each target minimal-size into build-cross/<name>/ and copies the binary to dist/<name>/.

Adding a platform

  1. Make sure the target’s compiler is in the image — for another musl arch, add its triple to MUSL_TRIPLES in tools/build-env/Dockerfile_ubuntu_2404.

  2. If new CMake settings are needed, add a toolchain file under toolchain/ (the parametric linux-musl.cmake already covers any musl triple via -DMUSL_TARGET=).

  3. Add a line to tools/targets.txt.

No driver changes are needed; the toolchain/*.cmake convention is shared with the native build.

CI (Jenkins)

The matrix is wired into the Jenkinsfile: the build-env image installs the musl toolchains, a parallel stage runs tools/cross-build.sh, and a packaging stage emits delta-<branch>-<build>-linux-<arch>-musl.tar.xz whose names match the existing publish globs — so the FTP publishers and archiveArtifacts pick them up with no publisher changes. Adding an arch in tools/targets.txt is enough to ship it.

Notes

  • musl static binaries embed no libc — ideal for heterogeneous firmware fleets.

  • Big-endian (mips BE) is supported: Delta is endian-agnostic (it parses /proc text and hex strings, not raw structs).

  • For air-gapped builds, point MUSL_MIRROR / TOOLCHAIN_MIRROR at an internal mirror.