yunomuのブログ

趣味のこと

GHCをビルドする

その昔、ソフトウェアのインストールというのが一大イベントだった時代があったという。って20年前くらいですけど。
なぜ難しいかというと、今のようにパッケージ管理なんてものは無かったし、そもそもバイナリ配布できるほどいろんなものの規格が統一されてなかったりとかconfig系のライブラリが充実してなかった……のかな? まあそこら辺はよく知らないんですが、そんなわけで、今よりは人間力に頼る部分が多かったそうで。具体的にはコンパイルオプションや定数なんかを自分の環境に合わせて調整して、自分でソースからビルドしなきゃいけなかったとか。クロスコンパイル環境を作るのが難しかったってのもあるのかもしれないですね。

で、インストールが難しいの代表格がコンパイラLaTeXだったそうです。LaTeXはいいや。

そんな時代なのでコンパイラだってソースからビルドすることになるんですが、コンパイラをビルドするためにはコンパイラが必要になる。
じゃあそのコンパイラはどこからやってくるのかというと、実はコンパイラだけは色んな環境で動くように作られた最小セットの実行ファイルが配布されていて、そのコンパイラを使って少し機能を追加したコンパイラをビルドする。そして新しい機能を使ってさらに機能を追加したバージョンのコンパイラをビルドする。……というのを繰り返して、最終的に最新版のコンパイラをビルドして、そのコンパイラとそのコンパイラを使ってビルドしたコンパイラの差分が無くなるまでビルドを繰り返して、差分が無くなったら完成。らしい。
それって最新版をビルドするために過去のバージョンのコンパイラのビルド時間+最新版のビルド時間がかかるって事になるんじゃないですかね。面白そうだけどあまり自分ではやりたくないというか、コンパイラの機能追加の時にいろんな事を考えなきゃいけなさそうで、大変そうだなぁ。どうだったんだろうなぁ。

で、このコンパイラのビルドの仕組みを悪用したのが有名なKen Thompsonのバックドアなわけですね。一番最初のコンパイラに「login.cを見つけたらバックドアを仕込む」というコードをコンパイラのビルド時にコンパイラに仕込むというコードを仕込んだという、なんかそういうあれ。こんがらがる。

まあ与太話はいいや。
ということで、ghcをビルドしてみようと思うんですが、ghcをビルドするためにはghcをインストールしておかないといけないみたいです。とはいえそこら辺はインストールの前準備の段階でスクリプトが色々やってくれてるみたいなので何も心配する必要は無くて、つまりここまでの話は完全に無駄話というわけです。ここまで全部読んだ方はお疲れ様でした。

本題。

前回の記事の最後に

というか、ghciのコード直した方がよくない?

などと偉そうな事を書いたので、とりあえずビルドできる状態くらいは作っておこうかなぁと思って。ghcソースコードリーディングなんてイベントもあることですし、いずれ読むにしても私はビルドできないソースは読みたくないので。
(!会場は新宿です!) GHCソースコードリーディング勉強会 第0回(準備編) - [PARTAKE]

プラットフォームはこれです。
x86_64-apple-darwin
Macですね。

何はなくともとりあえずgit cloneして、そしたらMakefileがあったのでいきなりmakeしてみました。

# git clone https://github.com/ghc/ghc.git
# cd ghc
# make
Makefile:39: mk/config.mk: No such file or directory
Makefile:41: *** Please run ./configure first.  Stop.

ですよねー。config.*みたいなのがあるのにconfigure無いもんね。ここらへんはさすがにルーチンワークです。無い人はautoconfとautomakeを入れるとかしてください。

# autoconf
# ./configure
mk/config.h.in doesn't exist: perhaps you haven't run 'perl boot'?

するとまた罠が。perl使うの!? さすがにここでHaskell使えとは言いづらい、のかな? いやghcは実行ファイル吐けるからいいのか。まあいいや。

# perl boot
mk/config.h.in doesn't exist: perhaps you haven't run 'perl boot'?
Maybe you haven't done './sync-all get'? at boot line 74, <PACKAGES> line 46.

たらい回しか!

# ./sync-all get
(なんかいっぱいパッケージが入る)
# perl boot
(略)
WARNING: You don't have a mk/build.mk file.

By default a standard GHC build will be done, which uses optimisation
and builds the profiling libraries. This will take a long time, so may
not be what you want if you are developing GHC or the libraries, rather
than simply building it to use it.

For information on creating a mk/build.mk file, please see:
    http://hackage.haskell.org/trac/ghc/wiki/Building/Using#Buildconfiguration

なんか出た。この辺はメモって放っておくとかでいいでしょう。
やってみた人はわかると思いますが、ここの"sync-all"ってスクリプトでビルドに必要なパッケージを色々と入れてるみたいですね。本当にそうなのかは知りませんが。ちなみにこいつもperlです。
ここまでで準備OKです。あとは例によってな感じなんですが、コンパイラの置き換えというのはそれなりにアレな作業ですので、ちゃんとconfigureでインストール位置を指定してあげたほうがいいと思います。私はやりませんでしたけど。詳しくは

# ./configure --help

を参照。というか--prefix=***なんですけど。そういうのを無視して以下のようにすると/usr/localに入る。ちなみにMacのHaskell Platformで入れるとデフォでは/usrに入ってるので、一応上書きはされていない。でも遊びで入れてるのにinstallの度にsudoしたくないよねぇ。

# ./configure
(略)
Configure completed successfully.
(略)
# make
# make install

これでとりあえずビルドはできました。makeに2時間くらいかかったけど、初回ですしそんなもんでしょう。

なんとなく画面出力を眺めてたら、結構lhsで書かれたソースもあるっぽかったですね。あと.cも結構見た気がする。まあ半分寝ながらだったのであんまり覚えてませんが。
この中で出てくるghc-stage1とかghc-stage2ってのが中間生成のコンパイラなのかなぁと。調べてみるとどっちもghcそのものっぽかったですし。時間の内訳はたぶん、ghc-stage1を使ったビルドが終わるまでに1時間半ちょい、ghc-stage2が出てきたのは最後の10分くらいだった気がします。ghc-stage1のビルドにかかる時間は見てなかった。

まとめ

# git clone https://github.com/ghc/ghc.git
# cd ghc
# autoconf
# ./sync-all get
# perl boot
# ./configure
# make
# make install

実を言うと最初の与太話の下りの一部を含めてここに書いてあります。
全部読んだ方はお疲れ様でした。

Building – GHC

さあ壊すぞー