ビルド済みパッケージ配布を一括りにしない
「ソースからビルドせず、すぐ実行できるものが取得される」という利用体験だけを見ると、Nix、aqua、Homebrew、Conda、Spack は似て見える。しかし、何を一次成果物とみなし、誰がビルドし、キャッシュに目的物がないとき何が起きるかは大きく異なる。
少なくとも次のように分けて考えると整理しやすい。
| モデル | 代表例 | 一次的な記述/成果物 | キャッシュ・配布物がない場合 |
|---|---|---|---|
| build result substitution | Nix, Guix | derivation / build graph | ローカルまたはremote builderでビルドできる |
| recipe + binary cache | Homebrew Bottle, Spack Build Cache | formula/spec とビルド済みprefix | 条件が合わなければsource build |
| upstream release adapter | aqua | upstream release asset を選ぶregistry metadata | 原則asset取得。aquaにはGo build等への限定的fallbackもある |
| binary environment solver | Conda, Pixi | 依存metadataを持つbinary package群 | solverが互換なpackage集合を選ぶ |
| distribution binary repository | apt, rpm/dnf | ディストリビューションが作ったbinary package | 通常はrepository上のpackageが配布単位 |
この分類で重要なのは、「バイナリを配る」こと自体ではなくpackage identityをどこに置くかである。
Nix と Guix では、prebuilt object は本来のbuild resultを置き換える substitute である。Guixのマニュアルは substitute を明確に「local build results の代替」と説明し、derivation build の結果ならpackage binaryだけでなくsource tarballでもsubstituteになり得るとしている。Nixもsubstituterをstore objectを別storeから取得してbuildを省略する仕組みとして扱う。このモデルでは、recipe/build graphが先にあり、binary cacheはその結果の再利用層とみなせる。これは Nixのsubstituteは「バイナリパッケージ」よりbuild resultに近い と binary cacheの公開鍵を追加することはbuilderを信頼することに近い に繋がる。
一方 aqua の中心は、GitHub Releases等にupstream自身が公開したassetを、OS・architecture・versionに応じて選択し展開することにある。registryはbuild recipeというより「このversion・platformならどのassetを選ぶか」という正規化規則を持つ。この性格は aquaはupstream releaseを正規化するパッケージマネージャーと捉えられる で扱う。
HomebrewとSpackは中間にある。recipe/specを持ちながら、既にビルドした成果物をBottle/Build Cacheとして利用する。HomebrewはBottleが現在のsystemやCellar条件に合わなければ利用せず、Spackはconcretized specに対応するprebuilt packageをbuild cacheから使い、必要ならsource buildへ戻れる。この系統では ビルド済みバイナリのrelocationには複数の解法がある が大きな課題になる。
Conda系はさらに異なり、binary packageそのものがdependency metadataを持ち、solverが環境全体を構成する。CondaではOSだけでなく__glibcや__cudaなどhost側の条件もvirtual packageとしてsolver入力にできる。この問題は linux/amd64だけではビルド済みバイナリの互換性を表せない に繋がる。
したがって「ビルド済みパッケージマネージャー」という語を使う場合でも、最低限 build result cache型 / upstream artifact選択型 / binary repository + solver型 は分離して考えた方がよい。これらは同じUXを提供し得るが、再現性、fallback、trust、ABI互換性、storage効率に対して全く異なる設計を採る。
出典
🔗 リンクされているノート
- ビルド済みパッケージ管理 調査ノート
- OCI Registryはcontainer image以外のcontent distribution primitiveにもなる
- binary cacheとpackage repositoryは似ているが一次性が違う
- miseは異なる配布モデルをbackendで同じUXに重ねる
- prebuiltがないときのsource build fallbackは同じ意味ではない
- ビルド済みバイナリのrelocationには複数の解法がある
- aquaはupstream releaseを正規化するパッケージマネージャーと捉えられる
- Nixのsubstituteは「バイナリパッケージ」よりbuild resultに近い