前回のエントリーではWindows10 Homeエディション
でDocker Desktop
をインストールしました。そこで、このDockerを使用して、RaspberryPiのカーネルのクロスコンパイルを行ってみたいと思います。これまではVirtualBoxなどをインストールして環境を整えましたが、Dockerが使えればこれまでよりも軽量サイズに環境設定を整えることができます。
今回はRaspberryPi 4B
とコンテナ側はUbuntu
を使用しています。
参考
コンテナを起動する
Ubuntu
をベースに今回はクロスコンパイルを行うので、以下のようにコンテナを起動します。起動はPowershellで行います。
PS > docker run -it --name 【コンテナ名】 ubuntu
これでコンテナが起動します。
コンテナは起動するとrootユーザーでログインされるので、作業はrootユーザーで行っていきます。公式ページでは一般ユーザーでの設定になっているのでsudo
がついていますが、コンテナでは不要となります。
コンテナ側のUbuntuの事前設定
コンテナ側のOSが立ち上がったらカーネルの構築に必要なパッケージをインストールしていきます。make menuconfig
でカーネルやドライバの設定をしないのであれば、libncurses5-dev
は不要かもしれませんが、モジュール関係の設定ではほとんど使用するので、インストールしたほうが無難です。
必要なパッケージのインストールができたら、RaspberryPiのカーネルを構築するツールチェーンのインストールを行っています。ツールチェーンがインストールできたら、.bashrc
にパスを追加しておきます。
コンテナ側での操作
# cd # apt update # apt install git bc bison flex libssl-dev make libc6-dev libncurses5-dev # git clone https://github.com/raspberrypi/tools ~/tools # echo PATH=\$PATH:~/tools/arm-bcm2708/arm-linux-gnueabihf/bin >> ~/.bashrc # source ~/.bashrc
カーネルソースの取得とconfigファイルの作成
カーネルソースをgitでクローンしていますが、大きくなってしまうので--depth=1
を追加しています。これでcloneの対象を最新のコミットのみに限定して取得しサイズの大きさを軽減しています。
# git clone --depth=1 https://github.com/raspberrypi/linux # cd linux
configファイルの作成を行いますが、以下が使用するRaspberryPiの機種によって内容が異なります。今回はRaspberryPi 4Bを使用するので以下のようにします。
# KERNEL=kernel7l # make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2711_defconfig
その他機種は公式ページにかかれている以下のようになります。
Raspberry Pi 1, Pi Zero, Pi Zero W, and Compute Module default build configuration
# cd linux # KERNEL=kernel # make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcmrpi_defconfig
Raspberry Pi 2, Pi 3, Pi 3+, and Compute Module 3 default build configuration
# cd linux # KERNEL=kernel7 # make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig
Raspberry Pi 4 default build configuration
# cd linux # KERNEL=kernel7l # make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2711_defconfig
カーネルのコンフィギュレーションを行う必要がある場合には以下のコマンドのmenu形式での修正を行います。現時点では修正箇所はないので、このまま起動せず、コンパイル作業を行っていくことにします。
# make menuconfig
また、再構築したカーネルの名前が同じ担ってしまうことを防ぐため、MakefileのEXTRAVERSION
パラメータ(エクストラバージョン)を変更しておくと、変更後のカーネルで起動後にuname
コマンドで表示されるバージョン名をつけることができます。今回は以下のようにしてみました。
Makefile編集後
# SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 19 SUBLEVEL = 127 EXTRAVERSION = uepon #この部分を編集するとunameコマンドの表示に反映される (略)
カーネルコンパイル
以下の様に実行すれば、コンパイルが行われます。
# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs
さらに-j
オプションをつけることで並列でコンパイルすることができます。公式のドキュメントによればCPUのコア数の1.5倍までの数値を指定可能のようです。今回使用しているPCをのCPUがCore i7
の第4世代のものを使用しているので4コア8論理プロセッサとなっています。
そこで論理プロセッサ数である-j8
と論理プロセッサ数の1.5倍の値である-j12
を指定してみました。
ただ、時間がどの程度かかったのかを調べるので今回はtime
コマンドを使用しています。
-j8指定時
# time make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs -j8
(中略)
real 16m24.398s
user 109m33.360s
sys 9m58.042s
-j12指定時
# time make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs -j12
(中略)
real 14m48.798s
user 106m4.135s
sys 8m55.342s
-j8
では16分、-j12
では14分でした。RaspberryPi実機ではかなりかかったような気がしますが、仮想環境でのクロスコンパイルではこの程度で終了するとは!かなり短くて助かりますね!-j8
の場合にはCPU負荷は100%まで行きませんでしたが、-j12
では100%近くまでいっていました。ドキュメントの最適値は割と当たっているようです。
Dockerコンテナ作業による制限
あとは、出来上がったカーネルをRaspberryPi側に転送しなければいけないのですが、公式のドキュメントではRaspberryPiのSDカードメモリをマウントして転送するという形になるのですが、DockerのコンテナはSDカードメモリをマウントすることができません。そこで、ホストPC(Windows10)と共有ディレクトリを設定して、ファイルをそちらにコピーしてからSDカードメモリへ転送しようと思います。
ただ、既に作成したコンテナでホスト側のディレクトリをマウントする方法を探してみたのですが、どうも無いようです。
DockerとホストPCとのファイル共有を行う
docker run
などで作成したコンテナは、作成後後は変更できません。この場合には一度、コンテナをdocker commit
を使用して、イメージ化して、再度docker run
することでrun
時のオプションを変更(ホスト側のディレクトリをマウントすることも)できます。
PS > docker stop 【コンテナ名】 PS > docker commit 【コンテナ名】 【イメージ名】 PS > docker run -v /c/Users/【ユーザー名】/Documents/workspace:/data/workspace -it --name 【新規コンテナ名】 【イメージ名】
これでDockerのホストのWindows10とコンテナのUbuntuでファイルの共有ができるようになりました。今回はWindows側のC:/Users/【ユーザー名】/Documents/workspace
をUbuntu側の/data/workspace
にマウントしています。
では引き続きDockerコンテナで操作を行っていきます。最初からマウントすることができていれば、先程の作業は不要です。ではコンテナ側で以下の作業を行っていきます。
今回はコンパイル結果を/data/workspace/fat32(/bootに相当)
と/data/workspace/ext4(/に相当)
に格納して行きます。(公式ドキュメントでマウントするディレクトリ名似合わせています)
途中でkmod
というパッケージをapt install
していますが、これを行わないとモジュールのコンパイル(modules_install
)でdepmod
コマンドがないというエラーが出力されます。当然入っているものだと思っていたので少し驚きましたが、こちらインストールしておきましょう。
コンテナ側での操作
# cd linux # KERNEL=kernel7l # mkdir /data/workspace/fat32 # mkdir /data/workspace/ext4 # mkdir /data/workspace/fat32/overlays/ # apt install kmod # env PATH=$PATH make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=/data/workspace/ext4 modules_install # cp arch/arm/boot/zImage /data/workspace/fat32/$KERNEL.img # cp arch/arm/boot/dts/*.dtb /data/workspace/fat32/ # cp arch/arm/boot/dts/overlays/*.dtb* /data/workspace/fat32/overlays/ # cp arch/arm/boot/dts/overlays/README /data/workspace/fat32/overlays/
これでコンパイルしたカーネルとモジュールは共有したディレクトリに格納されます。
RaspberryPi側でカーネル、モジュールなどの置き換え
あとはRaspberryPi側を起動してファイルの置き換えを行っていきます。 SDカードを挿入してコピーするというのもありですが、今回はRaspberryPiを起動して対応してみます。(ext4のフォーマットのSDカードへの書き込みができるかわからなかったのでこのようにしています)
RaspberryPi 4Bでの操作
まずはscpなどで先程作成したファイルを/home/piにコピーしておきます。
自分が使用しているrlogin
というコンソールアプリはscp機能をGUI操作できるのでかなり楽でした。
C:/Users/【ユーザー名】/Documents/workspace/fat32/
(コピー元) →/home/pi/fat32/
(コピー先)C:/Users/【ユーザー名】/Documents/workspace/ext4/
(コピー元) →/home/pi/ext4/
(コピー先)
ではあとは規定場所にコピーを行います。
$ KERNEL=kernel7l $ sudo cp /boot/$KERNEL.img /boot/$KERNEL-backup.img $ sudo cp /home/pi/fat32/$KERNEL.img /boot/$KERNEL.img $ sudo cp /home/pi/fat32/*.dtb /boot/ $ sudo cp /home/pi/fat32/overlays/*.dtb* /boot/overlays/ $ sudo cp /home/pi/fat32/overlays/README /boot/overlays/ $ sudo cp -r /home/pi/ext4/* /
再起動&確認
コピーが終わったらRaspberryPiを再起動します。
$ sudo reboot
無事起動できたら、uname
コマンドで今回作成したカーネルか確かめてみます。
$ uname -a Linux raspberrypi 4.19.127uepon-v7l+ #1 SMP Thu Jun 18 14:14:39 UTC 2020 armv7l GNU/Linux
やりました!無事成功です!
ちゃんと差し替えたカーネルで起動しています! カーネルのクロスコンパイルは成功しました。中身は何も変わっていませんがw
おわりに
とりあえず、カーネルのクロスコンパイルがDockerのコンテナでできるようになりました。何かあればこちらで対応できそうです。Windows HomeでもDockerが動作するようになったので、RaspberryPiのカーネルのクロスコンパイルもOSによるハードルが下がりました。Dockerなので、かなりコンパクトに環境を保存しておけるのもいいですね。
これをやろうとした当初、カーネルコンパイルしないと対応されていなかったものがあったのですが、RaspberryPiのバージョンアップにより、デフォルトでの対応がなされてしまい、カーネルの再コンパイルの必要性はなくなってしまいました。最近は対応が早いので、この手法も必要があまりないのかもしれません。
Windows10の今回のアップデートはかなり助かる機能が増えた印象です。多分不具合もあるんでしょうけどね。