#author(“2018-11-23T05:53:08+00:00”,“game”,“game”)
#
コンパイラ構成論ソース読み会 〜ghc〜
#
ghcインストール前に入れる
1
|
$ git clone --recursive git://git.haskell.org/ghc.git
|
1
2
|
$ mkdir ghc_build
$ cd ghc_build
|
*
* cabalをインストールする
1
|
$ brew install cabal-install
|
* happyとAlexをインストールする
1
2
|
$ cabal install happy
$ cabal install Alex
|
* happyとAlexにシンボリックリンクを貼る
1
2
3
|
$ cd /usr/local/bin
$ ln -s ~/.cabal/bin/happy happy
$ ln -s ~/.cabal/bin/alex alex
|
#
インストール
1
2
|
https://ghc.haskell.org/trac/ghc/wiki/Building/GettingTheSources
% git clone --recursive git://git.haskell.org/ghc.git
|
1
2
3
4
|
% brew install m4
% brew install autoconf
% brew install automake
|
* 残念ながらpathが通らないのでbrew install時に出たパスをzshrcにいれる
1
|
$ git clone --recursive git://git.haskell.org/ghc.git
|
- install先を指定する場合は以下の処理を行ってから作業する
1
2
|
$ mkdir ghc_build
$ cd ghc_build
|
* ソースへのリンク作成
1
2
|
$ lndir ../ghc
$ ln -s ../ghc/.git
|
1
2
|
$ ./ boot
以前はPerlだったらしいがPythonに変わってた
|
* install先をしてする場合は以下のようにprefixを指定する
1
|
$ ./configure --prefix=$PWD
|
* configure時
configureにときにhappyが無いと言われるケースが存在する.
happyはhaskellのパーサジェネレータで,Haskellのstack(The Haskell Tool Stack)かcabalで導入する.
stackの場合 ghcも入る
1
2
|
$ brew install stack
$ stack install happy
|
cabal
1
2
3
|
$ brew install cabal-install
$ cabal update
$ cabal install happy
|
- build.mk の作成
- mk以下にbuild.mk.sampleというファイルがあるのでそれをコピーして編集
1
2
|
$ cp mk/build.mk.sample mk/build.mk
$ vim mk/build.mk
|
12行目辺りの以下の部分を#を消して有効に
80行目付近の以下の部分を
1
2
3
4
5
|
ifeq "$(BuildFlavour)" "perf"
# perf matches the default settings, repeated here for comparison:
SRC_HC_OPTS = -O -H64m
GhcStage1HcOpts = -O -fasm
GhcStage2HcOpts = -O2 -fasm
|
このように編集する
1
2
3
4
5
|
ifeq "$(BuildFlavour)" "perf"
# perf matches the default settings, repeated here for comparison:
SRC_HC_OPTS = -O -H64m
GhcStage1HcOpts = -O -fasm -DDEBUG
GhcStage2HcOpts = -O2 -fasm -DDEBUG
|
GhcStage1HcOpts = -O0 $(GhcFAsm) -fprof-auto -DDEBUG
GhcStage2HcOpts = -O0 $(GhcFAsm) -fprof-auto -DDEBUG
- makeとmake installする
- top levelのmakeが下のmakeを呼ぶときに -j が引き継がれるようにする。
1
2
|
$ make MAKE="make -j" -j
$ make install
|
prefixを指定した場所に、ghcができている。指定してなければ/usr/local/bin/。
- エラーと対処法
- Bad interface file: ***.hi-boot
- Bad interface file: ***.hi
- 異なるバージョンのghcでコンパイルされたバイナリが残っているのが原因なのでいちど.hi-boot,.hiファイルを消す。
* ghc-pkg: ghc no longer supports single-file style package databases
* ghc-pkg 7.9ではファイル形式のデータベースはサポートしていないのでinitし直す必要がある。
* 古いghcを消した時に発生した。
1
2
|
$ rm libraries/botstrapping.conf
$ ghc-pkg init libraries/bootstrapping.conf
|
#
1日目
#
どこのghcが呼ばれているのかを調べる
- 新しくインストールしたghcを、適当なディレクトリに移動する
これで、ghcを実行する時、どのファイルが呼ばれるかがわかる
#
lldbで追っかけようとした
1
|
$ lldb -- /Users/one/workspace... append.hs
|
これでは、mainがないというエラーが出る話が
#
アセンブラを生成する
1
|
$ ghc_build/bin/ghc -c append.hs
|
* .s(アセンブラコード)を生成
1
|
$ ghc_build/bin/ghc -S append.hs
|
#
ghc_build/compiler/main/HscMain.hsをghciで動かす
1
|
$ cd ghc_build/compiler
|
- Hscmain.hsを、ghciで動かすために様々なオプションを追加する
1
2
3
4
5
|
-cpp : Cのプリプロセッサを通す
-I : #includeファイルを探すディレクトリを、通常のCでの方法で指定する
-S : .s(アセンブラコード)を生成
-i : 必要なモジュールのディレクトリを指定する
-D : 値を定義する
|
1
2
|
$ ghc --help
$ man ghc
|
#
Main.hsを動かす
1
|
$ ghci -fno-code -cpp -DSTAGE=2 -I. -I../ghc -I./stage2 -I./stage2/build -iutils:main:prelude:hsSyn:types:typecheck:deSugar:stage2/build:parser:iface:basicTypes:profiling:specialise:coreSyn:cmm:simplCore:codeGen:nativeGen:StgSyn:cbits:rename:simplStg:specialise:stranal:types:vectorise:llvmGen ../ghc/Main.hs
|
-
この方法でghciは通った
-
次は、ghc_build/compiler/main/HscMain.hsを動かしたい
-
HscEnv とCompileFileを呼び出せばいい
-
InitSysToolsをつかってSettingsを作る
1
2
|
let s = SysTools.initSysTools ( Just "/Users/one/workspace/ghc_build/lib/ghc-7.9.20141204" )
ss <- s
|
- SettingsからDynFlagsが作れる (defaultDynFlags.Settings DynFlag.hs)
1
|
let df = DynFlags.defaultDynFlags s
|
- DynFlagsからHscEnvが作れる (newHscEnv HscMain.hs)
* ライブラリが見つからないと怒られる
#
2日目
#
Haskell Compilerについて勉強する
スライド(http://www.scs.stanford.edu/11au-cs240h/notes/ghc-slides.html#%281%29)を
読んで、Haskell Compilerについて勉強する。
#
GCについて勉強
スライド(http://www.slideshare.net/dec9ue/rts-gc)を読んで、
Gerbage Collectionについて勉強する。
#
Main.hsを動かす(2)
- .hiと.oがあると、ghciのbreak pointがかけられない。
1
|
$ -fno-code を適用すると .o が作成されなくなる
|
#
デバッグオプションがついてない?(問題編)
- configureを実行すると、GhcDebuggedがNOになる。
#
3日目
#
デバッグオプションがついてない?(解決編)
- 設定を書き換えたい分だけは、新しいファイル(build.mk)に書き込む。
- build.mkの作成
#
lldbで読もう
-
lldbでcプログラムを読むように、ghcの実行ファイルを読む。
-
nmコマンドを使って、symboltableから、調査対象の関数名とプログラムアドレスを抜き出す。
-
プログラムアドレスにbreak pointをあてて、そこからstep実行をして、動作を細かく調査しようとした。
-
lldbで読んだ結果
- ライブラリの読み込みやインダイレクトジャンプばかりをやっていて、追いにくそう..
#
parser/Lexer.x を読む。
定義を確認し、alexにかけることで**.hsに変換
alex Parser.x
変換したParser.hsを読む。
#
Lexer.hsをghciにいれてみる。
1
|
$ ../../build/bin/ghci -fno-code -cpp -DSTAGE=2 -I. -I../ghc -I./stage2 -I./stage2/build -iutils:main:prelude:hsSyn:types:typecheck:deSugar:stage2/build:parser:iface:basicTypes:profiling:specialise:coreSyn:cmm:simplCore:codeGen:nativeGen:StgSyn:cbits:rename:simplStg:specialise:stranal:types:vectorise:llvmGen ./parser/Lexer.hs
|
- Libraryが読み込めないからソースコードから読むことに。
- Lexer.hsには字句解析について書かれている。
- AlexInputが怪しいのでは?
- AlexInputが書かれているコードを探す -> Parser.yに書かれているらしい
#
parser/Parser.hsを読む
Parser.y を happyで *.hsに変換
#
ParseResultとは?
* parser/Lexer.hsにあるらしい
* runParser発見!
#
parser を実行したい
- parser/Parser.y
- happy parser/Parser.y
- parser は runParser で実行できそう? ソースにコメントで書かれてた
1
2
3
4
5
6
7
|
runParser :: DynFlags -> String -> P a -> ParseResult a
runParser flags str parser = unP parser parseState
where
filename = "\<interactive\>"
location = mkRealSrcLoc (mkFastString filename) 1 1
buffer = stringToStringBuffer str
parseState = mkPState flags buffer location in
|
#
PState とは?
- parser/HscMain.hsにcaseで使われてる。
#
Desugar を追う。
1
2
|
Hskellからcoreにするときにdesugarするので、Desugarを追う。
-> desugar/Desugar.hsに書かれてる。
|
#
dsLExprとは
- deSugar/DsExpr.hsに書いてある。
- coreExpr を発見
- coreSyn/CoreSyn.hsでcoreの定義がされている。
#
他に読むものは?
- typechaek/TcUnify.hsを見たら推論木がわかりそう。
- typecheck/TcType.hsを流し読み。
#
2018
#
Haskell入門
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
data Tree a v =
Node a v (Tree a v) (Tree a v)
| Leaf
deriving (Show)
insert :: (Ord a ) => Tree a v -> a -> v -> Tree a v
insert Leaf k v = Node k v Leaf Leaf
insert (Node k v left right) k1 v1
| k == k1 = Node k v1 left right
| k > k1 = Node k v (insert left k1 v1 ) right
| k < k1 = Node k v left ( insert right k1 v1)
test1 = Node 1 0 Leaf Leaf
test2 = insert test1 2 1
|
-
ghci Node.hs
-
ghcでcoreの出力を見る!!
-
mainが無いとghcでコンパイルできない
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
data Tree a v =
Node a v (Tree a v) (Tree a v)
| Leaf
deriving (Show)
insert :: (Ord a ) => Tree a v -> a -> v -> Tree a v
insert Leaf k v = Node k v Leaf Leaf
insert (Node k v left right) k1 v1
| k == k1 = Node k v1 left right
| k > k1 = Node k v (insert left k1 v1 ) right
| k < k1 = Node k v left ( insert right k1 v1)
test1 = Node 1 0 Leaf Leaf
test2 = insert test1 2 1
main = do
return test2
|