クロス開発環境というのは、プログラムの開発をするときに、
- プログラムのソースコードのコンパイルやデバッグをするコンピュータ
- 作成されたプログラムを実行するコンピュータ
の2台のコンピュータに分けて開発する、開発環境のことです。これに対して、普通は、プログラムをコンパイルするコンピュータと、プログラムを実行するコンピュータは、同じコンピュータの場合が多いです。
めんどくさそうな方法ですが、クロス開発というのは、携帯用の小型端末とか、電化製品などに組み込まれている小さなコンピュータ用にプログラムを開発する方法です。そういうコンピュータには、メモリが少ししかのっていないし、ハードディスクもないし、そもそもキーボードもディスプレイもつながらないので、そのコンピュータ上で、Cコンパイラとかデバッガとかを動かすことはできません。そのために、開発用に別のコンピュータがもう1台必要になります。
玄箱も、まさに、このクロス開発環境の適用対象にぴったりあいます。
一応、玄箱には、CD-ROMの中に、Cコンパイラやデバッガが入っているので、それらをインストールすれば、玄箱を使って、玄箱用のプログラムを開発することができます。しかし、玄箱は、CPUの処理速度はそんなに速くないしメモリも少ないので、開発効率はなかなか上がりません。
一方、そこらで5万円以下で安売りされているパソコンでさえも、玄箱よりは1桁くらい処理性能は上ですので、これを利用しない手はありません。
なお、クロスコンパイラのビルド方法に関して、以下をちょこっと参考にしました。
■ はじめに
クロス開発では、プログラムを実行する側のコンピュータをターゲット(target)、プログラムのコンパイルなどの行う側のコンピュータをホスト(host)と呼んで区別しています。
今回は、FreeBSDを動かしているパソコン側がhost、玄箱がtargetです。
クロス開発では、host側のOSとtarget側のCPUやOSが違っていてもかまいません。そのへんは開発ツールががんばってくれています(というか、それがクロス開発ツールの仕事)。
玄箱には、GNUの開発ツールのbinutils、GCC、GDBが用意されています。これらのツールは、もともとクロス開発にも使えるように作られています。今回は、FreeBSD上で、玄箱用のbinutilsとGCCをコンパイルします。デバッガのGDBは、まあ後回しでいいかな、と思ったのでまたいつか。必要なら、玄箱のGDBを使えばなんとかなるでしょう。
以下の作業は、NFSとamdの設定をすませたあとに、行っています。
■ binutilsをインストール
まず最初に、binutilsをコンパイル、インストールします。binutilsは、アセンブラ(as,gas)やリンカ(ローダ、ld)などから構成された、プログラム開発用ツール集です。
(1)ソースファイルの入手
binutilsのソースファイルは、たとえば、こんなところにあります。
ftp://ftp2.jp.freebsd.org/pub/FreeBSD/ports/distfiles/binutils-2.13.2.1.tar.bz2
portsがある場合は、以下のようなかんじで、make fetchでダウンロードすることもできます。
% cd /usr/ports/devel/i386-rtems-binutils/
% make fetch
ファイルがどこからダウンロードできるのかわからない場合に、この方法は、私もよく使っています。
この場合、ダウンロードしたファイルは、とくに何もports関係の設定を変更していないなら、
/usr/ports/distfiles/binutils-2.13.2.1.tar.bz2
におかれています。
(2)ソースファイルを展開
ファイルbinutils-2.13.2.1.tar.bz2を展開します。
% cd どこか作業用ディレクトリ
% tar jxf /usr/ports/distfiles/binutils-2.13.2.1.tar.bz2
% ls
binutils-2.13.2.1/
% cd binutils-2.13.2.1
(3)configureスクリプトを実行する
こんな感じでconfigureを実行します。
% ./configure --prefix=/usr/local/kuro-box
--target=powerpc-hardhat-linux
(見やすくなるように途中で改行していますが、実行するときは改行せずに1行です)
「--prefix=ディレクトリ」で、インストール先ディレクトリを指定します。とりあえず「/usr/local/kuro-box」にします。
「--target」で、ターゲットマシンのアーキテクチャを指定します。powerpc-hardhat-linuxというのを指定していますが、これは玄箱のbinutilsがこれを指定してコンパイルされていたからです。
(4) コンパイルする
% gmake
(5)インストールする
% su
Password:
# gmake install
(略)
# ls /usr/local/kuro-box/
bin lib powerpc-hardhat-linux
info man share
■ 玄箱からファイルをもらってくる
クロス開発を行う際に(FreeBSD上で、玄箱用のクロスコンパイラを実行する際に)、ターゲットマシンのヘッダファイル(*.h)とライブラリ(*.soとか*.a)が必要になります。
玄箱から、それら必要なファイルを、FreeBSDへコピーします。
(1)その前に、ついでに玄箱にbinutilsとgccをインストールする
本当に必要かどうかわかりませんが、ファイルをFreeBSDへコピーする前に、玄箱にbinutilsとgccをインストールしておきます。binutilsとgccでインストールされるファイルも必要になるかな?と思ったからですが、もしかするといらないかもしれません。
玄箱で以下を実行します。
root@KURO-BOX:/# cd /
root@KURO-BOX:/# tar zxf /mnt/share/binary/binutils-2.10.91.0.2.tar.gz
root@KURO-BOX:/# tar zxf /mnt/share/binary/gcc-2.95.3.tar.gz
(2)コピーするファイルをtarでアーカイブしておく
玄箱の/lib/以下のファイルと、/usr/include/以下のファイルがあれば十分だと思います。
root@KURO-BOX:/# tar cf /mnt/share/kuro-box-files.tar lib usr/include usr/lib
(3)tarアーカイブをFreeBSDで展開する
クロスコンパイル用のGCCは、ターゲットマシン用のファイルを、ディレクトリ(GCCのインストール先)/(--targetで指定したアーキテクチャ)/以下から持ってくるので、今回の場合、/usr/local/kuro-box/powerpc-hardhat-linux/以下へファイルを展開します。
# cd /usr/local/kuro-box/powerpc-hardhat-linux/
# ls
bin lib
# tar xf /net/kuro-box/mnt/share/kuro-box-files.tar
# ls
bin lib usr
ファイルの置き場所を、少し変更します。
# mv lib/* ../lib/
# rmdir lib
# mv usr/* .
# rmdir usr
# ls
bin include lib
/usr/local/kuro-box/powerpc-hardhat-linux/include/
には、玄箱の/usr/include以下にあったファイルをおいて、
/usr/local/kuro-box/powerpc-hardhat-linux/lib/
には、玄箱の/usr/lib以下にあったファイルをおきます。
/usr/local/kuro-box/lib/
には、玄箱の/lib以下にあったファイルをおきます。
それから、あとでGCCで(正確に言うとldで)エラーがでてしまうので、いくつかシンボリックリンクを作成します。
# cd /usr/local/kuro-box/powerpc-hardhat-linux/lib/
# ln -s ../../lib/libc.so.6 .
# ln -s ../../lib/libc-2.2.3.so .
# ln -s ../../lib/libc.so.6 .
# ln -s ../../lib/ld-2.2.3.so .
# ln -s ../../lib/ld.so.1 .
これは、ldがlic.so.6とld.so.1を探しにいくときに、/usr/local/kuro-box/lib/は見てくれないための措置です。これ以外に、もうすこしスマートな方法がありかもしれません。
■ GCCをインストール
玄箱用にコンパイルされたGCCがバージョン2.95なので、それにあわせてGCC 2.95.3をインストールします。
(1) gcc-2.95.3のソースファイルを展開
2.95.3は、かなーり古いバージョンなので、きっとたくさんパッチがでているはずです。パッチをあてるのがめんどくさいので、FreeBSDのportsを使ってみました。
# cd /usr/ports/lang/gcc295/
# make patch
===> Extracting for gcc-2.95.3_2
=> MD5 Checksum OK for gcc-core-2.95.3.tar.bz2.
=> SHA256 Checksum OK for gcc-core-2.95.3.tar.bz2.
=> MD5 Checksum OK for gcc-g++-2.95.3.tar.bz2.
=> SHA256 Checksum OK for gcc-g++-2.95.3.tar.bz2.
===> Patching for gcc-2.95.3_2
===> Applying FreeBSD patches for gcc-2.95.3_2
これで、ソースファイルのダウンロードして、パッチをあてるところまでやってくれます。便利ですねぇ。
ソースファイルは、portsの設定をとくに変更していない場合は、/usr/ports/lang/gcc295/work/以下に展開されています。
portsのコンパイル作業ディレクトリは、環境変数WRKDIRPREFIXで変更できます。/etc/make.confでたとえば
WRKDIRPREFIX=/home2/ports.work
とか書いておくと、/home2/ports.work/なんとか/かんとか/・・・以下に展開されるようになります。
ファイルを展開したところで、こんなかんじです。
# cd /home2/ports.work/home2/ports/lang/gcc295/work/gcc-2.95.3/
# ls
.brik config.guess install-sh
.cvsignore config.guess.orig libiberty
COPYING config.if libio
COPYING.LIB config.sub libstdc++
ChangeLog configure ltconfig
FAQ configure.in ltmain.sh
INSTALL contrib missing
MAINTAINERS etc mkinstalldirs
Makefile.in faq.html move-if-change
README gcc symlink-tree
config include texinfo
config-ml.in install ylwrap
(2)configureを実行
さきほどインストールしたbinutilsへPATHが通しておきます。
# setenv PATH /usr/local/kuro-box/bin:$PATH
configureを実行します。
# cd /home2/ports.work/home2/ports/lang/gcc295/work/gcc-2.95.3/
# ./configure --prefix=/usr/local/kuro-box
--target=powerpc-hardhat-linux
--with-gnu-ld --with-gnu-as --disable-nls
(3)コンパイルする
# gmake
しばらくすると・・・えーと・・・エラーでとまってしまいました。
とりあえず、エラーを無視して、インストールしてしまいます。
# gmake install
そして、GCCのファイルをすべて削除し、ソースを展開する(make patch)ところから、もう一度、同じ事をくりかえします。すると、2回目のgmakeは成功しました。
エラーメッセージを調べたところ、includeファイルを探すときに、
/usr/local/kuro-box/powerpc-hardhat-linux/lib/gcc-lib/powerpc-hardhat-linux/2.95.3
というディレクトリが作成されていないと、うまく見つけられないようなかんじでした。一度gmake installを実行すると、このディレクトリが作成されるので、2回目以降は成功する、というわけです。
■ Hello Worldを実行してみる
クロスコンパイラが、正しく動くか確認するために、Hello Worldプログラムで試してみます。
ソースファイルは、こんなかんじです。
% cat hello.c
#include <stdio.h>
int
main( int argc, char* argv[] )
{
printf("Hello world\n");
return 0;
}
コンパイルします。
% /usr/local/kuro-box/bin/powerpc-hardhat-linux-gcc hello.c
-o hello
% ls -l hello
-rwxr-xr-x 1 nhh wheel 5567 Jan 22 21:40 hello*
なにやら、できたっぽいです。
% file hello
hello: ELF 32-bit MSB executable, PowerPC or cisco 4500, version 1 (SYSV),
for GNU/Linux 2.0.0, dynamically linked (uses shared libs), not stripped
玄箱へコピーします。
% cp hello /net/kuro-box/mnt/share
玄箱にログインして、実行してみます。
root@KURO-BOX:/mnt/share# ./hello
Hello world
どうやら、無事に、実行できたようです。
■ C++コンパイラ(g++)
g++も一応コンパイルされているのですが、実は、ライブラリlibstdc++がビルドされていません・・・うーむ・・・
C++コンパイラも必要な場合は、2回目のGCCのコンパイルのときに、以下のように--enable-languages=c++をつけます。
# ./configure --prefix=/usr/local/kuro-box
--target=powerpc-hardhat-linux
--with-gnu-ld --with-gnu-as --disable-nls
--enable-languages=c++
以下、C++版のHello Worldでテストした例です。
まずFreeBSDでコンパイル。
% cat hello.cc
#include <iostream.h>
int
main( int argc, char* argv[] )
{
cout << "Hello world ++" << endl;
return 0;
% /usr/local/kuro-box/bin/powerpc-hardhat-linux-g++ hello.c
c -o hello++
% cp hello++ /net/kuro-box/mnt/share
玄箱で実行。
root@KURO-BOX:/mnt/share# ./hello++
Hello world ++
動きました。ちなみに、「bash: ./hello++: Text file busy」というエラーメッセージが表示されたことがあったのですが、なんなんでしょう???
■ トラブルシューティング
クロスコンパイラでコンパイルエラーになる場合、gccに「-v」オプションをつけて実行すると、どのようなファイルを参照しているか、ログメッセージとして表示されるようになります。玄箱からファイルをコピーしわすれていたり、コピー先の場所が違っていたりしないか、これで確認できるようになります。
ldでエラーになったケースがあって、これがやっかいでした。しかたないので、ldのラッパーを作成しました。
/usr/local/kuro-box/powerpc-hardhat-linux/bin/ld
を
/usr/local/kuro-box/powerpc-hardhat-linux/bin/ld.org
に名前を変えて、
/usr/local/kuro-box/powerpc-hardhat-linux/bin/ld
を、以下のようなシェルスクリプトに置き換えて、どういう引数が渡されているかを表示させました。
% cat /usr/local/kuro-box/powerpc-hardhat-linux/bin/ld
#! /bin/sh
echo =====
echo $*
echo =====
exec /usr/local/kuro-box/powerpc-hardhat-linux/bin/ld.org $*
gccへの引数で、なんとかできそうな気がしますが、調べてもすぐにわからなかったので、こういう乱暴な手を使いました。
■ 次回予告
ためしにtcshをクロスコンパイラでビルドしてみました。