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.

industry

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.

  1. Setup Yocto as described here https://docs.yoctoproject.org/brief-yoctoprojectqs/index.html

  2. Set Up local.conf to Enable Rust Support Add the following lines to your local.conf file:

    ENABLE_RUST = "1"
    IMAGE_FEATURES:append = " debug-tweaks ssh-server-openssh"
    
  3. Ensure Necessary Meta-layers Are Present in bblayers.conf Verify that the following meta-layers are included in your bblayers.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.

  1. 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

  2. Use devtool for Development

    Add 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 the Cargo.lock file.

    At this point, you can remove any unnecessary tasks from the autogenerated BitBake file to keep it streamlined and focused.

  3. 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.

  4. 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.

  1. 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
    
  2. 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

  1. Install kas

    First, install kas on your development machine using pip:

    pip install kas
    
  2. Create a kas Configuration File

    Create a kas.yml configuration file with the necessary settings for a qemux86-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
    
  3. 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.

References

  1. Using Rust with Yocto Project by Paul Barker
  2. Yocto Project Documentation
  3. Rust Cross-Compilation Guide
  4. kas Documentation