Yocto Projectの初回ビルドに数時間かかって絶望した経験、あなたにもあるはず。core-image-sato を何も設定せずにビルドすると、マシンスペックによっては半日以上かかることもある。
この記事では、Yocto Scarthgap 5.0 LTS(2028年4月までサポート)をベースに、ビルド時間を劇的に短縮するテクニックを優先度順に紹介する。「何から手をつければいいかわからない」という人は、上から順番に試すだけでいい。
なぜYoctoのビルドは遅いのか
原因を理解しないまま対策しても効果は薄い。まずYoctoビルドのボトルネックを整理しよう。
Yoctoのビルドシステム(BitBake)は、数千のタスクを依存関係に従って実行する。core-image-sato の場合、約6GBのソースコードをダウンロードし、数千のパッケージをコンパイルする。このプロセスで主にボトルネックになるのは3つだ。
1. ストレージI/O
ビルド中に大量のファイルを読み書きする。HDDでビルドしているなら、これが最大のボトルネック。NVMe SSDに変えるだけで体感が変わる。
2. CPU並列度の設定ミス
BitBakeはデフォルトでCPUコア数を自動検出して並列ビルドするが、RAMが足りないとOOM Killerに殺される。逆に並列度を下げすぎるとCPUが遊ぶ。
3. キャッシュの未活用
2回目以降のビルドで sstate-cache(Shared State Cache)を活用すれば、変更のないタスクはスキップできる。しかしデフォルト設定のまま使うと、ビルドディレクトリを消すたびにキャッシュも消える罠がある。
ハードウェア要件を見直す
ソフトウェアの設定を変える前に、まずハードウェアを見直そう。公式ドキュメントが示す最低要件と、実用上の推奨スペックには大きな開きがある。
| 項目 | 公式最低要件 | 実用上の推奨 |
|---|---|---|
| RAM | 8 GB | 32 GB 以上 |
| ディスク | 90 GB(core-image-sato) | 500 GB NVMe SSD |
| CPU | 4コア | 8〜12コア |
RAMの考え方
BitBakeの並列タスク数(BB_NUMBER_THREADS)× 約2GBがビルド中に必要になる。8スレッド並列なら16GB、それに加えてOSやページキャッシュ用のメモリが必要だから、32GBは確保したい。
64GBあれば多くのファイルがOSのページキャッシュに乗り、I/O待ちが減る。
CPUの考え方
Yoctoのビルドは約12コアまでスケールするが、それ以上はI/Oがボトルネックになって効果が頭打ちになる。クロック周波数の高い8〜12コアのCPUが最もコストパフォーマンスが良い。
ストレージの考え方
HDDからNVMe SSDへの変更が最も効果が大きい。 ビルド中の大量の小さなファイルの読み書きでHDDは完全にボトルネックになる。SATA SSDでも改善するが、NVMe SSDなら更に速い。
rm_work クラスを使わない場合、core-image-sato のビルドには約90GBのディスク容量が必要になる。rm_work を有効にすれば約22GBまで削減できるが、それでも500GB以上のSSDがあると余裕を持って複数プロジェクトを扱える。
sstate-cacheで2回目以降を80%短縮
sstate-cache(Shared State Cache)は、Yoctoビルドを高速化する最も効果の高い仕組みだ。一度ビルドしたタスクの出力を保存し、入力が変わっていなければ再利用する。
デフォルト設定の罠
デフォルトでは sstate-cache はビルドディレクトリ内に作られる。
# デフォルトの保存先(build/ 以下)
build/sstate-cache/
build/downloads/
問題は、rm -rf build/ でビルドディレクトリを削除すると キャッシュも一緒に消える こと。新しいブランチを試すためにビルドディレクトリを消す、というのはYocto開発でよくある操作だ。
キャッシュを外部に出す
conf/local.conf に以下を追加する。
# conf/local.conf
SSTATE_DIR = "/home/shared/yocto/sstate-cache"
DL_DIR = "/home/shared/yocto/downloads"
これだけで、ビルドディレクトリを削除してもキャッシュは保持される。複数プロジェクトが同じキャッシュを共有できるので、プロジェクト間でも2回目以降のビルドが高速になる。
チームでキャッシュを共有する
チーム開発では、1台のサーバーにsstate-cacheを置いてHTTP/NFS経由で共有すると、全員が高速なリビルドの恩恵を受けられる。
# conf/local.conf — リモートミラーからキャッシュを取得
SSTATE_MIRRORS = "file://.* http://sstate-server.local/sstate/PATH;downloadfilename=PATH"
PATH はYoctoが自動的に展開する特殊な変数で、アーキテクチャ固有のディレクトリパスに置き換わる。
ソースコードのミラーも同様に設定できる。
# conf/local.conf — ソースミラー
SOURCE_MIRROR_URL = "http://mirror-server.local/sources/"
INHERIT += "own-mirrors"
BB_GENERATE_MIRROR_TARBALLS = "1"
BB_GENERATE_MIRROR_TARBALLS = "1" を設定すると、Gitリポジトリのソースもtarball化して DL_DIR に保存する。デフォルトでは無効になっているが、オフラインビルドやチーム共有には必須だ。
BB_NUMBER_THREADSとPARALLEL_MAKEの最適値
BitBakeの並列度を制御する変数は2つある。混同しやすいが、役割が違う。
| 変数 | 制御対象 | デフォルト |
|---|---|---|
BB_NUMBER_THREADS | BitBakeタスクの並列実行数 | CPUコア数(自動検出) |
PARALLEL_MAKE | make のジョブ並列数(-j N) | CPUコア数(自動検出) |
デフォルトはどちらもCPUコア数に自動設定される。meta/conf/bitbake.conf で以下のように定義されている。
BB_NUMBER_THREADS ?= "${@oe.utils.cpu_count()}"
PARALLEL_MAKE ?= "-j ${@oe.utils.cpu_count()}"
なぜ調整が必要なのか
デフォルトの自動検出は「コア数が全部使える」前提だが、RAMが足りない場合はOOM Killerに殺される。逆にRAMに余裕があるなら、デフォルトのままで問題ない。
調整する場合の設定
# conf/local.conf — 例: 8コア / 32GB RAM
BB_NUMBER_THREADS = "8"
PARALLEL_MAKE = "-j8"
注意点: BB_NUMBER_THREADS だけ下げても PARALLEL_MAKE が高いままだと、個々のmakeプロセスが大量のスレッドを使ってRAMが溢れる。両方セットで調整する こと。
Pressure-based制御(Langdale 4.1以降)
Langdale(4.1)以降のBitBakeでは、固定値ではなくシステム負荷に基づいて動的に並列度を調整する変数が使える。Scarthgapでも利用可能だ。
# conf/local.conf — 負荷ベースの動的制御
BB_PRESSURE_MAX_CPU = "150"
BB_PRESSURE_MAX_IO = "80"
BB_PRESSURE_MAX_MEMORY = "50"
これはLinuxの /proc/pressure/ を利用してCPU/IO/メモリのプレッシャーを監視し、閾値を超えたら新しいタスクの開始を遅らせる仕組みだ。固定値よりも柔軟で、ハードウェア構成を変えても再調整の手間がない。
ファイルシステムとストレージの最適化
NVMe SSDを使っている場合でも、ファイルシステムの設定次第で更にパフォーマンスが上がる。
マウントオプション
公式ドキュメントが推奨するのは noatime と commit= の設定だ。
# /etc/fstab — ビルド用パーティション
/dev/nvme0n1p2 /home/build ext4 defaults,noatime,commit=30 0 2
- noatime: ファイルアクセス時刻の更新を無効化。大量の小さなファイルを読むビルドでは効果がある
- commit=30: ディスクへの書き込み間隔をデフォルトの5秒から30秒に延長。停電リスクは増すが、ビルド中の書き込み頻度が減る
tmpfsの利用(効果は限定的)
TMPDIR をtmpfs(RAMディスク)に置くと速くなると思うかもしれないが、公式ドキュメントはこう述べている。
"While this can help speed up the build, the benefits are limited due to the compiler using
-pipe."
コンパイラが -pipe オプションを使うため、中間ファイルをディスクに書き込まない設計になっている。64GB以上のRAMがあり、他の最適化を全て適用した後の最後の手段として試す価値はあるが、優先度は低い。
パッケージング形式の選択
PACKAGE_CLASSES のデフォルトは package_rpm(RPM形式)だ。
# conf/local.conf — IPKは最も軽量
PACKAGE_CLASSES = "package_ipk"
IPK形式はRPMより軽量で、パッケージング処理が速い。組み込み用途ではIPKが一般的なので、特にRPMにこだわる理由がなければIPKに変更しよう。
不要機能を削ってビルドを軽くする
Yoctoのデフォルト設定には、組み込み用途では不要な機能が多数含まれている。ビルド対象を減らすことで、ビルド時間とイメージサイズの両方を削減できる。
DISTRO_FEATURESの削減
Scarthgapのデフォルト DISTRO_FEATURES には以下が含まれている。
# Pokyデフォルトの DISTRO_FEATURES(Scarthgap)
# acl alsa bluetooth debuginfod ext2 ipv4 ipv6 pcmcia usbgadget
# usbhost wifi xattr nfs zeroconf pci 3g nfc x11 vfat seccomp
# + Poky追加分: opengl ptest multiarch wayland vulkan
ヘッドレスの組み込みデバイスなら、GUI関連は全て不要だ。
# conf/local.conf — ヘッドレス構成の例
DISTRO_FEATURES:remove = "x11 wayland opengl vulkan bluetooth wifi 3g nfc pcmcia"
rm_workでディスク使用量を削減
ビルド後のワークディレクトリを自動削除する rm_work クラスを使うと、ディスク使用量が劇的に減る。
# conf/local.conf
INHERIT += "rm_work"
# デバッグしたいレシピは除外できる
RM_WORK_EXCLUDE += "my-custom-recipe"
公式の数字では、core-image-sato のビルドで 90GB → 約22GB まで削減される。ディスクキャッシュに乗るデータが増えるので、間接的にビルド速度も向上する。
デメリットはビルド後のソースコードやオブジェクトファイルが消えるため、デバッグが困難になること。RM_WORK_EXCLUDE で調査対象のレシピを除外しておこう。デバッグの具体的な手順はビルドエラーデバッグガイドで解説している。
デバッグパッケージと静的ライブラリの無効化
# conf/local.conf
INHIBIT_PACKAGE_DEBUG_SPLIT = "1"
デバッグシンボルの分割パッケージを生成しなくなる。プロダクション向けイメージでは不要な場合が多い。
VPSビルドサーバーという選択肢
手元のラップトップでYoctoをビルドすると、他の作業ができなくなる。VPSをビルドサーバーとして使えば、手元の環境を圧迫せずにビルドできる。
なぜVPSが合うのか
- 高スペックを必要なときだけ使える: 16コア / 32GB RAMのマシンを常時持つ必要がない
- sstate-cacheをサーバーに蓄積: チームで共有すればコスト以上のリターンがある
- CI/CDとの統合: GitHub ActionsやGitLab CIからビルドサーバーに接続する構成も作れる
推奨スペック
Yoctoのフルビルドには最低でも8コア / 32GB RAMが欲しい。以下のスペックを目安にしよう。
| 用途 | CPU | RAM | ストレージ |
|---|---|---|---|
| 最小構成(core-image-minimal) | 4コア | 16 GB | 100 GB SSD |
| 標準構成(core-image-sato) | 8コア | 32 GB | 300 GB SSD |
| 大規模・チーム共有 | 16コア | 64 GB | 500 GB+ NVMe |
初期費用無料・時間課金で始められるVPS
- 1GBプラン 月額468円〜(36ヶ月)
- 初期費用無料・時間課金あり(2.5円/時)
- SSD 100GB・仮想2コア
老舗の安定感。エンコード用途にも使える国内VPS
- 2GBプラン 月額1,594円〜(石狩)
- 東京・大阪・石狩の3リージョン
- SSD 100GB・仮想3コア
VPS上のセットアップ手順
Ubuntu 24.04 LTSの場合、必要なパッケージは以下の通り。
sudo apt update
sudo apt install -y gawk wget git diffstat unzip texinfo gcc build-essential \
chrpath socat cpio python3 python3-pip python3-pexpect xz-utils debianutils \
iputils-ping python3-git python3-jinja2 python3-subunit zstd liblz4-tool \
file locales libacl1
sudo locale-gen en_US.UTF-8
その後、pokyをクローンしてsstate-cacheを外部パスに設定すれば、すぐにビルドを開始できる。
git clone git://git.yoctoproject.org/poky
cd poky
git checkout -t origin/scarthgap -b my-scarthgap
source oe-init-build-env
# conf/local.conf に sstate-cache と DL_DIR の外部パスを設定
echo 'SSTATE_DIR = "/home/build/sstate-cache"' >> conf/local.conf
echo 'DL_DIR = "/home/build/downloads"' >> conf/local.conf
bitbake core-image-minimal
まとめ
Yoctoのビルド高速化は、効果の大きいものから順に取り組むのが鉄則だ。
| 優先度 | テクニック | 効果 |
|---|---|---|
| 最優先 | sstate-cache/DL_DIRを外部に出す | 2回目以降80%以上短縮 |
| 高 | NVMe SSDへの変更 | I/Oボトルネック解消 |
| 高 | BB_NUMBER_THREADS/PARALLEL_MAKE調整 | OOM回避・CPU利用率最適化 |
| 中 | rm_work有効化 | ディスク90GB→22GB |
| 中 | DISTRO_FEATURES削減 | ビルド対象のパッケージ数削減 |
| 中 | PACKAGE_CLASSES をIPKに変更 | パッケージング処理の高速化 |
| 低 | noatime/commit= 設定 | 小〜中程度の改善 |
| 低 | tmpfs | 効果は限定的(公式見解) |
最初の一歩として、sstate-cacheとDL_DIRを外部に出すだけで、日常的なリビルドの体験が劇的に変わる。そこから先は必要に応じてチューニングを進めていけばいい。
Yoctoのビルド環境をもっと深く知りたい人には、以下の書籍がおすすめだ。特に『Mastering Embedded Linux Development』はScarthgapに対応した最新版で、ビルドシステムの仕組みから実践的なレシピの書き方まで網羅している。