Was cross-compiling and cross-running tests always this simple?

66 points FormalFerret

I just discovered that on amd64 Debian, all you need to do is:

Install some packages:

for a in arm64 armel armhf i386 ppc64el s390x; do dpkg --add-architecture $a; done
apt update
apt install rust-all libstd-rust-dev:{arm64,armel,armhf,i386,ppc64el,s390x} gcc-{aarch64,i686,powerpc64le,s390x}-linux-gnu gcc-arm-linux-gnueabi{,hf} qemu-user

Add to ~/.cargo/config.toml:

[target.aarch64-unknown-linux-gnu]
linker = "/usr/bin/aarch64-linux-gnu-gcc"
runner = "/usr/bin/qemu-aarch64"
[target.armv7-unknown-linux-gnueabihf]
linker = "/usr/bin/arm-linux-gnueabihf-gcc"
runner = "/usr/bin/qemu-arm"
[target.armv5te-unknown-linux-gnueabi]
linker = "/usr/bin/arm-linux-gnueabi-gcc"
runner = "/usr/bin/qemu-arm"
[target.i686-unknown-linux-gnu]
linker = "/usr/bin/i686-linux-gnu-gcc"
#runner = Heh. Multiarch.
[target.powerpc64le-unknown-linux-gnu]
linker = "/usr/bin/powerpc64le-linux-gnu-gcc"
runner = "/usr/bin/qemu-ppc64le"
[target.s390x-unknown-linux-gnu]
linker = "/usr/bin/s390x-linux-gnu-gcc"
runner = "/usr/bin/qemu-s390x"

And that's it. You can do cargo test --target aarch64-unknown-linux-gnu (Barring dependencies with complex C/C++ builds).

It might seem a bit much because I'm setting up all the possible targets. If you just want one, it's only three lines of config. I'm calling this simple because it doesn't require anything fancy like

  • VMs
  • docker or let alone buildkit
  • cross
  • Setting up binfmt\_misc
  • A statically linked build of qemu-user (Which you'll need if you want to use binfmt\_misc through docker.)

It doesn't even require a "true multiarch" distro like Debian. The reason I noticed this is because I tried on Arch Linux first, and then wanted to post it here without being too distro-specific. On Arch, it's also possible, but quite a bit trickier:

pacman -Sy --needed rustup base-devel riscv64-linux-gnu-gcc aarch64-linux-gnu-gcc qemu-user
rustup default stable
rustup target add aarch64-unknown-linux-gnu
# You can also go via pacman -S rust rust-src, but then you need -Zbuild-std. I'll stop here before the Rust police arrests me.

And the ~/.cargo/config.toml

[target.aarch64-unknown-linux-gnu]
linker = "/usr/bin/aarch64-linux-gnu-gcc"
runner = "/usr/bin/env QEMU_LD_PREFIX=/usr/aarch64-linux-gnu LD_LIBRARY_PATH=/usr/aarch64-linux-gnu/lib64:/usr/aarch64-linux-gnu/lib qemu-aarch64"
# You can also bake the library search path into the executable
#rustflags = ["-C", "link-arg=-Wl,-rpath=/usr/aarch64-linux-gnu/lib64:/usr/aarch64-linux-gnu/lib"]
# But I don't think there is a way to do that for the path of the library loader itself.

[target.riscv64gc-unknown-linux-gnu]
linker = "/usr/bin/riscv64-linux-gnu-gcc"
runner = "/usr/bin/env QEMU_LD_PREFIX=/usr/riscv64-linux-gnu LD_LIBRARY_PATH=/usr/riscv64-linux-gnu/lib qemu-riscv64"

And even for that I was already surprised that it worked.

So yeah, was it always this easy, just install a few things from the package manager, add a few lines to config, that's it?