https://unsplash.com/photos/U2L0qbBw9Jo

さあ来いnix-2.4

2021-03-08にnix-2.4のpre-release版が三ヶ月ぶりに更新されて、ようやくnixを置き換えてもエラーなく使えるようになりました。(いやそうでもないみたいだぞ。。。@2021-03-16) なので早速Splrで使ってみたのでいくつかメモ。

restricted modeとは

nix-env -uでエラーはなくなったものの、flake.nixを作ろうとすると相変わらずrestricted modeではxxxxにアクセスできないというようなエラーが出る。これは--impureフラグを渡してやるといい。nix --helpによると、

When the --expr option is given, all installables are interpreted as Nix expressions. You may need to specify --impure if the expression references impure inputs (such as <nixpkgs>).

ということで、多分12月頃からこうすればよかったようだ。

$ nix flake init --impure
$ nix build --impure

flake.nixはどう書けばいいのか

Nix Wikiに出てくるのは以下の例

{
  inputs = {
    home-manager.url = "github:nix-community/home-manager";
  };
}
{
  outputs = { self, nixpkgs }: {
     # replace 'joes-desktop' with your hostname here.
     nixosConfigurations.joes-desktop = nixpkgs.lib.nixosSystem {
       system = "x86_64-linux";
       modules = [ ./configuration.nix ];
     };
  };
}

しかし、2020年5月の記事だけどNIX FLAKES, PART 1: AN INTRODUCTION AND TUTORIALの以下の例がまず足掛かり。

{
  description = "A flake for building Hello World";
  inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-20.03;
  outputs = { self, nixpkgs }: {
    defaultPackage.x86_64-linux =
      # Notice the reference to nixpkgs here.
      with import nixpkgs { system = "x86_64-linux"; };
      stdenv.mkDerivation {
        name = "hello";
        src = self;
        buildPhase = "gcc -o hello ./hello.c";
        installPhase = "mkdir -p $out/bin; install -t $out/bin hello";
      };
  };
}

これを真似すればよさそうだが、この例ではsystemが x86_64-linux に限定されている。 いや darwin メインだし将来的には aarch65 も期待したいのでもっとスマートな方法はないかと探すと、 Nix Wikiで使われているflake-utilsがよさそうである。このパッケージは

eachDefaultSystem -> (<system> -> attrs)

を提供している。ええと、これは返値がないように見えるけどこういうこと:

eachDefaultSystem :: (<system> -> attrs) -> attrs

ただし、使い方は微妙である。 よくわからないまま使うと、例えばdefaultPackege.x86-64-darwinがエクスポートされていないというエラーが出てしまった。 でこれによく似た関数eachSystemサンプルをよく見る:

eachSystem allSystems (system: { hello = 42; })
# => {
   hello.aarch64-darwin = 42,
   hello.aarch64-genode = 42,
}

引数closureの中でhelloを使うと最終的にhello.${system}にpopulateされるのだから、defaultPackege.色々なシステムをpopulateするにはclosureの中ではdefaultPackageにderivationを束縛すればいい。 ということで

{
  inputs.flake-utils.url = "github:numtide/flake-utils";
  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem (system: {
      defaultPackage =
        with import nixpkgs { system = "${system}"; };
        stdenv.mkDerivation {...};
    });
}

とするのが正解。 実際のコードはこれ:

{
  description = "A modern SAT solver in Rust";
  inputs.flake-utils.url = "github:numtide/flake-utils";
  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem (system: {
      defaultPackage =
        with import nixpkgs { system = "${system}"; };
        stdenv.mkDerivation {
          name = "splr";
          src = self;
          buildInputs = [ cargo rustc ];
          buildPhase = "cargo build --release";
          installPhase = "mkdir -p $out/bin; install -t $out/bin target/release/splr target/release/dmcr";
        }
      ;
    })
  ;
}

これでgit cloneしてnix buildでインストールできるようになりました。 うむ。簡単。 オーバレイでnixパッケージ化するよりもお手軽なので、SAT-benchも乗り換えるかも。

初めてFlakesを知ってから半年というか約1年。 長い道のりでした。

MacOSでRustのプログラムがコンパイルできない

framework Securityがないとか言われるなら、それはnixパッケージ化した時と同じような環境を作ってやらなければ。 ということでwebまわりの機能を使うSAT-benchの場合は以下の修正が必要だった。

1 file changed, 1 insertion(+), 1 deletion(-)
flake.nix | 2 +-

modified   flake.nix
@@ -8,7 +8,7 @@
         stdenv.mkDerivation {
           name = "SAT-bench";
           src = self;
-          buildInputs = [ cargo rustc ];
+          buildInputs = rustc.buildInputs ++ [ cargo rustc libiconv openssl pkgconfig ];
           buildPhase = "cargo build --release";
           installPhase = "mkdir -p $out/bin; install -t $out/bin target/release/sat-bench target/release/benchm";
         }