カーネル・rootfs・ブートローダの一括生成
ビルドシステムが「OSを組み立てる」とは、別々に開発されている部品をまとめて作ることを指します。具体的には、ハードを制御するLinuxカーネル(zImageやuImage)、コマンドやライブラリを収めたルートファイルシステム(rootfs)、電源投入直後にカーネルを起動するブートローダ(U-Bootなど)の3つです。Buildrootなら output/images/、Yoctoなら tmp/deploy/images/ボード名/ に、これらが書き込みやすい形式で出力されます。3点が揃って初めて、ストレージに書いて起動できる1つのシステムになります。
ビルドシステムが「OSを組み立てる」と言うとき、実際に行われているのは、別々に開発されている複数の部品をまとめて作り、ひとつの起動可能なまとまりに仕上げることです。概念の節でも触れたとおり、その部品は大きく3つに分かれます。ハードウェアを制御するLinuxカーネル(bs-kernel)、コマンドやライブラリを収めたルートファイルシステム(bs-rootfs)、そして電源投入直後にカーネルを起動するブートローダ(bs-bootloader)です。この節では、それぞれが具体的にどんなファイルとして出力され、どこに置かれるのかを、BuildrootとYoctoの両方について見ていきます。生成物の正体をきちんと知っておくと、続く確認作業や、実機ストレージへの書き込み作業の意味が、ぐっと腑に落ちます。漠然と「イメージができた」で終わらせず、何が何のために作られたのかを押さえましょう。
カーネルイメージ
1つ目のカーネルは、コンパイルされた結果が圧縮されたイメージファイルとして出力されます。Armの世界でよく見るのは zImage(自分自身を展開する機能を備えた圧縮済みカーネル)や、それにU-Boot用のヘッダ情報を付けた uImage です。x86系では bzImage という名前になります。あわせて、ボードのハードウェア構成、つまりどこにどんなデバイスがどう接続されているかを記述したデバイスツリーブロブ、拡張子 .dtb のファイルも一緒に作られることがほとんどです。カーネルはこの .dtb を起動時に参照し、自分が載っている基板の構成を知って、適切なドライバを動かします。同じカーネルでも .dtb を差し替えれば別のボードに対応できる、という柔軟さもここから生まれます。組込みでは「カーネル本体 + .dtb」がセットで起動に必要になる、という点を押さえておくとよいでしょう。なお、本体には組み込まずに後から読み込む形のドライバ(カーネルモジュール、拡張子 .ko)も、必要に応じてrootfsの中へ一緒に配置されます。
ルートファイルシステム
2つ目のルートファイルシステムは、起動後に / としてマウントされる「中身」一式です。中にはBusyBoxによる基本コマンド群、共有ライブラリ、各種設定ファイル、起動スクリプトなどが収められており、これがユーザーやアプリの実際の活動の場になります。/bin や /etc、/lib といった、CLIトラックで見慣れたディレクトリ構成が、ここで一から組み上げられていると考えると分かりやすいでしょう。出力形式は用途によって複数あり、設定に応じて選べます。tar でひとまとめにした rootfs.tar、ext4ファイルシステムのイメージにした rootfs.ext4(またはext2)、フラッシュ向けに読み出し専用で圧縮した rootfs.squashfs、起動初期にメモリ上へ展開して使う initramfs 用の cpio 形式などが代表的です。SDカードにパーティションを切って書き込むなら ext4、内容を変更しない前提でコンパクトに収めたいなら squashfs、というように、ターゲットのストレージの種類と運用方針に合わせて適切な形式を選びます。同じ中身でも、どの容れ物に詰めるかを選べる、というイメージです。
ブートローダと、3点がそろう意味
3つ目のブートローダ(bs-bootloader)は、組込みではU-Bootが定番で、u-boot.bin や u-boot.img といったファイルとして出力されます。電源が入ると、CPUはまずこのブートローダを実行します。ブートローダはハードウェアの最低限の初期化を行ったうえで、ストレージからカーネルとデバイスツリーをメモリに読み込み、起動パラメータ(どのデバイスをルートファイルシステムとしてマウントするか、コンソールをどこに出すか等)を渡して、カーネルへ制御を引き渡します。ここで強調したいのは、この3点がそろって初めて1つの起動可能なシステムになる、ということです。カーネルだけ、あるいはrootfsだけでは、機器は決して立ち上がりません。ブートローダがカーネルを起こし、カーネルがハードを初期化してrootfsをマウントし、その中の最初のプロセス(initやBusyBox)が動き出す——このリレーが順に成立して、ようやく電源を入れれば使える製品になります。どれか1つでもバージョンや設定がかみ合わないと、このリレーはどこかで途切れ、起動の途中で止まってしまいます。
出力先 — BuildrootとYoctoの違い
では、これらの成果物(bs-image)はどこに出力されるのでしょうか。Buildrootの場合は単純で、書き込み対象のイメージはすべて output/images/ にまとまります。ここを覗けば zImage や rootfs.ext4、SDカード用に全体をまとめた sdcard.img などが一覧でき、ls(ls-images)で眺めるだけで何が出来たかを把握できます。一方Yoctoでは、出力先は tmp/deploy/images/ボード名/ という、ボードごとに分かれたディレクトリになります。bitbake(bitbake)でビルドした結果のカーネル・rootfs・ブートローダがここに集まり、ディレクトリがボード名で分かれているため、複数の機種を並行して扱っても成果物を取り違えにくい作りになっています。なお、このディレクトリには、実体ファイルと、それを指す「最新版」を表すシンボリックリンクが併存することが多く、リンクをたどれば常に直近のビルド結果にアクセスできるようになっています。出力先のパスや整理の流儀は両者で違いますが、「カーネル・rootfs・ブートローダが、書き込める形でそろう」という最終的な結果は共通しています。どこに出るかを最初に把握しておけば、ビルド後に成果物を見失わずに済みます。次の節では、これらを書き込む前に点検する具体的な方法を扱います。