タラバガニー設計局stalins.clubNOTE/notes/binary-relocation-strategies

ビルド済みバイナリのrelocationには複数の解法がある

ビルド済みpackageを別マシンへ配るとき、単にarchiveを展開すれば動くとは限らない。compiled binaryやscriptには、build時のinstall prefix、library search path、interpreter pathなどが埋め込まれることがある。これを別のprefixへ移す relocation は、binary package managerの設計を左右する基本問題である。

ビルド済みパッケージ配布を一括りにしない で挙げたHomebrew、Spack、Conda、Nixは、この問題にかなり異なる方法で対処する。

Homebrew: relocatableかを判定し、無理ならBottleを使わない

Homebrew Bottleにはcellarという情報があり、BottleがbuildされたHOMEBREW_CELLARへの参照を持つかどうかを扱う。公式ドキュメントは、多くのcompiled softwareがbuild locationへの参照を持つため、単純にはどこへでも移せないと説明している。

Bottleが:anyまたは:any_skip_relocationなら別Cellarでも使える。一方、BottleのCellarが現在のHOMEBREW_CELLARと合わず、relocatableでもない場合、HomebrewはそのBottleを使わない。

ここでは「artifactを無理にどこでも動かす」より、relocation可能性をpackage metadataに持たせ、適合しなければprebuilt pathを諦める戦略になっている。

Spack: install prefixを書き換える

Spack Build Cacheは、installed specとdependenciesのinstall prefixをtarball化して配る。別マシンではinstall rootが異なる可能性があるため、Spackはbinaryやscriptに埋め込まれたpathをinstallation時にrelocateする。

ただし任意長のpathを書き換えられるわけではない。元のbinary中に確保されている領域より長いprefixへ移そうとすると失敗する場合があり、Spackはbuild時にinstall rootへpaddingを入れておくことを推奨している。relocation不能ならsource buildが必要になる。

これは binaryを書き換えて新しいprefixへ適合させる戦略である。

Conda: prefix replacementをpackage formatの一部にする

Conda packageでは、build prefixを含むfileをinfo/has_prefix等で記録し、install時にtarget prefixへ置換する。text fileだけでなくbinary fileも対象になり得る。

binary replacementでは長さを保つ必要があるため、Conda buildは長いplaceholder prefixを使い、install prefixがその範囲に収まるようにする。またLinux/macOSではobject file側を相対pathへ変換する処理も行う。

Spackと似ているが、Condaでは relocation metadataとplaceholder設計をpackage formatそのものへ組み込む点が特徴的である。

Nix: むしろstore pathをidentityの一部にする

Nixは別方向を取る。通常、artifactは/nix/store/<hash>-nameという固有pathに置かれ、dependencyへの参照もそのstore pathを前提にする。つまり「任意prefixへinstallして後から書き換える」より、content/build identityに結び付いた予測可能なstore namespaceへ配置することでrelocation問題を避ける方向である。

その代わり、Nix store同士でobjectをcopyする際にはstore directoryが同じことが基本条件になる。NixのHTTP Binary Cache Storeのstore設定にも、store pathをcopyできるのは同じstore設定同士という制約が記載されている。

relocation問題はABI問題とは別

pathを書き換えられたとしても、そのbinaryが別hostで動くとは限らない。glibc version、CPU instruction set、CUDA driver、OS APIなどの互換性は linux/amd64だけではビルド済みバイナリの互換性を表せない の問題である。

したがってprebuilt artifactのportabilityは少なくとも二段階に分けるべきである。

  1. location portability: 別prefixへ置けるか
  2. runtime compatibility: そのhost ABIで実行できるか

Homebrew、Spack、Conda、Nixの違いを見ると、relocationは単なる実装上の後処理ではなく、package identityとfilesystem layoutをどう設計するかという根本問題だと分かる。

#ツールチェーン

出典

▸ ノート一覧に戻る