yocto cheat sheet
はじめの一歩
ビルドに必要なパッケージのインストール。
sudo apt install build-essential chrpath cpio debianutils diffstat file gawk gcc git iputils-ping libacl1 liblz4-tool locales python3 python3-git python3-jinja2 python3-pexpect python3-pip python3-subunit socat texinfo unzip wget xz-utils zstd
# リリース一覧: https://wiki.yoctoproject.org/wiki/Releases
git clone git://git.yoctoproject.org/poky.git -b scarthgap
source poky/oe-init-build-env <working directory name>
bitbake core-image-minimal # ビルドする
Ubuntu24.04 だとビルドできず、22.04 を使っています。
ビルド
raspi 用のイメージを作る
git clone https://github.com/agherzan/meta-raspberrypi.git -b scarthgap
bitbake-layers add-layer ./meta-raspberrypi/
sudo bmaptool copy tmp/deploy/images/raspberrypi3-64/universal-gateway-raspberrypi3-64.rootfs.wic.bz2 /dev/sda
成果物を SD カードに焼く
cd tmp/deploy/images/$MACHINE/
sudo dd if=core-image-minimal-genericx86-64.rootfs.wic of=/dev/<media>
bmaptool を使うとより速い (けど macOS は非対応)
sudo bmaptool copy core-image-minimal-genericx86-64.rootfs.wic /dev/<media>
カスタマイズ
ファイルをイメージに追加する
# レイヤを作成
bitbake-layers create-layer myproject
bitbake-layers add-layer myproject
# myapp を作成
cd myproject
rm -r recipes-example/
mkdir -p recipes-myproj/myapp/files
vim recipes-myproj/myapp/myapp_1.0.bb # 中身は下段
echo 0.0.1 > recipes-myproj/myapp/files/myapp_version
echo 'IMAGE_INSTALL:append = " myapp"' >> ../build/conf/local.conf
SUMMARY = "My Application"
DESCRIPTION = "My Application"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "file://myapp_version"
S = "${WORKDIR}"
FILES:${PN} += "/version"
do_install () {
install -m 0755 myapp_version ${D}/version
}
変数の意味: https://docs.yoctoproject.org/ref-manual/variables.html
プログラムをビルドして追加する
先ほどの myproject をいじる。
SUMMARY = "My Application"
DESCRIPTION = "My Application"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "file://hello.c"
S = "${WORKDIR}"
do_configure () {
# Do nothing
:
}
do_compile () {
${CC} ${LDFLAGS} hello.c -o hello
}
do_install () {
install -d ${D}${bindir}
install -m 0755 hello ${D}${bindir}
}
hello.c は files 以下に作成する
cat > recipes-myproj/myapp/files/hello.c <<EOF
#include <stdio.h>
int main() {
printf("Hello Yocto!\n");
}
EOF
既成のパッケージを追加する
poky が提供しているパッケージは IMAGE_INSTALL
の指定で簡単にインストールできる。
https://git.yoctoproject.org/poky/plain/meta/recipes-extended/ などから目的のパッケージを選ぶ。
以下のように指定する
echo 'IMAGE_INSTALL:append = " zip"' >> build/conf/local.conf
あるいは packagegroup も使える。何が使えるかは例えば https://git.yoctoproject.org/poky/plain/meta/recipes-extended/packagegroups/packagegroup-core-base-utils.bb を見ればわかるはず
echo 'IMAGE_INSTALL:append = " packagegroup-core-base-utils"' >> build/conf/local.conf
デーモンの起動スクリプトを追加する (SysVinit編)
以下のように、2つのファイルを作成する
recipes-myproj/mydaemon/
├── files
│ └── mydaemon
└── mydaemon_1.0.bb
update-rc.d はすでにレシピがあるので、inherit update-rc.d
を唱えれば、よしなに反映してくれる。
SUMMARY = "My Daemon"
DESCRIPTION = "My Daemon"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "file://mydaemon"
S = "${WORKDIR}"
# do update-rc.d
inherit update-rc.d
INITSCRIPT_NAME = "mydaemon"
INITSCRIPT_PARAMS = "defaults 90"
do_install () {
install -d ${D}${sysconfdir}/init.d
install -m 0755 ${S}/mydaemon ${D}${sysconfdir}/init.d/mydaemon
}
files/mydaemon は https://raw.githubusercontent.com/fhd/init-script-template/refs/heads/master/template あたりを参考に、一般的な init スクリプトを作成して配置する。
あとは IMAGE_INSTALL に追加して↓、ビルドすればOK。
ehco 'IMAGE_INSTALL:append = " mydaemon"' >> build/conf/local.conf
デーモンの起動スクリプトを追加する (systemd編)
TODO
see https://docs.yoctoproject.org/dev-manual/new-recipe.html#enabling-system-services
レイヤ一覧
bitbake-layers show-layers
bbファイルのライセンス宣言を非公開のものにする
LICENSE = "CLOSED"
LIC_FILES_CHKSUM = ""
ファイルシステムを Read Only にする
TODO
rootfs のサイズを拡張する
bbclass か local.conf で以下を定義する
IMAGE_ROOTFS_EXTRA_SPACE = 1048576 # 1GB 余分に確保
IMAGE_ROOTFS_SIZE = 1048576 # / を1GB きっかりにする
/ については↓の --size
を定義する方法だと、パーティションのサイズは変わるけど、ファイルシステムのサイズは変わらない。これらの変数を定義する必要がある。
ディスクイメージにパーティションを追加する (手動)
build ディレクトリに、test.wks
を作成する。core-image-minimal-genericx86
は対象に合わせる。
include tmp/deploy/images/genericx86-64/core-image-minimal-genericx86.wks
part /data --ondisk sda --size 5120 --fstype=vfat --label data --align 1024
これを使って、以下のように作成する
wic create ./test.wks -e core-image-minimal -o output
ls output/test-*-sda.direct
output/test-202502241431-sda.direct # < これをSDカードにddで書き込む
ディスクイメージにパーティションを追加する (レイヤに組み込む)
上で作った myproject
を使う。
cd myproject
mkdir wic
mkdir classes
wic/custom-wic.wks
を作成する。
ここでは build/tmp/deploy/images/genericx86-64/core-image-minimal-genericx86.wks を参考に、以下のようにした。
part /boot --source bootimg-efi --sourceparams="loader=grub-efi" --ondisk sda --label msdos --active --align 1024
part / --source rootfs --ondisk sda --fstype=ext4 --label platform --align 1024 --use-uuid
part swap --ondisk sda --size 44 --label swap1 --fstype=swap
part /data --ondisk sda --size 5120 --fstype=vfat --label data --align 1024 --use-uuid
bootloader --ptable gpt --timeout=5 --append="rootfstype=ext4 console=ttyS0,115200 console=tty0"
wks のマニュアル: https://docs.yoctoproject.org/ref-manual/kickstart.html
次に classes/custom-wic.bbclass
を作成する
ROOTFS_POSTPROCESS_COMMAND += "create_data_dir;"
WKS_FILE = "custom-wic.wks"
IMAGE_FSTYPES += "wic"
create_data_dir() {
mkdir ${IMAGE_ROOTFS}/data
}
最後に local.conf でこれを有効にして、ビルドする
echo 'INHERIT += "custom-wic"' >> build/conf/local.conf
bitbake core-image-minimal
ビルドしたディスクイメージの中身を見る
$ wic ls tmp/deploy/images/$MACHINE/core-image-minimal-genericx86-64.rootfs.wic
1 1048576 30726143 29677568 fat16
2 31457280 405320703 373863424 ext4
3 405798912 8995733503 8589934592 fat32
4 8995733504 9041870847 46137344 linux-swap(v1)
この場合、多分2が /
なので、
$ wic ls core-image-minimal-genericx86-64.rootfs.wic:2/bin | head
debugfs 1.46.5 (30-Dec-2021)
13 40755 (2) 0 0 4096 9-Mar-2018 12:34 .
2 40755 (2) 0 0 1024 5-Apr-2011 23:00 ..
14 120777 (7) 0 0 19 9-Mar-2018 12:34 ash
18 120777 (7) 0 0 14 9-Mar-2018 12:34 busybox
28 120777 (7) 0 0 20 9-Mar-2018 12:34 chown
51 120777 (7) 0 0 16 9-Mar-2018 12:34 gunzip
40 120777 (7) 0 0 19 9-Mar-2018 12:34 dnsdomainname
60 100755 (1) 0 0 157824 9-Mar-2018 12:34 kmod
32 120777 (7) 0 0 19 9-Mar-2018 12:34 cpio
みたいにファイルの確認ができる
rootfs のサイズを拡張する
# 5GB 余分にスペースを作る
echo 'IMAGE_ROOTFS_EXTRA_SPACE = "5242880"' >> build/conf/local.conf
ビルドしたパッケージに含まれるパッケージの一覧
build/tmp/deploy/images/qemux86-64/*.manifest
パッケージから特定の機能を無効化する
パッケージによっては PACKAGECONFIG
で有効無効を制御できることがあります。
python の場合:
bitbake -e python3 | grep PACKAGECONFIG
(snip)
PACKAGECONFIG="editline gdbm "
editline はまずいらないと思われるので、無効化します
PACKAGECONFIG:remove:pn-python3 = "editline"
あるいは bbappend で
PACKAGECONFIG:remove = "editline"
kernel をカスタマイズする
bitbake virtual/kernel -c menuconfig
# 必要な変更を加える
bitbake virtual/kernel -c kernel_configcheck -f # コンフィグチェック
bitbake virtual/kernel -c diffconfig # 差分を確認
bitbake virtual/kernel -c savedefconfig
(snip)
Saving defconfig to:
/..(snip).../linux-genericx86_64-standard-build/defconfig
$ mkdir -p recipes-kernel/linux/linux-yocto/
$ cat recipes-kernel/linux/linux-yocto_\%.bbappend
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
KCONFIG_MODE = "alldefconfig"
SRC_URI += "file://defconfig"
$ cp /path/to/defconfig recipes-kernel/linux/linux-yocto/
特定の MACHINE にのみ適用したい場合は recipes-kernel/linux/linux-yocto/
の下にさらに x86-64
などのディレクトリを作って、そこにdefconfigを入れる。
ここで指定する linux-yocto
は環境によって異なる。これは以下のように探すことができる
bitbake core-image-minimal -e | grep '^PREFERRED_PROVIDER_virtual/kernel'
PREFERRED_PROVIDER_virtual/kernel="linux-yocto"
Go のアプリケーションをビルドする
https://github.com/zakkie/go-helloworld これを使う。
DESCRIPTION = "go-helloworld"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
GO_IMPORT = "github.com/zakkie/go-helloworld"
GO_INSTALL = "${GO_IMPORT}/cmd/helloworld"
SRC_URI = "git://${GO_IMPORT}.git;branch=main;protocol=https"
SRCREV = "ab099a502097f072b8837eb1642aeb14782e61bc"
# "inherit go" と書いてあるサンプルもあるけど、go は古い。
# go.mod があるような最近のプロジェクトは go-mod を使うべき。
inherit go-mod
# デフォルトではビルド中のネットワークアクセスは禁止されている(セキュリティのため)
# go build 時にパッケージを fetch するので、これがないとビルドがコケる。
do_compile[network] = "1"
do_compile[network] = "1"
を使わずにビルドする方法はいくつか提案されているようだけど、どれも決め手にかけるように見える。
ビルド高速化
並列度を上げる
echo 'PARALLEL_MAKE="-j 12"' >> build/conf/local.conf
echo 'BB_NUMBER_THREADS="9"' >> build/conf/local.conf
PARALLEL_MAKE
はコア数の1.5倍、BB_NUMBER_THREADS
はコア数の1.2倍程度がちょうど良いっぽい。
デフォルトではコア数になるぽい。
ダウンロードキャッシュを使う
mv build/downloads /path/to/downloads # 既存のダウンロードキャッシュを移動 (必要なら)
echo 'DL_DIR = "/path/to/downloads"' >> build/conf/local.conf
ビルドキャッシュを使う
mv build/sstate-cache /path/to/sstate-cache
echo 'SSTATE_DIR = "/path/to/sstate-cache/${MACHINE_ARCH}"' >> build/conf/local.conf
bitbake 関連
bitbake core-image-minimal -c listtasks # タスク一覧
bitbake core-image-minimal -c clean
デバッグ
QEMU で動かす
runqemu nographic serialstdio qemuparams="-m 1024"
root/(nopassword) でログインできる。
QEMU を終了する
Ctrl-A + Ctrl-X
or ゲストOSで shutdown -h now
する
ストレージ容量を使っているファイルを調べる
buildhistory という機能を使う。
以下2行を local.conf に追加する
INHERIT += "buildhistory"
BUILDHISTORY_COMMIT = "1"
ビルドする。たぶん、事前に clean が必要。
bitbake core-image-minimal -c clean
bitbake core-image-minimal
build/buildhistory/images/raspberrypi3_64/glibc/core-image-minimal/installed-package-sizes.txt
あたりにファイルができているので確認する
24091 KiB kernel-image-image-6.6.63-v8
17361 KiB vim-common
13936 KiB libgtk-3.0
10220 KiB vim-help
10191 KiB systemd
... vim さん、あなた結構ボリューミーなのね。
パッケージの依存関係を調べる
先ほどの buildhistory を有効にして、installed-package-sizes.txt と同じディレクトリにある depends.dot
というファイルで調べられる
graphviz で画像にすると、とても巨大で使い物にならない。grep 等で目的のパッケージを探した方が有用。
トラブルシュート
RDEPENDS が反映されない
アプリレシピ recipes-test/myapp/myapp_1.0.bb
などで、RDEPENDS を使って依存するパッケージを宣言し、成果物に組み込むことができます。python3 をインストールしたい場合:
RDEPENDS:${PN} += "python3"
しかし、この設定はパッケージマネージャ (rpm や dpkg) が管理します。そして core-image-minimal などではインストールされません。結果、宣言してもエラーにもならず無視されます。
そのような場合は local.conf などで、EXTRA_IMAGE_FEATURES += "package-management"
を有効にする必要があります。
ガセだった。パッケージマネージャがなくても反映されます。
IMAGE_INSTALL でパッケージの追加ができない
build/conf/local.conf
に IMAGE_INSTALL:append = " myapp"
のように書いて myapp を追加することができます。
これを以下のようにすると反映されません。
# NG な書き方。理由は分からない...
IMAGE_INSTALL += "myapp"
Discussion