Jonathan's Blog

Cross Compiling Rust for the Raspberry Pi

Published on 2024-11-01

To get this blog up and running I had to endure the horrors of cross-compiling Rust. I currently use a MacBook Air that I do most of my programming on. This blog is simply a Cargo project that I compile and rsync over to my Raspberry Pi to run. The issue of course is that compiling the Rust binary on my MacBook means cross compilation. Here’s a detailed outline of the steps I took to get this working to save future people pain.

Specs

Technology is always changing and both MacBooks and Raspberry Pis will both continue to update. Here are the exact tech specs I’m working with. If yours are different you may have to adapt these instructions.

I’m working on a 2020 M1 MacBook Air. The Raspberry Pi is a gen 4 Model B Rev 1.4.

Install musl-cross

This Homebrew formula contains a ton of cross-compilation tools for every architecture under the sun. I originally installed it to cross-compile Golang projects that relied on cgo for a x86_64 Linux server but it had the required tools to also compile Rust for a Raspberry Pi.

Install Rust std lib

Next you’ll need the Rust standard library for the Raspberry Pi. If you’re using Rust you should have rustup installed. Run rustup target add aarch64-unknown-linux-musl to add the std lib for the Raspberry Pi.

Side note here, from my limited understanding it seems like both arm and aarch64 can run on the RPi but arm is 32 bits while aarch64 is 64 bits as the name implies. Not completely sure about this though.

Add the linker for the target

While it doesn’t seem like you need to specify CC, you do need a linker. Create a file at .cargo/config.toml and put the following config options into it to specify the linker for the aarch64-unknown-linux-musl target we’ll be using.

[target.aarch64-unknown-linux-musl]
linker = "aarch64-linux-musl-ld"

This part tripped me up because I assumed that this must be an older way of configuring Cargo because everyone knows config options go in the Cargo.toml file right? Wrong. Apparently the Cargo.toml and .cargo/config.toml both serve different functions as shown by the docs here, and here, respectively.

Compiling

Now we can cross-compile our project with the command cargo build --release --target=aarch64-unknown-linux-musl. One weird bug I haven’t quite ironed out yet is that if I run that shell command directly on the command line it compiles correctly but if I run it from a Makefile then it throws a weird error while compiling a sqlx macro. I’ll update this blog if I figure out why that is.

Changes