Linuxカーネル(2.6系)のビルドの流れ
(2014/9/22)本記事の手順はカーネル3.x系についても同様となる。ブートローダについてはGRUB Legacy(GRUB 1)についてを扱っているが、GRUB 2ではカーネルは自動検出されて起動するための項目群は自動的に生成される。「ヘルパースクリプトを使用した場合のGRUB 2(1.96)の設定方法(全般とカーネル関係)」も参照。
- ソースの入手・展開
- 必要に応じてパッチ当て
- 必要に応じてバージョン番号(EXTRAVERSION)を付ける
- ビルド設定のコピー
- ビルドの設定
- 組み込みとモジュール
- 設定のヒント
- ビルドとインストール
- ビルド後のソースツリー
ソースの入手・展開
確実に、ディストリのパッケージになっている。Debian,Ubuntuでは「linux-source」、Gentoo Linuxでは種類によりパッケージ名が異なるが、通常は「gentoo-sources」。展開は、自動的にされるディストリとされないディストリとがあるが、Debian,Ubuntuでは、ソースのtar.bz2ファイルが置かれるようなので、これを手動で展開する。
展開場所は/usr/src/以下が一般的。更に、
$ ls -l /usr/src/ 合計 36 lrwxrwxrwx 1 root root 21 2007-07-17 22:23 linux -> linux-2.6.22-suspend2 drwxr-xr-x 20 root root 4096 2007-07-14 21:40 linux-2.6.22-gentoo-r1 drwxr-xr-x 20 root root 4096 2007-07-21 20:38 linux-2.6.22-suspend2
のように、新しく使用するソースツリーにリンクを張る。Gentoo Linuxでは展開までを行い、「symlink」のUSEフラグを付けると、/usr/src/linuxのシンボリックリンクまで作ってくれる。
必要に応じてパッチ当て
ディストリのカーネルソースパッケージは色々な修正が入っているのだが、その中に入っていないパッチを当てたい場合、ここで当てる。パッチを当てる際には、対象ファイルのある階層が重要なので、注意する。パッチファイルの先頭が
--- linux-2.6.22/Documentation/kernel-parameters.txt 2007-07-11 22:18:38.000000000 +1000 +++ suspend2-2.2.10-for-2.6.22/Documentation/kernel-parameters.txt 2007-07-11 22:25:42.000000000 +1000
のようになっている場合、1番目のディレクトリ(suspend2-2.2.10-for-2.6.22/)を省く。ディレクトリ階層を省くには、patchコマンドの-p[省略したい階層数]オプションを使う。下は、bzip2圧縮されたパッチで1階層削った例。/path/to/filename.patch.bz2は、実際のファイル名に合わせる。
# cd /usr/src/linux # bzcat /path/to/filename.patch.bz2 | patch -p1
gzip圧縮されている場合はzcatで.patch.gzファイルを指定し、圧縮されていないファイルの場合、
# patch -p1 < /path/to/filename.patch
のようにして直接読み込む。
なお、パッチファイルの拡張子は.patchであることが多いが、.diffとなっている場合もある。中身は同じ形式。
処理が開始されて
patching file [ファイル名]
という行だけが出て終了した場合は成功。
Hunk #2 succeeded at 1215 (offset -2 lines).
というようなメッセージが出る場合も、適用場所が何行目なのかがずれていたりするだけで、適用自体は問題なく済んでいる。*1
Hunk #1 FAILED at 28. Hunk #2 succeeded at 3312 (offset 186 lines). 1 out of 2 hunks FAILED -- saving rejects to file block/ll_rw_blk.c.rej
のように、「FAILED」が出ている場合は失敗で、.rejファイルに、適用の失敗した領域(Hunk)が書き出される。
必要に応じてバージョン番号(EXTRAVERSION)を付ける
/usr/src/linux/Makefileの先頭に、VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 22 EXTRAVERSION = -suspend2
のようなバージョン表記があり、unameコマンドで出力されるバージョン情報や、カーネルモジュールの場所(/lib/modules/[バージョン])、/boot/以下の
- System.map-[バージョン]
- config-[バージョン]
- vmlinuz-[バージョン]
といったファイル/ディレクトリ名の一部にも使われる。
同じバージョンのカーネルを使って、設定を別のものにしてビルドする場合、上記のEXTRAVERSIONの部分を変えることで、異なるバージョン表記にすることができる。これは設定の試行錯誤をするときなどに便利。
ビルド設定のコピー
カーネルビルドの設定は、/usr/src/linux/.configというファイルに書き出され、使用される。ディストリのカーネルを使っている場合、設定ファイル/boot/config(-[バージョン])を/usr/src/.configとしてコピーすると、そのカーネルと同じ設定から始められる。
# cp /boot/config /usr/src/config
もしくは、
General setup ---> <*> Kernel .config support [*] Enable access to .config through /proc/config.gz
というように設定しておくことで、動作中のカーネルの設定を
# zcat /proc/config.gz > .config
として出力させることもできる。
ビルドの設定
下は、設定ファイル/usr/src/linux/.configを含めて、ビルド時に生成された全てのファイルを消す。ディストリのカーネルソースパッケージでは、この作業が必要な場合がある。# make HOSTCXX="ccache g++" CC="ccache gcc" mrproper
設定ファイルはそのままで、生成されたファイルだけ消すには
# make HOSTCXX="ccache g++" CC="ccache gcc" clean
を実行。その他に、distcleanというターゲットもあるが、通常は、上の2つで事足りる。
下は、既存の設定/usr/src/linux/.configを読み込んで、新しく追加された設定項目のみ設定する方法。一度設定を作ってしまえば、カーネルのバージョンが新しくなったときにこれを指定することで、追加された機能を設定しつつ、その他の設定は保持できる。
# make HOSTCXX="ccache g++" CC="ccache gcc" oldconfig
下は、端末上で動作する設定ツールで設定する方法。ncursesライブラリ(開発ファイル含む)が必要。
# make HOSTCXX="ccache g++" CC="ccache gcc" menuconfig
Xを使っている場合のみ、GTK+ 2やQt 3といったGUIツールキットライブラリ(開発ファイル含む)を使用したGUI設定ツールで設定ができる。それぞれ
# make HOSTCXX="ccache g++" CC="ccache gcc" gconfig
と
# make HOSTCXX="ccache g++" CC="ccache gcc" xconfig
となる。
組み込みとモジュール
幾つかの項目は、有効/無効の二択以外に、有効/モジュール/無効という三択の設定ができる。モジュールというのは、使用されていないときには読み込まれず、その機能を使いたいときに読み込んで使う形式。有効にしたものは、カーネルに組み込まれ、常にその機能が使える。menuconfigでは「< >」というかっこになっているものがモジュールにできるもの(「<M>」がモジュール、「<*>」が組み込み)。xconfigではチェックボックスを何回かクリックして、四角の中に丸(サイコロの1のような形)になるものがそう。
設定のヒント
カスタムカーネルを作成する場合、初期RAMディスクイメージ(initrd)は使わないで済むようにできる(下のインストール手順でも触れていない)。その際に注意するのが、- 起動するハードディスクに関連したコントローラ(PATA/SATA)のデバイスドライバが組み込みになっているか
- 起動するパーティションのファイルシステムのサポート(ext3など)が組み込みになっているか
といった辺りで、ディストリのカーネルの設定をそのまま使用しようとすると、ext3パーティションがマウントできない、などの理由でカーネルパニックになってしまったりすることがある。*2
その他、環境に合った設定を目指すためのヒントになるかもしれないことを幾つかメモ。
- 使用していないデバイスのドライバは、モジュールにしていても、ビルド時間・電力・ディスク領域を無駄にするだけなので、なるべく減らすのがよい。
- デバイスドライバに関しては、確実に「必要ない」と言えるものに関しては無効にして、よく分からないものに関してはモジュールにしておく(モジュールにできないものは有効にする)。
- 新しいカーネルで動作に支障が無ければ、更に絞っていくことを繰り返す。ただし、一度に沢山の項目を無効にしすぎないで、段階的に減らしていく。
- どのデバイスドライバが必要かよく分からないとき、ディストリのカーネル*3を使用していれば、lsmodで、使用されているモジュール名を見て、設定の参考にする。
- 設定ファイルは、こまめにファイルに書き出す。バージョン(「2.6.xx」の「xx」部分)が上がったときも、古いバージョン向けのファイルとは別に新しく設定ファイルを書き出す。
ビルドとインストール
# make HOSTCXX="ccache g++" CC="ccache gcc"
ビルドしているカーネルと同一バージョンのモジュールが/lib/modules/以下にある場合、削除してからモジュールをインストールする。そうでなければこれはする必要がない。
# rm /lib/modules/[バージョン]/ -fr
# make HOSTCXX="ccache g++" CC="ccache gcc" modules_install
installターゲットは、/boot/以下に
- System.map-[バージョン]
- config-[バージョン]
- vmlinuz-[バージョン]
をインストールし、更に
- /boot/System.map
- /boot/config
- /boot/vmlinuz
のシンボリックリンクを最新のファイルに張る。既に同名のファイルがあるものは[元のファイル名].oldと名前変更される。もう一度installをしてしまうと、.oldファイルだったものは上書きされて無くなってしまう。
# make HOSTCXX="ccache g++" CC="ccache gcc" install
カーネル自身を手動でコピーしたい場合、
# cp arch/[i386やx86_64など]/boot/bzImage /boot/vmlinuz-2.6.xx
のようにする。
いずれの方法でカーネルをインストールしても、grubブートローダの設定は行われないため、設定ファイル/boot/grub/menu.lstのkernel行で
title Linux new root (hd0,x) kernel /vmlinuz root=... boot title Linux old root (hd0,x) kernel /vmlinuz.old root=... boot
のように、シンボリックリンクに対して設定しておけば、直前のカーネル(/boot/vmlinuz.old)でも起動できるようにしつつ、最新カーネル(/boot/vmlinuz)も使え、カーネルの更新ごとにkernel行を書き換えたりする必要もなくなる。