シェルのワンライナーでNetBSDのカーネルビルド環境を作る方法

[NetBSD Advent Calendar 2018](https://qiita.com/advent-calendar/2018/netbsd) 13日目の記事です。
今日はNetBSDのカーネルビルド環境を手早く用意する手順を紹介しようと思います。

## NetBSDのカーネルビルド環境

[NetBSD Advent Calendar](https://qiita.com/advent-calendar/2018/netbsd)を書いていると、実験用に手早くNetBSDのカーネルビルド環境が欲しくなる時があります。

[NetBSDインストール](https://qiita.com/furandon_pig/items/8b7d13a119067098d561)は配布パッケージも小さいことから文字通りものの数分で仮想マシン上にインストールできてしまいます。そこにカーネルのビルド環境を構築すれば準備万端なのですが、その手順が手元のメモに埋もれていました。
そこで今日の記事では、自分の備忘録を兼ねたNetBSDカーネルビルド環境の構築手順になります。

## ワンライナーでNetBSDのカーネルビルド環境構築

実際にカーネルビルド環境を構築するワンライナーは以下になります。これをNetBSD環境上でrootとして実行して数分待つと、カーネルビルド環境ができあがります。
(あらかじめ `pkg_add curl` しておいてください)

```sh
for src in gnusrc.tgz sharesrc.tgz src.tgz syssrc.tgz xsrc.tgz
do
   [ ! -f ${src} ] && curl -s -O http://ftp.jaist.ac.jp/pub/NetBSD/NetBSD-8.0/source/sets/${src}
   tar zxvf ${src} -C /
done && cd /usr/src && ./build.sh -m amd64 -a x86_64 -T /usr/src/tooldir.NetBSD-8.0-amd64 -r -o -U tools
```

NetBSDのカーネルソースは、例えば以下のURL等で配布されており、上記のワンライナーはソースアーカイブをここからダウンロードしてきています。

 * [http://ftp.jaist.ac.jp/pub/NetBSD/NetBSD-8.0/source/sets/](http://ftp.jaist.ac.jp/pub/NetBSD/NetBSD-8.0/source/sets/)

ワンライナーでの処理内容は以下になります。単に毎回手動で実行しているコマンドを一行にまとめた形になります。

 * カーネルソースのダウンロード
 * tgzファイルの展開( `/usr/src` )
 * ツールチェインのビルド

しばらく待つと、以下のようにツールチェインが生成された状態になります。
(Core-i5クラスのCPUであれば、VitrualBox＋NetBSDな環境でも20分程度でビルドが完了します)

```sh 
for src in gnusrc.tgz sharesrc.tgz src.tgz syssrc.tgz xsrc.tgz
do
   [ ! -f ${src} ] && curl -s -O http://ftp.jaist.ac.jp/pub/NetBSD/NetBSD-8.0/source/sets/${src}
   tar zxvf ${src} -C /
done && cd /usr/src && ./build.sh -m amd64 -a x86_64 -T /usr/src/tooldir.NetBSD-8.0-amd64 -r -o -U tools
...ちょっと時間がかかる(といっても20分程度)...
===> build.sh ended:      Mon Dec 17 18:23:25 JST 2018
===> Summary of results:
         build.sh command:    ./build.sh -m amd64 -a x86_64 -T /usr/src/tooldir.NetBSD-8.0-amd64 -r -o -U tools
         build.sh started:    Mon Dec 17 17:57:30 JST 2018
         NetBSD version:      8.0
         MACHINE:             amd64
         MACHINE_ARCH:        x86_64
         Build platform:      NetBSD 8.0 amd64
         HOST_SH:             /bin/sh
         No $TOOLDIR/bin/nbmake, needs building.
         Bootstrapping nbmake
         MAKECONF file:       /etc/mk.conf (File not found)
         TOOLDIR path:        /usr/src/tooldir.NetBSD-8.0-amd64
         DESTDIR path:        /usr/src/destdir.amd64
         RELEASEDIR path:     /usr/src/releasedir
         Removing /usr/src/tooldir.NetBSD-8.0-amd64
         Removing /usr/src/destdir.amd64
         Created /usr/src/tooldir.NetBSD-8.0-amd64/bin/nbmake
         Updated makewrapper: /usr/src/tooldir.NetBSD-8.0-amd64/bin/nbmake-amd64
         Tools built to /usr/src/tooldir.NetBSD-8.0-amd64
         build.sh ended:      Mon Dec 17 18:23:25 JST 2018
===> .
Mon Dec 17 18:23:25 JST 2018
```

## ツールチェインを用意しておくと地味に便利

NetBSDのツールチェインを用意しておくと、カーネルビルドだけでなく、ユーザランドのコマンドのビルドも行えるので、ちょっとした実験に重宝します。また、[クロスコンパイル環境でNetBSD-hpcmipsなカーネルをビルドしてみる](https://qiita.com/furandon_pig/items/68cd2c191d50a3010d55)の記事にもあるように、別のCPUアーキテクチャ向けのNetBSDカーネルをクロスコンパイルすることも可能になります。

### カーネルのビルド

NetBSDカーネルのビルドは以下の手順で実行します。

```sh
# cd /usr/src/sys/arch/amd64/conf/
# cp GENERIC HELLO
# /usr/src/tooldir.NetBSD-8.0-amd64/bin/nbconfig HELLO
Build directory is ../compile/HELLO
Don't forget to run "make depend"
# cd ../compile/HELLO/
# /usr/src/tooldir.NetBSD-8.0-amd64/bin/nbmake depend
# /usr/src/tooldir.NetBSD-8.0-amd64/bin/nbmake
```

### カーネルモジュールのビルド

```sh
# cd /usr/src/sys/modules/examples/hello
# ls -F
CVS/      Makefile  hello.c
# make
#   compile  hello/hello.o
/usr/src/tooldir.NetBSD-8.0-amd64/bin/x86_64--netbsd-gcc -O2 -g   -std=gnu99    -Wall -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Wno-sign-compare  -Wsystem-headers   -Wno-traditional   -Wa,--fatal-warnings  -Wreturn-type -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -Wextra -Wno-unused-parameter -Wno-sign-compare -Werror   -ffreestanding  -fno-strict-aliasing -Wno-pointer-sign -mno-red-zone -mno-mmx -mno-sse -mno-avx -msoft-float -mcmodel=kernel -fno-omit-frame-pointer  -I/usr/src/common/include --sysroot=/ -I/usr/src/common/include  -nostdinc -I. -I/usr/src/sys/modules/examples/hello -isystem /usr/src/sys -isystem /usr/src/sys/arch -isystem /usr/src/sys/../common/include -D_KERNEL -D_LKM -D_MODULE -DSYSCTL_INCLUDE_DESCR -c    hello.c
/usr/src/tooldir.NetBSD-8.0-amd64/bin/nbctfconvert -L VERSION hello.o
#      link  hello/hello.kmod
/usr/src/tooldir.NetBSD-8.0-amd64/bin/x86_64--netbsd-gcc  --sysroot=/ -Wl,-z,relro -Wl,--warn-shared-textrel -nostdlib -r -Wl,-T,/usr/src/sys/../sys/modules/xldscripts/kmodule,-d  -Wl,-Map=hello.kmod.map  -o hello.kmod hello.o
/usr/src/tooldir.NetBSD-8.0-amd64/bin/nbctfmerge -t -L VERSION -o hello.kmod hello.o
# ls -F
CVS/            amd64@          hello.kmod      hello.o         machine@
Makefile        hello.c         hello.kmod.map  i386@           x86@
```


### ユーザランドのコマンドをビルドする

例えば `echo` コマンドをビルドする場合は以下の手順になります。

```sh 
# cd /usr/src/bin/echo
# ls -F
CVS/         Makefile     echo.1       echo.c       echo.html1
# make
rm -f .gdbinit
touch .gdbinit
#   compile  echo/echo.o
/usr/src/tooldir.NetBSD-8.0-amd64/bin/x86_64--netbsd-gcc -O2 -fPIE    -std=gnu99    -Wall -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Wno-sign-compare  -Wsystem-headers   -Wno-traditional   -Wa,--fatal-warnings  -Wreturn-type -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -Wextra -Wno-unused-parameter -Wno-sign-compare -Wold-style-definition -Wsign-compare -Wformat=2  -Wno-format-zero-length  -Werror    --sysroot=/  -c    echo.c
/usr/src/tooldir.NetBSD-8.0-amd64/bin/nbctfconvert -g -L VERSION echo.o
#      link  echo/echo
/usr/src/tooldir.NetBSD-8.0-amd64/bin/x86_64--netbsd-gcc    --sysroot=/  -pie  -shared-libgcc  -Wl,-z,relro -Wl,--warn-shared-textrel     -o echo  echo.o  -Wl,-dynamic-linker=/libexec/ld.elf_so -Wl,-rpath,/lib  -L=/lib
/usr/src/tooldir.NetBSD-8.0-amd64/bin/nbctfmerge -t -g -L VERSION -o echo echo.o
nbsd8tmp# ls -F
.gdbinit     CVS/         Makefile     echo*        echo.1       echo.c       echo.html1   echo.o
# ./echo hello,world
hello,world
```

## まとめ

ワンライナーでNetBSDでのカーネルビルド環境を作る手順を紹介しました。実際、[NetBSD Advent Calendar 2018](https://qiita.com/advent-calendar/2018/netbsd)の記事で挙げられている手順はこのワンライナーを用いてインストール直後のまっさらな状態からカーネルビルド環境を構築しています。

自分で実験的に手を加えたカーネルやカーネルモジュール、ユーザランドのコマンドのビルドに利用できるので、皆様の環境でも試してみてはいかがでしょうか。