ビルド方法を制御する

 パッケージのビルドの方法を切り替えたい場合もあります。例えば、OSがWindowであればWin32パッケージのモジュール、そうでなければunixパッケージのモジュール、というように環境に応じて別のパッケージで提供されているモジュールを利用したい場合などです。この場合、Cプリプロセサを使って、Haskellソースコード上で環境ごとに利用するモジュールを変えるよう記述するだけでは不十分です。Cabalではパッケージで提供されているモジュールを利用するには、*.cabalファイルのbuild-depends:フィールドにモジュールを提供するパッケージを書く必要があるからです。したがって、環境ごとに利用するパッケージを変えるには、*.cabalファイルのbuild-depends:フィールドの内容を環境ごとに変える必要があります。

 また、32ビット版WindowsのGHCを利用しているかどうかで、FFIを使って関数を呼び出すために利用する呼び出し規約を変えたいといったこともあります。

 このような場合、以下のように条件式を使ってビルド方法を制御できます(参考リンク)。

Library
~ 略 ~
  build-depends: base < 5
  if os(windows)
    build-depends: Win32
  else
    build-depends: unix

  if os(windows) && arch(i386)
    cpp-options: "-DCCONV=stdcall"
  else
    cpp-options: "-DCCONV=ccall"

 「os」でwindowsやunixなどのOS名、「arch」でi386やx86_64などのハードウエア・アーキテクチャを指定し、!(not)や&&(and)、||(or)と組み合わせて条件式を作成します。条件式が真の場合と偽の場合のそれぞれにビルド方法を記述します。なお、条件式が偽の場合の記述(else節)は省略可能です。

 osとarchの値には、基本的にはbaseパッケージのSystem.Infoモジュールで定義されているosとarchの値や、CabalパッケージのDistribution.Systemモジュールで定義されているOS型とArch型の値が使えます(参考リンク)。

 osやarchといった定義済みの値ではなく、ユーザーが定義できるフラグを判定に使いたいこともあります。そうした場合には、Flagという項目を使ってユーザー定義のフラグを追加できます。

 例えば、vectorパッケージでは、パッケージのデバッグ時により厳しい範囲外検査を行うために、ユーザー定義のフラグを利用しています。

Flag UnsafeChecks
  Description: Enable bounds checking in unsafe operations at the cost of a
               significant performance penalty
  Default: False

Flag InternalChecks
  Description: Enable internal consistency checks at the cost of a
               significant performance penalty
  Default: False

 新たに定義したフラグのデフォルトの値は有効(True)になっています。フラグのデフォルトの値を無効(False)にしたい場合には、default:フィールドで設定します。

 Flagで設定したフラグは、flagを使って条件式の部分に記述できます。上に示した二つのフラグを使ってみましょう。

Library
  Extensions: CPP, DeriveDataTypeable
  Exposed-Modules:
  ~ 略 ~
        Data.Vector
  ~ 略 ~
  if flag(UnsafeChecks)
    cpp-options: -DVECTOR_UNSAFE_CHECKS

  if flag(InternalChecks)
    cpp-options: -DVECTOR_INTERNAL_CHECKS

 なお、ここで設定したフラグは、configureコマンドの実行時、あるいはconfigureコマンドなしでcabal installコマンドを実行するときに、-f<フラグ名>オプションで明示的に有効化、-f-<フラグ名>オプションで明示的に無効化できます(参考リンク)。