Developing Rust Applications for Embedded Linux
In embedded systems and industrial edge computing, using a reliable, efficient, and safe language like Rust is crucial
for developing applications where performance and memory safety are critical. This post presents how to develop
Rust-based applications using Yocto Linux’s default Rust compiler setup without relying on the meta-rust
layer.
Image by Saad Salim from unsplash
This guide focuses on configuring a Yocto build environment, building a Rust application using Yocto’s native Rust support, cross-compiling the project, and deploying it to an embedded device.
Setting Up the Yocto Build Environment (without kas)
The following steps show how to manually configure Yocto’s environment without relying on kas
to build and run Rust
programs on embedded Linux devices:
You can manually configure your Yocto environment by downloading the necessary repositories, setting up local.conf to enable Rust support, and initializing the build environment. If you prefer an automated setup, refer to the Appendix on using kas for automating the Yocto build environment.
-
Setup Yocto as described here https://docs.yoctoproject.org/brief-yoctoprojectqs/index.html
-
Set Up
local.conf
to Enable Rust Support Add the following lines to yourlocal.conf
file:ENABLE_RUST = "1" IMAGE_FEATURES:append = " debug-tweaks ssh-server-openssh"
-
Ensure Necessary Meta-layers Are Present in
bblayers.conf
Verify that the following meta-layers are included in yourbblayers.conf
:BBLAYERS ?= " \ ${TOPDIR}/../meta-edge-controller \ ${TOPDIR}/../meta-openembedded/meta-oe \ ${TOPDIR}/../poky/meta \ ${TOPDIR}/../poky/meta-poky \
Building a Rust-based Application
With the Yocto environment set up, the next step is to create and compile your Rust application using Yocto’s built-in
Rust compiler, without relying on the meta-rust
layer. This approach simplifies the process by utilizing Yocto’s native
Rust toolchain.
It is recommended to begin with a basic Rust project to ensure the initial setup works correctly. Once the basic application is successfully built, you can progressively introduce more dependencies and functionality.
-
Create a Rust Project Locally
Clone your Rust project repository:
git checkout https://github.com/<username>/<your-repo-name>
For example:
git clone https://github.com/konsulko/hello-rust
-
Use
devtool
for DevelopmentAdd the project to Yocto’s workspace using
devtool
:devtool add /path/to/<your-repo-name>
Navigate to
build/workspace/recipes/<your-repo-name>
and modify the BitBake recipe as follows:inherit cargo cargo-update-recipe-crates
For example:
build/workspace/recipes/hello-rust
The cargo class allows Yocto to compile Rust programs by handling the integration of the Cargo build system, while the cargo-update-recipe-crates class enables automatic updates of the list of Cargo crates in
SRC_URI
by reading theCargo.lock
file.At this point, you can remove any unnecessary tasks from the autogenerated BitBake file to keep it streamlined and focused.
-
Update Cargo Dependencies
Run the following command to generate the
crates.inc
file:bitbake -c update_crates <your-repo-name>
Add the line
require ${BPN}-crates.inc
to your recipe. -
Build and Test
Use the
devtool
to build the project:devtool build <your-repo-name>
Add the project to the Yocto image by modifying
local.conf
:IMAGE_INSTALL:append = "<executable-name>"
For example:
IMAGE_INSTALL:append = "hello-rs"
Build the full image:
bitbake core-image-minimal
Cross-Compiling the Rust Application
Yocto’s built-in toolchain for Rust ensures that your project is compiled for the architecture specified in your local.conf
or, if using kas, in the kas.yml
configuration.
Yocto’s built-in toolchain for Rust ensures that your project is compiled for the architecture specified in the
kas.yml
configuration.
Deploying to the Embedded Target
After building the application, the next step is to deploy it to your target embedded device.
-
Run the Emulator
Once the image is built, you can run the emulator to test your Rust application in a virtual environment:
runqemu qemux86-64 nographic slirp
-
Run the Application
After booting the system, run your Rust application directly from the terminal:
<executable-name>
Note: Replace
<executable-name>
with the actual name of the binary you built, for example,hello-rs
.
By using kas to manage your Yocto build environment and leveraging Yocto’s default Rust support without relying on
meta-rust
, you simplify the process of setting up and maintaining your build configurations. Combining Rust’s
performance and safety with Yocto’s flexibility is an excellent choice for creating efficient and secure embedded
applications.
For more context, this approach builds on the concepts outlined in Paul Barker’s original post on using Rust with Yocto, with the newest version of Yocto Scarthgap
Appendix
Automating the Yocto Build Environment with kas
-
Install kas
First, install kas on your development machine using
pip
:pip install kas
-
Create a kas Configuration File
Create a
kas.yml
configuration file with the necessary settings for aqemux86-64
machine:header: version: 14 defaults: repos: branch: scarthgap machine: qemux86-64 local_conf_header: dev: | ENABLE_RUST = "1" IMAGE_FEATURES:append = " debug-tweaks ssh-server-openssh" storage: | INHERIT+="rm_work" distro: poky repos: poky: url: https://github.com/yoctoproject/poky.git layers: meta: meta-poky: meta-openembedded: url: https://github.com/openembedded/meta-openembedded.git layers: meta-oe: target: - core-image-minimal
-
Initialize the Build Environment
Use kas to set up and enter the build environment:
kas shell qemux86-64.yml -c bash
This command sets up the build environment and opens a new shell where you can run BitBake commands.
After initializing the build environment using kas, you can now proceed to building a Rust-based application.