なにの開発環境かというと、当然ながら Jz47xx の開発環境だ。OS は、64bit の Linux で RHEL 6.1 clone 。
後述するが、64bit の Linux というのは重要な要素。64bit が使えるマシンを持っていなかったので、わざわざ新調することにしたのだ。
CPU は、AMD Fusion E-350 。64bit だけでなく、仮想化の機能も使ってみたい。低消費電力も重視しているので、これになった。
RHEL 6.1 clone と書いたのもわけがある。Scientific Linux や CentOS が有名 だが、そのどちらでもないし、最終的に 全部自分でビルドしたものに置き換えるつもりなので、野良 clone になりそう。
さて、64bit Linux を使う思惑の説明をしておこう。
(1) qemu は、マシンそのもののエミュレータのほかに、Linux のバイナリの実行もサポートしている。... 要するに mipsel の 32bit の環境を作れば、chroot することで 動かすことができる。
(2) 64bit の x86_64 の環境は、/lib64 , /usr/lib64 を使うようになっていて、32bit の 共有ライブラリと共存できる。この特徴を利用して、i386 + x86_64 環境ではなく、mipsel + x86_64 環境にしてしまおうというのが思惑。
(3) rpm 関係をはじめとして、devel 以外の環境は x86_64 のものを使えるし、noarch パッケージも ビルドする必要はない。これはありがたい。
ちなみに、x86_64 では i386 などを動かせるという 定義を rpm で しているわけだが、mipsel も 動かせるという定義に変えないといけないはず。ちょっと面倒かも。
こういう思惑で進めていて、うまくいけば RHEL 6.1 相当の mipsel 環境ができあがる。ただ、失敗するかも知れない。なかなか難しいのだ。
どう進めていくかもうすこし説明しておこう。
(1) まずは、chroot する x86_64 自体のビルド環境を作る。実環境は壊したくないし、最終的に mipsel の ビルド環境も chroot して作る予定なわけで その予行演習にもなる。
(2) まず、devel パッケージをいれて、最低限度のものはすべてビルドできるようにする。
最低限度のもの ... という定義はかなり面倒。ちゃんとビルドできることも確かめておかないとならない。... でビルドできることを確かめる過程で 野良 clone ができてしまうわけだ。
この作業を進めていたが、だいぶ目処が立った。ただし、ビルド環境のみを重視しているので、gnome などは排除している。
(3) 次に qemu と クロスのビルド環境を作る。
クロスといっても fullset はすこぶる面倒。fortran とか java とかあるし それらに必要なライブラリ群も膨大になる。まずは、gcc と g++ をなんとか作り上げる。
この作業も進めているが、gcc をビルドするのに glibc が必要だったりする。その上なぜか 実行できるかチェックしていたりして ... qemu の環境も必須だったりした。
ちゃんとした glibc はないので、Ingenic のサイトから とってきた glibc のバイナリ から の crtX.o とか libc.a とかを借用することで、gcc はなんとかビルドできた。
また、ヘッダファイルも一式必要のようだ。target は mipsel-linux にした。これは、x86_64 の ヘッダファイル と Linux カーネルの mips の asm からとりあえずでっちあげて /cross/mipsel-linux/include に置いた。(あと prefix は /cross )
ちなみに使った gcc は、4.4.3 (patch なし) 。あくまで仮置き。
この gcc で Jz47xx のカーネルがビルドできるか試してみたところ OK 。動くものが出来たかどうかは分からないが、たぶん大丈夫だろう。たとえ、ここでやめても一応成果にはなった。
gcc と g++ ができたら、次は glibc のビルド。 glibc が出来れば、ちょっと一息つけるのだが、まだ出来ていない。
(4) それが出来たら、少しづつパッケージをビルドしていく。パッケージをビルドするのは、依存関係があるから 一筋縄ではいかない。エラーになったら 依存関係があるもののビルドをやって、再度ビルドしなおし。たいへんな作業なのだが、x86_64 環境を作る過程で かなり練習している。ただ devel パッケージを当てて端折ったところもあるから、難しいところも出てくるはず。
(5) パッケージがだいぶ揃ったら mipsel をメインにして 新たなビルド環境を作る。ビルドのほとんどは gcc (g++) の実行が占める。これを qemu のエミュレーション でやっていたら終わらないので クロスの gcc は残す。ほかに ビルドが出来なかった devel でない環境は x86_64 のものを流用する。
このビルド環境で再度作ってみる。一回作れたので問題はないはず。
(6) 最後にできたものを 実機にもっていく。ひょっとしたら大きな落とし穴があって動かないかも知れない。... といっても glibc ぐらいのもののはずで、(5) の環境で作り直す。
ちなみに、softfloat にはしない。Jz4760 は fp があるし、ないものでも カーネルでのエミュレーションでなんとかなる。
(7) 最終目標は、自分自身をビルドできる最小セット。ビルドに関係ないものは切り捨てるし、最小にするために、SPEC ファイルも書き換える。(gnome とか ビルドしないつもりだし、ドキュメント関係も 切り捨てるつもり)。予想では RHEL 6 全パッケージの 1/4 〜 1/3 ぐらいの規模になる。
... とまぁ遠大な計画。まだ (3) の途中だし挫折するかも知れない。すくなくとも時間はかかる。時間がかかると、途中で別のことがしたくなって中断するかも。
前に redhat-7 の環境をどうのということを書いたが、よくよく見たら ビルド環境がなかったのでパス。もっともそれがあったとしても RHEL 6 レベルに到達するのはかなり難しい。今回は、RHEL 6 どうして arch の乗り換えという方針。これなら成功すれば 一気に最新の環境が出来上がる。うまくいけば ppc も作りたい。arm までは手を出さない。(RPM ベースでは arm の実績はないようだ、ppc や mips は 64bit 版がある)
追記1 -- 気がついたことを追記していこうと思う
- glibc は、RHEL のビルド途中のもの (すなわち正規のパッチを当てたもの) のビルドがなんとかできた。(ただし gcc,g++ までで addon も rtkaio は失敗)
ftp://ftp.ingenic.cn/3sw/01linux/00toolchain/
jz-crosstools-src.tar.bz2 67863 KB 2009/04/03 0:00:00
ビルドするにあたり、これに含まれている ビルドスクリプトが大変参考になった。
ちなみに、正規の glibc は mips に対応していない。ビルドするには、glibc-ports を glibc のディレクトリに置いて addon のリストに top ディレクトリを加えるそうだ。 - ただ、gcc はあくまでクロス用のものしか作れていない。なにが不便かというとライブラリを /cross/mipsel-linux/lib に置かないといけないということ。/lib , /usr/lib を使うようなものにしたかったのだが、挫折。
だが、よくよく考えてみれば、本当にクロス... というか native で動かしたいのは、cc1 と cc1plus のみ。 rpmbuild で mipsel 用の gcc の パッケージが作れれば それを当ててから cc1 と cc1plus を置き換えれば良い。当面は rpmbuild でビルドしていくこと をやっていこう。
binutils は、cc1 と cc1plus ほどは CPU を消費しない。mipsel のパッケージを作って エミュレーションで動かしても良いかも知れない。 - rpmbuild についてだが、--target=mipsel を付けるだけでビルドできるものがあった。/usr/lib/rpm/macros を編集しないといけないと思っていたのだが、単純なものはそれすら必要ない。
ただ、作ったものは rpm でインストールできない。結局は /usr/lib/rpm/macros を編集しないといけない。 - rpmbuild では、mipsel だけの依存関係は見てくれない。x86_64 の rpm があれば通ってしまい、必要なものがないのにビルドしようとする。
これは、困るので一旦 devel パッケージ群を アンインストールすることにした。
ビルドが通ったら、x86_64 の devel をインストールして、mipsel の共有ライブラリを /cross に コピーしていく作戦。
実は、言うはやすし、なのだ。devel パッケージは 200-300 個ぐらいある。やってられないので、早めに gcc の rpm を作って rpm コマンドが使えるようにしたい。 - rpm で、システムの arch を見ている。/bin/arch や /bin/uname 経由なら 割と簡単にごまかして mips に見せかけられそうだが、システムコールで見ているとちょっとやっかい。これは調べておかないと。
ちなみに mipsel のバイナリになってしまえば qemu が "mips" を返すようになる。"mipsel" でなくて構わないのか? という気がするが カーネルがどうなっているか調べて 必要ならそれに合わせようと思う。
追記2 -- いくつか失敗したのでメモ
- gcc や binutils は、本来 rpm を作成する予定のソースコードを使い、機能に関するオプションも同じにしておく。
gcc の パッケージのビルドは、作成した gcc を使ってライブラリを作成する。作成した gcc とは、mips だから cc1/cc1plus を含め qemu で動作する。そうなると時間がかかってしょうがないのだ。
正規のパッケージを作成するときは止むをえない。(セルフ環境が出来ていたら、そちらを使った方が良い)。だが、とりあえず、バイナリが使いたいだけなので、ビルドを一旦止め x86_64 の cc1 に置き換えるとかした方が良い。
最終的なクロス環境でも x86_64 の cc1/cc1plus 置き換える予定だから、同じオブジェクトが出るようにしておいた方が良いという理由もある。
binutis は、シビアではないと思うが、些細な差異が問題が出るといやなので同じにしておく。
ちなみに --target は、mipsel-linux で良いと思う。 - x86_64 で動かす クロス用の 環境がビルドできたら、mipsel に見せかけるように環境を変える。/usr/bin の gcc とか as,ld などは、mips のものに置き換える。
あと /usr/include や /lib /usr/lib も置き換え。/cross/mipsel-linux 以下にあるものをコピー。
(簡単なプログラムが ちゃんと コンパイルできて、動作するかも確認しておく)
/usr/lib/rpm/macros は、x86_64 を mipsel に置き換える。あと %mips mipsel を追加。
/bin/uname , /bin/arch も mips を返すようにすべきだが、まだやっていない。
追記3 binutils/gcc/glibc の変更
- http://fedoraproject.org/wiki/Architectures/MIPS
ここを見ると、fedora 13 は、mips64el への移植プロジェクトがあって、バイナリとソース RPM をリリースしている。
で、オリジナルの fedora 13 のパッケージと spec ファイルを比べると、どこに変更が必要かわかる。binutils でさえパッチが追加になっていて、一筋縄ではいかないような感じ。RHEL6 をベースにして target だけ変更すれば良いような甘いものではなかったらしい。
ちなみに差分について、メモに残しておく。
binutils
Patch101: binutils-2.19.51.0.2-ls2f.patch
Patch102: binutils-2.20-loongson2f.patch
+%ifarch mips64el
+# no this feature in mips
+OPT_FLAGS=`echo $OPT_FLAGS|sed -e 's/-fstack-protector//g'`
+%endif
+%ifarch mips64el
+ --disable-multilib \
+ --disable-fixed-point --without-ppl --without-cloog \
+ --disable-checking --disable-werror \
+%endif
+%ifnarch mips64el
mkdir -p %{buildroot}%{_prefix}/sbin
gcc -static -Os %{SOURCE1} -o %{buildroot}%{_prefix}/sbin/libgcc_post_upgrade
strip %{buildroot}%{_prefix}/sbin/libgcc_post_upgrade
+%endif
+%ifnarch mips64el
%post -n libgcc -p %{_prefix}/sbin/libgcc_post_upgrade
+%endif
+%ifnarch mips64el
%{_prefix}/sbin/libgcc_post_upgrade
+%endif
glibc:
+Source2: glibc-ports-9f99a41.tar.bz2
+Patch2: %{glibcsrcdir}-fedora-mips.patch
+mv glibc-ports-* ports
+%ifarch mips64el
+%define _lib lib32
+%define _libdir %{_prefix}/lib32
+BuildFlags="-Wp,-U_FORTIFY_SOURCE"
+GCC="gcc -march=mips3 -mabi=n32 -mplt -fPIC -fexceptions -Wa,-mfix-loongson2f-nop"
+GXX="g++ -march=mips3 -mabi=n32 -mplt -fPIC -fexceptions -Wa,-mfix-loongson2f-nop"
+%endif
+%ifarch %{portarches}
+AddOns=,ports$AddOns
+%endif
+%ifarch mips64el
+/lib32
+/usr/lib32
+%endif - gcc のビルドにすごく時間がかかるのだが、ほとんどは、fixed-point の生成。(さらに エミュレータ環境では これのための時間が飛躍的に増える) 使いもしないのに、やってられないので、disable することは重要。
- glibc に mips を対応させるには、 glibc-ports が必要。
- -march=mips3 -mabi=n32 これはどうすべきなのだろう?
- redhat 系の mips では、64bit が標準で 32bit は lib32 を使うものらしい。-- これは 気に入らない。x86_64 のように lib と lib64 を使うようにして欲しかった。まぁ好き勝手に作るので、32bit 専用で lib を使うようにしたい。
- 上でも書いたが soft-float にはしない。Jz4760 は FP を持っているし、次に出る Jz4770 も持っている。その前のものは FP がないが、別にカーネルでのエミュレーションで問題ないはず。soft-float にすると FP を持っている CPU がそれを生かせない。-- こっちのデメリットの方が大きい。
ビルドを進めていたのだが、gcc のビルドで internal error になる。x86_64 の cc1 を置き換えても同じ結果。
だんだん面倒になってきたので、mips64el で実績のあるパッケージを使うことにした。64bit だが、実績のないものより随分マシ。
RHEL6 の gcc は、4.4.5 ベース。だが、/usr/lib/gcc/x86_64-redhat-linux/ を見ると 4.4.5 は 4.4.4 のシンボリックリンクで 4.4.4 と共用できるようにしているように見える。
さて、gcc-4.4.4 というと fedora 13 。
さて、この fedora 13 (MIPS) の binutils/gcc/glibc をビルドして、x86_64 の環境も入れ替えることをまずやろうと思う。
... これはなんとかなった。いろいろ問題があるもののパッケージも作れた。
次は、cross 用の もののビルド。
binutils は簡単だ。
--define "binutils_target mipsel-linux" --without testsuite
このオプションを追加するだけで良いらしい。
問題なのは、gcc 。
../configure --prefix=/usr --target=mipsel-linux --enable-shared \
--enable-threads=posix --enable-__cxa_atexit --disable-libunwind-exceptions \
--enable-gnu-unique-object --enable-languages=c,c++ --disable-libgcj \
--disable-multilib --disable-fixed-point --without-ppl --without-cloog \
--disable-checking --disable-werror --disable-libgomp
クロスの環境は、これでなんとか。ただし、include ファイル一式と glibc を用意しないといけなかった。(さらに mipsel の gmp-devel, mpfr-devel libz-devel 相当も用意した)
実をいうと、この bootstrap となる環境をどう作ったのか良くわかっていない。最終目的のモノが出来てしまえば それを使うようにすれば良いから 気にしないことにする。
いちおうメモしておくと、もともとの ヘッダーファイルは fc13 mips64el のパッケージから。glibc は Ingenic が提供しているバイナリ(たぶん soft-float) 。それを元に中途半端に作ったものを入れ替えつつ試行錯誤した。
さて、これを元に glibc
インストールした gcc/g++ は、prefix なしの as/ld を使うようなので、binutils のコマンドを /cross/mipsel-linux/bin とかに prefix なしでコピーしておく。
で、build 用ディレクトリは、x86_64 用に rpmbuild で作った上で、glibc-ports , を ports に rename して入れ、glibc-2.12-2-gc4ccff1-fedora-mips.patch を当てる。
export PATH=/cross/mipsel-linux/bin:$PATH
../configure \
CC="mipsel-linux-gcc" \
CXX="mipsel-linux-g++" \
CFLAGS="-fexceptions -DNDEBUG -g -O3" \
--prefix=/usr --enable-add-ons=ports,nptl,c_stubs,libidn --without-cvs --enable-kernel=2.6.18 --with-headers=/usr/mipsel-linux/include \
--enable-bind-now --with-tls --with-__thread \
--enable-multi-arch --disable-profile --enable-experimental-malloc --disable-nss-crypt \
--build=mipsel-linux
追記: 2011/10/04
なんだか 遅々として進まない。
MIPS 用の gcc パッケージのビルドで失敗する。... ひょっとしてメモリ(というより空間)不足?
MIPS の 32bit は、ユーザ空間(kuseg) が Max 2GB で小さい。3GB とか 場合によっては、4GB 弱使える i386 より不利な面がある。 クロスなので、メモリ自体は不足しないと思うのだが、リソース制限がかかってエラーになっているかも知れない。
それはともかく、飽きたので まずは自分自身をビルドできるものをちゃんと作ることにした。
それは、随分進んだ。(jdk の 2-3 のパッケージを除き)ビルドしたパッケージだけを使って自分自身を作れている。 だいたい必要な SRPM 数は 600 弱。java なしで済ませられると 500 以下にできるのだが、まだうまくいっていない。ちなみに gnome は外してある。latex など一部のドキュメント・ツールと emacs も外している。
当てたパッケージの総数は、1000 弱。
これを fix させてから再び MIPS に挑戦するつもり。
追記: とりあえず今の状況とビルドメモ
まず、RHEL6 野良clone だが、ほぼ自分自身がビルドできるようになった。
できないのは、gcc の i686 ライブラリのパッケージのみ。32bit の環境まで作れば問題ないはずだが、面倒なのでパス。
作ったのは、1301 の rpm に加えて java 関係 をビルドするためのパッケージ 205 と i686 glibc パッケージ 8 。まぁ 1500 個ものパッケージがある。
http://nmj.sumomo.ne.jp/my-rhel6/
ここに野良ビルド版の 全て -- ソースRPM と RPM を置いておく。ただ、大きいので予告なしに消すかも知れない。
これを元に mips 版を作るのが目標
0) 準備
ビルドする環境は、作った RHEL6 野良clone 。これの tarball を元に chroot での環境を作る。まず、この環境の 32bit は mips にするので、i686 パッケージは全部アンインストールしておく。
次に qemu をビルドして、/usr/bin/qemu-mipsel をインストール。あと これを実行するように binfmt_misc を設定する。
1) クロス版 binutils の ビルド。
RHEL6 では、オリジナルの binutils でクロス版も作れるようになっている。
# rpmbuild --define "binutils_target arm-linux-gnu" \
--define "binutils_target mipsel-linux" \
--rebuild binutils-xxxx.src.prm
とりあえず、こんな感じで作って インストールする。
ちなみに、これで作った binutils は、普通のクロス用と違う。ld のパスが セルフ用と同じになっている。/lib /usr/lib がデフォルト。
2) クロス版 gcc の ビルド(1)
つぎに gcc だが、mips の libc やヘッダファイルが必要 。で、gcc が出来たら glibc を作って libc やヘッダファイルを作る。--- 巡回してしまっていて ゼロからのビルドは大変難しい。おすすめは、
ftp://ftp.ingenic.cn/3sw/01linux/00toolchain/
から toolchain のバイナリ と ソースを取ってくること。ソースにはどうやってビルドするかが分かるスクリプトも付いている。
クロスの環境は、/usr/mipsel-linux に作る。この下に 最初に使う libc,libm と include ファイルが必要になる。
インストール先は、上記だけで済まない。/lib と /usr/lib/gcc/mipsel-linux , /usr/libexec/gcc/mipsel-linux を使う。
gcc のソースコードは、RHEL6 のもの -- gcc-4.4.5-6.el6.src.rpm を使う。これを普通にビルドし、configure を終了したところで止める。
このソースツリーを使って mips 用の config をする。
# ../configure --prefix=/usr --target=mipsel-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
最初は、シェアードライブラリがない ので disable にする。また、libstdc も無理なのでパス。
これで configure して make , make install 。
3) glibc のビルド 。
これもまた、RHEL6 のものを使う。glibc のビルドでは、カーネルヘッダのみあれば良い。前に使った include ファイル や libc.libm は一回捨てて、カーネルヘッダのみを /usr/mipsel-linux/include に展開する。とりあえずは、ingenic のサイトの toolchain の ソースに付属するもので良い。
さて、mips の glibc をビルドするには、glibc-ports が必要 ... なのだが、RHEL6 の glibc は、正規版ではなく、ある時点でのスナップショットのため完全に対応する glibc-ports がない。
しょうがないので、glibc-ports-2.12.1.tar.bz2 をベースにする。上記のように glibc のソースを展開したあと、これを展開して、ports に リネーム。
実をいうと、glibc-ports-2.14 の ports/sysdeps/mips だけ入れ替えている。ただし、fpu/ftestexcept.c , fpu/feupdateenv.c はエラーになるので 12.1 に戻している。
# ../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
いまのところこれ。add-ons から rtkaio を除いているし、disable-nss-crypt の指定をしている。nss-crypt がビルドできるようになったら enable して glibc を作りなおさないといけない。... ただし先の話。
ビルドが完了したら インストールするのだが、x86_64 の環境を壊してしまうとまずいので、install_root を指定する。
# make install_root=/tmp/new-glibc install
たとえばこんな風にする。new-glibc にインストールされた、lib 配下を /lib に移動する。
そして、usr/include を /usr/mipsel-linux/include に移動。
あと usr/lib を /usr/mipsel-linux/lib に移動。ただし問題がいくつかあって fix しないといけない。
- いくつかの .so は ../lib のもののリンクになっている。これを /lib になるように張り替える。
- libc.so などは、テキストで、/usr/lib を指しているところがある。これを /usr/mipsel-linux/lib になるように編集する。
4) クロス版 gcc の ビルド(2)
正しそうな 環境ができたので、作りなおす
(1回目) --disable-shared --disable-libstdc__-v3
(2回目) --enable-shared
最終的には、--disable-libmudflap --disable-libgomp も削除しないといけないし、gcj もビルドしないと。でも、それは先の話。
さて、これで gcc と glibc が出来た。このバイナリ一式があれば、gcc も glibc も再ビルドできる。整理して、ダウンロードできるようにしておこうと思う。
ここまでがクロスの環境。
さて、ここからは、qemu-mipsel を使った 擬似セルフ環境に移る。
(前に戻れなくなると困るので、以上の chroot 環境を fork する。)
5) rpmbuild できるように 環境を切り替え
まず、
/usr/lib/rpm/platform/xx/macros
/usr/lib/rpm/rpmrc
に mipsel の定義を追加。
次に、/usr/bin/gcc など を mips 版に置き換える。setarch が使えると便利なのだが、調べていない。手動で置き換えても ... まぁなんとか。
こうすると、次から ビルドするものは すべて mipsel になる。rpmbuild での指定は、
rpmbuild --target mipsel ....
とする。
簡単なものは、これでビルドできてしまう。うまくいくかどうかのチェックには、zlib と mingetty を使っている。
ここからが大変。必要な パッケージは x86_64 で すべて当たっている。 依存関係が分からない状況で ビルドしていく。できた mipsel 版の rpm も rpm コマンドでインストールしない。rpm2cpio を使って /lib /usr/lib を中心に取り出して 手動でインストールする。
/lib, /usr/lib にインストールされている ダイナミックライブラリ の 元となる ソースパッケージは、280 ぐらい。これらを地道に 作っていく。なかには、gcc (セルフ)など手強いものがある。が、クロスでの gcc ビルドは諦めた。実機で ビルドするつもり。
追記: これなのだが、妙にうまくいっていない。
dlopen が見つからないとか 作ったシェアードライブラリがリンクできないとか 色々。
どうも MIPS の場合は、-fPIC でないとシェアードライブラリが作れないような ...
dlopen が見つからないというのは、明示的に -ldl を指定していないことが理由。
あと -D__mipsel__ が自動では定義されていない。普通は rpm の設定でごまかせるのだが、ごまかせない rpm もある。
さらに、gcc は、/usr/mipsel-linux/xx を必要とするのだが、prefix が /usr になっているので、両方に同じものを用意しないとまずい。
まぁ、色々あるのではあるが、bash も ビルドは出来て、qemu-mipsel では動いている。binutils の セルフ版もビルドは出来た。glibc は惜しいところまで行く。(locale 作成で メモリ不足のためエラー )
gcc も 途中までは出来る。クロスで一旦全部作ったから、gcc や g++ のフロントエンドだけが欲しい。( cc1 などは、クロスのものを使いたいし ライブラリも全部できている ) 。エラーが起きるのは確か cc1plus の 2 回目のビルドだったと思うので、gcc , g++ はできているかも知れない。
あと、メモリ不足の件。これは実際は 空間不足のはずで、ヒープのスタートアドレスとか ダイナミックライブラリのスタートアドレスが関係しているのだと思う。だが、どこで定義しているのかまだ分かっておらず直せていない。
調査(1)
- __mipsel__ を定義したいのだが、誰がどこで定義するのが正しい?
gcc を見たら、__x86_64__ などは、gcc/config/i386 の配下で見つかった。答えは gcc 。gcc は、cpp/gcc/cc1 のパーツに別れているのだが、関係あるのは (おそらく) cpp 。
で、定義するのは、gcc/config/mips/linux.h (の TARGET_CPU_CPP_BUILTINS() ) が普通らしい。この定義の中で TARGET_64BIT, TARGET_BIG_ENDIAN を参照して、
__mipsel__ , __mipseb__ , __mips64el__ , __mips64eb__
のどれかを定義することにした。 - メモリ不足はなぜ起きるのか? まずは map から
# cat /proc/プロセス番号/maps
とすることで、どこに map しているかが分かる。qemu-mipsel を使っても 元の mips の mapping に従っているように見える。maps を 整理すると ...
00400000- プログラム(cc1 など)
xxxxxxxx- heap (text - data - bss の次から)
40000000-40001000 ---p
40001000-40a01000 rw-p stack
40a01000- /lib/ld-2.12.so
40000000- /lib/ld.2.12.so
40b1c000- libgcc_s.so.1
60000000- qemu-mipsel
6d523000-6d544000 [heap] (qemu 自体の)
2b898922c000- /lib64/ld-2.12.so
heap や stack について、簡単なプログラムで printf してチェックしたところ、heap は、プログラムの終わりから stack は、40a10000 あたりから逆向き に割り当てられることが分かった。
要するにプログラムが使えるアドレス空間は、ダイナミックライブラリを除くと 00400000 - 40000000 の 約 1GB ということになる。これが足りない.... ということが 起きるかどうかは、分からない。随分前のバージョンでも 数百MB なら使っているのを見たことがある。
問題は、スタックかも知れない。 40000000 からの 1ページは、アクセス不可になっている。ということは、これがボトムで これを超えることは出来ないのかも。そうだとすれば 40a01000 までの 10MB がスタックに割り当てられた 領域。
stack も alloca を使うと大量に消費することになるから、stack 領域の不足 の可能性は高い。
ただ、 40000000 にアクセスしたときに copy-on-write で割り当て直すかも知れない。これも簡単なプログラムで確かめることが出来る。確かめてみたところ、40001000 には書き込めたが、40000000 だと core dump した。たぶん、stack bottom は超えられないのだろう。
追記: 調べていたら、qemu の -s オプションでスタックサイズを変更できることが分かった。
たとえば、qemu-mipsel -s 67108864 /bin/bash.mips として 起動すると /lib/ld-2.12.so のアドレスが 44001000 に変わる。
で、ソースを見てみると ... ulimit も参照してスタックサイズを決めている。
stack size (kbytes, -s) 10240
ulimit で見てみたら、10MB にしていたのは、自分であった。そして、たとえば ulimit -s 65536 とすれば、64MB 確保されることが確認できた。
virtual memory exhausted: Cannot allocate memory
それはクリアできたが、やはりダメだ。... というより悪化しているかも。
追記: 結構出来てきた。パッケージ数にして 208 個。(... といっても 1/5 ぐらい。)
- cc1 , cc1plus
なんとか セルフで cpp, gcc , g++ と cc1, cc1plus を作ることはできた。忘れないように書いておくが、エラーになったら prev-gcc の cc1 を クロスのものに置き換える。2 回ぐらい置き換えたら なんとか誤魔化せた。
セルフ環境では、セルフで作成した binutils , glibc の rpm を使っている。
binutils は、オリジナルの srpm で OK だったが、glibc は locale の作成でメモリ不足でエラー。
まとめて変換しているところを 1 つづつ行うように修正。それでも最後はダメなので、いくつか 削除しておく。
元のインクルードファイルは、一旦 /usr/include-x86_64 に rename して新しく作った glibc-headers と glibc の作成に使った カーネルヘッダをベースにした。
で、基本は、cc1, cc1plus をクロスのものに置き換えて使う。
... これで良いかと思ったのだが、クロスは、/usr/mipsel-linux/include を要求する。これはシンボリックでごまかす。ただし、/usr/mipsel-linux/lib を作るとまずい。-ldl がないといったエラーは lib も作ったためのようで、かなりハマった。
良く知らないのだが、cc1 は cpp の機能も兼ねるのが原因みたい。__mipsel__ などの定義も クロスでは作っていないので、有効にならない。これも要注意。
binutils も 実をいうと良くわからない。セルフで作った ld は、/usr/lib /lib を見てくれるが、クロス用は ちょっと挙動が違うような ...
あと /usr/bin/ldd と /sbin/ldconfig は、新しく作った glibc のものと置き換えた。
- pkgconfig
もともと pkgconfig は、/usr/lib64/pkgconfig に *.pc として 作られている。
これらは、/lib64 などを参照するように書かれている。これらを全部書き換えるのではなく、
セルフ用に 作った pkgconfig を使うようにしている。こうすると 新しく作った /usr/lib/pkgconfig/*.pc のみを参照するようになる。
足りないものは、x86_64 の方から取ってきて書き換える。 - linux/xx.h
Ingenic のカーネルヘッダが元だが、足りない定義がある。問題が起きるのは、audit など
capability.h falloc.h netfilter.h
いまのところ上記を置き換えている。 - libgcrypt
-DNO_ASM を指定するとなんとか。 - elfutils
ビルドできていない。どうしたものか。 - メモリ不足(空間不足)
解決できていない。gcc のビルドや、glibc のビルドで起きている。 - chrpath
- いんちき spec
rpm の依存関係がループしていたりするので、いきなり 正しい rpm は作れない場合がある。こういうのは、とりあえず作っておいて、後で作り直す。
... で、そういう対応をしたものが実に多かったりする。特に python とか。
当面の目標は、python をビルドすること。これができると 大分進んだことになる。 - PATH_MAX
この定義がないのでエラーが起きるものがいくつかある。正しく修正したいが、どこを修正すべきか分かっていない。 - valgrind ( arch がないというエラー )
とりあえず、python が出来た。だが、perl も rpm もビルドできていない。あと ポイントになりそうなもので、mesa がある。
rpm にために必要なもので作れていないのは、elfutils と nss (nspr, nss-softokn, nss-util) - libtiff , tcp_wrappers
どうもおかしい。ちゃんとリンクできないみたいだ。