NetBSD/amd64でNetBSD/i386用のパッケージをビルドする

この記事は、NetBSD Advent Calendar 2019 20日目の記事です。

# NetBSD/i386
今さら説明するまでもないですが、NetBSD/i386 は、NetBSDの 32ビットモードのx86プラットフォーム用ポートです。正確には、x86CPUを搭載した PC互換機用のポートであって、x86CPUを積んでいてもNetBSD/i386でサポートできないプラットフォームも(過去には)たくさんありました。[^1]

昨今流通しているx86系のマシンは、たいてい 32ビットモードと64ビットモードを備えていて、NetBSD/amd64も動かせます。よって、NetBSD/i386の出番は減っていると思いますが、組み込み用途の小さいx86ベースのSoCは存在しますし、64ビットモードのあるPC互換機であってもメモリを4Giバイト未満しか積んでないような場合はNetBSD/i386が選択されることもあると思います。[^2]

## NetBSD/i386 のビルド
x86なマシンに NetBSD/i386 をインストールする時、公式のインストールイメージをダウンロードしてきてもいいですが、自前でビルド(したい|せざるをえない)場合があります。

* そもそもメモリが少ないマシン用なので、カーネルも作り直して小さくしたい
* 実際のCPUにあわせて最適化するコンパイルオプションを指定したい
* i486以前のCPU用にビルドしたい[^4]

NetBSD/i386を自力でビルドする場合、NetBSD/i386上でコンパイルしなければならない、というようなことはありません。amd64な爆速マシン上でビルドできます。 更に言えば、NetBSD上である必要もなく、Linux か WindowsのCygwin、または WSL上で NetBSD/i386 をクロスビルドすることができます。

NetBSDのソースツリーを展開したら、
```
./build.sh -mi386 -DDESTDIR -TTOOLDIR -RRELASEDIR build release
```
とするだけでOK。クロスコンパイラを別途入手して、それに合わせて環境変数を設定して… みたいな手間は不要。とても簡単です。

## pkgsrc のクロスコンパイル
上記のように、NetBSD のbuild.sh によるクロスビルドは良くできていて、ARMなどの組み込みシステムでNetBSDを選択する理由の一つになりえます。NetBSDの標準構成と自前のアプリケーションだけで済むならとても簡単なのです。

ただし、実際には各種のサードパーティ製ソフトウェアが必要になり、ここが悩みの種になります。世の中の大半のソフトウェアは、ビルド環境=実行環境の前提で作られていて、クロスビルドを考慮していないのです。その場合、実機上でサードパーティ製ソフトウェアをビルドせざるをえず、対象プラットフォームが非力な場合にはとても時間がかかったり、全く不可能だったりします。

なので、pkgsrc がクロスビルドできれば、多くの人の助けになるのですが、中々簡単にはいかないようです。そういえば、**@h_kenken がそのネタで何か書くと言っていたはず** ですが、どうなったでしょうか。

#NetBSD/i386用のpkgsrcクロスコンパイル
上述のように、pkgsrcのクロスコンパイルは一般に難関なのですが、NetBSD/amd64上で NetBSD/i386用のパッケージをビルドするのは例外的に簡単なので、以下にその方法を紹介します。

## i386用chrootサンドボックスでビルドする
NetBSD/amd64上でNetBSD/i386用のクロスビルドが簡単なのは、NetBSD/amd64が NetBSD/i386用バイナリを直接実行できるからです。これは Linux や Windows と同様です。
NetBSD/amd64上で NetBSD/i386のバイナリを実行すると、i386用のシステムコールエントリーが選択されます。uname(3) も i386 として応答するので、プログラム側からは NetBSD/i386上で動作しているように見えます。

```
% uname -mprs
NetBSD 9.99.17 amd64 x86_64
% /some/where/destdir.i386/usr/bin/uname -mprs
NetBSD 9.99.17 i386 i386
```

そこで、chroot したディレクトリツリーを NetBSD/i386用のコマンドやライブラリで埋めてやれば、仮想マシンなどを使わなくても NetBSD/i386な環境が構築でき、その中でサードパーティ製ソフトウェアをビルドすれば i386 用のバイナリを得られるわけです。

chroot サンドボックス内でビルドする、というのはクロスビルドを前提にしなくても有用なので、pkgsrc にそのための手段が pkg_comp として用意されています。 pkg_comp は、chroot サンドボックスの構築に sandboxctl(8) を使用します。
pkg_comp の制御に pkg_comp.conf(5)、sandboxctl の制御に sandboxctl.conf(5) の二つの設定ファイルを準備します。

## sandboxctl.conf

```sandbox.i386.conf
SANDBOX_TYPE=netbsd-release
SANDBOX_ROOT=/some/where/for/root
NETBSD_RELEASE_RELEASEDIR=/foo/bar/ReleaseDir/i386
NETBSD_RELEASE_SETS="base.tgz comp.tgz etc.tgz"
```

/usr/pkg/share/examples/sandboxctl/default.conf に雛形がありますが、我々の目的に必要なのは上記の4行です。

NETBSD_RELEASE_RELEASEDIR には、build.sh に -R オプションで指定したディレクトリ + /i386 を書きます。その下に binary/sets があるはずの所です。

NETBSD_RELEASE_SETS には、展開すべきtarball を書きますが、最低限上記の3つは必要です。sandboxctl が /dev/MAKEDEV を実行するので、etc.tgz も必要です。 X11関連のパッケージを作成するなら xbase.tgz と xcomp.tgz も追加します。

sandboxctl.conf を書いたら、sandboxctl(8) を実行して試してみることができます。(root権限が必要です)


```
# sandboxctl -c CONFFILE create
# sandboxctl -c CONFFILE shell    # chroot サンドボックスでサブシェルが起動する
# uname -mprs
NetBSD 9.99.17 i386 i386
# exit
```

詳しくは、sandboxctl(8)とsandboxctl.conf(5)のマニュアルを参照してください。

## pkg_comp.conf

```pkg_comp.i386.conf
# Additional configuration files to support this setup.
EXTRA_MKCONF="/some/where/extra.mk.conf"
SANDBOX_CONFFILE="/some/where/sandbox.i386.conf"

# Remote VCS configuration.
#FETCH_VCS=cvs
#CVS_ROOT=:ext:anoncvs@anoncvs.NetBSD.org:/cvsroot
#CVS_TAG=pkgsrc-2017Q1
#GIT_URL=https://github.com/NetBSD/pkgsrc.git
#GIT_BRANCH=trunk

# Host file layout.  These directories point to trees managed outside of
# the sandbox and are exposed within the sandbox via null mounts.
PKGSRCDIR="/usr/pkgsrc"
DISTDIR="${PKGSRCDIR}/distfiles"
PACKAGES="${PKGSRCDIR}/packages"
PBULK_LOG="${PACKAGES}/log"
PBULK_PACKAGES="${PACKAGES}/pbulk"

# Enable interactive pkgsrc development via sandbox-shell.
#PKG_DEVELOPER=yes
# List of packages to build during automatic execution.
#AUTO_PACKAGES="bash emacs kyua pkg_comp tmux"
```

これも、/usr/pkg/share/examples/pkg_comp に雛形があります。上記の設定では、pkgsrc のソースツリーが展開済みの前提ですが、コメントアウトされた行でわかるように、CVS や git で取ってくることもできるようです。[^3]

EXTRA_MKCONF で指定したファイルはchrootサンドボックスの /etc/mk.conf から読み込まれます。ACCEPTABLE_LICENSES や特定CPU向けの CPUFLAGS を設定できます。

**注意**：ここで、上の ```sandboxctl create``` で作成されたchroot用ディレクトリを削除してください。下の pkg_comp sandbox-create と干渉するので。

pkg_comp.i386.conf が準備できたら、

```
# pkg_comp -c pkg_comp.i386.conf sandbox-create
# pkg_comp -c pkg_comp.i386.conf bootstrap
```
で準備完了です。後は、

```
# pkg_comp -c pkg_comp.i386.conf build PACKAGE-NAME
```
を実行して、パッケージをビルドできます。

詳しくは、pkg_comp(8)とpkg_comp.conf(5)のマニュアルを参照してください。

[^1]: NetBSD/pc98 はどうなってますでしょうか
[^2]: メモリ利用効率的に有利だと思うので、私はそうしていますが、この点を真面目に検証したことはないです。誰かお願いします
[^3]: 未検証
[^4]: 実際に可能なのか知りませんけど