PR

ビルドに必要な内容を記述する

 これらのフィールドの後に「library」もしくは「executable」という項目があります。libraryとexecutableの内容はほとんど同じです。ただし、libraryはライブラリを作成するための項目、executableは実行可能ファイルを作成するための項目なので、目的に応じた違いがあります。

library

library
  -- Modules exported by the library.
  -- exposed-modules:     
  
  -- Modules included in this library but not exported.
  -- other-modules:       
  
  -- Other library packages from which modules are imported.
  build-depends:       base ==4.5.*

executable

executable sample
  -- .hs or .lhs file containing the Main module.
  -- main-is:             
  
  -- Modules included in this executable, other than Main.
  -- other-modules:       
  
  -- Other library packages from which modules are imported.
  build-depends:       base ==4.5.*

 libraryでは1行目に「library」と記されているだけです。これに対し、executableでは、1行目の「executable」の右に、生成する実行可能ファイル名が記されます。上の例では「sample」になっています。

 また、libraryではライブラリとして公開するモジュールを列挙するための「exposed-modules:フィールド」がコメントアウトされています。これに対し、executableではMainモジュールとして使う対象のファイルを示す「main-is:フィールド」がコメントアウトされています。

 なお、cabal initコマンドを実行する前にHaskellのソースコードが存在する場合には、exposed-modules:フィールドはコメントアウトされません。パス付きのソースコードのファイル名から拡張子を除いた名前が、階層化されたモジュール名の形で自動的に列挙されます。例えば、ソースコードとしてsrc\Test.hsとsrc\Test\Test.lhsが存在する場合には、exposed-modules:フィールドにはTestとTest.Testが列挙されます。

 ほかに、「other-modules:フィールド」と「build-depends:フィールド」があります。これらはlibraryとexecutableに共通のフィールドです。other-modules:フィールドは、Mainモジュールやライブラリとして公開するモジュール以外の、内部的に利用するモジュールを列挙するのに使います。build-depends:フィールドには、ライブラリや実行可能ファイルのビルドに必要な依存パッケージを列挙します。

 これらのフィールドの書き方を見ていきましょう。

 main-is:フィールドでは、Mainモジュールとして指定するファイルを*.hsや*.lhsといった拡張子付きの名前で指定します。

 other-moudles:フィールドやlibraryのexposed-moudles:フィールドでは、拡張子付きのファイル名ではなく、拡張子のないモジュール名を列挙します。列挙するモジュールの区切りには、コンマやスペース、改行を利用できます。

Exposed-Modules:   Text.Regex.TDFA.Text, Text.Regex.TDFA.Text.Lazy

Exposed-Modules:   Text.Regex.TDFA.Text Text.Regex.TDFA.Text.Lazy

Exposed-Modules:   Text.Regex.TDFA.Text
                   Text.Regex.TDFA.Text.Lazy

 other-modules:フィールドやexposed-modules:には、hsやlhsといった拡張子を持つファイル以外のモジュールも記述できます。例えば「hsc2hsを使うことで、拡張子がhscのファイルを拡張子がhsのファイルに変換できる」ということをCabalは知っています。したがって、拡張子hscのファイルも、モジュールとしてそのままother-modules:フィールドやexposed-modules:フィールドに記述できます。other-modules:フィールドやexposed-modules:フィールドに拡張子hscを省略したファイル名を書いておけば、Cabalが自動的にhsc2hsを使ってhsファイルに変換してくれます。

 build-depends:フィールドには、依存するパッケージを列挙します。必要があれば、依存するパッケージのバージョンの制約も指定します。

 cabal initコマンドを実行する前に現在のディレクトリにHaskellのソースコードが存在しない場合には、build-depends:フィールドにはbaseパッケージだけが記述されます。

  -- Other library packages from which modules are imported.
  build-depends:       base ==4.5.*

 Haskellのソースコードが存在する場合には、build-depends:フィールドに、それぞれのソースコードが依存するパッケージの一覧が列挙されます。

  -- Other library packages from which modules are imported.
  build-depends:       base ==4.5.*, repa ==3.2.*, repa-algorithms ==3.2.*, time ==1.4.*

 依存するパッケージのバージョンの制約は、バージョンの上限や下限を示す形式でも記述できます。

build-depends:  base < 5, random, stm

build-depends:  base >= 3 && < 5, random, stm

 一つのパッケージでlibraryとexecutableの両方を提供する場合には、executableをlibraryで提供するライブラリに依存させることができます。

name:                sample
~ 略 ~

library
  exposed-modules:     Sample
  build-depends:       base ==4.5.*

executable sample
  main-is:             Test.hs
  build-depends:       base ==4.5.*, sample

 ここまでは、ディレクトリに直下にソースコードを配置することを想定しました。hs-source-dirs:フィールドを使えば、指定したサブディレクトリにファイルを配置できます。ディレクトリ直下に複数のモジュールがある場合には、srcディレクトリなどのサブディレクトリを作り、そこにソースコードを配置するほうがよいでしょう。

  hs-source-dirs:       src 

 なお、フィールド名が「dirs」と複数形になっていることからわかるように、ソースコードを配置するディレクトリとして複数のディレクトリを列挙できます。

  hs-source-dirs:       parser, typechecker, compiler 

 なお、パッケージの開発段階ではビルドの対象を制御したいことがあります。テスト対象のソースコードだけをビルドしたい場合などです。こうしたときに利用するのが、buildable:フィールドです。ライブラリや実行可能ファイルのbuidable:フィールドをFalseに設定することで、そのライブラリや実行可能ファイルはビルドされなくなります。

executable sample
~ 略 ~
  buildable: False 

 cabal-versionフィールドでCabal 1.10以上を利用するよう指定している場合には、default-languages:フィールドを使って、パッケージのソースコードがHaskellの言語仕様のどのバージョンを想定しているかを指定することが推奨されます。

 $ cabal check
The following warnings are likely affect your build negatively:
* Packages using 'cabal-version: >= 1.10' must specify the 'default-language'
field for each component (e.g. Haskell98 or Haskell2010). If a component uses
different languages in different modules then list the other ones in the
'other-languages' field.

 今のところdefault-language:フィールドには、Haskell98とHaskell2010の2種類の言語仕様が指定可能です。現在の Haskell Platform 2012.2.0.0で提供されているGHC 7.4.1ではHaskell2010がデフォルトなので、特別な理由がない限り、ここにはHaskell2010を指定しておきましょう。

  default-language:    Haskell2010

 default-extensions:フィールドでは、パッケージのソースコードで利用する言語拡張を指定します。パッケージのソースコードの多くで同じ言語拡張を利用している場合には、default-extensions:フィールドにデフォルトで利用する言語拡張を書いておくと便利です。

  default-extensions:    CPP

 パッケージのビルド時に利用したいGHCのオプションがある場合には、ghc-options:フィールドで指定します。

  ghc-options:      -Wall -threaded

 ghc-options:フィールドとは別に、プロファイル用にビルドする場合だけに利用するオプションを指定するghc-prof-options:フィールドもあります。

  ghc-prof-options:      -fprof-auto

 Cプリプロセサにオプションを渡すためのcpp-options:フィールド、Cコンパイラにオプションを渡すためのcc-options:フィールド、リンカにオプションを渡すためのld-options:フィールドも用意されています。

 Cプリプロセサの利用や外部ライブラリの関数の呼び出しに、Cのヘッダ・ファイルが必要になることがあります。そうした場合には、includes:フィールドにヘッダ・ファイルを列挙したり、include-dirs:フィールドにヘッダ・ファイルを提供するディレクトリを列挙できます。includes:フィールドの代わりにinstall-includes:フィールドを利用すると、パッケージのインストール時に、ヘッダ・ファイルがパッケージの一部としてインストールされます。

 FFIを使った外部関数の呼び出しなどのために、使用している環境にインストール済みのヘッダ・ファイルを利用する場合には、install-include:ではなくincludes:を使いましょう。使用している環境にすでにインストールされているヘッダをパッケージの一部として改めてインストールすると、問題が生じる可能性があるからです。

 install-include:が適している場合もあります。第38回のコラムで説明した「Cプリプロセサを用いて段階制御の一括管理を行う例」では、パッケージが独自に提供するヘッダ・ファイルに定義したマクロが、パッケージのコンパイル時だけでなく、パッケージのコンパイル後にも必要になります。このような場合にはinstall-includes:を使います。

 FFIを使って外部関数を呼び出す場合には、ヘッダ・ファイルだけではなく、関数を定義したライブラリも必要です。外部関数の呼び出しに必要なライブラリはextra-libraries:フィールド、ライブラリのあるディレクトリはextra-lib-dirs:フィールドで列挙します。また、pkg-configコマンドを使って参照するライブラリの依存関係は、pkgconfig-depends:フィールドに列挙します(参考リンク)。Mac OS Xのframeworkは、frameworks:フィールドに列挙します(参考リンク)。

 C++のライブラリの関数をC経由で呼び出す場合には、外部関数の呼び出しのためにCのソースコードが必要になることがあります。そうした場合には、Cのソースコードをc-sources:フィールドに列挙します(参考リンク)。