Using Cargo with Buildroot (full build)

Cargo is the official Rust package manager. It will fetch the dependencies of a Rust project and compile everything. Adding support for Cargo in Buildroot will allow the end user to to easily cross-compile programs for an embedded system.

We assume that a Buildroot-based environment as been set up as described previously.

Build Cargo

Grab the source code of the latest version (0.9.0) and extract it.

git clone --recursive https://github.com/rust-lang/cargo \
    -b 0.9.0 \
    $HOME/build/demo-rust/qemu/arm/build/host-cargo-0.9.0

Cargo needs OpenSSL and CMake (and Python, but it is assumed that a Python interpreter is available on the build machine):

make O=$HOME/build/demo-rust/qemu/arm host-openssl host-cmake

It also depends on the host version of libssh2, which is unfortunately not available in Buildroot. But it is easy to add it:

echo '$(eval $(host-autotools-package))' >> package/libssh2/libssh2.mk
make O=$HOME/build/demo-rust/qemu/arm host-libssh2

Configure and build:

export PATH=$HOME/build/demo-rust/qemu/arm/host/usr/bin:$PATH
export PKG_CONFIG=$HOME/build/demo-rust/qemu/arm/host/usr/bin/pkgconf
export LIBRARY_PATH=$HOME/build/demo-rust/qemu/arm/host/usr/lib
pushd $HOME/build/demo-rust/qemu/arm/build/host-cargo-0.9.0
./configure --prefix=$HOME/build/demo-rust/qemu/arm/host/usr \
            --localstatedir=$HOME/build/demo-rust/qemu/arm/host/var/lib \
            --sysconfdir=$HOME/build/demo-rust/qemu/arm/host/etc
make
make install
popd

Note that Cargo bootstrap itself, as seen in the build log:

[...]
curl -o target/dl/cargo-nightly-x86_64-unknown-linux-gnu.tar.gz \
     https://static.rust-lang.org/cargo-dist/2016-01-31/cargo-nightly-x86_64-unknown-linux-gnu.tar.gz
[...]

Test Cargo

Now is the time to test Cargo. Create a new crate for the "Hello World" program:

mkdir -p $HOME/src
pushd $HOME/src
cargo new --bin hello-rust

To allow cross-compilation of a crate, some parameters must be set in the Cargo configuration file. Create this file as follow:

mkdir .cargo
cat <<EOF > .cargo/config
[target.arm-buildroot-linux-gnueabihf]
linker = "arm-buildroot-linux-gnueabihf-gcc"
EOF

Here, Cargo is instructed to use the linker from the toolchain generated by Buildroot when the target is "arm-buildroot-linux-gnueabihf".

Tell the Rust compiler where the target specification can be found:

export RUST_TARGET_PATH=$HOME/build/demo-rust/qemu/arm/host/etc/rustc

Now, build the crate:

cargo build \
      --target=arm-buildroot-linux-gnueabihf \
      --release

Once the build is finished, check the result executable is for an ARM machine:

$ file -b target/arm-buildroot-linux-gnueabihf/release/hello-rust
ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 4.5.0, not stripped

Finally, copy the result binary file in the target rootfs:

cp -a target/arm-buildroot-linux-gnueabihf/release/hello-rust \
   $HOME/build/demo-rust/qemu/arm/target/usr/bin

For futher details on using Cargo and creating crates, please refer to the Cargo documentation.