.cabalファイルのghc-optionsに何を書くべきか

ふと、Haskellパッケージの.cabalファイルのghc-optionsフィールドに何を書いておくとよいか不安になったので、少し調べた。

なお、cabalが実際にどのようなオプションをghcに与えているかは--verboseオプションで確認できる。

$ cabal build --verbose

stackを使う場合、--verboseオプションはstack自身の、--cabal-verboseオプションはcabalのverbosityを制御する。

$ stack build --verbose --cabal-verbose

参考:

-Wall -fno-warn-unused-imports

これらは書くようにしている。

"-Wall"はご存知コンパイラの警告を全て表示するオプションである。

"-fno-warn-unused-imports"は不必要なモジュールやシンボルのimportに対する警告を無効化するものである。古いバージョンのghcでは必要だったimportが新しいバージョンのghcでは必要無くなることがあるのだが、このオプションがないとそんな場合にも警告が出てうっとうしいからだ。

-O[n]

最適化オプション。個人的には、これは書かなくてよいと思っている。

cabalはデフォルトで-Oオプションをghcに渡してコンパイルするらしい(cabal-install-1.24.0.0時点)。この挙動はconfigure時に設定できる。

$ cabal configure -O2

デフォルトでレベル1の最適化をするので、まあ特に設定しなくていいかなと思っている。他人のパッケージの.cabalをいくつか見てみたが、-O2と書いているものもあれば、何も書いてないものもあり、まちまちなようだ。

他のオプションでもそうだが、最終的にはユーザーがビルドする際に上書き設定すればよいだろう。

-X[LANGUAGE_EXTENSION]

ghc拡張機能スイッチ。これは書くべきではない。.cabalではdefault-extensionsフィールドとother-extensionsフィールドが使える(Cabal-1.10から。それより前ならextensionsフィールドが使える)ので、こっちを使うべきである。

なお、default-extensionsフィールドに書いた拡張機能はパッケージ内の全モジュールで有効になる。other-extensionsフィールドはパッケージが使う拡張機能を宣言するだけのものであり、各モジュールはLANGUAGEプラグマを使って必要な拡張機能のみを有効にする。

-threaded

OSスレッドを使用する。リンカオプションなのでlibraryセクションでは(多分)不要。他は個別の事情に合わせて、といったところだろう。

プログラムの作りによっては-threadedオプションがないと動かなかったり、逆にあると動かなかったりするので注意を要する。

以前、同じテストプログラムを-threadedのあるバージョンとないバージョンで2通りテストしたいことがあったが、結局test-suiteセクションをコピーして2つ並べてしまったことがある。何かよい方法はないだろうか。

-rtsopts

コマンドラインやGHCRTS環境変数からのRTSオプションを全て受け付ける。リンカオプションである。入れたほうがexecutableを使う立場としては便利だが、セキュリティ上のリスクがあるのかもしれない。

なお、デフォルト(-rtsopts=some)ではごくごく一部のRTSオプションしか受け付けないらしい。

"-with-rtsopts=-N[n]"

"-with-rtsopts"はRTSオプションをリンク時に指定する。-Nオプションはn個のOSスレッドの同時使用を許可する。n省略時はCPUコア数に応じたよしなな値が使われる。-threadedをつけるならセットでつけておいた方がなにかと便利だろう。

なお、-with-rtsoptsによる設定は-rtsoptsがなくても有効になる。-rtsoptsはあくまでプログラム実行時にRTSオプションを設定できるかどうかを制御するものである。

また、-with-rtsoptsではスペース区切りで複数のRTSオプションを並べることができるが、これを.cabalに書くには上に示したように-with-rtsopts=...全体をダブルクォートするべしとのこと( https://github.com/haskell/cabal/pull/1346 )。

"-with-rtsopts=-M512m"

"-M"オプションは最大ヒープサイズを制限する。自分の書いたプログラムのバグによってメモリが無限に食いつぶされるのが怖いので、自分はtest-suiteにはこれをいれるようにした。(参考: http://qiita.com/debug-ito/items/87fa50d5324e20936d7e )