4

I want to cross-compile my Rust application on macOS to a Raspberry Pi 2. I searched a lot, but did not find a working solution. The last solution I tried was following this answer, but I couldn't get it to work.

  • macOS version: 10.13.5 (High Sierra)
  • rustup version: 1.11.0
  • cargo version: 1.26.0

What I did:

  • I cloned raspberrypi/tools
  • Installed arm-unknown-linux-gnueabihf and armv7-unknown-linux-gnueabihf toolchains via rustup
  • Created .cargo/config file in the root of my project with following content

    [target.armv-unknown-linux-gnueabihf]
    linker = "/Users/user/Documents/Programming/RustProjects/hello-pi/../../Utils/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-gcc"
    
  • Then I run cargo build --target=arm-unknown-linux-gnueabihf

I get the following error:

linking with /Users/user/Documents/Programming/RustProjects/hello-pi/../../Utils/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-gcc failed: exit code: 126
....
cannot execute binary file

It seems that I cannot run the ...gcc binary on my macOS machine. What would be the right way to cross-compile my Rust application from macOS to the ARM architecture for a Raspberry Pi 2?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
grahan
  • 2,148
  • 5
  • 29
  • 43
  • 1
    The tools from https://github.com/raspberrypi/tools are compiled for Linux and can only be run from Linux. You'll likely need to build the cross-compiler yourself. – kennytm Jun 21 '18 at 08:44
  • I didn't know that before, thanks for clarifying. So essentially I need to compile `/arm-linux-gnueabihf-gcc` for Mac OS ? And then use my personal compiled version as the linker ? So maybe use something like [crosstool-ng](https://github.com/crosstool-ng) ? – grahan Jun 23 '18 at 11:40

1 Answers1

2

rust-std library relies on glibc for things like syscalls and other low-level stuff, in order to cross-compile a Rust binary, one needs the appropriate C toolchain to be present as well. And this is where crosstool-NG comes into play.

crosstool-NG is in the toolchain building business. You’re going to use it to build yourself a toolchain for linking against ARMv7-compatible glibc, which will in turn allow you to successfully build your Rust binary for the Pi.

  • Clone the repo to a good location and bootstrap it:
cd /Users/USER
git clone https://github.com/crosstool-ng/crosstool-ng
cd crosstool-ng
./bootstrap
  • Configure the installation and run it. To set where the tool goes on install, run:
./configure --prefix=$PWD
make
make install
export PATH="${PATH}:${PWD}/bin"

If all things went as expected, you should be able to run ct-ng version and verify the tool’s ready to go.

  • Configure the tool to build your ARMv7 toolchain. Luckily, crosstool-NG comes with some preset configurations, namely armv7-rpi2-linux-gnueabihf. Run:
ct-ng armv7-rpi2-linux-gnueabihf

There should be some output indicating that it’s now configured for armv7-rpi2-linux-gnueabihf. You just need to tell ct-ng where the toolchain ought to go:

mkdir /Users/USER/ct-ng-toolchains
cd /Users/USER/ct-ng-toolchains
ct-ng menuconfig

It can be overwhelming, as there are a ton of options, but stick to the Paths and misc options ---> menu option. Highlight it and hit Enter.

Under *** crosstool-NG behavior ***, scroll down until you see this long string: (${CT_PREFIX:-${HOME}/x-tools}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}) Prefix directory - Hit Enter, delete the contents, and replace it with /Users/USER/ct-ng-toolchains. - When you’re finished, hit Enter to confirm, scroll over and save, and then exit the configurator.

  • Build your toolchain (this may take half an hour):
ct-ng build
  • If it worked successfully, You should see a great many binaries now in /Users/USER/ct-ng-toolchains/armv7-rpi2-linux-gnueabihf/bin, namely armv7-rpi2-linux-gnueabihf-gcc.

  • For cargo to build using your new cross-compiler, you must:

    1. Add the bin folder listed above to your PATH:
export PATH="${PATH}:/Users/USER/ct-ng-toolchains/armv7-rpi2-linux-gnueabihf/bin"
  1. Update (or create) your global /Users/USER/.cargo/config file with (you can avoid this and use it in local .cargo/config):
[target.armv7-unknown-linux-gnueabihf]
linker = "armv7-rpi2-linux-gnueabihf-gcc"

3.Return to your Rust project and rerun cargo build:

cd /Users/USER/rust/hello
cargo build --target=armv7-unknown-linux-gnueabihf
  1. The output should be something similar to:
   Compiling hello v0.1.0 (file:///Users/USER/rust/hello)
    Finished dev [unoptimized + debuginfo] target(s) in 0.85 secs
  1. SCP your file over to the RPi and run the binary remotely:
scp target/armv7-unknown-linux-gnueabihf/debug/hello pi@192.168.1.43:
ssh pi@192.168.3.155 'chmod +x ~/hello && ~/hello'
Hello, world!

Credit goes to Kappel Codes I tried to summarize it here, as I found this question hours before I get that article :)

Hasan A Yousef
  • 22,789
  • 24
  • 132
  • 203