GNU make でのコンパイル

OCamlMakefile と組み合わせて GNU make を使う

OCamlMakefile は、 複雑なOCamlプロジェクトのコンパイル作業をとても楽にする生成的な Makefile だ。

標準のライブラリのみを使う基本的なOCamlプログラムやライブラリについては、 単にカレントディレクトリにOCamlMakefileをコピーし、 以下の Makefile を作成する:

RESULT = myprogram
SOURCES = \
  mymodule1.mli mymodule1.ml \
  myparser.mli myparser.mly mylexer.mll mymodule2.ml \
  mymainprogram.ml
  
OCAMLMAKEFILE = OCamlMakefile
include $(OCAMLMAKEFILE)

これは5つのコンパイル対象がある上に ocamlyacc と ocamllex をも使う、かなり複雑なプログラムだ。 ocamlyacc が生成する .mli ファイル(この例では myparser.mli) 以外の ソースファイルだけ書く必要がある。

(上記例の最後で include される) OCamlmakefile はいろんなターゲットを提供する。 詳細は OCamlMakefile のドキュメントを参照してもらうとして、ここでは主なものを 紹介する:

nc           ネィティブコードの実行ファイル作成
bc           バイトコードの実行ファイル作成
ncl          ネィティブコードのライブラリ作成
bcl          バイトコードのライブラリ作成
libinstall   ocamlfindを用いたライブラリのインストール
libuninstall ocamlfindを用いたライブラリのアンインストール
top          あなたのモジュールでカスタマイズされたトップレベルの生成
clean        OCamlMakefile で自動生成されたファイルの削除

OCamlMakefile + ライブラリ + Camlp4 の構文解析

OCaml ライブラリのインストールの推奨ツールが Findlib (コマンド名は ocamlfind) だ。 パッケージのインストール先を把握し、依存性に応じてロードし、 あたえられた状況下でどのファイルを使うべきかを知っている。

もし Findlib を使わない場合、 標準ランタイムライブラリをロードするには LIBS と INCDIRS 変数を設定しておけばよい。 LIBS は .cma や .cmxa 拡張子をのぞいたライブラリファイル名 (xxx.cma や xxx.cma の xxx 部分) を羅列する:

LIBS = str unix

もし非標準のライブラリを標準ライブラリと同じディレクトリに インストールしてない場合、 INCDIRS 変数にそのディレクトリを羅列する必要がある。

INCDIRS = /path/to/somelibdirectory/

これは普通、一つの方法でいろんな環境にインストールする、 慣習的には configure スクリプトで行う類の前準備段階で必要になる。 他にも、デフォルトサーチパスに含まれていない標準ディレクトリ (たとえば /path/to/stdlib/camlp4) でも同じだ。 この場合は以下のように書けば十分で、この方が可搬性がある:

INCDIRS = +camlp4

よし。だがライブラリは ocamlfind を使ってインストールする方が好ましい。 OCamlMakefile を使う場合、PACKS 変数を設定する必要がある:

PACKS = netstring num

標準ライブラリの一部ではないが、 OCaml の標準インストールに添付される unix, str, bigarray のような ライブラリは、Findlib が自動認識してくれる。 つまりこれらのパッケージを要求されるとき (例えば netstring は unix と pcre を要求する)は自動でロードされる。

camlp4 による構文拡張はどうだろうか。 プリプロセッサでロードされるバイトコードユニットみたいに 構文拡張を定義しているパッケージがあるかもしれない。 OCamlMakefile を使う場合、 プリプロセッサを使いたいときにはファイルの1行目に以下の定義をする:

(*pp ...

つまりこのように書く:

(*pp camlp4o -I /path/to/pa_infix pa_infix.cmo *)

うーん、このやりかたはちょっと不便だ。 だから各ファイルで同じプリプロセッサを使うことにして、 Makefile の PP 変数にこの共通の方法を代入する:

PP = camlp4o -I /path/to/pa_infix pa_infix.cmo
export PP

そうすれば、OCaml ファイルはこう始められる:

(*pp $PP *)

このプリプロセッサ定義でもまだ満足できない。 ocamlfind の特長と同じようにして構文拡張ファイルを取り込みたい。 そのためには、camlp4find スクリプトが使える。 普通、PACKS 変数に使うパッケージを羅列しておくと、 camlp4 が ocamlfind と同じように構文拡張をロードしてくれる:

PACKS = unix micmatch_pcre \
   pa_tryfinally pa_lettry pa_forin pa_forstep pa_repeat pa_arg
PP = camlp4find $(PACKS)
export PP

まとめ

必要なもの:

  • GNU make
  • OCamlMakefile (プロジェクトのメインディレクトリにコピーする)
  • Findlib (ocamlfind)
  • camlp4find (プロジェクトのメインディレクトリにコピーする)
  • ocamlfind でインストールした Camlp4 パッケージ
  • 以下の雛型を元に小さい Makefile を書く
  • ソースファイルの先頭行におまじないを書いておく

ocamllex と unix, micmatch_pcre ライブラリを使う例を全部示す。 Makefile はこんな感じだ:

RESULT = myprogram
SOURCES = mymodule1.mll mymodule2.mli mymodule2.ml mymainmodule.ml
PACKS = unix micmatch_pcre
PP = camlp4find $(PACKS)
export PP
CREATE_LIB = yes # ???
OCAMLMAKEFILE = OCamlMakefile
include $(OCAMLMAKEFILE)

.ml や .mli ファイルは以下の行で始める:

(*pp $PP *)