NixOSで各言語のパッケージをNix経由での管理にせずに開発環境を作る

NixOSでは共有ライブラリの管理方法が他のlinuxディストリビューションと違い、/nix/storeに置いてある。 よって、例えば無邪気にnpm installでいれたcliがnot found扱いとなる。 なのでベーシックなやりかたとしては、Nixを使って各言語のパッケージも管理するというのがあって、 patchELFでpatchをあててinterpreterとrpathをセットし直すという形でderivationを書いたり、あるいは、そういった形でNixのパッケージとして公開されている。

ただ、Nixで各言語のパッケージを管理したくない気持ちというのはまぁあって、普通にnpmで管理して、雑にnpm installして動く、みたいなのがいいとおもうこともあるはずだ。

今回はelectronをリポジトリローカルなモジュールとして管理したかったというシチュエーションだったので、この条件を満たすshell.nixをつくった。

{ pkgs ? import <nixpkgs> {} }:

with pkgs;

let
  sharedDeps = atomEnv.packages ++ [
    libdrm
    libxkbcommon
    mesa
  ];

in
  (buildFHSUserEnv {
    name = "electron-test-env";
    targetPkgs = pkgs: sharedDeps ++ [
      nodejs-12_x
    ];
  }).env

やっていることとしてはnodeの依存とelectronの実行に必要な共有ライブラリの依存が入った環境をbuildFHSUserEnvを使って用意している。

shell.nixを用意する場合、mkDerivationmkShellを使うと思うが、その場合は、共有ライブラリの検索のためのコード(LD_LIBRARY_PATHの設定、あるいは、rpathのパッチ)とELFのインタープリタのパッチのコードが必要になってしまう。

しかし、buildFHSUserEnvを使うと、FHSに準拠した形で環境を用意してくれるので、必要なライブラリを依存に入れるnixファイルを書くだけで済む。

こういったshell.nixをプロジェクトルートにでも置いて、nix-shellを呼び出すだけで、あとは各言語のパッケージ管理ライブラリのみでパッケージを管理できる。(このnix-shellで起動したshellの中なら、無邪気にnpm installしたcliも動く。今回の場合はelectronのcliが問題なく動く。

結果的にはほとんどDockerfileを書いているのに近い感覚で開発環境を作ることができる。

すげえ便利なので、NixOSユーザーはbuildFHSUserEnvを使ってみると良いでしょう。

なお、詳細はNixOSのマニュアルにあるので、使う前は要チェックです。