ocamlfind の公式ドキュメントの個人的まとめ

パッケージのインストールや依存関係の管理は `opam` を使えばよいが、ちょっとしたコンパイルや古めのソースを確認するときには依然`ocamlfind` の知識は必要そうなので、公式ドキュメントの個人的まとめ。

- [The findlib User's Guide](http://projects.camlcity.org/projects/dl/findlib-1.7.3/doc/guide-html/c37.html)

## ocamlfind の依存管理が解決するもの

1. ライブラリをファイル階層順に保存する
2. 保存したライブラリを使用したプログラムのコンパイルとリンク
3. ライブラリの依存管理

Findlibは、特定のディレクトリ構造を保つことが必要。
任意の場所にファイルをインストールすることはできない。
findlibはファイルリストを保持していない。
すべてのライブラリは、ライブラリのアーカイブファイルとインタフェースファイルのような独自のディレクトリに格納される。


## Findlib
ocamlfind は Findlib のコマンドラインインターフェイス。

1. ocamlc、ocamlopt、ocamlmktop、ocamlcpを呼び出して、パッケージングやリンクに必要なコンパイラの引数を自動的に追加できる
2. パッケージのインストールとアンインストール
3. 依存パッケージの発見

## 簡単な使い方

- 他の人が書いたパッケージをリンクする場合
    - コンパイラを起動するコマンドを変更
    - `ocamlc program.ml` → `ocamlfind ocamlc -package name_of_package_to_use -linkpkg program.ml`
        - `program.ml` 内の指定されたパッケージを参照することができる
- モジュールのコレクションをパッケージにする場合
    - 必要な他のパッケージなど、必要な情報を記述した管理ファイル（META）を書き込む

### Packages を使う

`ocamlfind list` でインストールされてるパッケージ一覧を表示。 `-describe` オプションで詳細も表示。

### パッケージのあるディレクトリを表示
`ocamlfind query 名前`
ちなみに標準では `/usr/local/lib/ocaml/site-lib` にOCamlライブラリが格納されることが多い(らしい)。

環境変数 `OCAMLPATH` が設定されていると、先にそのパスを見に行く。
次に `findlib.conf (ocamlfind.conf?)` の設定を見に行く。

```
$ cat ~/.opam/4.06.0/lib/findlib.conf
destdir="/Users/hoge/.opam/4.06.0/lib"
path="/Users/hoge/.opam/4.06.0/lib"
ocamlc="ocamlc.opt"
ocamlopt="ocamlopt.opt"
ocamldep="ocamldep.opt"
ocamldoc="ocamldoc.opt"
```

### METAファイル

METAファイルの記述例

```
description = "説明文をここに"
requires = "必要なパッケージ名をカンマ区切りで並べて書く,hoge,fuga" 
version = "1"

パッケージが使用するときに実際にリンクするファイル名をカンマ区切りで並べる(byte, native で別に書く)
archive(byte) = "p.cma" 
archive(native) = "p.cmxa" 
```
上記の `(byte)` や `(native)` などの括弧内の値の指定を `述語` という。

#### METAファイルに記述されている情報の取得

`ocamlfind query -long-format パッケージ名`
や `-predicates` オプションで述語指定したりもできる。
`ocamlfind query -long-format -predicates byte,native camlp4`
`-recursive` を付けると、 `require` で指定されている依存先パッケージのMETAの情報も見れる。

## findlibでプログラムをコンパイル&リンクする

### コンパイル

`ocamlfind ocamlc -package hoge -c main.ml` 

これは以下と等価(ライブラリのパスは例)
ライブラリのインクルードをよしなに行ってくれる。

`ocamlc -I /usr/local/lib/ocaml/site-lib/hoge -c main.ml`

### リンク

`ocamlfind ocamlc -o program -package hoge -linkpkg prog1.cmo prog2.cmo prog3.cmo`

これは以下と等価。

`ocamlc -o program -I /usr/local/lib/ocaml/site-lib/hoge hoge.cma prog1.cmo prog2.cmo prog3.cmo`


ocamlfind経由で呼び出される場合は、コンパイラオプションはオリジナルのもの加えてocamlfindが提供するものも使えるようになる。

- `-package <name>`
- `-linkpkg`
- `-predicates <predicate-list>`
- `-dontlink <name>`
- `-passopt <opt>`

コンパイルのみを行う場合、つまり `-c` オプションが有効な場合、通常は `-package` オプションが必要

## インストールしたパッケージのサブコマンドを呼び出す
PATHを通さなくても ocamlfind 経由で呼び出せて便利

`ocamlfind パッケージ名/バイナリ名`

例: `ppx_tools` でインストールされるコマンドを呼び出す

```bash
$ opam install ppx_tools
The following actions will be performed:
  ∗  install ppx_tools 5.1+4.06.0

=-=- Gathering sources =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=  🐫 
[default] https://opam.ocaml.org/archives/ppx_tools.5.1+4.06.0+opam.tar.gz downloaded

=-=- Processing actions -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=  🐫 
∗  installed ppx_tools.5.1+4.06.0
Done.

$ ocamlfind ppx_tools/dumpast -e "1 + 2"
1 + 2
==>
{pexp_desc =
  Pexp_apply ({pexp_desc = Pexp_ident {txt = Lident "+"}},
   [(Nolabel, {pexp_desc = Pexp_constant (Pconst_integer ("1", None))});
    (Nolabel, {pexp_desc = Pexp_constant (Pconst_integer ("2", None))})])}
=========
```