Skip to content
Liva edited this page May 1, 2016 · 1 revision

newlibとは

Wikipedia

gcc with newlibで何ができるの

標準関数(printfとか)が使えるようになります。 g++なら、STLも使えます。

この記事について

newlibを組み込んだgccコンパイラを作成します。ちなみに、この記事は以前Livaが書いたブログ記事(ドメインごと破棄済み)を掘り起こしたものです。更新日が2010-12-09なので、もしかしたらいろいろ違ってたり、もう少し楽にできたりするかもしれません。参考までに。

ではここから6年前の記事になります。

環境:

WindowsXP 32bit

(UNIX,Linux,MacOSXでも殆ど同じ手順で行けると思います。むしろCygwinの導入やCygwin固有の問題がないので楽かもしれません。あと、MacOSXではMacPortsにi386-elf with newlibがあるので、それを使えばすぐに構築できます)

コンパイルに必要なもの:

Cygwin

※追加パッケージのインストールが必要なので、既にCygwinをインストールしている方も説明を読んで下さい。

GCC,binutilsのソース

GMP

MPFR

MPC

※GCCはgcc-coreとgcc-g++の二つのファイルをダウンロードし、同じフォルダに展開(ここではC:\build)してやるとソースサイズが小さくなります。

参考サイト:

osdev.org

http://www.sixnine.net/cygwin/translation/devel/cygwin-to-newlib-cross-howto.html ※2016年時点でリンク切れです。キャッシュとか残ってるかもしれないので、一応書いておきます。

GCCのコンパイルはかなり時間がかかるので、一日潰せるくらいの余裕がある日にやってください。 ※2016年時点ではマルチコアの力でぶん殴れば割とコンパイルはすぐ終わるようになりました。jオプションを忘れないでね

あと、一連のステップを全て終わらせるまで、bashシェルは閉じない方がいいと思います。

それじゃあ、行きましょうか。

Step1:Cygwinのインストール

インストール自体は至って簡単です。Googleで「Cygwin インストール」と検索をかければ一瞬です。

が、パッケージ選択の所だけは注意してください。Develカテゴリ内のautomake、binutils、bison、flex、gcc-core、gcc-g++、makeにチェックを付ける必要があります。(binutilsにはチェックを付けた覚えがないのですが、確認したらインストールされていたので、一応チェックをつけておいて下さい。たぶんgcc-coreと一緒に自動でチェックが付くとはおもいますが。後、C++を使わない人はgcc-g++のチェックをはずしても結構です)

後、MacPortsでインストールされるi386-elf-gccではgettextも使っているようですので、一応gettextにもチェックをつけておいてください。(ちなみに、この記事通りに試しても、MacPorts版と同一になるわけではなく、むしろこの記事で紹介しているMacPorts版でないi386-elf-gccとほぼ同一になります)

インストールはそこそこ時間がかかりますので、少し暇つぶしをしていて下さい。

インストールが終わり次第、Cygwinのbashシェル(Cygnusだっけ?忘れたけど)を開きましょう。

Step2:ファイルの展開

GCC、binutils、GMP、MPFR、MPCのソースは全てダウンロード済みだと思うので、どこかのディレクトリに展開してください。

ここではC:\buildに展開したものとします。

Step3:binutilsのコンパイル

binutilsをコンパイルしていきます。

ここからbashで作業をします。

以下の様に入力してください。($はbashが入力待ちの時に表示されるやつ)

$ cd C:/build

$ export TARGET=i386-elf

$ export PREFIX=/usr/local/gcc

$ mkdir build-binutils

$ cd build-binutils

$ ../binutils-2.10.1(←ダウンロードしたバージョンに置き換えて下さい)/configure --target=$TARGET --prefix=$PREFIX --disable-nls

$ make all

$ make install

これで終了です。ちょっと時間がかかりますが、簡単です。

次のステップに進む前に、少しやっておかないといけない事があるので、それを済ましてしまいましょう。

$ export PATH=$PATH:/usr/local/oasis/bin

$ i586-elf-ld --version

$ i586-elf-ld --versionできちんとldのバージョン情報が表示されれば成功です。

command not foundとか言われたら、どこかが間違っているので、検証してみてください。

ちなみに、最後のステップまで終わらせる前にbashシェルを閉じてしまった場合は、次のbashの起動時に上の二行をもう一度打ち直し、パスを通して下さい。

Step4:各種ライブラリのインストール

GCCの4.3以降のコンパイルにはGMP,MPFRの二つのライブラリが必要です。また、GCC4.5以降のコンパイルにはMPCが必要になります。

Cygwinのパッケージからインストールすることもできますが、バージョンが古く、バグが含まれているようなので、ここで一気にコンパイルしちゃいます。(※GMP、MPFR、MPCのコンパイルの順番は変えないで下さい)

$ cd ../ (ここでC:/buildに戻るはず)

$ mkdir build-gmp build-mpfr build-mpc

$ cd build-gmp

$ ../gmp-"gmpのバージョン"/configure --prefix=/usr

$ make

$ make install

$ cd ../build-mpfr

$ ../mpfr-"mpfrのバージョン"/configure --prefix=/usr

$ make

$ make install

$ ../mpc-"mpcのバージョン"/configure --prefix=/usr

$ make

$ make install

これで終わり。

Step5:GCCのコンパイル

ここから少し鬼門です。

落として来たソースコードのファイル名が一部崩壊している(たぶん解凍に失敗した)ため、それを修正してやらなくてはいけません。

さらに、設定が少し狂っているようなので、ソースコードを一部いじってやる必要もあります。

とりあえず、それは置いておき、試しにコンパイルしてみましょう。

$ cd ../

$ ln -s ../newlib-"newlibのバージョン"/newlib ../gcc-"gccのバージョン"

$ mkdir build-gcc

$ cd build-gcc

$ ../gcc-"gccのバージョン"/configure --enable-languages=c,c++ --disbale-nls --target=$TARGET --without-included-gettext --enable-obsolete --with-newlib --disable-libgfortran --with-gxx-include-dir=$PREFIX/$TARGET/include/c++/"gccのバージョン"/

$ make

$ make install

たぶん、一発ではコンパイルが通りません。

エラーが発生したら、Googleで検索をかけて柔軟に対応していく必要があります。

僕が発見したエラーはこの二つ。

checking for shl_load... configure: error: Link tests are not allowed after GCC_NO_EXECUTABLES.

error:ext/pb_ds/detail/resize_policy/hash_load_check_resize_trigger_size_base.hpp: No such file or directory

前者は正直日記に解決策が載っていました。

ただし、autoconfはGCCのソースのルートディレクトリだけではなく、libstdc++-v3でもしてください。(ルートディレクトリは必要ないかもしれません。未検証)

あと、autoconfを一回かけると、autoconfのこのバージョンを使え!みたいなエラーがでるので、対応するautoconfをインストールし、それでコンパイルしてやる必要があります。

ソース

ちなみに、GCC4.5.1ではautoconfのバージョンは2.64でした。

$ ../autoconf-"autoconfのバージョン"/configure --prefix=/usr

$ make

$ make install

後者は、ファイルの解凍ミスです。

たぶんファイル名が長すぎるんでしょうね。(ちなみに、Lhaplusで解凍しました)

仕方がないので、ないと言われるファイルを開いてみてください。

ext/pb_ds/detail/resize_policy/hash_load_check_resize_trigger_size_base.hppがない、と言われた場合、

C:\build\build-gcc\i386-elf\libstdc++-v3\include\ext\pb_ds\detail\resize_policy\hash_load_check_resize_trigger_size_base.hppを開きましょう。

メモ帳で開くと、

㰡祳汭湩㹫/cygdrive/c/build/gcc-4.5.1/libstdc++-v3/include/ext/pb_ds/detail/resize_policy/hash_load_check_resize_trigger_imp.hpp

みたいな感じになります。

そこで、C:\build\gcc-4.5.1\libstdc++-v3\include\ext\pb_ds\detail\resize_policyに移動します。すると、元のファイル名がhash_load_check_resize_trigger_imp.hppだと辛うじてわかるような残骸状態のファイルがあるので、リネームして正しいファイル名に直してやります。

具体的にはcc_hash_max_collision_check_resize_trigger_imp.hppがcc_hash_max_collision_check_resize_tri0000644になっていたりします。

ファイル名がおかしくなっているのはdetailフォルダ内に散在しているので、C:\build\build-gcc\i386-elf\libstdc++-v3\include\ext\pb_ds\detailとC:\build\gcc-4.5.1\libstdc++-v3\include\ext\pb_ds\detailをExplorerで同時に開き、名前のおかしいファイルを一つ一つ修正していってください。コツが掴めると、結構早く作業が終わると思います。

たぶんこの二つのエラーを解決すると、コンパイルが通ると思います。コンパイルが止まった所からやり直してみてください。(例えば、makeの途中で止まった場合、エラー箇所を修正した後でもう一度makeと打つ)

最終的に150MBくらいのi386-elf-gccが完成すると思いますが、もっと減量する事ができるので、それをやっておきましょう。まずはC:\Cygwin\usr\local\gcc\binへ移動。

このフォルダ内のEXEには使われないゴミデータが書きこまれているので、C:\Cygwin\bin\strip.exeでそれを落としてやります。C:\Cygwin\usr\local\gcc\bin内のファイルを全選択し、(EXE以外のファイルはUnknown file formatと言って無視してくれるので問題ありません)strip.exeのアイコンにドラッグ&ドロップしてやると、かなりEXEファイルが小さくなります。(確かi386-elf-ld.exeなんかは2MBくらいあったのが、700KBまで減量された気がします)

同じ事をC:\Cygwin\usr\local\gcc\i386-elf\binとC:\Cygwin\usr\local\gcc\libexec\gcc\i386-elf"GCCのバージョン"でも実行。

さて、C:\Cygwin\usr\local\gcc\binに戻り、GCCのEXEファイルの起動に必要なDLLファイルをコピーしてやります。

Cygwinで作ったEXEはC:\Cygwin\bin内にあるDLLがないと動作しないので、いざコンパイル、という時にエラーにならないよう、予め対策をしておくわけです。

というわけで、i386-elf-gcc.exeをダブルクリック、”コンポーネントが存在しません”エラーが出るので、そこに書いてあるDLLファイルをC:\Cygwin\binからC:\Cygwin\usr\local\gcc\binへコピーしてやります。

お疲れさまでした。これで全ての作業が終了です。

ちなみに、このクロスコンパイラはかなり貧弱です。具体的には以下の事ができません。

・リンク後の出力フォーマットにi386-elf以外を指定するとLDがエラーを吐きます。 ※2016年加筆:newlibのライブラリファイルをi386-elfでコンパイルしたんだから、そりゃそうだよね

・Cygnus上から実行しないと、共有ライブラリがないとか言われます。 ※2016年加筆:PATHが通ってないんじゃね?

原因は不明。ご存知の方、ご教授願います。

以下、2016年加筆

実際にnewlibをリンクしてコンパイルするにはPorting Newlibを参考にして関数を実装してください。