OPAM パッケージ化のススメ
Tags: ocaml
Published: 2020-01-23 16:16:26

※この記事は 2016年06月03日 に Qiita に投稿したものです。

---


OCaml を使い慣れてくると、そのうち依存するライブラリのバージョンの管理に悩まされるときが来ると思います。 OCaml のライブラリは依存するライブラリが多くて、 OCaml またはライブラリのバージョンを上げたらビルドできなくなったというトラブルが少なくないかと思われます。私も何度か困りました。 [core](https://opam.ocaml.org/packages/core/core.113.33.03/) とか見てください。一体いくつのライブラリに依存してるんですか。まあ core も含めてほとんどが Jane Street 製ですけど。

そこで OPAM パッケージ化の勧めです。大半の OCaml ユーザーは OPAM でパッケージ管理を行っているかと思います。パッケージ化というと敷居が高い気がしますが、そう難しくもありませんでした。 `opam install` を何度も実行して依存するライブラリをインストールしてはバージョン違いによるビルドエラーに悩む日々とサヨナラです。偉そうに言ってる私もビルドエラーの原因探しで困っていたところに「 OPAM で管理しなよ」と言われて今に至ります。

さらに詳しくは [OPAM のマニュアル](https://opam.ocaml.org/doc/Manual.html)を参照してください。英語しかないけどがんばって。フランス語で書かれるよりましです。

## OPAM パッケージ化のメリット

- OCaml のバージョンを依存するライブラリのバージョンを指定できます。
- 依存するライブラリをインストールしてくれます。
- ローカルのみの OPAM パッケージとして使えます。
- インストールは `opam install` だけで OK です。

OPAM パッケージ化は、ファイルを一つ書けばいいだけで簡単です。ローコストでこれだけのメリットがあって損はありません。偉そうに言っている私も（ry

## サンプルプログラム

サンプルとして [RPN 電卓を作ってみました。](https://github.com/szktty/ocalc)あまり簡単な例を出してもかえって頭に入ってこないかなと思いまして、自分で使ってみようと思ってそこそこ作ってあります。ときどき Python の対話モードを電卓代わりに使っているんですが + を何度も書くのが面倒で、数字だけ並べて一気に足せると楽そうです。こんな感じ。 +! でスタック内の数値を全部足します。

```
$ ocalc
Try "h" for more information.
>>> 1 2 3 4 5 6 7 8 9 10 +!
55
```

先にインストールの方法について触れときます。このリポジトリをダウンロードしたら、トップディレクトリで次のコマンドを実行するとインストールできます。

```
$ opam pin add ocalc .
$ opam install ocalc
```

上のコマンドが、ローカルな OPAM パッケージをローカル OPAM リポジトリに追加します。追加したら、以降はいつもの `opam install` でパッケージをビルド、インストールできるようになります。アンインストールは `opam uninstall ocalc` です。

## OPAM パッケージを作る

OPAM パッケージ化は簡単です。 [opam](https://github.com/szktty/ocalc/blob/develop/opam) という名前のファイルを用意するだけです。これが中身です。

```
opam-version: "1.2"
version: "1.0.0"
authors: "SUZUKI Tetsuya <tetsuya.suzuki@gmail.com>"
maintainer: "SUZUKI Tetsuya <tetsuya.suzuki@gmail.com>"
homepage: "https://github.com/szktty/ocalc"
bug-reports: "https://github.com/szktty/ocalc/issues"
dev-repo: "https://github.com/szktty/ocalc.git"
license: "Apache License, Version 2.0"
build: [
  [ "omake" "PREFIX=%{prefix}%" ]
]
install: [
  [ "omake" "install" "PREFIX=%{prefix}%" ]
]
remove: [
  [ "omake" "uninstall" "PREFIX=%{prefix}%" ]
]
depends: [
  "omake" { = "0.9.8.6-0.rc1" }
  "menhir" { = "20160504" }
  "spotlib" { = "3.1.0" }
]
available: [
  ocaml-version >= "4.03.0"
]
```

このファイルのフォーマットは YAML に見えなくもないですが OPAM 専用です。見た感じ適当にやってもどうにかなるでしょう。

`license` までの前半は特に説明不要かと思います。それ以降の項目はビルド処理と依存の指定です。 `available` で OCaml のバージョンを、 `depends` で依存ライブラリやツール＋バージョンを指定します（バージョン未指定でもOKです）。 ocalc は次のライブラリとツールに依存していますので、それを `depends` に記述しています。

- OMake: ビルドツール
- Menhir: いわゆる yacc
- Spotlib: コンパクトな便利ライブラリ

特に明確な方針があるわけでもないんですが、 OCaml のバージョンは 4.03.0 「以降」、依存ライブラリはバージョンを「固定」しています。 OCaml 以外は仕様変更で ocalc がビルドできなくなる可能性が高いので固定しておきます。

`build`, `install`, `remove` の項目は、それぞれ OPAM から呼ばれたときに実行されるコマンドのリストです。 `build` と `install` は `opam install` 時に呼ばれ、 `remove ` は `opam uninstall` 時に呼ばれます。基本的に OMake を呼ぶだけですが、 `%{prefix}` と書くとそこに OPAM のパスが置換されるので、それを OMake に渡しています。 OMakefile には PREFIX で指定されたパスにプログラムをインストールする設定を書いてあります。

`build`, `install`, `remove` は OPAM から呼ばれるだけの項目なので、実際にインストールやアンインストールを行う必要はありません。システムにインストールしたくないアプリケーションでも、ここを空にしておけば OPAM のバージョン依存管理の恩恵を受けられます。

## 注意点

- OPAM に登録されているライブラリは、依存するライブラリのバージョンが指定されていないことがあります。 ~~例えば [core](https://opam.ocaml.org/packages/core/core.113.33.03/) はこれだけ依存ライブラリが指定されていますが、 OCaml のバージョンが指定されていません。最新版の OCaml で過去の core を使ったり、あるいは過去の OCaml で最新の core を使おうとすると、他ライブラリで指定される OCaml のバージョンと競合する可能性があります~~ (現在は OCaml のバージョンが指定されています) 。既存のプロジェクトを OPAM パッケージ化する場合、できるなら OCaml とライブラリをすべて最新版に保つのがいいです。
- もちろん OPAM 自身もバージョンが上がると仕様が変わります。当然設定ファイルの内容も変わったりするので、常に最新版を使いましょう。