開発環境の整備とかいうタイトルにしてしまったが、Android とはほぼ関係ない。では、なにをやろうとしているかといえば ... Redhat Enterprise Linux 6 (RHEL6) の mipsel 版 clone を作ること。ただし、ブート可能なのはとりあえず目標としていない。まずは、RPM をビルドできる環境として root を 展開して chroot するものを目指す。
何故 他のものではなく、fedora でもなく RHEL なのか? ... というと基本的に RPM を使っているシステムが好きなのだ。で、fedora はでかいし更新が頻繁で、作っているうちに時代遅れになってしまうのが嫌なのだ。RHEL は更新の頻度は低め だし、6 ならしばらく使えそうだ。あと、断っておくが全部をビルドするつもりはない。目指すのはあくまでビルド環境として成り立つ最低限度のもの。
どこまで出来るかは分からないのだが、やってみている。現状は、 RHEL6(clone) の chroot 環境 に qemu-mipsel を入れて セルフだか クロスだかよく分からないような 環境になっている。その環境で、 343 個の rpm をビルドした。最終的に 1000 個ぐらい必要なので、1/3 ぐらいの達成度。
ビルドするにあたっての基本方針
- 64bit(x86_64) ではもともと i386 環境と共存できるようになっていて、 /lib , /usr/lib は 32bit 環境用に空けてある。
i386 の代わりに mipsel を突っ込む というのが基本的なアイディア。その環境で qemu の usermode というのを使って mipsel のバイナリを動かす。rpm コマンドとかビルドするのが難しいものは、 x86_64 を使って 親の 環境を流用する。 - 準備 src.rpm から ビルドして x86_64 の野良クローンを作る。
この方針だと x86_64 と mipsel が同じバージョンでないと困る。多少のバージョンが違ってもなんとかなるが、まったく同じものをベースにして置き換えていくのがベストなのだ。
まずは、ベースとなる環境を作ってみることから始める。これも出来ないのでは、mipsel 版なぞ無理な話なわけで、mipsel 版の ビルドの 予行演習でもある。
また、どこまで作るのか ... 全てを作っていては とても巨大になる。どれを ビルドするのかを見極めることも 同時に行う。
最低限度必要なのは、自分自身をビルドできるもの 。gnome など当面必要なさそうなものは、はずす。
この作業は クリアした。まぁ適当なものだが、
に置いておく。mindev10bin2.iso と mindev10src5.iso だが、どちらも 2GB 弱もある。bin の方は、すべての RPM と rootfs の tarball -- mindev10.tgz が入っている。
root になるディレクトリを作って そこに root 権限で
# tar -zxvpf mindev10.tgz
とする。(いきなり usr とかになっているので 注意)。あとは、chroot して、
# mount /sys
# mount /proc
とすれば、だいたい使える。これ自体 (java 系を除く) すべての x86_64 RPM をビルドできる環境になっている。
ただし、i686 パッケージが入っている。これは mipsel の環境を作るには邪魔なので、アンインストールしておく。
ちなみに src の iso はすべての SRPM と minroot.tgz 。
minroot.tgz は、boot 可能な(はずの)最小の環境。これには rpm コマンドが入っているので、ここから RPM をインストールしていくことができる。
この root イメージに chroot する親OS のディストリビューションは、あまり関係ない。Linux のバージョンの方が重要だが、2.6.24 以降なら問題ないはず。
さて、これら以外に mipsel-devkit1-wk0.tar というファイルがあるが、mipsel 版について、いままでの成果をつっこんだもの。ただしまとまってはいない。
mipsel 開発環境
まずは、なにをするのか ... というと qemu のビルド。qemu といっても QEMU user-mode というもので、linux のカーネル機能 binfmt_misc とあわせることで、mipsel などのバイナリを native のように動かせるもの。
mipsel-devkit1 に qemu-bin.tgz に最低限必要なバイナリを入れてある。
startup.sh
usr/bin/qemu-arm
usr/bin/qemu-mipsel
usr/bin/qemu-ppc
mipsel 以外に arm とか ppc も入れてみた。.... mipsel が移植できるなら arm や ppc も同じやりかたでできるはずなのだ。mipsel がうまくいくようなら、これらもやってみるかも知れない。
このバイナリを作った SRPM も SRPMS-cross に入れてある。
クロス版 binutils , gcc , glibc
最初に必要になるのは、この 3 つ ... なのだが すでに 擬似セルフ環境に移行しているので、あまり重要ではなくなっている。だが、arm などの移殖のために、どうやって作っていったのかをメモしておく。それに GPL はソースだけでなく、どうやって作ったかの情報をも要求している。説明可能になってないと厳密にはまずい。
- 0) 準備 (種となる libc.a と include ファイルを用意)
- 1) gcc のビルド (最小環境)
- 2) glibc のビルド
- 3) gcc のビルド (stdlibc++ を含めた環境)
- 0) 準備
ビルドで、実行可能なファイルが作れるかチェックしているので、適当なものでよいから libc.a などが必要なのだ。で、ちゃんとした include ファイルと glibc を用意できれば、標準的なビルドが可能になる。- 1) gcc のビルド (最小環境)
SRPMS に (変更した) gcc の SRPM を入れてある。これをとりあえず rpmbuild で configure するところまで 進める。
パッチを当ててくれるし、config.log に config のオプションが残っているので テンプレートとして使えて便利。
../configure --prefix=/usr --target=mipsel-redhat-linux \
--build=x86_64-redhat-linux --host=x86_64-redhat-linux \
--disable-threads --disable-checking --with-system-zlib \
--enable-__cxa_atexit --disable-libunwind-exceptions \
--enable-gnu-unique-object --enable-languages=c,c++ --disable-libgcj \
--disable-libmudflap --disable-libgomp --disable-libssp \
--disable-shared --disable-libstdc__-v3
最初の configure はこれ。ほとんどのライブラリを disable にするし、libc.a しかないのでシェアードライブラリも disable に。
あと、--disable-fixed-point も入れておくと 使わない固定小数点ライブラリをビルドしないので、ビルド時間を短縮できる。
これが終わったら、インストールディレクトリを用意して
# make DESTDIR=xxx install
これで、一応ファイルをチェック。必要そうなものだけ、選んで / に展開しなおす。(後述) - 2) glibc のビルド
glibc のビルドに gcc は必要だが、ほかに カーネルヘッダーが必要。
Ingenic のサイトにあった、linux-headers-2.6.24.3.tar.bz2 をおいてある。これを /usr/mipsel-linux/include におく。
で、gcc と同じように SRPMS においた (変更した) glibc を途中までビルド。これを元に configure しなおして、ビルドする。
../configure CC=mipsel-linux-gcc CXX=mipsel-linux-g++ \
AR=mipsel-linux-ar RANLIB=mipsel-linux-ranlib --prefix=/usr \
--enable-add-ons=nptl,c_stubs,libidn,ports --without-cvs \
--enable-kernel=2.6.18 --enable-bind-now --with-tls --with-__thread \
--disable-multi-arch --disable-profile --enable-experimental-malloc \
--disable-nss-crypt \
--host=mipsel-linux --build=x86_64-redhat-linux \
--with-headers=/usr/mipsel-linux/include
glibc も インストールするディレクトリを用意するのだが ... オプションが違うので注意。
make install_root=/tmp/new-glibc install
mipsel-devkit1-inc0.tgz
mipsel-devkit1-lib0.tgz
これらが、作ったもの ... のはず。(実はすでに セルフで RPM が作れているので、そこからとってきている)
inc0 の方は、クロスでは、/usr/mipsel-redhat-linux に展開し、lib0 は / に展開して /lib と /usr/lib にインストールする。 - 3) gcc のビルド (stdlibc++ を含めた環境)
まずは、上記の inc0 を /usr/mipsel-redhat-linux に展開して lib00 を展開する。
lib0 でも良いかも知れないが、/usr/lib のファイルを /usr/mipsel-redhat-linux/lib に移動しないとだめかも。
3) のステップでは後ろ 2 行を変更。
--enable-libmudflap --enable-libgomp --disable-libssp \
--enable-shared --enable-libstdc__-v3
だいたい enable にする。libssp は使わないと思うので disable のまま。
mipsel-devkit1-gcc0.tgz は、これで作ったバイナリ。すべてではなく、必要そうなファイルを選んである。
以上 ... なのだが、これらのうち 3) で作った gcc の一部 は セルフ環境でも使う。ただし、cc1 , cc1plus 以外の実行形式のファイルはセルフのものと置き換えている。
mipsel-devkit1 の mipsel-devkit1-lib00.tgz には 3) が可能になる 最低限のファイルを入れてある。( /lib を使うので注意 )
1) から行う場合は、このうち usr/mipsel-redhat-linux/lib の crt*.o libc.a だけが必要。
擬似セルフ環境
以上は、x86_64 システム自体は壊さない範囲での作業だった。これからは rpmbuild でパッケージをビルドできるように システムのファイルも書き換えていく。
そのため、chroot 環境を別に用意する。最終的には、実機で chroot して動かせる 本当のセルフ環境を作るのが目的だが、今は それができない ので擬似セルフ環境としておく。
擬似セルフ環境は次のステップで作っていく。- 1) rpmbuild ができるようにする
- 2) 作った binutils , glibc , gcc に置き換える。
- 3) 作った RPM を 手動でインストールしていき、さらに ほかの RPM をビルドできるようにする。
3) が作業のメインなのだが、一筋縄ではいかない。依存関係が巡回しているのだ。そのため、仮に作った RPM をインストールして 全部そろったところで 再度正規の RPM をビルドしなおすことになる。この作業は非常にたいへんなので、説明が長くなる上、整理できていない。3) は後回しにして その成果物を先に紹介する。 - 1) gcc のビルド (最小環境)
- 1) rpmbuild ができるようにする
正確には、
rpmbuild --target mipsel --rebuild xx.src.rpm
ができるようにするわけだ。セルフ環境を目指しているわけで、ビルドに必要なものは、/usr/include /lib /usr/lib にインストールされていなければならない。そして、一部のものは、/usr/bin のコマンドを入れ替える必要もある。
とりあえず、include については、上記のものを /usr/include にインストールする。もとの include は、/usr/include-x86_64 とでもしておいて、参考にしている。
また、セルフ用のコマンドに置き換えるまでは、/usr/mipsel-redhat-linux/ の include や lib が参照される。include は、/usr/include へのリンクで済むが、lib はちょっと面倒だったりするので、早い段階で binutils や gcc を置き換える。
/usr/bin の置き換えについてだが、とりあえず mipsel-redhat-linux-xx をすべて xx に置き換える。本当は、 /usr/mipsel-redhat-linux/bin に集めてパスを通すのが正統のような気もするが まぁ今はこれでやっている。
以上の作業をすれば、一応は rpmbuild はできるようになる。ただし、いくつかの設定が具合が悪い。/usr/lib/rpm/macros , /usr/lib/rpm/redhat/macros , /usr/lib/rpm/rpmrc あたりを編集しなければならないが、ちゃんと整理できていないので説明できない。 - 2) 作った binutils , glibc , gcc に置き換える。
最初にビルドすべきなのは、zlib 。ビルドしたのは良いとして、どうやってインストールするかが次の問題。
全部は置き換えたくないのだ。
# rpmbuild --target mipsel --rebuild zlib-xxx.src.rpm
これでできた RPM に対して
# rpm2cpio zlib-xxx.mips.rpm | cpio -id
# rpm2cpio zlib-devel-xxx.mips.rpm | cpio -id
こうやって展開する。このうち /usr/include , /lib , /usr/lib (pkgconfig も) をインストール。
/lib , /usr/lib は基本的に問題がない。/usr/include も置き換えると決めたので問題なし。 問題なのは、/usr/bin だが as,ld など binutils のコマンド cpp , gcc , g++ , c++ といった gcc のコマンド、 あと pkgconfig と chrpath それに パッケージ固有の xx-config あたりは置き換えることにする。
glibc のパッケージでは、/sbin/ldconfig と /usr/bin/ldd あたり? ほかもありそうなのだがいまのところこれぐらい。
こうやって置き換えては、ビルドを続け、さらに置きかえる。x86_64 がすでにインストールされているから、依存関係のチェックは効かない。
こうやって作っていくのだが、gcc がビルドできないことが最初の壁。
どうしたものかと思ったのだが、ビルドでエラーになったら 手動で make する。prev-gcc/cc1 をクロスのものと置き換えることを 2 回ぐらいやれば、なんとか最後まで行く。
で、上記のクロス版とあわせるのだ。実行形式の cpp , gcc, g++ などは置き換えてしまう。ただし、cc1 , cc1plus を置き換えるとビルドが遅くなる。一応切り替えるようにしておいて 問題なければ クロス版を使う。
*) 現在のバイナリ
devkit にある
gcc-bin-self.tgz
mipsel-devkit1-bin.tgz
mipsel-devkit1-inc.tgz
mipsel-devkit1-lib.tgz
mipsel-devkit1-xx.tgz は、devel-rpms.sh で生成した。不完全であれば作りなおせる。
ちなみに、cc1-libs.tgz は、将来 mipsel に全部置き換えた上で、cc1/cc1plus のみ クロスを使う場合に使うつもりのもの。今は関係ない。
こうやって mipsel-devkit1 を作ってはみたが、実際の環境そのものではない。いろいろ不完全なところがあるので、動作を確かめた上で fix していこうと思う。
まずは、binutils 。これは、オリジナルの SRPM が、クロス用を作れるようになっている。
rpmbuild --without testsuite --define "binutils_target mipsel-redhat-linux"
--rebuild binutils-xxx.src.rpm
これで、できるので、インストールしておく。redhat になっているが、とりあえずなので、気にしない。
さて、これからが大変
という手順。
追記: 問題点多数
- セルフとして作ったつもりだが、/usr/mipsel-redhat-linux/include を要求される。
/usr/mipsel-redhat-linux には、/usr/include と /usr/lib への シンボリックリンクを作る。 - 正しく環境設定できれば、PATH_MAX が定義されないという状態にはならない。
#include <stdio.h>
#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
main() {
#ifdef __mipsel__
printf("hello world (mips) %d\n",PATH_MAX);
#else
printf("hello world\n");
#endif
}
たとえばこんな ソースをコンパイルして
/usr/mipsel-redhat-linux/lib/gcc/mipsel-redhat-linux/4.4.5/include/limits.h
/usr/mipsel-redhat-linux/include/limits.h
/usr/mipsel-redhat-linux/include/bits/posix1_lim.h
/usr/mipsel-redhat-linux/include/bits/local_lim.h
/usr/mipsel-redhat-linux/include/linux/limits.h
この順番で linux/limits.h が include されれば OK 。絶対パスで記述したが、実際の読み込みのパスは次のようになっている。
/usr/mipsel-redhat-linux/bin/../lib/gcc/mipsel-redhat-linux/4.4.5/../../../../mipsel-redhat-linux/include/...
これは、/usr/mipsel-redhat-linux/bin に gcc などバイナリを置いた場合。/usr/bin に上書きすると、相対パスと絶対パスが入り交じって少々ややこしくなる。
コンパイルは、gcc , gcc -static , g++ , g++ -static で試す。
ちなみに、現在の壁は、openldap と python 。python はビルドできたが、モジュール関係のビルド 環境が変。そしてこの 2 つの パッケージのせいで、多数の spec ファイルを書き換えるハメになっている。出来たら解決しておきたい。
openldap は、nss, nspr と unixODBC を要求する。unixODBC は、qt を要求するのだが、spec を書き換えてユーザインターフェイスをなしに出来て、なんとかビルドできた。だが nspr とかは全然進捗なし。結構厳しい。
それでも結構な数の RPM は、ビルドできた。現在は 430 個。... といっても SRPM の数で言えば 160 。作ろうとしてる SRPM は全部で 500弱。やっぱり 1/3 ぐらい。
バイナリを /usr/bin 以外に置く場合、/usr/lib/rpm/ の設定を変更しないといけない。/usr/bin/strip など 絶対パスが入っているものは、都合が悪い。
環境を変更したのだが、問題点が多くて.... もういちど作りなおそうとしている。
まず、gcc 関係の バイナリが足りない。cpp も入れ忘れたし、cc1 , cc1plus も 古いものにしてしまった。
asis にしてもちょっとひどいので、作りなおす。
gcc の実行環境は、やっぱりよく分からない。