OPAM の依存関係ソルバーと戯れてみた

Posted on January 23, 2015

前置き

最近のモダンなパッケージマネージャは充足可能性理論を利用した優秀な依存 関係ソルバーを持っていることがある。これはどういうものかと言うと、依存 するパッケージ名およびバージョン制約を与えると、そこから“最適”なインス トール手順(解)を導き出すものだ。“最適”というのは場面によって意味が異 なり例えば以下のようなものが考えられる。

  1. 現在の状態を極力変化させずにリクエストされたパッケージをインストー ルする解を選択する
  2. 現在の状態は極力変化させないが依存パッケージは最新にアップグレード しつつリクエストされたパッケージをインストールする解を選択する
  3. 与えられた制約を満たす解の内、インストールされるパッケージが最も少 なくなるような解を選択する

素朴なパッケージマネージャーは基本的にパッケージのアップグレードしか考 えないため、例えばあるインストール済みパッケージをダウングレードするこ とで全体の制約を満たすことが可能だとしても、むなしく依存関係解決エラー になって終了したりする。さらに悪いものになると依存関係解決エラーにすら ならず、実行時になるまで非互換性に気付かなかったりする。いわゆる “Dependency hell” の一端なのだが、依存関係ソルバーがあればかなり軽減で きる。

後発の OPAM は当然ながら依存関係ソルバーを持っている。しかもユーザーに よって制御可能だ。本エントリではこの依存関係ソルバーの考え方と基本的な 使い方を紹介したいと思う。

インストール戦略

インストール戦略 1を指 定するには opam install--criteria オプションを渡せば良い。デフォ ルトでは次のようなインストール戦略が使われる。2

-count(removed),-notuptodate(request),-count(down),-notuptodate(changed),-count(changed),-notuptodate(solution)

これは辞書順で次のように読む。

  1. 削除されるパッケージ数を最小化する
  2. リクエストされた(opam install に与えられた)パッケージで最新版で ないパッケージ数を最小化する。つまりできるだけ最新版をインストールする
  3. ダウングレードされるパッケージ数を最小化する
  4. 最新でない追加・削除パッケージ数を最小化する。つまり追加・削除・アッ プグレード・ダウングレード時にできるだけ最新版をインストールする
  5. 追加・削除パッケージ数を最小化する
  6. 解の内、最新版でないパッケージ数を最小化する。つまりできるだけ最新 版をインストールする

かなり複雑だがやろうとしていることは分かるはずだ。語彙や仕様について詳 しくは以下の PDF を参照されたい。

http://www.dicosmo.org/Articles/usercriteria.pdf

この PDF からいくつか例を紹介しよう。

以下はパラノイド向けのインストール戦略である。

-count(removed),-count(changed)

changed は削除および追加されるパッケージの集合である。つまりこれはシ ステムへの変化を最小限に抑えるインストール戦略なのだ。

以下はパラノイド向けであるができるだけ最新も追うインストール戦略である。

-count(removed),-notuptodate(request),-count(down),-count(changed)

-notuptodate(request) はリクエストされたパッケージが最新版でないもの を最小化しようとする。つまり、リクエストされたパッケージについてはでき るだけ最新版をインストールしようとするのだ。

他にもいくつか面白い例が挙げられているので興味のある人はぜひ PDF を参 照されたい。

戯れる

実際に戯れてみよう。まず実験環境に入る。

実験に使うパッケージは ocamlfindppx_monadic にしよう。 ocamlfind の最新版は現時点で 1.5.5ppx_monadic1.0.2 で ある。 ppx_monadicocamlfind に依存しているが、バージョン制約は 特にない。

まず ocamlfind1.5.2 をインストールしてみよう。

次に ppx_monadic1.0.0 をインストールしてみよう。

ocamlfind1.5.5 にアップグレードされなかった。

これはなぜかというとデフォルトのインストール戦略が依存パッケージのバー ジョンをできるだけ保とうとするからだ。デフォルトのインストール戦略を再 掲する。

-count(removed),-notuptodate(request),-count(down),-notuptodate(changed),-count(changed),-notuptodate(solution)

-notuptodate(changed),-count(changed) が該当の部分だ。これを削除する と、 -notuptodate(solution) が強く作用しパッケージを積極的にアップグ レードするようになる。実際にやってみよう。

期待通り ocamlfind1.5.5 にアップグレードされた。次に普通に ppx_monadic をインストールしてみよう。

(期待に反して) 1.0.2 にアップグレードされなかった。試しに以下を実 行してみる。

どうやらインストール済みのパッケージをバージョン指定なしでインストール しようとすると、インストール済みパッケージのバージョンが指定されたとい う解釈になるようだ。こういった場合は opam install の代わりに opam upgrade を使うか、バージョンを指定する。

最後に荒技をやってみよう。以下のコマンドは指定されたパッケージが依存し ないパッケージをシステムから削除するコマンドである。

インストール戦略は、できるだけ最新版をインストールしつつ、解は最小化し、 削除するパッケージ数を最大化している。

こういう技を臨機応変に繰り出せるのは OPAM の設計の素晴しいところだと思 う。ただ、しばらく戯れた印象では --criteria オプションを使うことは滅 多にないと思われる。あったとしても正しく指定できる自信がない。結構、 (狙って面白い例を作るのが)難しいのだ。

具体的な実践例について続くかもしれない。


  1. 若干語弊があるかもしれないが分かりやすさのためにこの言葉を使う

  2. OPAM 1.2.0 の man ページより