7.1. GHCを使う¶
7.1.1. 始めよう: プログラムをコンパイルする¶
この章では,400を超えるフラグを含むGHCのコマンドライン構文の完全なリファレンスを示します. GHCは大きく複雑なシステムで,大量の詳細がありますのですので,どう始めてよいのかが判りにくでしょう. これを踏まえて,この節ではHaskellプログラムをコンパイルするためのGHCの基本的な使い方をざっと紹介します. これを読んでから,以降の節での完全な構文の解説に飛び込むのがいいでしょう.
Hello World プログラムを作って,これをコンパイルして,走らせてみましょう.
まず,以下のHaskellコードを含む hello.hs
を作成しましょう.
main = putStrLn “Hello, World!”
このプログラムをコンパイルするには以下のようにGHCを使います.
$ ghc hello.hs
(ここで $
はシェルのプロンプトですので,タイプする必要はありません.)
GHCはソースファイル hello.hs
をコンパイルして,オブジェクトファイル hello.o
と
インターフェイス hello.hi
を生成してから,オブジェクトをGHC付属のライブラリとリンクして,
Unix/Linux/Mac では hello
という実行可能ファイルを Windowsでは hello.exe
という実行ファイルを生成します.
デフォルトではGHCは自身の動作について寡黙で,表示するのはエラーメッセージだけです.
裏で何が行われているか詳細をみたいときには,コマンドラインに -v
を追加すれば良いでしょう.
コンパイルができたら,以下のようにすればプログラムを実行できます.
$ ./hello
Hello World!
プログラムが複数のモジュールから構成されている場合でも,単に Main
モジュールのファイル名を指定するだけですみます.
GHCは Main
モジュールの import
宣言を見て,プログラムを構成するその他のモジュールを見つけ,そのソースファイルを探します.
したがって Main
モジュールを除くモジュールのソースファイルはモジュール名を反映していなければなりません
(ドットはディレクトリ区切り子に変換します).
たとえば Data.Person
モジュールは,Unix/Linux/Macでは Data/Person.hs
というファイルに,
Windowsでは Data\Person.hs
というファイルに置くことになります.
7.1.2. オプションの概要¶
GHCの振る舞いはオプションによって制御します. 歴史的理由からオプションのことをコマンドラインフラグとかコマンドライン引数ともいいます. オプションの指定方法は3つあります.
7.1.2.1. コマンドライン引数¶
GHCを起動する構文は以下の形式になります.
ghc [argument...]
コマンドライン引数はオプションもしくはファイル名です.
コマンドラインオプションは -
で始まります.
これをひとまとめにすることは**できません**.
-vO
と -v -O
とは違うものであるということです.
オプションをファイル名より前で指定する必要はありません.
たとえば ghc *.o -o foo
のようにできます.
すべてのオプションを処理してから,それらをすべてのファイルに適用します.
そのため ghc -c -O1 Foo.hs -O2 Bar.hs
とやって Foo.hs
と Bar.hs
に異なる最適化水準を適用することはできません.
Note
コマンドラインオプションは 順序依存 であることに注意してください.引数は左から右へ評価されます.
このことによって,フラグの連動がある場合おかしな効果があらわれことがあります.
たとえば -fno-specialise
と -O1
(このフラグにより -fspecialise
が有効になる) とを考えてみましょう.
つぎの2つのコマンドラインは全く別ものです.
-fno-specialise -O1
-fno-specialise
に-O1
が上書きして-fspecialise
が有効になります.
-O1 -fno-specialise
-O1
に連動する-fspecialise
は-fno-specialise
で上書きされてしまうので有効になりません.
7.1.2.2. ソースファイル中のコマンドラインオプション¶
ソースファイルとコマンドラインを強く結びつけた方が便利なことがあります.
たとえば,意図して名前のシャドーイングをおこなっているHaskellソースがあれば,
そのファイルについては -Wno-name-shadowing
オプション付きでコンパイルすべきです.
Makefile
をつかって,ファイルごとのオプション一覧を管理する代りに,
OPTIONS_GHC
pragma を使ってソースファイルに直接書いておけます.
{-# OPTIONS_GHC -Wno-name-shadowing #-}
module X where
...
OPTIONS_GHC
は ファイルヘッダプラグマ (OPTIONS_GHC pragma 参照)です.
OPTIONS_GHC
プラグマ中で使えるのは 動的 フラグだけです(静的オプション,動的オプション,モード指定オプション 参照).
コマンドシェルからこのソースオプションを取得するわけではなく,
コンパイラが内部的に保持しているコマンドライン引数配列に含めるだけであることに注意してください.
そのため OPTIONS_GHC
の中でワイルドカードを使おうとすると残念なことになります.
Note
OPTIONS_GHC
の内容はコマンドラインオプションの後に連結するので,
コマンドラインで与えられたオプションがソースファイルオプションで上書きされます.
Makefile の内容をすべてソースファイルに移すのは推奨しませんが,
場合によっては OPTIONS_GHC
プラグマを使うのが正しいやり方になります.
(-keep-hc-file
を使っていて,モジュールに OPTION
フラグがあるなら,
生成した .hc
ファイルには OPTIONS_GHC
が置かれます.)
7.1.3. 静的オプション,動的オプション,モード指定オプション¶
GHCのコマンドラインオプションは,静的オプション,動的オプション,モード指定オプションのいずれかに分類されます.
フラグの参照表は(Flag reference)にはそれぞれどのフラグがどれに分類されているかが判るようになっています.
静的でありながら,GHCiの :set
コマンドで設定できるフラグも少しながらあります.
これは参照表では「static/:set
」と表記されています.
7.1.4. 重要な意味のあるファイル接尾辞¶
「意味のある」接尾辞 (たとえば .lhs
あるいは .o
)の付いたファイルは,それにしたがって「適切な」方法で処理されます.
.hs
- Haskellモジュール.
.lhs
「文芸的Haskell」モジュール.
.hspp
- プリプロセッサが生成したファイル.
.hi
- Haskellインターフェイスファイル,コンパイラが生成したものであることが多い.
.hc
- Haskellコンパイラが生成した中間のCファイル.
.c
- Haskellコンパイラが生成したCファイル以外のCファイル.
.ll
- 中間言語llvmのソースファイル.通常コンパイラが生成する.
.bc
- 中間言語llvmのビットコードファイル.通常コンパイラが生成する.
.s
- アセンブリ言語のソースファイル.通常コンパイラが生成する.
.o
- アセンブラが生成するオブジェクトファイル.
これ以外の接尾辞が付く(あるいは接尾辞の付かない)ファイルは直接リンカに渡されます.
7.1.5. 実行モード¶
GHCの振る舞いはまずモード指定フラグで制御します. モード指定フラグは1つしか与えられませんが,コマンドラインにおいて最初のオプションである必要はありません. 以下は指定例です.
$ ghc Main.hs --make -o my-application
モード指定フラグがない場合,コマンドラインでHaskellのソースファイルが指定されていれば --make
モード(ghc –make を使う)になり,そうでなければ,コマンドライン中で指定さたオブジェクトをリンクして実行可能ファイルを生成します.
以下のモード指定フラグが利用可能です.
-
--make
このモードではGHCは複数のモジュールからなるHaskellプログラムを依存性を解析しながら自動的にビルドします. 単純なHaskellプログラムなら,これは make を使うよりずっと簡単でしかも速くビルドできます. makeモードについては ghc –make を使う で解説しています.
コマンドラインでHaskellのソースコードを指定した場合は,このモードがデフォルトになります. その場合
--make
オプションは省略できます.
-
-E
-
-C
-
-S
-
-c
これは伝統的なバッチ処理コンパイラモードです.GHCは1度に1つのソースファイルをコンパイルするか, オブジェクトファイルをリンクして1つの実行可能ファイルを生成します. 一括コンパイラモード を参照してください.
-
-M
依存性生成モード.このモードでは,GHCを使って
Makefile
ファイルで使うのに適した依存性情報を生成できます. Dependency generation を参照してください.
-
--frontend
⟨module⟩
¶ 指定したフロントエンドプラグインを使ってGHCを走らせます.詳細は Frontend plugins を参照してください.
-
--mk-dll
DLL作成モード(Windows のみ). Creating a DLL を参照してください.
-
--show-iface
⟨file⟩
¶ ⟨file⟩ 中のインターフェイスを読んで,それをテキストとして
stdout
にダンプします. たとえばghc --show-iface M.hi
のように使います.
-
--show-options
サポートしているコマンドラインオプションを表示します.シェルでの自動補完のために使えます.
-
--info
コンパイラに関する情報を表示します.
-
--numeric-version
GHCのバージョンを数値でのみ表示します.
-
--print-libdir
GHCライブラリディレクトリのパスを表示します. このパスはGHCのライブラリ,インターフェイス,インクルードファイルが置かれているディレクトリツリーの最上位です (通常 Unix では
/usr/local/lib/ghc-8.0.2
のような場所です). これはパッケージの設定ファイル(Packages 参照)における$libdir
の値です.
7.1.5.1. ghc
--make
を使う¶
このモードではGHCは複数のモジュールからなるHaskellプログラムをビルドします.
このとき,GHCは1つ以上のルートモジュール(通常は Main
のみ)から依存性を追跡します.
たとえば Main
モジュールが Main.hs
というファイルに置かれているとき,
次のようにすればこのプログラムをコンパイルリンクできます.
ghc --make Main.hs
実際には,コマンドライン中に1つでもHaskellソースファイルがあり,他のモードが指定されていなければ,GHCは自動的にmakeモードになります. したがって,これ例では以下のようにタイプするだけでよいのです.
ghc Main.hs
ソースファイル名やモジュール名はいくつでも指定できます.
GHCは,指定されたこれらの初期ファイルからインポートを追いかけて,プログラムに含まれるすべてのモジュールを見つけだします.
次に,最新ではないモジュールの再コンパイルを試み,最後に Main
モジュールがあれば,プログラムをリンクして実行可能形式にします.
伝統的な Makefile
に対して ghc --make
を使う利点は,以下のようなことです.
コンパイルごとにGHCを再起動する必要がないので,それぞれのコンパイル間で情報をキャッシュできます. 複数のモジュールからなるプログラムを
ghc --make
でコンパイルする方が, 個々のソースファイルを1つずつコンパイルするより2倍も速くなることがあります.Makefile
を書かなくて済みます.GHCは起動されるごとに依存関係を再計算するので, ソースとの整合性が失われることはありません.
-j
フラグを使えば,モジュールを並列にコンパイルできます.-j⟨N⟩
と指定すれば ⟨N⟩ 個のジョブが並列に走ります.N を省略した場合は,デフォルトではプロセッサの数になります.
この章でこれ以降に解説するコマンドラインオプションはどれも --make
オプションと共用できます.
ただし,コマンドラインから与えれらたオプションはコンパイルするすべてのソースファイルに適用されるので,
個別のファイルにだけ適用したいオプションについては OPTIONS_GHC
プラグマを使う必要があります(ソースファイル中のコマンドラインオプション 参照).
プログラムを追加のオブジェクト(たとえば,補助的なCのコード)とリンクする必要があるなら, そのオブジェクトファイルをコマンド行で与えれば,GHCは実行可能ファイルをリンクするときに指定されたオブジェクトを含めます.
既存の make スクリプトとの後方互換性確保のため -c
と組み合わせて使うと,リンクのフェーズは省略します
(--make -no-link
を指定したのと同じ).
GHC はソースファイルがあるときにしか依存性を追跡できないので, ソースファイルのないモジュールがプログラムに含まれていると, たとえそのモジュールのオブジェクトファイルとインターフェイスファイルがあっても, GHCは文句をいうことに注意してください. ただし,パッケージモジュールの場合は例外で,このときはソースファイルはあってもなくてもかまいません.
プログラムのソースファイルはすべて同一のディレクトリにある必要はありません.
-i
オプションを使って探索パスを追加できます(The search path 参照).
-
-j
[N]
¶ 可能であればコンパイルを並列で行います.GHC はコンパイル中に ⟨N⟩ 個までのスレッドを使います. N の指定が省略されたばあいは,デフォルト値はプロセッサ数です. モジュールのコンパイルは,それが依存しているモジュールのコンパイルが済んでから開始するということに注意してください.
7.1.5.2. 式評価モード¶
このモードは対話モードとほぼ同じですが,評価する式は1つだけで,コマンドラインから -e
オプションの引数として指定します.
ghc -e expr
コマンドラインで Haskell のソースファイルを指定することもできます. 指定したファイルは対話モードと全く同じようにロードします. 指定した式はロードしたモジュールの文脈で評価します.
たとえば Main
というモジュールを含む Haskell プログラムをロードして走らせるには,次のようにすればよいでしょう.
ghc -e Main.main Main.hs
また,このモードを使えば,単に式を Prelude
の文脈で評価できます.
$ ghc -e "interact (unlines.map reverse.lines)"
hello
olleh
7.1.5.3. 一括コンパイラモード¶
一括処理モード で GHC はコマンドラインで指定した1つ以上のソースファイルをコンパイルします.
複数ある段階のどこから始めるかは,それぞれのファイルの接尾辞によって決まります. どこで終るかはフラグで指定します. 特にフラグによる指定がなければ,リンクまでの全ての段階を実行します. 以下の表にまとめておきます.
コンパイルシステムの段階 | 「ここから開始」の接尾辞 | 「ここで終了」のフラグ | 出力ファイルの接尾辞 |
---|---|---|---|
文芸形式プリプロセッサ | .lhs |
.hs |
|
C プリプロセッサ(省略可) | .hs (-cpp を使う) |
-E |
.hspp |
Haskell コンパイラ | .hs |
-C , -S |
.hc , .s |
C コンパイラ(省略可) | .hc or .c |
-S |
.s |
アセンブラ | .s |
-c |
.o |
リンカ | ⟨other⟩ | a.out |
そういうわけで,多くの場合,次のように起動します.
ghc -c Foo.hs
これで,Haskellのソースファイルが Foo.hs
をコンパイルすると,オブジェクトファイル Foo.o
が生成されます.
Note
Haskellのコンパイラが実際に出力するのが何かはバックエンドのコード生成器が何であるかによります. 詳細については GHC Backends を参照してください.
Note
C のプリプロセッサは省略可能で -cpp
フラグを指定すれば有効になります.
詳細については Options affecting the C pre-processor を参照してください.
Note
-E
オプションを指定するとコンパイラのプリプロセス段階だけが実行され結果がファイルに出力されます.
Note
-C
オプションはGHCが未登録モードでビルドされているときにだけ利用可能です.
詳細については Unregisterised compilation を参照してください.
7.1.6. 饒舌性に関するオプション¶
実行モード にある --help
, --version
, --numeric-version
, --print-libdir
の各モードについても参照してください.
-
-v
-v
オプションにより GHC は 饒舌 になります. GHCはバージョン番号を報告し,コンパイルシステムの各段階ごとに,どのように起動したかを(標準エラー出力に)表示します. さらに,ほととんどの段階に-v
フラグを渡し,それぞれがバージョン番号(やそれ以外の情報)を報告します.バグ報告するときは,お願いですから
-v
を使ってください. 正しいことが正しい順序でおこなわれていることを先ず確認したいからです.
-
-v
⟨n⟩
より細かく饒舌性を制御するために
-v
は省略可能は数値引数を与えられるようになっています.-v
を単独で指定するのは-v3
を指定するのと同じです.その他のレベルには以下のものがあります.-v0
- 本質的ではない全てのメッセージを無効にします(これがデフォルト).
-v1
- 最小限の饒舌性.コンパイルごとに1行表示します(
--make
あるいは--interactive
が指定されたときはこれがデフォルト). -v2
- 各コンパイル段階を実行するときに,その段階の名前が表示されます(
-dshow-passes
を指定したのと同じ). -v3
- 各コンパイル段階について完全なコマンドライン(あれば)を表示します.それ以外は
-v2
と同じです. -v4
- 各コンパイル段階が終った後に (プリプロセッサの結果およびC/アセンブリファイルを除く) その段階での中間形式でプログラムを表示します.
-
-fprint-potential-instances
GHC はクラスのインスタンスを見つけられなかったら,判っているインスタンスのうちいくつかを並べて表示します. このフラグが指定されているときには,判っているインスタンスを すべて 表示します.
以下のフラグはGHCのエラーメッセージとGHCiとにおける型情報の表示方法を制御するものです.
-
-fprint-unicode-syntax
このフラグが有効になっていれば,GHC は型シグネチャを言語拡張
-XUnicodeSyntax
由来のユニコード記号を使って表示します. たとえば,以下のような表示になります.ghci> :set -fprint-unicode-syntax ghci> :t (>>) (>>) :: ∀ (m :: * → *) a b. Monad m ⇒ m a → m b → m b
-
-fprint-explicit-foralls
-fprint-explicit-foralls
を指定すると GHC は型のトップレベルに,通常は表示されないforall
量化子を表示します. GHCi では,たとえば,以下のようになります.ghci> let f x = x ghci> :t f f :: a -> a ghci> :set -fprint-explicit-foralls ghci> :t f f :: forall a. a -> a
ただし,このフラグの設定いかんにかかわらず,以下の場合には量化子が表示されます.
入れ子になった
forall
ghci> :t GHC.ST.runST GHC.ST.runST :: (forall s. GHC.ST.ST s a) -> a
量化子付きの型変数のどれかがカインド変数で言及されているカインドをもつ
ghci> :i Data.Type.Equality.sym Data.Type.Equality.sym :: forall (k :: BOX) (a :: k) (b :: k). (a Data.Type.Equality.:~: b) -> b Data.Type.Equality.:~: a -- Defined in Data.Type.Equality
-
-fprint-explicit-kinds
-fprint-explicit-kinds
を指定すると,通常は表示されないカインドが型に表示されます. カインド多相を使っているときには重要な機能です.ghci> :set -XPolyKinds ghci> data T a = MkT ghci> :t MkT MkT :: forall (k :: BOX) (a :: k). T a ghci> :set -fprint-explicit-foralls ghci> :t MkT MkT :: forall (k :: BOX) (a :: k). T k a
-
-fprint-explicit-runtime-reps
-fprint-explicit-runtime-reps
が有効になっていると, GHC は実行時表現多相型についてRuntimeRep
型変数を表示します. このフラグが有効になっていなければデフォルトではPtrRepLifted
になります. 以下はその表示例です.ghci> :t ($) ($) :: (a -> b) -> a -> b ghci> :set -fprint-explicit-runtime-reps ghci> :t ($) ($) :: forall (r :: GHC.Types.RuntimeRep) a (b :: TYPE r). (a -> b) -> a -> b
-
-fprint-explicit-coercions
-fprint-explicit-coercions
を指定すると GHC は型の変換を表示します. 異なるカインドの型間の相等性を証明しようとすると,GHC は型レベルの変換を使います. ユーザがこれ見なければならなくなるのは稀です.あくまでもコンパイラ内部のできごとだからです.
-
-fprint-equality-relations
-fprint-equality-relations
を使って GHC に表示の際に相等性の関係を識別するよう指示できます. たとえば~
均質な持ち上げ(2つの引数は同じカインドをもつ)相等性関係であり,~~
は異質な持ち上げ(2つの引数の型が異なる)相等性関係であり,~#
は異質な持ち上げていないGHC内部のソルバで使われる相等性関係です. 一般にユーザはこの微妙な部分について気を配る必要があるべきではなく,~
が ユーザが欲っしているものでしょう.-fprint-equality-relations
が指定されていなければ,GHCはすべて~
として表示します. Equality constraints も参照してください.
-
-fprint-expanded-synonyms
これが有効になっていれば,GHC は型エラーメッセージで型シノニムを展開した型も表示します. たとえば,以下のような型シノニムがあったとしましょう.
type Foo = Int type Bar = Bool type MyBarST s = ST s Bar
以下のような型エラーメッセージ
Couldn't match type 'Int' with 'Bool' Expected type: ST s Foo Actual type: MyBarST s
が以下のような型エラーメッセージになります.
Couldn't match type 'Int' with 'Bool' Expected type: ST s Foo Actual type: MyBarST s Type synonyms expanded: Expected type: ST s Int Actual type: ST s Bool
-
-fprint-typechecker-elaboration
これが有効であれば GHC は警告メッセージで型検査器よりの追加の情報を表示します. たとえば,
main :: IO () main = do return $ let a = "hello" in a return ()
であるとします.以下の警告メッセージは
A do-notation statement discarded a result of type ‘[Char]’ Suppress this warning by saying ‘_ <- ($) return let a = "hello" in a’ or by using the flag -fno-warn-unused-do-bind
は以下のように表示されるようになります.
A do-notation statement discarded a result of type ‘[Char]’ Suppress this warning by saying ‘_ <- ($) return let AbsBinds [] [] {Exports: [a <= a <>] Exported types: a :: [Char] [LclId, Str=DmdType] Binds: a = "hello"} in a’ or by using the flag -fno-warn-unused-do-bind
-
-ferror-spans
これを有効にすると,GHC はエラーメッセージに関連する構文上の実体のソースコード上の範囲を表示します. 通常 GHC は構文上の実体のソースコードの開始位置だけを表示します.
たとえば,
test.hs:3:6: parse error on input `where'
という表示だったものが,
test296.hs:3:6-10: parse error on input `where'
のような表示になります.また,範囲は複数行にまたがることもあるので,その場合は
test.hs:(5,4)-(6,7): Conflicting definitions for `a' Bound at: test.hs:5:4 test.hs:6:7 In the binding group for: a, b, a
のようになります.行番号は1から数えますが,カラム番号は0から数えることに注意してください. このような数えかたになっているのは,既存のよくある慣習(たとえば Emacs)にしたがったからです.
-
-H
⟨size⟩
¶ ヒープの最小サイズを ⟨size⟩ に設定します.このオプションは
+RTS -Hsize
と同じです. RTS options to control the garbage collector を参照してください.
-
-Rghc-timing
GHC の実行に要した時間について統計情報を1行にまとめて表示します. このオプションは
+RTS -tstderr
と同じです. RTS options to control the garbage collector を参照してください.
7.1.7. プラットフォーム固有のオプション¶
特定のターゲットプラットフォームについてのみ意味のあるフラグがいくつかあります.
-
-msse2
(x86 のみ.GHC 7.0.1 で追加) native code generator を使う場合, 浮動小数点演算を実装するのに SSE2 のレジスタと命令セットを使います. これを指定すれば大幅に浮動小数点演算が改善されますが,コンパイルして得たコードは SSE2 をサポートしているプロセッサ(Intel の Pentium 4 以降と AMD Athlon 64 以降)上でないと動きません. プロセッサが SSE2 をサポートしていれば LLVM backend は SSE2 を使いますが, こちらは自動で認識しますので,フラグでの指定は不要です.
x86-64 のプラットフォームでは SSE2 は無条件で使われます.
-
-msse4.2
(x86 のみ.GHC 7.4.1 で追加). native code generator を使う場合, いくつかの浮動小数点演算とビット演算を実装するのに SSE4.2 命令セットを使います. コンパイルして得たコードは SSE4.2 をサポートしているプロセッサ(Intel の Core i7 以降)上でないと動きません. プロセッサが SSE4.2 をサポートしていれば LLVM backend は自動的にそれを認識しますので, して使うようになりますので,フラグ指定は不要です.