7-2. Yocto
Yoctoは、組込みLinuxディストリビューションを作成するためのプロジェクトです。製品固有のLinuxディストリビューションを作成、管理できるため、組込みLinux開発で広く用いられています。ここで言うLinuxディストリビューションは、Linux kernel、ライブラリ、アプリケーションを全て含みます。
日本語のまとまった書籍は、2019年現在ありませんが、雑誌インタフェースなどで、Raspberry Piの独自環境構築や、FPGAボードZynqの環境構築方法が紹介されています。みつきんのメモは、Yocto関連のノウハウが多く掲載されており、普段からお世話になっています。
ここでは、RustプロジェクトをYoctoビルド環境にインテグレーションする方法を紹介します。想定する利用方法は、ホスト上のRustツールチェインで一通り開発、デバッグを行った上で、distributionに取り込んで配布する、というものです。
Yoctoの基礎から説明するスキルが著者にないため、Yoctoを触ったことある方向けの情報になります。ご了承下さい。
ターゲット環境はRaspberry Pi3で、Yoctoのバージョンはthud
です。
meta-rust
meta-rustは、既存のRustプロジェクトをYoctoでビルドできるようにするための、Yoctoのレイヤです。
まず、raspberry pi3環境をビルドするためのレイヤを取得します。
mkdir -p rpi-thud/layers
cd rpi-thud/layers
git clone git://git.yoctoproject.org/poky.git -b thud
git clone git://git.yoctoproject.org/meta-raspberrypi -b thud
git clone git://git.openembedded.org/meta-openembedded -b thud
次に、Rustのパッケージを含んでいるmeta-rust
をcloneします。
git clone https://github.com/meta-rust/meta-rust.git
環境変数を読み込みます。
source layers/poky/oe-init-build-env build
ビルド対象のレイヤを追加します。
bitbake-layers add-layer ../layers/meta-openembedded/meta-oe
bitbake-layers add-layer ../layers/meta-openembedded/meta-python
bitbake-layers add-layer ../layers/meta-openembedded/meta-networking
bitbake-layers add-layer ../layers/meta-raspberrypi
bitbake-layers add-layer ../layers/meta-rust
local.conf
を修正します。
ターゲットをRaspberry Pi3にします。
MACHINE = "raspberrypi3"
Rustのサンプルパッケージをrootfsにインストールするようにします。
IMAGE_INSTALL_append = " rust-hello-world"
ビルドします。
bitbake core-image-base
dd
コマンドでマイクロSDカードにイメージを書き込みます。
sudo dd if=tmp/deploy/images/raspberrypi3/core-image-base-raspberrypi3.rpi-sdimg of=/dev/sdX bs=100M
/sdX
は使用している環境に合わせて適宜変更して下さい。
raspberry pi3を起動して、rust-hello-world
を実行します。
# rust-hello-world
Hello, world!
無事、実行できます。
cargo-bitbake
cargo-bitbakeは、既存のCargoプロジェクトからmeta-rust
のYoctoレシピを作成してくれるCargoの拡張機能です。
cargo-bitbake
はlibssl-dev
を使用するため、インストールします。
sudo apt install libssl-dev
cargo-bitbake
をインストールします。
cargo install cargo-bitbake
Rust製grepツールのripgrepを取り込んでみます。
git clone https://github.com/BurntSushi/ripgrep.git
cd ripgrep
cargo bitbake
これで、レシピが自動生成されます。
head ripgrep_11.0.1.bb
# Auto-Generated by cargo-bitbake 0.3.10
#
inherit cargo
# If this is git based prefer versioned ones if they exist
# DEFAULT_PREFERENCE = "-1"
# how to get ripgrep could be as easy as but default to a git checkout:
# SRC_URI += "crate://crates.io/ripgrep/11.0.1"
SRC_URI += "git://github.com/BurntSushi/ripgrep.git;protocol=https"
LIC_FILES_CHKSUM
だけは、手動で変更する必要があります。
# FIXME: update generateme with the real MD5 of the license file
LIC_FILES_CHKSUM=" \
file://Unlicense OR MIT;md5=generateme \
"
ripgrep
では、COPYING
ファイルにライセンス情報が記載されています。md5sum
コマンドでチェックサムを計算して、レシピを修正します。
md5sum COPYING
034e2d49ef70c35b64be514bef39415a COPYING
レシピは次のようになります。
LIC_FILES_CHKSUM=" \
file://COPYING;md5=034e2d49ef70c35b64be514bef39415a \
"
layers/meta-rust/recipes-example/ripgrep/
ディレクトリを作成し、自動生成されたレシピファイルをコピーします。
mkdir ../layers/meta-rust/recipes-example/ripgrep/
cp <path to ripgrep>/ripgrep_11.0.1.bb ../layers/meta-rust/recipes-example/ripgrep/
ビルドします。
bitbake ripgrep
これで、ripgrep
がビルドできます。
meta-rust-bin
meta-rust
では、LLVM、Rustコンパイラ、CargoをビルドしてRustツールチェインを構築するため、ビルド時間が大幅に増加します。それにも関わらず、Yoctoで作成したクロス開発環境には、このツールチェインが含まれません。純粋に、Rustのプロジェクトをビルドするだけであれば、既存のRustツールチェインバイナリを取得する方がよほどお手軽です。
そこで、Rustのツールチェインバイナリを取得して、Rustプロジェクトをビルドするmeta-rust-binがあります。
meta-rust
と異なり、こちらは、pokyのバージョンがsumo
までしか対応されていません (2019/6/22現在)。
mkdir -p rpi-sumo/layers
cd rpi-sumo/layers
git clone git://git.yoctoproject.org/poky.git -b sumo
git clone git://git.yoctoproject.org/meta-raspberrypi -b sumo
git clone git://git.openembedded.org/meta-openembedded -b sumo
git clone https://github.com/rust-embedded/meta-rust-bin
環境変数を読み込みます。
source layers/poky/oe-init-build-env build
ビルド対象のレイヤを追加します。
bitbake-layers add-layer ../layers/meta-openembedded/meta-oe
bitbake-layers add-layer ../layers/meta-openembedded/meta-python
bitbake-layers add-layer ../layers/meta-openembedded/meta-networking
bitbake-layers add-layer ../layers/meta-raspberrypi
bitbake-layers add-layer ../layers/meta-rust-bin
meta-rust-bin
には、レシピ例が同梱されていないため、サンプルアプリのレシピを作成します。meta-rust
のrust-hello-world
レシピがそのまま利用できます。
cp -r <path to meta-rust>/recipes-example/rust-hello-world/ ../layers/meta-rust-bin/
local.conf
を修正します。
ターゲットをRaspberry Pi3にします。
MACHINE = "raspberrypi3"
Rustのサンプルパッケージをrootfsにインストールするようにします。
IMAGE_INSTALL_append = " rust-hello-world"
ビルドします。
bitbake core-image-base
dd
コマンドでマイクロSDカードにイメージを書き込みます。
sudo dd if=tmp/deploy/images/raspberrypi3/core-image-base-raspberrypi3.rpi-sdimg of=/dev/sdX bs=100M
/sdX
は使用している環境に合わせて適宜変更して下さい。
raspberry pi3を起動して、rust-hello-world
を実行します。
# rust-hello-world
Hello, world!
無事、実行できます。
meta-rust-bin
でもripgrep
をビルドしてみます。レシピの用意は簡単です。
inherit cargo
SUMMARY = "ripgrep recursively searches directories for a regex pattern"
HOMEPAGE = "https://github.com/BurntSushi/ripgrep"
LICENSE = "MIT"
SRC_URI = "git://github.com/BurntSushi/ripgrep.git;tag=${PV};protocol=https"
S = "${WORKDIR}/git"
LIC_FILES_CHKSUM = "file://LICENSE-MIT;md5=8d0d0aa488af0ab9aafa3b85a7fc8e12"
bitbake ripgrep
これで、ripgrep
がビルドできます。
meta-rustとの比較
ラズパイ3のcore-image-base
にrust-hello-world
を追加したイメージのフルビルドにかかる時間を計測したろころ、meta-rust
が約220分、meta-rust-bin
が約75分でした。Yoctoのバージョンが異なるため、完全なベンチマークとは言えませんが、meta-rust-bin
の方がビルド時間がかなり短いです。
meta-rust-bin
はビルド済みのRustツールチェインを利用するため、Rustコンパイラをカスタマイズしてビルドする、ということができません。Rustが公式にサポートしていないアーキテクチャをターゲットにする場合は、meta-rust
の利用が必要です。
また、ビルド済みのRust標準ライブラリを利用するため、カスタムビルドされた標準ライブラリよりパフォーマンスが低い可能性があります。
cargo-bitbake
で自動生成するレシピは、meta-rust-bin
のclassとは互換性がありません。meta-rust-bin
のレシピを用意するのは、それほど難しくないため、大きなデメリットではありません。