異なるアーキテクチャ間でクロスコンパイル環境をつくる
作成した仮想マシン上でクロスコンパイル環境を作ります。 今回はこんな環境を想定しています。
- 常時起動のサーバ
- ネットワークは 192.168.0.120 。CPU は Pen4 。 i686 。 distcc で投げる側。
- 作った[http
- //d.hatena.ne.jp/korokorokoron/20100317#1268848095:title=仮想マシン]:ネットワークは 192.168.0.130 。CPU は Core-i7 。 x86_64 。 distcc で受ける側。
投げる側と受ける側とでアーキテクチャが違う (i686 / x86_64) ことに注意。
distccの導入
投げる側と受ける側双方に distcc をインストールします。 distcc は分散コンパイルのためのパッケージです。
@192.168.0.120 $ sudo emerge -v distcc
@192.168.0.130 $ sudo emerge -v distcc
crossdevの導入
crossdev は異なるアーキテクチャ間でクロスコンパイルを行う際に必要となるツールをビルドするためのパッケージです。今回は受ける側の x86_64 な環境で i686 をコンパイルする環境を作る必要があるため、受ける側にいれます。
受ける側で、 crossdev をインストールします。
@192.168.0.130 $ sudo emerge -v crossdev
crossdev の使い方を見てみます。
実際に作成…する前に、とりあえずヘルプを見てみます。
@192.168.0.130 $ sudo crossdev --help Usage: crossdev [options] --target TARGET Options: --b, --binutils ver Specify version of binutils to use --g, --gcc ver Specify version of gcc to use --k, --kernel ver Specify version of kernel headers to use --l, --libc ver Specify version of libc to use -S, --stable Use latest stable versions as default -C, --clean target Uninstall specified target -P, --portage opts Options to pass to emerge (see emerge(1)) --with[out]-headers Build C library headers before C compiler? Stage Options: -s0, --stage0 Build just binutils -s1, --stage1 Also build a C compiler (no libc/C++) -s2, --stage2 Also build kernel headers -s3, --stage3 Also build the C library (no C++) -s4, --stage4 Also build a C++ compiler [default] Extra Fun (must be run after above stages): --ex-only Skip the stage steps above --ex-gcc Build extra gcc targets (gcj/ada/etc...) --ex-gdb Build a cross gdb --ex-insight Build a cross insight Target (-t) takes a tuple ARCH-VENDOR-OS-LIBC; see 'crossdev -t help'
とりあえず、 -t ARCH で間違いないようですが、一応 -t help もみておきます。
@192.168.0.130 $ sudo crossdev -t help Supported Architectures: - alpha - arm / armeb - hppa (parisc) - ia64 - i386 / i486 / i586 / i686 (x86) - m68k - mips / mipsel / mips64 / mips64el - powerpc (ppc) / powerpc64 (ppc64) - sparc / sparc64 - s390 / s390x - sh / sh[1-5] / sh64 - x86_64 (amd64) Supported C Libraries: - glibc (gnu) - klibc [prob wont work] - newlib [bare metal/no operating system] - uclibc [not all arches are ported] Special Targets: - avr http://www.nongnu.org/avr-libc/ - bfin http://blackfin.uclinux.org/ - h8300 http://h8300-hms.sourceforge.net/ - mingw32 http://www.mingw.org/ - msp430 http://mspgcc.sourceforge.net/ - nios2 http://www.altera.com/products/ip/processors/nios2/ni2-index.html - xc16x http://www.infineon.com/ - ee / iop / dvp (ps2) [Playstation 2 targets] - ppu / spu (cell) [Cell/Playstation 3 targets] Softfloat toolchains: Include 'softfloat' in the 'vendor' field e.g. armeb-softfloat-linux-uclibc powerpc-booya_softfloat-linux-gnu
今回は crossdev -t i686 でいいようです。
実際に crossdev でツールを作ってみます (失敗編)
実際に作ってみます。
@192.168.0.130 $ sudo crossdev -t i686
i686 用の binutils/gcc/linux-headers/glibc をコンパイルし始めます。ちょっと待っていれば終わります。
…とココで問題が。 crossdev で入れたツールのバージョンが何かやたらと新しいです。
@192.168.0.130 $ emerge -pv gcc ∗ cross-i686-pc-linux/gcc Latest version available: 4.4.3 Latest version installed: 4.4.3 ∗ sys-devel/gcc Latest version available: 4.3.4 Latest version installed: 4.3.4
下に出ている sys-devel/gcc は入れたばかりの仮想マシンで実際に動いているバージョン。 amd64 の安定版です。対し、上が crossdev で作ったバージョン。ずいぶんと新しい。当然ながら、投げる側のマシンにもこんな新しいバージョンは入っていません。クロスコンパイル時にコンパイラ等のバージョンが異なるのは不具合の原因になるので揃えたい。てことでやり直し。
実際に crossdev でツールを作る前に (リトライ編)
投げる側のバージョンを調べます。
@192.168.0.120 $ emerge -p binutils linux-headers gcc glibc These are the packages that would be merged, in order: Calculating dependencies... done! [ebuild R ] sys-devel/binutils-2.18-r3 [ebuild R ] sys-kernel/linux-headers-2.6.30-r1 [ebuild R ] sys-devel/gcc-4.3.4 [ebuild R ] sys-libs/glibc-2.10.1-r1
パッケージ | バージョン |
---|---|
binutils | 2.18-r3 |
linux-headers | 2.6.30-r1 |
gcc | 4.3.4 |
glibc | 2.10.1-r1 |
crossdev で作るツールのバージョンを指定する (リトライ編)
そのまま crossdev -t するとバージョンがあわなかったので、先程調べた投げる側のそれに合わせてあげます。バージョンを指定する方法は先程みたヘルプに書いてあったもの (--b とか --binutils とか) を使います。
@192.168.0.130 $ sudo crossdev -t i686 --b 2.18-r3 --k 2.6.30-r1 --g 4.3.4 --l 2.10.1-r1
ちなみに安定版の最新パッケージで揃えるというのなら、 -S オプションもいいと思います。最新の安定版がはいります。異なるアーキテクチャ間で stable 版のバージョンが一緒だとは限らないのですけれども、だいたいの場合は一緒です。
@192.168.0.130 $ sudo crossdev -S -t i686
USE フラグも揃えたいならこうかな…やってないけど。
@192.168.0.130 $ sudo USE="xxxx" crossdev -S -t i686
終わったら、念のためバージョンを確認します。
受ける側の distcc の設定を行う
設定ファイルを書き換えて、投げる側 (192.168.0.120) からのリクエストを受け付けるようにします。念のため、自分のアドレスも書いておきましたが、予備的に書いてあるだけで本来は不要です。
@192.168.0.130 $ sudo nano -w /etc/conf.d/distccd DISTCCD_OPTS="${DISTCCD_OPTS} --allow 192.168.0.120 192.168.0.130"
設定が終わったら distccd サービスを起動し、デフォルトのランレベルに加えておきます。
@192.168.0.130 $ sudo /etc/init.d/distccd start @192.168.0.130 $ sudo rc-update add distccd default
投げる側の distcc の設定を行う
投げる側は、どこに投げるかという設定を行います。
@192.168.0.120 $ sudo distcc-config --set-hosts "192.168.0.130"
emerge でも distcc が有効になるよう、 /etc/make.conf を書き換えます。同じ変数名を使った場合はあとから書かれた方で上書きされるので、下のほうに書くようにします。
また、投げる側では CFLAGS 変数に『 march=native 』は指定しません。指定した場合はうまくいかないはずです。ちなみにうちのサーバでは単純にこんな感じになっていますが、昔のおんぼろ PC で並列処理させていたころからの名残です。互換性は抜群ですが最適化も何もあったもんじゃありませんw
@192.168.0.120 $ sudo nano -w /etc/make.conf CFLAGS="-march=i686 -O2 -pipe" ←march=native とかにはしない FEATURES="distcc" ←必須 DISTCC_HOSTS="192.168.0.130" ←投げる先 MAKEOPTS="-j9" ←例によって適当
最後に、ココにあるとおりにラッパースクリプトを作成してリンクを張ります。こんな感じになっています。
@192.168.0.120 $ ls -la /usr/lib/distcc/bin/ 合計 12 drwxr-xr-x 2 root root 4096 2010-03-18 09:21 . drwxr-xr-x 3 root root 4096 2009-05-28 09:54 .. lrwxrwxrwx 1 root root 25 2010-03-18 09:21 c++ -> i686-pc-linux-gnu-wrapper lrwxrwxrwx 1 root root 25 2010-03-18 09:21 cc -> i686-pc-linux-gnu-wrapper lrwxrwxrwx 1 root root 25 2010-03-18 09:21 g++ -> i686-pc-linux-gnu-wrapper lrwxrwxrwx 1 root root 25 2010-03-18 09:21 gcc -> i686-pc-linux-gnu-wrapper lrwxrwxrwx 1 root root 15 2009-05-28 09:54 i686-pc-linux-gnu-c++ -> /usr/bin/distcc lrwxrwxrwx 1 root root 15 2009-05-28 09:54 i686-pc-linux-gnu-g++ -> /usr/bin/distcc lrwxrwxrwx 1 root root 15 2009-05-28 09:54 i686-pc-linux-gnu-gcc -> /usr/bin/distcc −rwxr-xr-x 1 root root 69 2010-03-18 09:20 i686-pc-linux-gnu-wrapper
- 28:53+09:00">(追記):実はこれだけでは不十分でした。 cc が呼ばれると上記ラッパー経由で i686-pc-linux-gnu-cc を呼びに行きますが、ご覧の通りそんなものはありませんので落ちます。 cc が呼ばれたら gcc を呼んでやればいいので、環境変数 CC に gcc を呼びに行くようにセットしてやります。投げる側の /etc/make.conf に CC="i686-pc-linux-gnu-gcc" の一文を追加します。
@192.168.0.120 $ sudo nano -w /etc/make.conf CC="i686-pc-linux-gnu-gcc" ←この一文を追加する
実際に投げてみる
投げる側のマシンで emerge してやるだけでです。
@192.168.0.120 $ sudo emerge -v1 bind-tools とか @192.168.0.120 $ sudo FEATURES="${FEATURES} distcc" emerge -v1 bind-tools とか @192.168.0.120 $ sudo FEATURES="${FEATURES} distcc" DISTCC_HOSTS="192.168.0.130" MAKEOPTS="-j9" emerge -v1 bind-tools などなど
受ける側では ps aux | grep distcc とか top とかで確認することができます。 distccmon-text でもいいらしい?
22018 ? SN 0:00 /usr/x86_64-pc-linux-gnu/i686-pc-linux-gnu/gcc-bin/4.3.4/i686-pc-linux-gnu-gcc -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -fno-delete-null-pointer-checks -Os -m32 -msoft-float -mregparm=3 -freg-struct-return -mpreferred-stack-boundary=2 -march=i686 -mtune=generic -Wa,-mtune=generic32 -ffreestanding -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -fno-stack-protector -fomit-frame-pointer -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -c -o /tmp/distccd_d4d00739.o /tmp/distccd_d53a0739.i
192.168.0.120 から 192.168.0.130 に投げてみたところです。こんな感じで 192.168.0.130 側では i686 用のコンパイラが動いてます。 CFLAGS は投げたマシン側のが使われているはず。たぶん。
投げる側のマシンで distccd サービスが立ち上がっている必要は必ずしもないはずですが、もし自分自身にも投げて高速化を狙うのであれば、当然必要になってきます。ただし、あまりにも性能差があったりすると、遅いマシンに投げた場合は丸投げするよりも遅くなるので注意です。
MAKEOPTS の数値によっても結構かわるので、最適な設定を探ってみるといいです。
ちなみに
うちの環境だとマシン2つでコンパイルするよりも全てを Core-i7 に丸投げした方が速かったです。仮想環境につくったマシンとはいえ世代差が大きすぎました。ただし、 ./configure とかその辺は高速化できないしネットワークに送るロスもあるので、思ったよりは微妙な感じです。