Nixで、あるパッケージがどのパッケージに依存しているのかを調べたくなったのを発端に、パッケージやその依存関係の調べ方についていろいろ調べた。
要約
- アプリ・ツールがどのパッケージに収録されているのかを知る
- NixOS Search や
nix search
コマンドを使う which
やrealpath
コマンドから/nix/store
下のディレクトリがわかるのでそこからパッケージ名を知る- nix-index、 nix-index-databaseを使う
- NixOS Search や
- derivationの詳細を知る:
nix derivation show [drv or output]
- output ⇔ derivation
- outputがどのderivationでビルドされたのかを知る:
niq-store --query --deriver [output]
- derivationのoutputを知る:
nix-store --query --outputs [drv]
- outputがどのderivationでビルドされたのかを知る:
- derivationについて
- build dependenciesを知る:
nix-store --query --references [drv]
- 間接的なbuild dependenciesもすべて知る:
nix-store --query --requisites [drv]
- build dependenciesを知る:
- outputについて
- runtime dependenciesを知る:
nix-store --query --references [output]
- 間接的なruntime dependenciesもすべて知る:
nix-store --query --requisites [output]
- runtime dependenciesを知る:
前置き
用語解説
いろいろとNix固有(?)の言葉が出てくるため、ここでまとめて解説しておく。
GlossaryとNix Pills Chapter9を参考にする。
- パッケージ:ファイルやデータの集まり。
- derivation:何らかのビルドタスクを行うための記述書。端的にはパッケージを作るための仕様書である。次の節で詳しく述べる
- output:derivationから生成されたもの
- store object:Nixによって管理されているあらゆるオブジェクトをさす。通常は
/nix/store/
に保管されているはず - store path:store objectが置かれている場所。通常は
/nix/store/
にあるはず - build depencencies:ビルドの時点で必要になる依存関係。ビルドに必要なソースコードや、derivationの中で参照されている別のderivationを指す。これはderivationに記載されている
- runtime dependencies:実行時に必要になる依存関係。動的ライブラリや、ほかのパッケージの実行ファイルなどを指す
- これを検出する方法は素朴で、生成したパッケージをNAR形式で固め、そこに埋め込まれているoutputのパスがruntime dependenciesと判定するだけである
- NAR (Nix Archive):tarのように複数ファイルを1つのファイルに固めた形式。ただし、同じアーカイブ対象であればまったく同じNARファイルができるように、tarに比べてシンプルなつくりになっている。例えば、tarだとアーカイブする度にタイムスタンプ(
mtime
フィールド)が埋め込まれるが、NARにはそれがない(参考)- NARが作られた背景について、edolstra氏のPh.D論文のp.91が詳しい
nix nar dump-path <ファイル・ディレクトリ名>
で、NAR形式がどんなものか見ることが可能(バイナリなので、odやhexdumpコマンドを嚙ませたほうが見やすいかも)
- closure:あるstore pathに直接または間接的に依存するstore pathの集合
- 閉包(closure)という名の通り、closureの任意のstore pathについて、それに依存するstore pathは必ずそのclosureの要素になっている(言い換えると、ある要素に対して「その依存関係を列挙する」という操作を定義したとき、closureはその操作について閉じている)
パッケージのビルドとderivationについて
NixOSを使うとなるとたいていはconfiguration.nix
やhome.nix
を設定するだけなので、derivationに触れない場合が多いかもしれないので、一応ここで少し詳細な解説をはさむ。
derivationは、(一つの使い道としては)ビルドの仕様書である。原義としては、公式docを引用すると、
a specification for running an executable on precisely defined input files to repeatably produce output files at uniquely determined file system paths
である。「正確に定義された入力ファイルをもとに繰り返し出力ファイルを生成し、一意に定められたシステムパスにそれを配置するための実行ファイルを動かすための仕様書」ということになる。つまり、derivationには、
- 入力
- (何らかの出力を生成する)実行ファイル
を書くことができる。
この特徴はプログラムのビルドに使える。例えば何らかのプログラムをビルドしたいという場合、ライブラリを持ってきて、それをコンパイルして、適当な所に生成物を配置する、という過程を踏むことになる。この情報をderivationに書くことができる。 Nixではあらゆるツールやアプリケーションのビルド方法をderivationで記述する。
もちろん、derivationの定義としては別にビルドに限らず使える。例えばbuildEnvは、アプリケーションをビルドするのではなく、アプリケーションを集めたディレクトリ構造を生成する。
あるアプリ・ツールがどのパッケージに収録されているのかを知る
パッケージ名を推測して調べる場合
- NixOS Searchを用いる
- CLI上で調べたいなら、
nix search
コマンドを用いる。例えばnix search nixpkgs <正規表現>
で、nixpkgsの中から<正規表現>
に合致するパッケージを検索してくれる。
インストール済みのバイナリ・ファイルから調べたい場合
すでにアプリ・ツールが自分の環境に入っており、それがどのパッケージに収録されていたのかを特定したい場合。
which
とrealpath
を組み合わせて、アプリケーションが/nix/store
のどのディレクトリに配置されているのかを確認する。
|
|
ここで現れる /nix/store
直下のディレクトリ名は {hash}-{package name}-{version}
の形式になっているはず。そのため、{package name}
のところからパッケージ名が分かる。
インストール済みでないバイナリ・ファイルから調べたい場合
まだアプリが自分の環境にインストールされておらず、どのパッケージを入れれば目的のアプリが手に入るのか分からない場合。
その場合はnix-indexを使う。
nix-indexを使うためには一度データベースを作成する必要があるが、生成には時間がかかるため、代わりにすでに作成済みのnix-indexであるnix-index-databaseを使うとよい。
以下は、lsコマンドの入っているパッケージを検索する例。-r
引数をつければ正規表現で検索できる。
|
|
derivationの詳細を知る
derivationファイルの内容を確認したい場合、nix derivation showコマンドを使う。
以下はlsコマンドが収録されているパッケージのderivationの情報を出力する例。
|
|
ちなみに、アプリケーションの実行ファイルそのものではなく、直接drvファイルを指定することも可能(その場合は、末尾に ^*
をつけたほうがよいっぽい)。
|
|
なお、nix derivation show
コマンドは /nix/store/g0kqr7b99b70kb10vmqg10vkj9nfk7zm-coreutils-full-9.3.drv
をJSONで分かりやすく出力しているに過ぎず、drvファイル自体はATermという形式で書かれている(参考)。これをJSONに変換して出力している。生のデータを見てみたいなら直接 cat
で見てみるとよい。以下はcoreutilsの結果(分かりやすく改行している)。
|
|
outputがどのderivationでビルドされたのかを知る
niq-store --query --deriver
を用いる。以下はlsコマンドがどのderivationで生成されたのかを知る例。
|
|
derivationのoutputを知る
nix-store --query --outputs
を使う方法が最もシンプル。
|
|
なお nix derivation show
のjsonからも取り出せる。
|
|
derivationのbuild dependenciesを知る
nix-store --query --references
を使う方法がシンプル。--references
オプションを用いることで、derivationに直接依存する入力を検索する。
|
|
さらに深い階層をインタラクティブに確認したい、という場合には、nix-treeを使うとよい。
なお nix derivation show
のjsonからも取り出せる。inputDrvs
とinputSrcs
に書かれているものがそれである。
|
|
derivationの間接的なbuild dependenciesもすべて知る
nix-store --query --requisites
で可能。--requisites
をつけることで、依存関係の閉包(closure)を求めることができる。
閉包という名のとおり、このコマンドで出力されたdrvの集合に対して、どのdrvもそれに依存するdrvが集合の中に存在する(つまり集合の中で「閉じている」という状態)。
|
|
ツリー形式で出力したいなら、nix-store --query --tree
で可能。 [...]
で省略されているものはおそらく、同じ出力が出ないようにキャッシュされているもの(いわゆる枝狩り)。
|
|
outputのruntime dependenciesを知る
これもnix-store --query --references
で可能。drvではなくバイナリのパスを指定すれば、それに依存するruntime dependenciesを知ることができる。
|
|
outputの間接的なruntime dependenciesもすべて知る
これもnix-store --query --requisites
で可能。drvではなくバイナリのパスを指定すれば、それに依存するruntime dependenciesを知ることができる。
|
|