LoginSignup
14
7

More than 3 years have passed since last update.

GHCの最新のソースコードをビルドし、すこしいじる

Last updated at Posted at 2018-04-06

GHCの最新のソースコードをビルドし、すこしいじる

はじめに

GHCのソースコードを読んでみたい。あるいは、GHCに自分の考えた機能を追加してみたい。誰もが一度は思うことだ。そのとき、意外とハードルが高いのが「ダウンロードとビルドの手間」だ。難しいことはほとんどないけれど、道標がないと腰が重くなってしまう。この作業を記事にしよう。

難しいことはほとんどない。ビルドしたあと、すこしだけいじってみて、自分オリジナルのGHCをビルドして悦に入ってみようかと思う。

以下の記事を参考にした。@takenobu-hsさん、良記事をありがとうございます。

Haskell GHCをソースからビルドする手順 @takenobu-hs

上記の記事のGentoo版のような位置づけになるかと。ただし、できるだけGentooの機能を使わずにstackを使うようにしたので、ほかの環境でも応用がききやすいかとは思う。

前提とする環境

いろいろとインストールずみのシステム上での作業だと、「何が必要なのか」が不明確になるため、最低限のところから作業をすすめていくことにした。この記事をテストする環境は以下の記事で作成される最低限のGentooシステムとする。

Gentooの最小限のシステムを構築する(BIOS編)

ほかの環境でも、Haskellのパッケージ以外について、それぞれの環境でのやりかたに変えれば応用できるはずだ。

この記事の書きかた

GHCのソースコードを取得して、それをコンパイルするなかで、エラーメッセージが出る。そのエラーメッセージをひとつひとつ解決していくというやりかたとする。

コードの取得

まずはコードを取得する。つぎのようなコマンドとなるだろう。

% git clone --recursive https://gitlab.haskell.org/ghc/ghc.git

しばらく待つ。するとカレントディレクトリ下にディレクトリghcができているので、そこに移動する。

% cd ghc

./boot

mk/build.mkを作成する。mk/build.mk.sampleをコピーして、編集する。

% cp mk/build.mk.sample mk/build.mk
% vi mk/build.mk
BuildFlavour = quick

BuildFlavourはquickがRECOMMENDEDになっていたので、そのようにした。no profilingと書かれているので、profileを無効にすることでビルドがはやくなるのだろう(多分)。

./bootを実行する。

% ./boot 

./configure

./configureをする。ここでは、いろいろなエラーが出る。それを解決していく。

% ./configure
...
checking for ghc... no
configure: error: GHC is required.

ここでは「GHCがない」と言われている。場合によっては、「GHCのバージョンが古い」と言われるかもしれない。どちらにしても、対処はおなじようにする。

stackとGHCの導入

stackを導入する。つぎのどちらかを実行する。curlとwgetのうち、システムにあるほうを使う。どちらもない場合は、どちらかをインストールしよう。

curlでは
% curl -sSL https://get.haskellstack.org/ | sh

wgetでは
% wget -qO- https://get.haskellstack.org/ | sh

パスワード入力が要求されたら、使っているアカウントのパスワードを入力する。また、今後stackを使っていくうえで、PATHに/home/[アカウント名]/.local/binを追加しておくと良い。

zshでは
% vi .zshrc
path=($HOME/.local/bin(N-/) $path)

bashでは
% vi .bashrc
PATH=$HOME/.local/bin:$PATH

GHCを導入する。つぎのようにコマンド入力する。

% stack setup

するとGHCがホームディレクトリ下の以下のようなパスにインストールされる。

.stack/programs/x86_64-linux/ghc-ncurses6-nopie-8.2.2/bin/ghc

システムによって、多少パスは変わるが、自分のシステムに置き換えて読み進めてほしい。この新しくインストールされたghcをコンパイルに使うことを、configureで設定する。

% ./configure GHC=/home/[使用しているアカウント名]/.stack/programs/x86-64-linux/ghc-ncurses6-nopie-8.2.2/bin/ghc
...
configure: error: Happy version 1.19.4 or later is required to compile GHC.

Happyの導入

こんどはHappyがないと言っている。つぎのようなコマンドでHappyをインストールする。HappyはHaskellのパーサジェネレータだ。

% stack install happy
% echo $PATH
/usr/local/bin:...

コマンドhappyはホームディレクトリ下の、つぎのパスにインストールされる。

.local/bin/happy

なので~/.local/bin/にパスが通っている必要がある。ZshまたはBashへの設定はしてあるので、一度exitして再度シェルに入り直す。

% echo $PATH
/home/tatsuya/.local/bin:/usr/local/bin:...

./configureをもう一度やってみる。

% cd ghc
% ./configure --with-ghc=/home/[アカウント名]/.stack/programs/x86_64-linux/ghc-ncurses6-nopie-8.2.2/bin/ghc
...
configure: error: Alex version 3.1.0 or later is required to compile GHC.

Alexの導入

今度はAlexが必要とのこと。AlexはHaskellの字句解析器ジェネレータ。おなじようにインストールする。

% stack install alex

再度./configureをする。

% ./configure --with-ghc=...
...
Confiture completed successfully.
...
...
...

うまく./configureできたようだ。

make

これでmakeできる。

% make

初回のmakeは当然、時間がかかる。僕の環境だと1時間とか2時間とか、そのくらいだ。Core-i3のうえの仮想環境なので、まあ「極非力なマシンで」ということだ。

まずはstage1コンパイラをビルドして、そのstage1コンパイラを使ってstage2コンパイラをビルドするというかたちだ。理由はよく知らない。新しいコンパイラで採用されたコードの最適化の恩恵によって、コンパイラ自体を速くするため、とかか?

makeが成功すると、つぎのパスにコンパイラが作成される。

ghc/inplace/bin/ghc-stage2

build.mkの編集

ここまでできたら、何はなくとも、まずやっておくことがある。mk/build.mkにstage=2を設定する。

% vi mk/build.mk
stage=2

これをしておかないと、ソースコードの些細な変更ごとにstage1コンパイラが更新され、そのためにstage2コンパイラを1から作り直すはめになる。

バージョン表示の変更

いろいろといじりたいが、まずは簡単なところから。バージョン表示をすこし編集してみよう。

% ./inplace/bin/ghc-stage2 --version
The Glorious Glasgow Haskell Compilation System, version 8.5.20180403

このようにバージョンが表示されるが、これにYoshikuni Editionを追加してみよう。

% vi ghc/Main.hs
showVersion :: IO ()
showVersion = putStrLn (cProjectName ++ ", version " ++ cProjectVersion ++ " Yoshikuni Edition")

これでmakeしてみよう。

% make

試してみる。

% ./inplace/bin/ghc-stage2 --version
The Glorious Glasgow Haskell Compilation System, version 8.5.20180403 Yoshikuni Edition

言語拡張LambdaCaseに別名をつける

バージョン表示をいじっただけでは、あまりにも簡単すぎるので、言語拡張に別名をつけてみよう。まずは、LambdaCase拡張を使うコードを書く。

% mkdir tmp
% vi tmp/lc.hs
{-# LANGUAGE LambdaCase #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

main :: IO ()
main = putStrLn $ hello "Yoshio"

hello :: String -> String
hello = \case
        "Yoshio" -> "Hello, darling!"
        n -> "Hi, " ++ n ++ "."

これをコンパイル、実行する。

% ./inplace/bin/ghc-stage2 tmp/lc.hs
% ./tmp/lc
Hello, darling!

さて、このLambdaCase拡張にLCという別名をつけてみよう。まずはソースコードの海をgrepする。

% grep '"LambdaCase"' */*/* 2>/dev/null
compiler/main/DynFlags.hs: flagSpec "LambdaCase"   LangExt.LambdaCase,

compiler/main/DynFlags.hsを編集すれば良さそうだ。

% vi compiler/main/DynFlags.hs
flagSpec "LambdaCase"    LangExt.LambdaCase,
flagSpec "LC"            LangExt.LambdaCase,

"LC"の行を追加した。makeする。

% make

これでLambdaCase拡張の別名としてLC拡張が使えるはずだ。テスト用のコードを編集する。

% vi tmp/lc.hs
{-# LANGUAGE LC #-}

LambdaCaseのところをLCに修正した。

% ./inplace/bin/ghc-stage2 tmp/lc.hs
% ./tmp/lc
Hello, darling!

言語拡張の一覧も表示してみよう。

% ./inplace/bin/ghc-stage2 --supported-extensions
...
LambdaCase
NoLambdaCase
LC
NoLC
...

ちゃんと言語拡張LCが表示されている。

まとめ

GHCの最新ソースコードの取得とコンパイルのしかたを、GHCさえインストールされてない状態から順に説明した。いろいろな環境で応用がきくように、できるだけ、ディストリビューション独自の機能は使わないようにして、stackを使うようにした。これで、オレオレGHCを作って遊ぶことができるようになった。

この先はコードリーディングするなり、新機能を実装するなり、各自楽しんでいただけたら幸いだ。

14
7
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
7