Embedded LinuxでRust GUIアプリケーション環境を作るには

100 Views

November 01, 26

スライド概要

Rust GUIアプリケーションをYoctoで作るEmbedded Linuxディストリビューションに搭載しようとしたときに、どのような実験を経て達成したのかを紹介

profile-image

Embedded Linux Hobbyists

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

ダウンロード

関連スライド

各ページのテキスト
1.

Embedded LinuxでRust GUI アプリケーション環境を作るには License: CC-BY-4.0

2.

背景 • 近年、Rustがバグの少ないソフトウェアを開発できる言語として注目されている • Eclipse Foundation参加のEclipse SDVでも、新規OSS開発の言語としてRustが高い頻 度で採用されている • S-Coreの各コンポーネント, Kuksa等 • 某OSSプロジェクトでも、Rustを導入できる環境を用意したい • GUIつきアプリをRustで作って搭載できることをゴールに設定 • Yocto wrynose環境(最新のLTS)がターゲット License: CC-BY-4.0

3.

Slint • Rustで書かれたGUIツールキット • 全体的にQtに似ている • GUIの動きはRustで記述 • GUIデザインは、QtのQMLのような独自言語を使う • Wayland, DRM/KMSなどの上で動作させることができる • ライセンスは、GPLv3, ロイヤリティーフリー, 商用から選べる • ロイヤリティフリーライセンスは、ディスクトップやモバイル向け で無償利用できるがembeddedでは使えない • 採用理由 • GUIツールキットもRust化したい License: CC-BY-4.0

4.

SlintをYoctoで使う • Meta-slint • Slintコミュニティで、slintをYocto環境で使 うために用意しているYocto Layer • Raspberry PiやRenesas RZ, NXP等の環 境に対応 • 古いYoctoバージョンから最新まで、main 一つで対応するポリシー • Rustのビルドインフラは、Yoctoのものではな く、meta-rust-binを使う License: CC-BY-4.0 https://github.com/slint-ui/meta-slint

5.

SlintをYoctoで使う • Meta-slintのサンプルアプリをビルドして動 かすところからスタート • いきなり、大量のワーニングをまき散らして ビルドが進む… • レシピの文法チェックに引っかかっていたので、 Issueを発行 • パッチのPRもあっさりマージされた License: CC-BY-4.0

6.

Slint+Rustアプリをビルド • ビルドするアプリは、偉い人が作ってくれた 偉い人近影 • レシピは、meta-slintのサンプルレシピをもとに作成 • ウインドウシステムを使わずに単独アプリとして動かしたいので、 バックエンドはdrm/kmsを選択 • レンダーバックエンドは高性能なskiaを選択 • レシピの記述に、意味を理解できないものが残っているものの、 とりあえず動作させることはできた この時のレシピはこちら https://git.automotivelinux.org/AGL/meta-agl-demo/tree/meta-agl-demo-shared/dynamic-layers/meta-slint/recipes-demo/aglslint-cluster/agl-slint-cluster_git.bb?h=vimba License: CC-BY-4.0

7.

やりたかったことと、できたこと • やりたかったこと • Yocto wrynose環境下で、フルrustのGUIアプリケーションをmeta-slintを使って作 成 • できたこと • Yocto wrynose環境下で、rust+slintでGUIアプリケーションをビルドして動かすこ とができた License: CC-BY-4.0

8.

わかったこと • そもそも、meta-slintを使う必要はなかった • Yoctoのビルドは、bitbakeがレシピをもとにパッケージの依存関係を追跡して、必要なものをビ ルドして統合する • Rustは、cargo(パケージマネージャ)が依存関係を追跡して、必要なものをビルドしてアプリのバ イナリ内に全部リンクする • Rustは、すべて静的リンクするのがスタンダード • アプリをビルドするとbitbakeで依存関係を追跡して、meta-slintのレシピでslintをビルドすると 思っていた • 実際は、アプリをビルドするとcargoが依存パッケージをアプリごとにダウンロードし、アプリビルド のなかでビルドする • • • Slintもこの仕組みでビルドされており、meta-slintのslintレシピは使っていなかった Meta-slintのbbclassはrustアプリのビルドでも使う 確かに、READMEの記載通りの働き • This layer contains recipes and classes for building Slint's C++ API, a class for building Rust applications that use Slint, as well as the Rust based demos. License: CC-BY-4.0

9.

改めて、slintをYoctoで使う • Meta-slintを使うことで発生した制約 • Yoctoのrustインフラとmeta-rust-binのrustインフラをまぜて使うことになる • Meta-rust-binはバイナリパッケージを使うため、すべてをソースからビルドして構築 することができなくなる • Yoctoのrustインフラが実現している、レシピ作成時にパッケージバージョンを固定 化して、再現性を高める仕掛けが使えない • これらの制約を解消するために、meta-slintをやめてYoctoのrustイン フラに移行する License: CC-BY-4.0

10.

改めて、レシピを書き直す • Googleで”Yocto rust recipe”のキーワードで検索 • ツールとして、cargo-bitbakeの存在を教えてくれる • WindowsのCopilotに、Yocto wrynoseでrustのレシピの書き方を聞く • ツールとして、cargo-bitbakeの存在を教えてくれる • Yoctoの最新LTS wrynoseには、cargo-bitbakeは存在しない • Geminiは正しい方法を回答してくれました • Wrynoseでは、cargo-update-recipe-cratesを使うのが正しい方法 License: CC-BY-4.0

11.

Yocto wrynoseで、Rustレシピを書く方法 • 最初に、最低限のレシピを作成する • 必要なもの • ライセンス情報 • ソースコード入手元 • 例と同じinherit文 • 次にbitbakeでupdate_cratesを実行 • レシピ名-crates.incを作成してくれる • ビルド対象のRustアプリの依存関係を 収集した情報 • レシピと同じディレクトリに作成してくれ る agl-slint-cluster_git.bb LICENSE = "MIT“ LIC_FILES_CHKSUM = "file://LICENSE;md5=1cd9f3535d038f9d1bb320918e6474b1" SRC_URI = " \ git://github.com/signal-slot/agl-slint-cluster.git;protocol=https;branch=main \ “ SRCREV = "37e37108d94a577e9f9beb85fe4c1901d0cc9507“ inherit cargo cargo-update-recipe-crates $ bitbake agl-slint-cluster -c update_crates agl-slint-cluster-crates.inc # Autogenerated with 'bitbake -c update_crates agl-slint-cluster2’ # from rust/Cargo.lock SRC_URI += " \ crate://crates.io/ab_glyph/0.2.32 \ crate://crates.io/ab_glyph_rasterizer/0.1.10 \ crate://crates.io/adler2/2.0.1 \ crate://crates.io/ahash/0.8.12 \ ….. License: CC-BY-4.0

12.
[beta]
Yocto wrynoseで、Rustレシピを書く方法
• レシピを更新する
• update_cratesで作成したレシピ名-

crates.incを、requireで取り込む
• ビルドするアプリのCargo.tomlを
CARGO_MANIFEST_PATHで指定
する

agl-slint-cluster_git.bb
LICENSE = "MIT“
LIC_FILES_CHKSUM = "file://LICENSE;md5=1cd9f3535d038f9d1bb320918e6474b1"
SRC_URI = " \
git://github.com/signal-slot/agl-slint-cluster.git;protocol=https;branch=main \
“
SRCREV = "37e37108d94a577e9f9beb85fe4c1901d0cc9507“
inherit cargo cargo-update-recipe-crates
require ${BPN}-crates.inc
CARGO_MANIFEST_PATH = "${S}/rust/Cargo.toml"

• ビルド
• $bitbake レシピ名
• 結果
• ビルドエラー祭り発生

License: CC-BY-4.0

13.

問題点 • Yoctoのrustインフラ移行時、依存関係をcargoに任せた • Rustインフラに閉じた依存関係は解決してくれるが、プラットフォームへの依存関 係は解決してくれない • OpenGLやビルドで使うネイティブツールなどへの依存関係はレシピで解決しない といけない • バックエンドで使っているskia • 少なくとも、Yocto環境下ではgccでビルドできない • Meta-slintのbbclassには、確かにskia用と思われるワークアラウンドが存在する License: CC-BY-4.0

14.
[beta]
問題点の対策
• Yocto wrynose環境用にbbclass

を作成

• Bbclassで、アプリではなくslintに起

因する依存関係やワークアラウンド
を一括コントロールする

agl-slint.bbclass
# Set Slint dependency
DEPENDS = " \
fontconfig libxkbcommon libdrm virtual/egl virtual/libgbm virtual/libgles2 \
ca-certificates-native curl-native ninja-native \
seatd udev libinput \
“
inherit pkgconfig features_check
REQUIRED_DISTRO_FEATURES:append = " opengl“
# Set Slint options
CARGO_BUILD_FLAGS += "--features slint/backend-linuxkms,slint/renderer-skia“
# Avoid skia build issue.
TOOLCHAIN = "clang“
export TARGET_CLANGCC_ARCH = "${TARGET_CC_ARCH}“
export CLANGCC = "${TARGET_PREFIX}clang --target=${TARGET_SYS}
${TARGET_CLANGCC_ARCH} --sysroot=${STAGING_DIR_TARGET}“
export CLANGCXX = "${TARGET_PREFIX}clang++ --target=${TARGET_SYS}
${TARGET_CLANGCC_ARCH} --sysroot=${STAGING_DIR_TARGET}“
export CLANGCPP = "${TARGET_PREFIX}clang -E --target=${TARGET_SYS}
${TARGET_CLANGCC_ARCH} --sysroot=${STAGING_DIR_TARGET}“
export SDKTARGETSYSROOT = "${PKG_CONFIG_SYSROOT_DIR}"

License: CC-BY-4.0

15.
[beta]
最終的にできたレシピ
agl-slint-cluster_git.bb
SUMMARY = "A digital instrument cluster written in Rust and Slint, built for Automotive Grade Linux.“
HOMEPAGE = https://github.com/signal-slot/agl-slint-cluster
LICENSE = "MIT“
LIC_FILES_CHKSUM = file://LICENSE;md5=1cd9f3535d038f9d1bb320918e6474b1

レシピでビルドするものを明ら
かにするための記述
ちゃんと書きましょう

PV = "0.1“
SRC_URI = " \
git://github.com/signal-slot/agl-slint-cluster.git;protocol=https;branch=main \
file://agl-slint-cluster.service \
“
SRC_URI:append:sparrow-hawk = " \
file://glutin-egl-dlsym-fallback.patch;patchdir=${CARGO_VENDORING_DIRECTORY}/glutin-0.32.3 \
“
SRCREV = "37e37108d94a577e9f9beb85fe4c1901d0cc9507“
inherit cargo cargo-update-recipe-crates systemd agl-slint

agl-slint.bbclassを使う

require ${BPN}-crates.inc
CARGO_MANIFEST_PATH = "${S}/rust/Cargo.toml“
SYSTEMD_SERVICE:${PN} = "agl-slint-cluster.service“
do_install:append() {
install -d ${D}${systemd_unitdir}/system
install -m 0644 ${UNPACKDIR}/agl-slint-cluster.service ${D}${systemd_unitdir}/system/
}
License: CC-BY-4.0

これらは、systemd serviceとして
アプリを起動するための記述

16.
[beta]
これは何?
agl-slint-cluster_git.bb
SRC_URI:append:sparrow-hawk = " \
file://glutin-egl-dlsym-fallback.patch;patchdir=${CARGO_VENDORING_DIRECTORY}/glutin-0.32.3 \
“

• YoctoのRustインフラに移行したことで、依存先のパッケージへのパッチ当てが可能になった
•
•
•

Rustビルドの場合、Cargoで依存パッケージをダウンロードして一緒にビルドしてしまうため、C/C++ライブラリのようにパッケージビルド時に
パッチ当てができない
YoctoのRustインフラを使うことで、cargoでソースコードを展開後にパッチを当てる仕組みが使えるようになった
patchdirは、一度対象のレシピをbitbakeした後、パスがわかるようになる
• CARGO_VENDORING_DIRECTORY=レシピ単位のビルドディレクトリ/sources/cargo_home/bitbake
• CARGO_VENDORING_DIRECTORYの下にパッケージ単位のディレクトリがあるので、そこからパッチを当てたいコ
ンポーネントを探す

• なぜパッチを当てたかったのか?
•
•
•

RETRONIX社のRenesas R-Car V4Hを搭載したSparrow Hawkボードに対応しようとしたところ、R-Car V4Hが、まさかのEGL1.5非
対応で1.4までしか使えなかった
Slintが依存しているglutinは、いまさら1.4はないだろうという考えか、1.5が必須
パッチを当てないと動作させられなかった
License: CC-BY-4.0

17.

まとめ • まとめ • Yoct wrynose環境で、RustでGUIアプリを作ることができるプラットフォーム構築した • GUIツールキットとしてslintの導入を試みたところ、様々な課題が見つかったが、解決できた • 考察 • 今回slintを使ったが、embeddedはロイヤリティフリーライセンスを使えないため、GPLv3か商用 ライセンスが必要. • Qtも同様のライセンスポリシーなので、slintが特別悪いわけではない • 商用利用するのに対価を支払わないといのもおかしな話 • 一方で、RustアプリをEmbedded Linuxで使う場合の課題も見えた • Qtなどの他のツールキットと違いすべてを静的リンクするため、アプリ間で同じslintを使っていて もすべて別のものになってしまう • 実行ファイルサイズの増大 • 実行時の物理メモリも個別に必要 • プロセスモデルを採用しない環境であればよいが、プロセスモデル前提のLinuxではこの悪い点が出てしまう License: CC-BY-4.0