How to add a Buildroot package for a Cargo crate

Proper support for Rust and Cargo in Buildroot is available in the "feature/rust" branch of this (personal) Buildroot repository.

In this article, we will explain how to add a Buildroot package for a Cargo crate (namely "hello-rust"). A Cargo package infrastructure may be added in the future, to make the package development easier.

We will take the example of building a QEMU/Aarch64 system, which will include the crate.

Creation of the Package

As the package for the "hello-rust" is of no use for upstream Buildroot, the package will be added to a project-specific directory. This type of set-up is described in the section 9.2 of the Buildroot user manual.

First, create the project-specific directory, including the directory for the package:

mkdir -p $HOME/src/br2-ext-rust/package/hello-rust

Then, add a Makefile fragment to declare the new package:

echo 'include $(sort $(wildcard $(BR2_EXTERNAL)/package/*/*.mk))' \
     > $HOME/src/br2-ext-rust/external.mk

Finally, add a file to declare a configuration entry for the new package:

echo 'source "$BR2_EXTERNAL/package/hello-rust/Config.in"' \
     > $HOME/src/br2-ext-rust/Config.in

Now is the time to create the package itself. Create a file named $HOME/src/br2-ext-rust/package/hello-rust/Config.in with the following contents:

config BR2_PACKAGE_HELLO_RUST
       bool "hello-rust"
       depends on BR2_PACKAGE_HOST_CARGO
       help
         "Hello World!" program written in Rust

Next, create the file $HOME/src/br2-ext-rust/package/hello-rust/hello-rust.mk, with the following contents:

################################################################################
#
# hello-rust
#
################################################################################

HELLO_RUST_VERSION = 0.1.1
HELLO_RUST_SITE = $(HOME)/src/hello-rust
HELLO_RUST_SITE_METHOD = local
HELLO_RUST_LICENSE = Public Domain

HELLO_RUST_DEPENDENCIES = host-cargo

HELLO_RUST_CARGO_ENV = \
    CARGO_HOME=$(HOST_DIR)/usr/share/cargo \
    RUST_TARGET_PATH=$(HOST_DIR)/etc/rustc

HELLO_RUST_CARGO_OPTS = \
    --target=$(GNU_TARGET_NAME) \
    --manifest-path=$(@D)/Cargo.toml

ifeq ($(BR2_ENABLE_DEBUG),y)
HELLO_RUST_CARGO_MODE = debug
else
HELLO_RUST_CARGO_MODE = release
endif
HELLO_RUST_CARGO_OPTS += --$(HELLO_RUST_CARGO_MODE)

define HELLO_RUST_BUILD_CMDS
    $(TARGET_MAKE_ENV) $(HELLO_RUST_CARGO_ENV) \
            cargo build $(HELLO_RUST_CARGO_OPTS)
endef

define HELLO_RUST_INSTALL_TARGET_CMDS
    $(INSTALL) -D \
            $(@D)/target/$(GNU_TARGET_NAME)/$(HELLO_RUST_CARGO_MODE)/hello-rust \
            $(TARGET_DIR)/usr/bin/hello-rust
endef

$(eval $(generic-package))

Building the Firmware Image

First, clone the Buildroot repository with Rust support and checkout the branch:

git clone https://github.com/elebihan/buildroot
cd buildroot
git checkout --track origin/feature/rust

To create a firmware image for a QEMU/Aarch64 system, a custom defconfig file, with the proper configuration for building Cargo crates, will be used. Create the defconfig file as follow:

cat <<EOF > qemu_aarch64_virt_rust_defconfig
BR2_aarch64=y
BR2_TOOLCHAIN_EXTERNAL=y
BR2_TARGET_GENERIC_GETTY_PORT="ttyAMA0"
BR2_SYSTEM_DHCP="eth0"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="4.5"
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="board/qemu/aarch64-virt/linux-4.5.config"
BR2_TARGET_ROOTFS_INITRAMFS=y
# BR2_TARGET_ROOTFS_TAR is not set
BR2_PACKAGE_HOST_CARGO=y
BR2_PACKAGE_HOST_RUST=y
EOF

Then, initialize the build environment, specifying the project-specific directory, as well as the custom defconfig:

make O=$HOME/build/demo-rust/qemu/aarch64 \
     BR2_EXTERNAL=$HOME/src/br2-ext-rust \
     BR2_DEFCONFIG=qemu_aarch64_virt_rust_defconfig \
     defconfig

Edit the configuration to select the "hello-rust" package, available in the "User-provided options" menu.

make O=$HOME/build/demo-rust/qemu/aarch64 menuconfig

Start the build:

make O=$HOME/build/demo-rust/qemu/aarch64

When the build is finished, check the hello-rust program is available on the target:

$ file -b $HOME/build/demo-rust/qemu/aarch64/target/usr/bin/hello-rust
ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=06d2333136445d9a331ad02fb47861cf10654477, stripped

Run Test Program from System

Now, you can start your system using QEMU:

qemu-system-aarch64 \
    -nographic \
    -M virt \
    -cpu cortex-a57 \
    -smp 1 \
    -kernel $HOME/build/demo-rust/qemu/aarch64/images/Image \
    -append "console=ttyAMA0" \
    -netdev user,id=eth0 \
    -device virtio-net-device,netdev=eth0 \
    -serial mon:stdio

Log as "root" (no password) and execute the test program:

Welcome to Buildroot
buildroot login: root
# hello-rust
Hello World!

That's it!