1
0
Fork 0
Proof of concept for nix cross compilation (with cross compiler and/or system emulation) and CI integration
Find a file
stefan aad3c40065
All checks were successful
/ Link Farm (push) Successful in 16s
/ Individual Build (cross aarch64-linux) (push) Successful in 13s
/ Individual Build (cross riscv64-linux) (push) Successful in 16s
/ Individual Build (cross x86_64-linux) (push) Successful in 15s
/ Individual Build (emulated aarch64-linux) (push) Successful in 14s
/ Individual Build (emulated x86_64-linux) (push) Successful in 14s
ci: Exclude emulate-riscv64 build
This build takes too long
2025-10-30 21:44:08 +01:00
.forgejo/workflows ci: Exclude emulate-riscv64 build 2025-10-30 21:44:08 +01:00
.gitignore Initial code import 2025-10-25 22:10:51 +02:00
ci.nix Initial code import 2025-10-25 22:10:51 +02:00
cross.nix Initial code import 2025-10-25 22:10:51 +02:00
emulated.nix ci: Exclude emulate-riscv64 build 2025-10-30 21:44:08 +01:00
main.cpp Initial code import 2025-10-25 22:10:51 +02:00
meson.build Initial code import 2025-10-25 22:10:51 +02:00
package.nix Initial code import 2025-10-25 22:10:51 +02:00
README.md Add README 2025-10-25 22:10:51 +02:00

Cross Compilation

In principle, there are two ways:

  1. Real cross compilation with a cross compiler (e.g. by using pkgsCross).
  2. Emulating user-space with qemu-user. Not technically cross compilation, but in the end a binary for a foreign architecture is output.

Basics

Cross Compilation

Getting a cross toolchain is as simple as import <nixpkgs> { crossSystem = "aarch64-linux" }.

Note that there is an older mechanism that uses pkgs.pkgsCross.aarch64-multiplatform. Internally it uses a internal function nixpkgsFun that allows to pass additional arguments to the current nixpkgs instance (it is in fact just passing crossSystem). The naming of the different platforms is a bit random, though. Also, it uses a the file <nixpkgs/lib/system/examples.nix> for predefined platforms. For more details about the “clean up” of the cross toolchain, see nixpkgs#34274.

The crossSystem argument originally specified a attrset which was quite complex. However, nowadays there is the elaborate function in between. This function takes a string (nix two tuple like aarch64-linux or a generic LLVM four tuple of the form <arch>-<os>-<vendor>-<abi>) and internally constructs the appropriate attrset.

Emulation

Instead of using a cross compiler, one can also emulate the compilation with qemu-user. This just runs the normal user space environment of the target system and emulates it.

This is as easy as using import <nixpkgs> { system = "aarch64-linux" }.

The advantage is that there are no cross-compilation specifics (e.g. bugs in the build scripts of the packages). The disadvantage is that it is quite slow.

To set up binfmt with qemu-user for the targets, add the following fragment to the NixOS configuration:

boot.binfmt.emulatedSystems = [ "aarch64-linux" "riscv64-linux" ];
boot.binfmt.preferStaticEmulators = true;