Gentooで異なるアーキテクチャ間でバイナリパッケージを作る

サーバ機のメンテナンスをしていて、デスクトップマシンとの性能差にうんざりしたので、どうにかしてもっと高速化できないものかと考えました。現在は distcc と crossdev で分散コンパイルとクロスコンパイルを行っているわけですが、サーバの I/O 性能の低さはいかんともしがたく。いくらコンパイル部分を高速化しても configure やソースの展開等で時間がかかってしまい、せっかくの高速化にも限界が。


それじゃぁと。いっそのことデスクトップマシン上でバイナリパッケージを作ってしまうことにしました。

その1 crossdev の機能を使う

先に結論から行くと、私はこの方法は使っていないのですが。

ココ とか ココ とかを見ていて気づいたのですが、環境変数で騙してやれば crossdev で作成したツールチェインを使って異なるアーキテクチャのバイナリを作成できるようです。emerge はシステムルートを環境変数 SYSROOT 変数で判断するようで、コレを / (リアルルート) 以外の場所にしてあげればいいと言うことのようですね。

デスクトップマシンは例によって amd64 環境で、サーバは x86 です。なのでデスクトップマシンで作成したツールチェインは x86 用の i686-pc-linux-gnu で、これは /usr/i686-pc-linux-gnu 以下に展開されています。この配下にサーバとそっくりの環境を整えてあげて SYSROOT="/usr/i686-pc-linux-gnu" を与えて emerge し、その際にバイナリパッケージもつくるようにしてしまえばいいことになります。

ということで作っていいきます。

サーバ上のファイル情報の取得

必要な情報 (ファイル) は以下のもの。


最初の2つは、 sftp なり NFS 共有なりで拾ってきます。最後のはサーバ上でこんな感じでいいかと。

$ ls /etc/make.profile -l
lrwxrwxrwx 1 root root   47 2009-10-30 05:07 /etc/make.profile -> ..//usr/portage/profiles/default/linux/x86/10.0
デスクトップ上のファイルの環境構築

サーバ上の情報を元に、こんな感じで配置します。サーバから取得した /etc/make.conf やら /etc/portage/package.* やらは、 /home/nanasi/ に置いてあることにしておきます。

$ sudo su -
# mkdir -p /usr/i686-pc-linux-gnu/etc/portage
# cp /etc/make.global /usr/i686-pc-linux-gnu/etc/
# cp /home/nanasi/make.conf /usr/i686-pc-linux-gnu/etc/
# cp /home/nanasi/package.* /usr/i686-pc-linux-gnu/etc/portage/
# ln -sn /usr/portage/profiles/default/linux/x86/10.0 / /usr/i686-pc-linux-gnu/etc/make.profile
# mkdir -p /usr/i686-pc-linux-gnu/var/lib/portage/
# cp /home/nanasi/world /usr/i686-pc-linux-gnu/var/lib/portage/

このとき、 /usr/i686-pc-linux-gnu/etc/make.conf の中身が i686 向けになっていることを一応確認しておきます。


あとは、ハンドブックに従い、こんな感じで emerge すると幸せになれるようです。 emerge コマンドに -b (または --buildpkg) オプションをつけると、バイナリパッケージが作成されます。デフォルトでは /usr/portage/packages/ 以下です。

# export SYSROOT="/usr/i686-pc-linux-gnu"
# CBUILD="i686-pc-linux-gnu" ROOT="$SYSROOT" PORTAGE_CONFIGROOT="$SYSROOT" emerge -avb ntp


その他ラッパースクリプトのようなものも、ハンドブックには書いてあります。

その2 chrootで32bit環境を作ってしまう

chroot でサーバと全く同じ環境を作ってしまう方法です。私はとりあえずこっちを使ってみることにしました。 crossdev でやっていてときどきコンパイルエラーを吐いたり、なぜか 64bit コンパイラが動いているように見えて不安だったからです。

chroot 環境は ココ にある手順にしたがって導入すれば簡単に作成できますが、サーバと同じ環境を作りたいため若干手を加えます。

  • /etc/make.conf はサーバにあるものとほぼ同じものを使う
  • /etc/portage/package.* をサーバからとってきて同じものを使う
  • /var/lib/portage/world をサーバにあるものと同じものにする
  • ローカルオーバーレイを反映させる
手順

先程と同様、サーバの設定ファイルは /home/nanasi/ 以下にあることとします。

$ cd /home/nanasi/
$ wget http://ftp.jaist.ac.jp/pub/Linux/Gentoo/releases/x86/autobuilds/current-stage3/stage3-i686-20100601.tar.bz2
(stage3 ファイルは最寄のミラーから最新のものを)


chroot 用のディレクトリをせっせとつくります。

$ sudo su -
# cd /mnt
# mkdir gentoo32
# cd gentoo32
# tar -xf /home/nanasi/stage3-i686-20100601.tar.bz2
# cp -L /etc/resolv.conf /mnt/gentoo32/etc/
# cp -L /etc/passwd /mnt/gentoo32/etc/


サーバから持ってきたファイルをコピーします。

# cp /home/nanasi/make.conf /mnt/gentoo32/etc/
# mkdir -p /mnt/gentoo32/etc/portage/
# cp /home/nanasi/package.* /mnt/gentoo32/etc/portage/
# mkdir -p /mnt/gentoo32/var/lib/portage
# cp /home/nanasi/world /mnt/gentoo32/var/lib/portage/


ハンドブックのとおりにリンク (bind) を張っていきます。

# mount -o bind /dev /mnt/gentoo32/dev
# mount -o bind /dev/pts /mnt/gentoo32/dev/pts
# mount -o bind /dev/shm /mnt/gentoo32/dev/shm
# mount -o bind /proc /mnt/gentoo32/proc
# mount -o bind /proc/bus/usb /mnt/gentoo32/proc/bus/usb
# mount -o bind /sys /mnt/gentoo32/sys


さらにハンドブックのとおりにリンクを張っていきます。自分の場合ローカルオーバーレイも使用しているので、これも忘れないように追加しておきます。今回のローカルオーバーレイは /usr/local/portage 以下です。

# mkdir -p /mnt/gentoo32/usr/portage/
# mount -o bind /usr/portage /mnt/gentoo32/usr/portage/
# mkdir -p /mnt/gentoo32/usr/local/portage
# mount -o bind /usr/local/portage /mnt/gentoo32/usr/local/portage/
# mount -o bind /tmp /mnt/gentoo32/tmp


最後に、 chroot します。自分の環境では linux32 コマンドは既にインストール済でした。またドキュメントでは emerge linux32 でインストールするように書いてありますが、これは若干古いようです。現在は linux32 コマンドは sys-apps/util-linux に入っている模様。

# emerge util-linux
# linux32 chroot /mnt/gentoo32 /bin/bash
# uname -m
i686


あとは、 emerge するだけです。 -b オプションをつけて emerge すればバイナリパッケージが作成されます。または make.conf 内で FEATURES="buildpkg" を指定してやると、常につくるようになります。繰り返しますが、作成先は /usr/portage/packages/ 以下です。 chroot 環境下のディレクトリに作成されます。

なお、作成先は PKGDIR 変数で指定されています。

# emerge --info | grep PKGDIR
PKGDIR="/usr/portage/packages"
追記 (2010/06/14)

こんな感じでやると、 chroot 環境に全く同じ環境を作りながらバイナリパッケージを作ります。

# cat /var/lib/portage/world | xargs emerge -b

バイナリパッケージをつかう

パッケージが作成されたら、サーバ上で emerge に -k (または --usepkg) オプションをつけると、バイナリからインストールしようとしてくれます。もちろんサーバから見て /usr/portage/packages/ (PKGDIR変数で指定したディレクトリ) 以下にファイルがなくてはいけませんので、このディレクトリは NFS で共有してしまうといいですね。
# むしろ /usr/portage ごと複数の PC で共有してしまうのが幸せです!

$ emerge -pk ntp
[binary   R   ] net-misc/ntp-4.2.4_p7-r1 

表示が binary になっていることを確認して下さい。

なお、 -G や -g なんてオプションも使えますが、詳しくは man emerge で。(笑)


肝心の高速化ですが、コンパイル作業そのものは全て高速な PC 上で行うのでかなり速くなると思います。しかしながらインストールしてあるパッケージを全部コンパイルしなおすことになるので、その時間が…w まぁ、せっかく gcc のバージョンもあがったし、 emerge -e world したと思えばいいかな。

あとは、バイナリからのインストールにそれなりに時間はかかるでしょうけど、それでもコンパイルするよりは速いはず! たぶん。