リソース付きRustプログラムのNixOSへのインストール

目標

同梱ファイルを参照するRustプログラムをNixOSにインストールしたい。

方法

  1. build.rsで頑張る →試してません
  2. 最終保存場所をソースに書き込む

ここでは2番目の手法についてメモしておきます。

前提条件

rustPlatform.buildRustProgramを使っている

実現手段

  1. patchPhaseでsedで$outをソースに埋め込む
  2. PostInstallで同梱ファイルを$outにコピーする

実例

sat-benchはSATソルバーのベンチマークをするためのユーティリティなので、 複数のCNFファイルを同梱している。実行時にはこのファイルを参照することが必要。 しかし、そもそもcargoは実行ファイルしかインストールしないので、コンパイルに使ったディレクトリは将来 もあるものと仮定して、CNFファイルはそのディレクトリを基準に指定するようにしてある。 そのためにコンパイル時にpwdをenv!("PWD")で埋め込んでいるが、一方コマンドラインからディレクトリを指定す るためのコマンドオプションも用意した。

しかし、これだとNixにインストールできないので、上の手法でパッチを当てることにする。 ディレクトリを指定しているのは以下のConfig::lib_dirのデフォルト値。

#[structopt(name = "sat-bench", about = "Run simple SAT benchmarks")]
struct Config {
    ...
    /// directory holding instances
    #[structopt(long = "lib", default_value = "")]
    lib_dir: String,

(別件だが、ここでdefault_value = env!("PWD")とか書きたいのだが、 そうするとコンパイルエラーになってしまう。残念。)

なのでこの行をsedで修正する。ここで、CNFファイルが保存されるのは$out/libとした。

  satbench = super.rustPlatform.buildRustPackage rec {
    ...
    patchPhase = ''
      sed -i "s|long = \"lib\", default_value = \"\"|long = \"lib\", default_value = \"$out/lib\"|" src/bin/sat-bench.rs
    '';

コンパイルやインストールの挙動はいじらないようにpostInstallフックを使って、 インストール後の処理としてファイルをターゲットディレクトリ$out/libにコピー。

    postInstall = ''
      mkdir -p $out/lib
      cp -r 3-SAT SAT09 SR2015 $out/lib/
    '';

このようなnix式を評価してパッケージをインストールすると、 以下のように適切なデフォルト値が埋め込まれているのがわかる。

$ sat-bench --help
...

OPTIONS:
    -K, --aux-key <aux_key>   [default: ]
    -H, --header <header>     [default: ]
        --lib <lib_dir>       [default: /nix/store/63765vm6s1gjp3sqmip7i1mp9xwm3nj5-satbench-0.4/lib]
    -M, --message <message>   [default: ]
...  

めでたし。