Gentoo made easy 〜 もしくはパッケージを更新しない自由について 〜

これはGentoo Advent Calendar 12/08分です。日付・・・・?なんのことです?

www.adventar.org

みなさん, emergeしてますか. emergeで困るのは謎のエラーです. たとえば以下のようなものを見たことがありませんか

Total: 35 packages (29 upgrades, 1 downgrade, 5 reinstalls), Size of downloads: 211,908 KiB

!!! Multiple package instances within a single package slot have been pulled
!!! into the dependency graph, resulting in a slot conflict:

app-text/hunspell:0

  (app-text/hunspell-1.5.3:0/1.5::gentoo, ebuild scheduled for merge) pulled in by
    (no parents that aren't satisfied by other packages in this slot)

  (app-text/hunspell-1.4.2:0/1.4::gentoo, installed) pulled in by
    >=app-text/hunspell-1.2.1:0/1.4= required by (app-text/enchant-1.6.0:0/0::gentoo, installed)
                             ^^^^^^^
    (and 1 more with the same problem)

NOTE: Use the '--verbose-conflicts' option to display parents omitted above

It may be possible to solve this problem by using package.mask to
prevent one of those packages from being selected. However, it is also
possible that conflicting dependencies exist such that they are
impossible to satisfy simultaneously.  If such a conflict exists in
the dependencies of two different packages, then those packages can
not be installed simultaneously. You may want to try a larger value of
the --backtrack option, such as --backtrack=30, in order to see if
that will solve this conflict automatically.

For more information, see MASKED PACKAGES section in the emerge man
page or refer to the Gentoo Handbook.

これはどのようなことが起きているのでしょうか? なんでemergeはビルドしてくれないのでしょうか.

sub-SLOT dependency

さっきのエラーを解説する前に, sub-SLOT dependencyという機能について見ていきます.

多くのプログラムはライブラリを使用します. すると, そのパッケージはそのライブラリに依存することになります. より詳しく言えば, 「ビルドした時点でのライブラリのABI」に依存することになります.

たとえば, パッケージXがライブリLを使うとして, L-1.0がある状態でXがビルドされると, XはL-1.0のABIに依存することになります. すなわち, ライブラリパッケージLが, L-1.0からL-1.1にアップデートされると, Xの動作は壊れてしまう可能性があります.

この問題の1つの解決策として, preserved-rebuildという機能がGentooでは提供されていました. これはXがL-1.1に対してリビルドされるまで, L-1.0のライブラリを残しておくという機能です.

しかし, この機能はpreserve-rebuild状態になったパッケージがリビルドされるまで, ライブラリが残ってしまいます.

こうした場合に依存関係を「壊して」, パッケージXをリビルドさせる方法はないでしょうか? ひとつの方法として, パッケージXに明示的に"=xxx-yyy/L-1.0"に依存させるという方法があります. すると, L-1.1にバージョンが上がると, Xの依存が壊れるので, 1) Lのバージョンを上げないか, 2) Xをリビルドするかで解決することになります.

だが, しかし, それは, Gentoo ではないんだなあ

Gentooは選択なので, パッケージXをL-1.0に対してビルドするか, L-1.1に対してビルドするかを選択できるべきです.

そこで, sub-SLOT dependencyという機能が導入されています. この機能はGentooのSLOT機能を拡張し, ABIに関する依存関係を記録できるようにしたものです. この機能が特徴的なのは, 依存関係がビルド時に書きこまれる, ということです.

たとえば, パッケージXに"xxx-yyy/L:0="と書くと, ビルド時に"xxx-yyy/L:0/1.0"(/の後はsub-SLOT)があれば, 依存に"xxx-yyy/L:0/1.0"が書きこまれます. 同様にビルド時のパッケージが"xxx-yyy/L:0/1.1"であれば, 依存に"xxx-yyy/L:0/1.1"が書かれます.

なぜemergeが文句を言うのか

それでは, sub-SLOT dependencyが分かったとして, なぜemergeが文句を言うのか見ていきましょう. エラーを再掲すると

app-text/hunspell:0

  (app-text/hunspell-1.5.3:0/1.5::gentoo, ebuild scheduled for merge) pulled in by
    (no parents that aren't satisfied by other packages in this slot)

  (app-text/hunspell-1.4.2:0/1.4::gentoo, installed) pulled in by
    >=app-text/hunspell-1.2.1:0/1.4= required by (app-text/enchant-1.6.0:0/0::gentoo, installed)
                             ^^^^^^^
    (and 1 more with the same problem)

こういうエラーです. なにを言っているのかちゃんと見てみましょう.

ここでは, "app-text/hunspell"が"app-text/hunspell-1.5.3:0/1.5"にupdateしようとしているのに対して, "app-text/enchant-1.6.0"が">=app-text/hunspell-1.2.1:0/1.4="と, hunspellのsub-SLOTに依存しているため, enchantの依存関係が壊れるのでemergeを行なうことができないよ!!と言っています.

Portageは現状, sub-SLOTによるリビルドを自動的に実行しません. これは, ある種パッケージのバージョン固定(ここではhunspell)を守るためと言うことができます.

いや, でも, 実際のところ, わりとどうでもいいこと多いよね. 自動的にやってほしくない?

autoemergeによる解決

っということで, こうしたコンフリクトを見つけて, 自動的に解決するスクリプトを書きました.

ここにあるよ. https://github.com/naota/emerge-wrapper/

この autoemerge スクリプトは, 以上のようなエラーを自動で解決します. しかも, この解決はemergeに"--reinstall-atoms="を自動的に追加して, 指定したatomにマッチするパッケージをrebuildしていいよ〜とPortageに伝えることで, 依存の解決を目指し, emergeの機能に閉じているので, 安心して使うことができます.

では, さきほどのケースではどのように使いどのように動くのか見ていきましょう. 中心となるのは"autoemerge"というスクリプトです. 以下のようにしてautoemergeを動かします. emergeと同じ引数を認識します. (というか, そのままemergeに渡していきます)

$ sudo python3.5 ./autoemerge -uDN -j2 world --keep-going --with-bdeps=y

するとemergeが依存を解決し, 以下のエラーを出します.

dev-lang/ocaml:0

  (dev-lang/ocaml-4.04.0:0/4.04.0::gentoo, ebuild scheduled for merge) pulled in by
    >=dev-lang/ocaml-4.04_beta:=[ocamlopt?] required by (dev-ml/camlp4-4.04_p1:0/4.04_p1::gentoo, ebuild scheduled formerge)
    ^^               ^^^^^^^^^

  (dev-lang/ocaml-4.03.0-r1:0/4.03.0::gentoo, ebuild scheduled for merge) pulled in by
    >=dev-lang/ocaml-3.12:0/4.03.0=[ocamlopt] required by (dev-ml/sexplib-113.33.00:0/113.33.00::gentoo, installed)
                         ^^^^^^^^^^
    (and 4 more with the same problem)

autoemergeはこれを解析して, 以下のようなログを出して, 適宜"--reinstall-atoms==dev-ml/sexplib-113.33.00"などをつけて再度依存関係を解析させます

reinstall (dev-ml/sexplib-113.33.00:0/113.33.00::gentoo, installed) for (dev-lang/ocaml-4.03.0-r1:0/4.03.0::gentoo, ebuild scheduled for merge)
reinstall (dev-ml/ocaml-re-1.7.1:0/1.7.1::gentoo, installed) for (dev-lang/ocaml-4.03.0-r1:0/4.03.0::gentoo, ebuild scheduled for merge)
reinstall (dev-ml/pcre-ocaml-7.2.3:0/7.2.3::gentoo, installed) for (dev-lang/ocaml-4.03.0-r1:0/4.03.0::gentoo, ebuild scheduled for merge)
reinstall (dev-ml/pcre-ocaml-7.2.3:0/7.2.3::gentoo, installed) for (dev-lang/ocaml-4.03.0-r1:0/4.03.0::gentoo, ebuild scheduled for merge)
reinstall (dev-ml/ocaml-re-1.7.1:0/1.7.1::gentoo, installed) for (dev-lang/ocaml-4.03.0-r1:0/4.03.0::gentoo, ebuild scheduled for merge)

この作業は再帰的に実行され, 全ての依存が解決された時点で, exec()システムコールでemergeが実行され, あたかも最初から適切な--reinstall-atomsをつけていたかのように, emergeが実行されます.

その他, emergeによってUSEフラグが更新された時に自動的にdispatch-confを呼びだして, emergeを再実行するなど, 手動でemergeを実行する様々な手間が省略されています.

さあ, みなさんautoemergeを使ってらっく〜にGentooを更新していきましょう. (バグが出たら, 笑って報告してね)

sub-SLOTを認め, ビルドしない自由を持つのがGentooなのだ

この後は特に読まなくていいとこです

そもそも, sub-SLOT dependencyが必要なのは, パッケージに"=xxx-yyy/L-1.0"などと書けないためです. ところがこれは, 世の多くのパッケージマネージャでは問題になりません. なぜでしょうか.

なぜなら, そうしたパッケージマネージャは基本的に, 1つのパッケージに対してひとつのバージョンしか提供せず, パッケージリポジトリが規定するライブラリとアプリケーションとの組み合わせをある種強制する, いわば「帝国主義的パッケージマネージャ」であるからです

だがしかし, そのような帝国主義的パッケージマネージャでは生きてはいけないのだ. たとえばお持ちのプログラムがPerl-5.20に依存すればどうなるか? ほしいパッケージが最新のディストリビューションリポトリにはあるが, そのリポジトリではperl-5.22がふってくるならどうすればいいのか. リポジトリに屈して, Perl-5.20および全てのそこに依存するパッケージを自分でビルドするのか? はたまたお手持ちのスクリプトをがんばってPerl-5.22に対応させ, リポジトリ内の最新のもろもろのパッケージに対応させるのか? どちらかを行わせる, これが帝国主義リポジトリの限界なのだ.

だが, われわれGentooには自由がある. お望みであれば, 好きにperlを5.20に留め, それでいて関係ないパッケージは最新にする, それがGentooの自由だ. 帝国主義リポジトリは打倒されるべきではないか? 立ち上がれ, 市民よ. Gentooの光を世界に広めるのだ.