Rust - X86 to ARM builds for Raspberry Pi 4

January 19, 2020   

Rust x86 to ARM for Raspberry Pi 4

Recently the Raspberry Pi 4 was released and I purchased several of them to replace my previous Raspberry Pi 3’s and RockPro64’s which had made up my previous home cluster (but are now re-purposed for other tasks).

My initial deployment of six Pi4’s was all on Manjaro Linux’s Arm Edition which was functional for the purposes of deploying a K3s kubernetes cluster, but I soon decided that I wanted to run an operating system with more of a security focus.

Since then I’ve redeployed all machines with CentOS 7’s ARMHFP Release for stability and out-of-the-box SELinux functionality as these machines are intended to manage some sensitive data and applications.

I’m using this cluster to work on a couple of different projects of mine in Rust, but had to overcome a couple of small hurdles to get to the point where I could build from my local Manjaro Linux workstation and cross-compile for ARM.

In this small post I’ll walk through quickly cross-compiling your programs to Raspberry Pi4 from an x86 host given the environment described above.

Project Template

To start, let’s create a new project with Cargo which we’ll use for this demo:

cargo new testpi --bin
cd testpi/

A “hello world” example is templated by default, which you can test:

$ cargo run
   Compiling testpi v0.1.0 (/home/shane/Code/testpi)
    Finished dev [unoptimized + debuginfo] target(s) in 0.52s
     Running `target/debug/testpi`
Hello, world!

Now we’re compiling for the local x86 system and it’s time to setup our build toolchain for cross-compiling to ARM.

Cross-Compile Build Toolchain

We need to install a toolchain capable of building for ARM, for many operating systems this is the arm-linux-gnueabihf-gcc package available via your package manager.

For instance if you’re on Arch Linux or Manjaro Linux and you have pamac available on your system you can install the toolchain from the AUR with the following line:

pamac build arm-linux-gnueabihf-gcc

This will install the AUR arm-linux-gnueabihf-gcc package.

Avoiding GLIBC

In this post I’m going to avoid GLIBC altogether by using a MUSL based arm build target to emit statically linked binaries using MUSL libc instead, since CentOS 7 only provides a very old version of GLIBC.

Cargo Setup

Now that you have the build toolchain you’ll need to configure Rust to use it. The best way to persistently configure cargo to build for your target appropriately is to add lines to the ~/.cargo/config file (create it if it doesn’t exist):

[target.armv7-unknown-linux-musleabihf]
linker = "arm-linux-gnueabihf-gcc"

This configures cargo to use our arm compiler installed in the previous step and utilize that for managing libc. Using the armv7-unknown-linux-musleabihf target with this compiler will handle automatically statically linking MUSL LIBC instead of dynamically linking GLIBC so that we don’t have to manage dynamic libraries for our binaries.

Building

Everything should be all set! Build your Raspberry Pi 4 binary with:

cargo build --target armv7-unknown-linux-musleabihf --release

For a quick test you can use scp to copy the binary over to your Pi and run it:

scp target/armv7-unknown-linux-musleabihf/release/testpi root@${SERVER_IP}:/usr/local/bin/testpi
ssh root@${SERVER_IP} testpi

From here you can expand upon this to build and deploy your Rust software to your Pi4’s, happy coding!