✍️

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
myapp_1.0.bb
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 をいじる。

myapp_1.0.bb
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 を唱えれば、よしなに反映してくれる。

mydaemon_1.0bb
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 を参考に、以下のようにした。

wic/custom-wic.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 を作成する

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 はまずいらないと思われるので、無効化します

local.conf
PACKAGECONFIG:remove:pn-python3 = "editline"

あるいは bbappend で

recipes-hoge/python/python3_%.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.confIMAGE_INSTALL:append = " myapp" のように書いて myapp を追加することができます。
これを以下のようにすると反映されません。

# NG な書き方。理由は分からない...
IMAGE_INSTALL += "myapp"

マニュアル等

Discussion