Rust ist bei Desktop- und Cloudanwendungen im Mainstream angekommen. Das heisst, dass Komponenten wie Compiler, Build-Tools, etc. einfach installiert werden können und dass die Integration ins gewünschte Betriebssystem ohne Schwierigkeiten funktioniert. Rust ist auch Teil des Linux-Kernels geworden und erlaubt damit die Entwicklung von Kernel-Modulen in Rust.
Wie steht es aber um den Einsatz von Rust auf Embedded-Linux-Plattformen und -Distributionen, die beispielsweise mit Yocto erstellt werden?
Wie kriege ich Rust in meinen Yocto-Build?
Rust ist schon da!
Vermutlich ist Rust und die nötige Toolchain bereits in Ihrem Yocto-Build vorhanden. Denn seit Yocto Honister ist Rust Teil von openembedded-core. Damit braucht man keine zusätzlichen Layer zu verwenden. Alle Abhängigkeiten und Rezepte sind bereits in poky/meta vorhanden.
| Rust Version | Yocto Version (Auswahl) |
| 1.84.1 | Walnascar |
| 1.75 | Scarthgap |
| 1.59 | Kirkstone |
| 1.54 | Honister |
Ich möchte Rust in einer neueren Version verwenden
Wenn man darauf angewiesen ist, sowohl eine ältere Yocto-Version als auch eine neue Rust-Version zu verwenden, zum Beispiel weil man die Edition 2024 von Rust braucht, können spezielle Yocto-Layer verwendet werden.
LTS Mixins
Mit dem Layer lts-rust-mixin kann eine jeweils aktuelle Rust-Version verwendet werden. In diesem Layer gibt es für jeweils ein paar ältere Yocto-Versionen Backports von aktuellen Rust-Versionen. Der Layer kann wie üblich zu BBLAYERS in bblayers.conf hinzugefügt werden, mit dem passenden Commit ausgecheckt.
Rust Binary
Der Layer meta-rust-bin verfolgt auch das Ziel eines Backports von modernem Rust zu älteren Yocto-Versionen. Im Gegensatz zum üblichen Ansatz in Yocto alle Tools auf dem Host zu kompilieren, bringt dieser Layer direkt Binaries mit – mit allen Vor- und Nachteilen von vorkompilierten Tools. Das Hinzufügen des Layers in bblayers.conf funktioniert wie oben. In Rezepten muss man darauf achten nicht inherit cargo, sondern inherit cargo_bin zu verwenden, um klar zu spezifizieren, welche Variante man verwenden möchte.
Meta Rust
Der historische Layer meta-rust muss nicht (und sollte auch nicht) in einer normalen Yocto-Distribution verwendet werden. Der Code darin ist in anderen Layers bereits enthalten.

Bereit für die Rust-Challenge?
Rust Programming Language Quiz
Stellen Sie Ihr Wissen auf die Probe! Machen Sie unser Quiz für Softwareentwickler und finden Sie heraus, wie fit Sie in Rust sind.
Was muss ich unternehmen, um eine Rust-Applikation in mein System zu integrieren?
Die Integration einer Rust-Applikation in ein System ist nicht fundamental anders als die Integration einer «C/C++»-Applikation. Um ein sinnvolles Szenario zu beschreiben, werden ein paar Annahmen getroffen:
- Yocto-Version ist Scarthgap mit Verwendung von
lts-rust-mixin - Die Applikation ist auf Github verfügbar. Die Applikation ist zwar einfach, hat aber doch einige Abhängigkeiten in der Form von Crates.
Projekt-Setup
In bblayers.conf muss der lts-rust-mixin-Layer hinzugefügt werden.
In local.conf, oder besser in einem eigenen distro.conf, wird Rust aktiviert und die Version festgelegt. Eine Angabe der Rust-Version ist nicht zwingend nötig, aber hilfreich, da es eine Fehlermeldung gibt, wenn der lts-rust-mixin-Layer falsch konfiguriert ist.
DISTRO_FEATURES:append = " rust"
RUST_VERSION = "1.85.1"
CARGO_VERSION = "1.85.1"
Yocto-Rezept
Das Rezept ist unabhängig davon, wie Rust für dieses System aktiviert wird. Hier ist ein minimales, aber komplettes Rezept, wie die Applikation kompiliert und auf dem Zielsystem installiert wird.
(1)
SUMMARY = "Simple Webserver"
DESCRIPTION = "A simple webserver in async rust"
HOMEPAGE = "https://github.com/<user>/simple_srv_rs"
LICENSE = "MIT"
LIC_FILES_CHKSUM = file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302
(2)
TAG = "0.1.6"
SRC_URI = "git://github.com/<user>/simple_srv_rs.git;branch=async_server;tag=v${TAG};protocol=https"
S = "${WORKDIR}/git"
(3)
TARGET_BIN_NAME= "webserver-rs" # Must match the project name in Cargo.toml
(4)
inherit cargo
do_fetch[network] = "1"
do_compile[network] = "1"
CARGO_BUILD_FLAGS:remove = "--frozen"
CARGO_DISABLE_BITBAKE_VENDORING = "1"
(5)
do_install() {
install -d ${D}${bindir}
install -m 0755 ${B}/target/${RUST_TARGET_SYS}/release/${TARGET_BIN_NAME} ${D}${bindir}/${TARGET_BIN_NAME}
# --- other install tasks ---
}
FILES:${PN} += "${bindir}/${TARGET_BIN_NAME}"
- Header mit den nötigen Namen und der Lizenz mit dem passenden Hash.
- Der gewünschte git-Tag vom gewünschten Branch wird verwendet.
- Der Name der Applikation wird von Bitbake nur unzulänglich erraten. Die Variable wird verwendet, um die Applikation zu installieren.
- Ableiten von der
cargo-Klasse, damit die folgenden Befehle und Variablen bekannt sind. Dierust-Klasse braucht man in der Regel nicht direkt.
Netzwerkzugang wird benötigt, um Crates herunterzuladen.CARGO_BUILD_FLAGS:remove = "—frozen"
Das Flag—frozenbedeutet—lockedund—offlinezusammen. Wenn im Rezept—frozenentfernt wird, hat Cargo Zugriff auf das Web, um Crates herunterzuladen. Für den Build in einer CI, oder aus anderen Gründen, kann man den Download Bitbake überlassen. Mehr dazu später.
Ausgeschaltetes Vendoring bedeutet, dass alle Dependencies heruntergeladen müssen. - Die Applikation wird auf dem Zielsystem installiert.
RUST_TARGET_SYSwird aus dem Rust-Target-Triple hergeleitet, also etwas wiearmv7-unknown-linux-gnueabihf. Per Default wird ein release-Build erstellt.
Zukunftssicher bleiben
Rust Transition Service
Der regulatorische Druck, Software sicherer, effizienter und wirtschaftlicher zu gestalten wird immer grösser – Rust nimmt Ihnen diesen Druck.
Dependencies von Yocto verwaltet
Oft möchte man, dass die Crates von Yocto verwaltet werden. Zum Beispiel, wenn in der CI/CD-Pipeline alle Abhängigkeiten cached werden sollen. Damit dies möglich ist, müssen die Abhängigkeiten im Rezept konkret angegeben werden in der Form:
SRC_URI += " \
crate://crates.io/addr2line/0.24.2 \
"
SRC_URI[addr2line-0.24.2.sha256sum] = "dfb..1c1"
Eine nicht-triviale Applikation hat schon mehrere Dutzend Abhängigkeiten. Damit das Rezept lesbar bleibt und, um Automatisierung zu ermöglichen, drängt es sich auf, diese Abhängigkeiten in ein <rezept>-crates.inc File zu packen.
Es gibt verschiedene Varianten, um die Abhängigkeiten zusammen mit ihrer Checksumme in diesem File aufzulisten.
- Das Bitbake-Kommando
bitbake -c update_crates <rezept>. Damit wirdCargo.lockgelesen und das<rezept>-crates.incFile erstellt.
Dieses Kommando muss manuell ausgeführt werden, wenn die Version der Applikation ändert. - Selbstgemachtes Script, das als Erstes im Rezept ausgeführt wird.
- Keine Option ist
cargo bitbake. Obwohl dieses Tool überall empfohlen wird, sind die generierten Rezepte unbrauchbar u.a., weil die Checksummen nicht integriert werden.
Hier das Rezept von vorhin, das aber diesen Ansatz verfolgt:
SUMMARY = "Simple Webserver"
DESCRIPTION = "A simple webserver in async rust"
HOMEPAGE = "https://github.com/<user>/simple_srv_rs"
LICENSE = "MIT"
LIC_FILES_CHKSUM = file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302
(1)
inherit cargo
inherit cargo-update-recipe-crates
(2)
require ${BPN}-crates.inc
TAG = "0.1.6"
SRC_URI = "git://github.com/<user>/simple_srv_rs.git;branch=async_server;tag=v${TAG};protocol=https"
S = "${WORKDIR}/git"
TARGET_BIN_NAME = "webserver-rs"
(3)
# Keep network access during fetch so that the initial download is possible
do_fetch[network] = "1"
# Remove network access during build since we have all dependencies
do_compile[network] = "0"
do_install() {
install -d ${D}${bindir}
install -m 0755 ${B}/target/${RUST_TARGET_SYS}/release/${TARGET_BIN_NAME} ${D}${bindir}/${TARGET_BIN_NAME}
# --- other install tasks ---
}
FILES:${PN} += "${bindir}/${TARGET_BIN_NAME}"
inherit cargo-update-recipe-crateswird benötigt, um dasbitbake -c update_crates <rezept>Kommando auszuführen.- Das File mit den Abhängigkeiten wird verwendet
- Während dem Kompilieren wird der Netzwerkzugang nicht mehr benötigt. Um die Crates initial zu erhalten, braucht es aber den Netzwerkzugang beim Fetch.
CARGO_DISABLE_BITBAKE_VENDORINGist per default auffalse.
Fazit
Rust ist auch auf Embedded-Linux-Systemen angekommen. Mit dem beschriebenen Vorgehen kann man eine einfache, aber komplette Applikation mit Yocto in ein Linux-System einbinden. Die langen Abhängigkeitslisten muss man Pflegen. Die richtigen Tools nehmen einem aber die manuelle Arbeit ab.
DAS KÖNNTE SIE AUCH INTERESSIEREN
Wie Sie Rust in «C/C++»-Projekten einbauen können
Rust: Werkzeuge für ein sicheres Dependency Management
Erfolgreiche Einführung von Rust in Ihrem Team
