Creating cross compile executable with RUST

Share on:

Creating executable for small embedded application can be tedious, especially if the plateform is not supporting executing compilation toochains.

Creating cross executable with RUST

In first place, creating an executable using rust is quite simple the typical steps are :

  • use rustup to add the target plateform, using the triplet describing the hardware, and system
  • use the cargo build --target <TRIPLET> command line to build

Thank’s to the community , these command line are easy to use and launch.

A more informative article details these paths : https://kerkour.com/rust-cross-compilation

in my use case, i wish to deploy a small rust executable, dealing with mqtt , on an old OrangePI HW, (Armv7 with some floating point hardware support), the OS was quite old (a couple of years since setup and not updated). The compilation with the –target=armv7-unknown-linux-gnuabihf generate the executable on my x64, bu when copied and launched on the Orangepi, the gclibc was too old for the dynlink, and i faced a GLIBC VERSION not found.

Dealing with the glibc and linkages

docker to the rescue from the information on the website : https://capnfabs.net/posts/cross-compiling-rust-apps-linker-shenanigans-multistrap-chroot/

Dockerfile:

 1FROM rustembedded/cross:armv7-unknown-linux-gnueabihf-0.2.1
 2
 3COPY rustup.sh /usr/local/bin/rustup.sh
 4COPY cargo-config /cargo/config
 5
 6ENV CARGO_HOME=/cargo \
 7    PATH=/cargo/bin:$PATH \
 8    USER=root
 9
10RUN bash /usr/local/bin/rustup.sh -y && \
11    rustup default stable && \
12    rustup target add armv7-unknown-linux-gnueabihf && \
13    rustup target add armv7-unknown-linux-musleabihf && \
14    rustup target add x86_64-unknown-linux-gnu
15
16RUN cargo install cross
17
18# Install multistrap
19RUN apt-get update && apt-get install multistrap --assume-yes
20# Put the target system here in /sysroot-armhf
21RUN mkdir /sysroot-armhf
22# We'll explain this in just a second
23COPY multistrap-config /
24WORKDIR /
25RUN multistrap -a armhf -f multistrap-config 
26
27ENV PKG_CONFIG_LIBDIR_armv7_unknown_linux_gnueabihf=/sysroot-armhf/usr/lib/arm-linux-gnueabihf/pkgconfig
28ENV PKG_CONFIG_SYSROOT_DIR_armv7_unknown_linux_gnueabihf=/sysroot-armhf
29
30
31

multistrap-config

 1use@alexa:~/rsiotmonitor/docker2$ more multistrap-config 
 2[General]
 3# target architecture
 4arch=armhf
 5
 6directory=/sysroot-armhf
 7
 8# Don't bother with authentication. I'd love to support this, but
 9# couldn't get it working! If you know how, please get in touch.
10noauth=true
11# Unpack the packages
12unpack=true
13# Tidy up afterwards (makes the container smaller)
14cleanup=true
15# Both of these refer to the 'Raspbian' stanza, below
16bootstrap=raspbian
17aptsources=raspbian
18
19[raspbian]
20# Required packages for our build
21packages=libasound2-dev libdbus-1-dev libssl-dev libc6-dev
22source=http://raspbian.raspberrypi.org/raspbian/
23# distribution version name
24suite=buster
25

cargo-config

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

constructing the image :

docker build -t crossbuild:local .


docker run -ti --rm -v `pwd`:/code crossbuild:local

cd /code


cargo build --target armv7-unknown-linux-gnueabihf

then the binary is copiable and work on the target system :

 1pi@OrangePi:~/tmp$ ll
 2total 57844
 3drwxrwxr-x 2 pi pi     4096 janv.  7 17:50 ./
 4drwxr-xr-x 9 pi pi     4096 janv.  7 12:19 ../
 5-rwxr-xr-x 1 pi pi 59220272 janv.  7 17:50 rsiotmonitor*
 6pi@OrangePi:~/tmp$ ldd rsiotmonitor 
 7	linux-vdso.so.1 =>  (0xbedc6000)
 8	libgcc_s.so.1 => /lib/arm-linux-gnueabihf/libgcc_s.so.1 (0xb68f4000)
 9	librt.so.1 => /lib/arm-linux-gnueabihf/librt.so.1 (0xb68de000)
10	libpthread.so.0 => /lib/arm-linux-gnueabihf/libpthread.so.0 (0xb68ba000)
11	libm.so.6 => /lib/arm-linux-gnueabihf/libm.so.6 (0xb6842000)
12	libdl.so.2 => /lib/arm-linux-gnueabihf/libdl.so.2 (0xb682f000)
13	libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6743000)
14	/lib/ld-linux-armhf.so.3 (0xb6fba000)
15pi@OrangePi:~/tmp$ 
16

binary size 52mb which is a bit large, stripping the symbols, and in release mode, the result is much smaller (8mb)

 1root@335ad79e967c:/code/target/armv7-unknown-linux-gnueabihf/release# ll
 2total 8708
 3drwxr-xr-x  7 root root    4096 Jan  7 16:59 ./
 4drwxr-xr-x  4 root root    4096 Jan  7 16:58 ../
 5-rw-r--r--  1 root root       0 Jan  7 16:58 .cargo-lock
 6drwxr-xr-x 68 root root    4096 Jan  7 16:58 .fingerprint/
 7drwxr-xr-x 11 root root    4096 Jan  7 16:58 build/
 8drwxr-xr-x  2 root root   20480 Jan  7 16:59 deps/
 9drwxr-xr-x  2 root root    4096 Jan  7 16:58 examples/
10drwxr-xr-x  2 root root    4096 Jan  7 16:58 incremental/
11-rwxr-xr-x  2 root root 8861924 Jan  7 16:59 rsiotmonitor*
12-rw-r--r--  1 root root      83 Jan  7 16:59 rsiotmonitor.d
13
14