Cross-compiling Rust programs for a Raspberry Pi from macOS

28-4-2020

This took me a while to figure out, so I’m putting this here to save someone some time! I wanted to cross-compile Rust programs on my Mac to run on a Raspberry Pi (Zero in this case, but that shouldn’t matter much).

The easiest way to do this is as follows:

  1. Install tools to generate binaries: brew install arm-linux-gnueabihf-binutils (note, you do not actually need this if you follow the alternative route described below!)
  2. Install an ARM Rust toolchain: rustup target add arm-unknown-linux-musleabi
  3. Configure Cargo to support ARM als a build target by creating a file .cargo/config:
[target.arm-unknown-linux-musleabi]
 linker = "arm-linux-gnueabihf-ld"
 [target.x86_64-linux-musleabi]
 linker = "x86_64-linux-gnueabihf-ld"

4. Build by calling cargo build --target=arm-unknown-linux-musleabi

The above configures Rust to generate armv6 binaries for Linux that are fully statically linked, making use of the musl standard library (which is a smaller and statically linked replacement of the GNU C/C++ standard library).

The above works fine for programs that are pure Rust. However many crates depend on C/C++ parts that are built during the build process. This fails on macOS, as there is no C compiler that compiles to ARM code on Linux. A typical error is Internal error occurred: Failed to find tool. Is `arm-linux-musleabi-gcc` installed?

To fix, simply download an appropriate prebuilt musl cross-compilation toolchain from lisa.musl.cc. I used this one. Unpack it in (for example) ~/musl. Then, call cargo build with the musl binaries in the path: PATH=$PATH:/Users/yourname/musl/arm-linux-musleabi-cross/bin cargo build --target=arm-unknown-linux-musleabi.

Note that you could theoretically replace ‘arm’ with ‘armhf’, ‘armel’, ‘armv7’, ‘aarch64’ to build code that is faster on newer Pi models. As far as I know however the standard ‘arm’ code runs fine on all Pi’s (except perhaps the Pi 4 which is 64 bit ARM or AArch64).