Linuxカーネルをビルドしてみる

2016-07-11

自作OSもくもく会の二回目に参加した。 前回は昔写経していたはりぼてOSを再び動かせるようにして自作OSの仕方を思い出すということをしていたが、今回は趣向を変えてLinuxをビルドするというのをしてみた。

Linuxのビルドの仕方とか全然わかってなかったので、「絶対わかる! Linuxカーネル完全入門」という本の中の、「スクラッチから作る自分だけのOS」という、Linuxのソースをビルドしてディストリビューションを作るという節を参考に作業してみた。

開発環境構築

記事ではFedora 18(32ビット版)を開発環境としているので、同じ環境を用意するためVagrantでセットアップ:

$ vagrant init fedora-18 http://static.stasiak.at/fedora-18-x86-2.box
# Vagrantファイルで共有フォルダの設定を追加する:
# config.vm.synced_folder ".", "/vagrant"
$ vagrant up
$ vagrant ssh
# 開発環境Fedora-18上
$ sudo yum update

再起動が必要とのことなのでその通りにする。

Fedoraに以降のビルドで使う開発ツールをいくつか入れる必要がある:

$ sudo yum install bzip2 gcc perl ncurses-devel libxslt

作業用ディレクトリ作成

以降は開発環境で、rootユーザに移って行う。

作業用のディレクトリ/usr/local/sourceと、生成先ディレクトリ/usr/local/mylinuxを作成する:

# mkdir -p /usr/local/source
# mkdir -p /usr/local/mylinux

ソースのダウンロード

カーネルのソースとして、glibc(Cライブラリ)、BusyBox(コマンド集)、kmod(モジュールローダーツール)、Kernelをビルドする。それぞれのtarをダウンロードするんだけど、本に書いてあるURLから変わってhttpsに置くようになったみたい:

wgetで取得するなりブラウザ上で取得してVagrantにぶち込むなり、好きなように。

/usr/local/source にtar.bz2を配置する。

ソースファイルの展開

# cd /usr/local/source
# tar xjvf glibc-2.16.0.tar.bz2
# tar xjvf busybox-1.21.0.tar.bz2
# tar xjvf kmod-12.tar.bz2
# tar xjvf linux-3.8.5.tar.bz2
# cd linux-3.8.5
# make mrproper
# make headers_check
# make INSTALL_HDR_PATH=header headers_install # カーネルにヘッダーファイルを作成

glibcのコンパイル

本によると、「展開したソースをそのままコンパイルすると途中でエラーが発生する」とのことでパッチを当てる必要があるらしいんだけど、ウェブで公開していたというパッチファイルが消えていたのでそのままビルドさせる。

ソースを展開したディレクトリとは別に作業用のディレクトリを作成し、その中でビルドする:

# mkdir -p /usr/local/source/glibc-work
# cd /usr/local/source/glibc-work
# ../glibc-2.16.0/configure --prefix=/usr --without-selinux --disable-profile \
--enable-add-ons --enable-kernel=3.6.10 \
--with-headers=/usr/local/source/linux-3.8.5/header/include \
libc_cv_forced_unwind=yes libc_cv_c_cleanup=yes
# make

特に何もエラーは出ずに、コンパイルが成功した。

コンパイルできたら/usr/local/mylinuxにインストール:

# mkdir -p /usr/local/mylinux/etc
# touch /usr/local/mylinux/etc/ld.so.conf
# make install_root=/usr/local/mylinux install

BusyBoxのコンパイル

# cd /usr/local/source/busybox-1.21.0
# make defconfig
# make

インストール:

# make CONFIG_PREFIX=/usr/local/mylinux install

kmodのコンパイル

# mkdir -p /usr/local/source/kmod-work
# cd /usr/local/source/kmod-work
# ../kmod-12/configure --prefix=/usr --exec-prefix=/usr/local/mylinux \
--sysconfdir=/usr/local/mylinux/etc
# make
# make install

kmod内のコマンドがBusyBoxにリンクされているので、リンクを修正する必要がある:

# cd /usr/local/mylinux/sbin
# ln -sf ../bin/kmod depmod
# ln -sf ../bin/kmod insmod
# ln -sf ../bin/kmod lsmod
# ln -sf ../bin/kmod modinfo
# ln -sf ../bin/kmod modprobe
# ln -sf ../bin/kmod rmmod

Kernelのコンパイル

いよいよLinuxカーネルのコンパイルを行う。 その前にビルドの設定をする必要があって、それを現在動かしている開発環境から持ってきてやる:

# cd /usr/local/source/linux-3.8.5
# cp -p /boot/config-3.8.4-202-1.fc18.i686.PAE .config

カーネルのバージョンに、自分でビルドしたという目印を入れる:MakefileEXTRAVERSION = の行を書き換えて、EXTRAVERSION = -mylinuxなどとする。

設定を反映させ、メニューで設定する:

# make oldconfig  # 問い合わせには「Enter」
# make menuconfig

メニューでは、Device Drivers > USB support > USB Mass Storage Supportを*にする。

makeとインストール:

# make
# make INSTALL_MOD_PATH=/usr/local/mylinux modules_install

デバッグシンボルの削除:

# cd /usr/local/mylinux/lib/modules/3.8.5-mylinux/kernel
# du -sh
502M
# find . -name "*.ko" -exec strip -S {} \;
# du -sh
31M

作成したカーネルファイル(bzImage)とSystem.mapファイルをコピー:

# mkdir -p /usr/local/mylinux/boot
# cd /usr/local/source/linux-3.8.5
# cp -p System.map /usr/local/mylinux/boot/
# cp -p arch/x86/boot/bzImage /usr/local/mylinux/boot/3.8.5-mylinux
# chmod 755 /usr/local/mylinux/boot/3.8.5-mylinux

以上でテキストベースのLinuxのコンパイルが終了。本ではこの後USBに焼いて起動、Xウィンドウの導入、と続くんだけど、それらはまた後ほど…。

Tips

  • もくもく会で今日の作業内容ということでLTした。そして「VirtualBoxでコアを複数割り当てて並列コンパイルしたら速い」と聞いた: make -j4