ocamlc -pack について

OCamlでは同じパス名を持つモジュールを二つ以上リンクすると、名前が衝突しちゃうのでエラーになります。
名前の衝突とは、例えば、プログラム中に M というモジュールが二つあったとしたら、M.x と書いたときどっちを見りゃいいんじゃ、ということ。*1

OCamlでは、.mlファイルはそのファイル名と同じ名前のモジュールを提供します。ですから、同じファイル名の .ml ファイルから作られた .cmo を一緒にリンクすることは*そのままでは*(後述)できません。ライブラリ(.cma)中にあっても同じです。自分のプログラムをライブラリとリンクしようとしたら、ライブラリ中のモジュール名と、自分の.mlファイルの名前が偶然同じでリンクできなかった、ということは時々おきます。

では、dir1/m.ml と dir2/m.ml という二つのモジュールパス M は同時にリンクできないかというとそんなことはなくて、コンパイラの -pack オプションによってモジュールパス名を変えてやれば混在が可能です。

ocamlc -pack -o pack1.cmo dir1/m.cmo

パッケージ化されたモジュールはパッケージモジュールに埋め込まれ、パッケージモジュール名を頭に付けたパスを使ったアクセスが可能になります。例えば、pack1.cmo をリンクするプログラムでは dir1/m.cmo は Pack1.M としてアクセスできるようになります。パス名が異なるので、pack1.cmo の Pack1.M と dir2/m.cmo の M は問題なくリンクできます。

上の例ではひとつの .cmo をパッケージに埋め込みましたが、複数の .cmo をひとつのパッケージにまとめることも可能です。

このモジュール名の衝突は、上述したように、複数のライブラリをリンクする時、偶然同じ名前のモジュールが含まれていた場合に起こります。これを避けるために、ライブラリを作る際には ライブラリ名.cma だけでなく、パッケージ化された ライブラリ名.cmo を提供することが(おそらく)推奨されます*2

*1:同名モジュールが二つあっても、それらが提供する物(型とか、値とか)が完全にdiscreteなら混ぜても多分問題ないけど、OCamlではそんなのメンド臭いからサポートしてない。

*2:-pack オプションがなかった10年ほど昔はリンクさせるライブラリなど余りなかったから、それでも不便には感じなかったし、基本全てソースからビルドなので、名前が衝突したらどれかのモジュール名を書き換えるだけですみました。今やバイナリインストールした複数ライブラリをリンクすることも多く、ライブラリ間で名前が衝突すると簡単に直せないし、ちょっと欝になります。