2011年11月05日

開発環境の整備(2)

前記事ではグダグダになってしまったので、一回整理。

開発環境の整備とかいうタイトルにしてしまったが、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 はソースだけでなく、どうやって作ったかの情報をも要求している。説明可能になってないと厳密にはまずい。

    まずは、binutils 。これは、オリジナルの SRPM が、クロス用を作れるようになっている。

      rpmbuild --without testsuite --define "binutils_target mipsel-redhat-linux"
      --rebuild binutils-xxx.src.rpm

    これで、できるので、インストールしておく。redhat になっているが、とりあえずなので、気にしない。

    さて、これからが大変

    • 0) 準備 (種となる libc.a と include ファイルを用意)
    • 1) gcc のビルド (最小環境)
    • 2) glibc のビルド
    • 3) gcc のビルド (stdlibc++ を含めた環境)

    という手順。

  • 0) 準備

    ビルドで、実行可能なファイルが作れるかチェックしているので、適当なものでよいから libc.a などが必要なのだ。で、ちゃんとした include ファイルと glibc を用意できれば、標準的なビルドが可能になる。

      mipsel-devkit1 の mipsel-devkit1-lib00.tgz には 3) が可能になる 最低限のファイルを入れてある。( /lib を使うので注意 )

      1) から行う場合は、このうち usr/mipsel-redhat-linux/lib の crt*.o libc.a だけが必要。

    • 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 以外の実行形式のファイルはセルフのものと置き換えている。

    擬似セルフ環境

    以上は、x86_64 システム自体は壊さない範囲での作業だった。これからは rpmbuild でパッケージをビルドできるように システムのファイルも書き換えていく。

    そのため、chroot 環境を別に用意する。最終的には、実機で chroot して動かせる 本当のセルフ環境を作るのが目的だが、今は それができない ので擬似セルフ環境としておく。

    擬似セルフ環境は次のステップで作っていく。

    • 1) rpmbuild ができるようにする
    • 2) 作った binutils , glibc , gcc に置き換える。
    • 3) 作った RPM を 手動でインストールしていき、さらに ほかの RPM をビルドできるようにする。

    3) が作業のメインなのだが、一筋縄ではいかない。依存関係が巡回しているのだ。そのため、仮に作った RPM をインストールして 全部そろったところで 再度正規の RPM をビルドしなおすことになる。この作業は非常にたいへんなので、説明が長くなる上、整理できていない。3) は後回しにして その成果物を先に紹介する。

  • 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 していこうと思う。

追記: 問題点多数

    環境を変更したのだが、問題点が多くて.... もういちど作りなおそうとしている。

    まず、gcc 関係の バイナリが足りない。cpp も入れ忘れたし、cc1 , cc1plus も 古いものにしてしまった。

    asis にしてもちょっとひどいので、作りなおす。

      gcc の実行環境は、やっぱりよく分からない。

    • セルフとして作ったつもりだが、/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 など 絶対パスが入っているものは、都合が悪い。
posted by すz at 11:05| Comment(0) | TrackBack(0) | Jz47xx(Linux)
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス: [必須入力]

ホームページアドレス: [必須入力]

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/49854758
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック