Rust製ツールをNixでoverrideする

16755 ワード

はじめに

Unstableチャンネルでも更新に追いついていないNixのパッケージを,各々でバージョンを指定して最新版を使いたいという欲求がよくある.

今回,Rustで書かれてCargoでビルドするようなパッケージの際,ハマった(というか何を書けば良いのかわからない)ので書き残しておく.

前提

例えば執筆時現在,TaploというTomlフォーマッタ,そのCLIのnixpkgsの定義は以下のようになっている

{ lib, rustPlatform, fetchCrate, stdenv, pkg-config, openssl, Security }:

rustPlatform.buildRustPackage rec {
  pname = "taplo-cli";
  version = "0.5.0";

  src = fetchCrate {
    inherit pname version;
    sha256 = "sha256-+0smR1FDeJMSa/LaRM2M53updt5p8717DEaFItNXCdM=";
  };

  cargoSha256 = "sha256-d7mysGYR72shXwvmDXr0oftSa+RtRoSbP++HBR40Mus=";

  nativeBuildInputs = lib.optional stdenv.isLinux pkg-config;

  buildInputs = lib.optional stdenv.isLinux openssl
    ++ lib.optional stdenv.isDarwin Security;

  meta = with lib; {
    description = "A TOML toolkit written in Rust";
    homepage = "https://taplo.tamasfe.dev";
    license = licenses.mit;
    maintainers = with maintainers; [ figsoda ];
    mainProgram = "taplo";
  };
}

見てわかるようにバージョン0.5.0ですが,このバージョンにはちょっとしたバグが合ったため,執筆時現在最新版の0.6.2を使いたいとします.

TL;DR

最終的には,適当なoverlayを書くことになる.[1]

{
  overlays = [
    (self: super: {
      taplo-cli = super.taplo-cli.overrideAttrs (old: rec {
        inherit (old) pname;
        version = "0.6.2";
        src = super.fetchCrate {
          inherit pname;
          inherit version;
          sha256 = "sha256-vz3ClC2PI0ti+cItuVdJgP8KLmR2C+uGUzl3DfVuTrY=";
        };
        cargoDeps = old.cargoDeps.overrideAttrs (super.lib.const {
          inherit src;
          name = "${old.pname}-${version}-vendor.tar.gz";
          outputHash = "sha256-m6wsca/muGPs58myQH7ZLPPM+eGP+GL2sC5suu+vWU0=";
        });
      });
    })
  ];
}

諸注意

ここから下は試行錯誤であって動かないので注意.最終的には参考文献を読んで解決した.

まず筆者はこうした.これは全く違うので注意.[2][3]

{
  overlays = [
    (self: super: {
      taplo-cli = super.taplo-cli.overrideAttrs (old: rec {
        version = "0.6.2";
      });
    })
  ];
}

drvファイルがtaplo-cli-0.6.2.drvのようになるので,なぜ…と思ったが,ソースファイルは普通にバージョン0.5.0のものを持ってきてビルドしている.

次にこう書いた.(sha256は適当に書くとビルド時に正しいものを教えてくれるので,それを)

{
  overlays = [
    (self: super: {
      taplo-cli = super.taplo-cli.overrideAttrs (old: rec {
        inherit (old) pname;
        version = "0.6.2";
        src = super.fetchCrate {
          inherit pname;
          inherit version;
          sha256 = "sha256-vz3ClC2PI0ti+cItuVdJgP8KLmR2C+uGUzl3DfVuTrY=";
        };
        cargoSha256 = "sha256-d7mysGYR72shXwvmDXr0oftSa+RtRoSbP++HBR40Mus=";
      });
    })
  ];
}

実はこれもダメだった,ダメ押しでlib.mkForceとかしたがダメだった.

余談で,これはかなり怪しい理解だが[4]src以下のsha256https://crates.ioからダウンロードされるソースコードのハッシュで,cargoSha256はCargoでビルドした生成物(*.tar.gz)のハッシュと考えている.

その後,参考文献を発見した.
曰く,pkgs.overrideAttrsで値を上書きしようとする対象はstdenv.mkDerivationに渡される属性であってrustPlatform.buildRustPackageのそれではない.
つまり,rustPlatform.buildRustPackageに渡されるcargoSha256overrideAttrsで上書きしようとしても意味がないといった旨が書かれている.

ではどうすればいいのかだが,rustPlatform.buildRustPackageは最終的にcargoDepsstdenv.mkDerivationに渡すので[5],これを上書きすればよいのである.再掲すれば以下.

{
  overlays = [
    (self: super: {
      taplo-cli = super.taplo-cli.overrideAttrs (old: rec { 
        src = super.fetchCrate {
          pname = "taplo-cli";
          version = "0.6.2";
          sha256 = "sha256-vz3ClC2PI0ti+cItuVdJgP8KLmR2C+uGUzl3DfVuTrY=";
        };
        cargoDeps = old.cargoDeps.overrideAttrs (super.lib.const {
          inherit src;
          name = "taplo-cli-0.6.2-vendor.tar.gz";
          outputHash = "sha256-m6wsca/muGPs58myQH7ZLPPM+eGP+GL2sC5suu+vWU0=";
        });
      });
    })
  ];
}

あとは各々の属性を継承元の値で再利用したりして整理すれば良い.

おわりに

Nix むずすぎる

ちなみにこの記事は,Dhallでdocker-compose.ymlを書く試みで環境構築をしていた際に発生した問題を記事にしたものである.
この試みについては,そのうち書きます.

参考文献

脚注
  1. 別に普通にパッケージインポート時にoverrideAttrsを呼んでも良い.筆者のケースだとTOMLに設定を書く関係でこうした. ↩︎

  2. 実際taplo -V0.5.0を出力する. ↩︎

  3. というかそもそも,普通のパッケージでこう書いても,違うバージョンが入るということは無いと思う,要検証. ↩︎

  4. なぜなら私はRustやCargoを解さないので ↩︎

  5. https://github.com/NixOS/nixpkgs/blob/823da4d492b8b4ad46bf812db8421d99ff17a8fc/pkgs/build-support/rust/default.nix#L61-L63 ↩︎