Cross compiling from linux to a raspberry pi
So I just got this starter kit: a small breadboard with a few simple components like LED, button and buzzer because I wanted to experiment a bit with GPIO. I opted out of easy mode and decided to do that in rust. That seems like a good fit, the language is low level and allow full control of the underlying hardware.
But before GPIO, I needed a Hello World.
Find the right target
Rustup has the concept of target and toolchains. So in theory, I can simply cargo build --target ???
and off I go.
A target in this context is the triple machine-vendor-operatingsystem
. Thankfully, I have gcc installed on my raspberry pi: gcc -dumpmachine
gives me arm-linux-gnueabihf
.
Now off to the list of supported targets for rustc! And I found no exact match.
There are two targets looking promising though:
arm-unknown-linux-gnueabihf
armv7-unknown-linux-gnueabihf
uname -m
gives me armv7l
, so I guess I'll roll with armv7-unknown-linux-gnueabihf
Linker woes
Install the toolchain: rustup target add armv7-unknown-linux-gnueabihf
and then:
cargo build --release --target armv7-unknown-linux-gnueabihf
vomits a scary looking error ending with:
/usr/bin/ld: rpi/target/armv7-unknown-linux-gnueabihf/release/deps/rpi-53051a58c3d5ca6d.rpi.9tay4t3s-cgu.0.rcgu.o: error adding symbols: file in wrong format
collect2: error: ld returned 1 exit status
😱 ðŸ˜
Not that straightforward. Thankfully that's when I stumbled upon this fantastic post which explains how to properly setup the toolchain.
Turn out, I need a whole set of binaries working for arm. In case the other post goes dark, I'll repeat the steps.
Head over to the arm website and download the correct archive. In my case, since I'm compiling from a linux host, I chose gcc-arm-10.2-2020.11-mingw-w64-i686-arm-none-linux-gnueabihf.tar.xz
.
Unpack, and add the bin
directory from that archive to your path: export PATH="$(pwd)/gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf/bin:$PATH"
.
However this is not enough yet, I need to tell cargo to use this specific arm linker. According to the section about configuration in the cargo book, I can do this through the file at .cargo/config.toml
:
[target.armv7-unknown-linux-gnueabihf]
linker = "arm-none-linux-gnueabihf-gcc"
And with this, I can finally compile !
Final test
Now I can test the produced binary on the target machine, you know, "trust but verify" stuff.
rsync --progress target/armv7-unknown-linux-gnueabihf/release/rpi pi:~/
and on the pi:
pi@raspberrypi:~ $ ./rpi
Hello World!
victory !
<(''<) <( ' ' )> (> '')>
Now I can make a LED blink !