Closed14

Nix について知りたい (→ PR を送ってみました)

toyboot4etoyboot4e

今知りたいこと

Nix 近辺

  • NixOS (システムレベルの設定):
    • /etc/nixos/configuration.nix: システムの設定ファイル
  • Flakes:
    • /etc/nixos/flakes.nix
    • Git リポジトリ
  • Nix (package manager):
    • home-manager: ユーザ環境を塗り替える
    • nix-shell: PATH が分離された? bash 専用の? 環境
    • nix-direnv: nix-shell の設定ファイルをユーザ環境のシェルに取り込む?
  • 配布:
    • パッチ?
    • dylib や固定パスなど

疑問点

  • Nix と Docker の使い分け (どちらも使ったことがない)
  • Flakes のキャッシュの効力 (ローカルで、 CI で) (crane など)
  • Nix で作られたビルド環境 (default.nixshell.nix?) にユーザ独自の開発環境 (言語サーバなど) を追加するには
  • 欲しいバージョンが channel に無かったらどうする
toyboot4etoyboot4e

個人的な用途では direnv で十分かも

プロジェクト毎に .envrc ファイルで PATH を書き換えてツール類を切り替えできます。間に合わせにはなるかも。

toyboot4etoyboot4e

Nix 言語に入門中

NixOS の設定 を終えました。 NixOS ならではの部分をかいくぐってしまったので、ここらで Nix (言語) について調べて基礎的なキャッチアップを図ります。

Nix は無難で実用的な関数型言語という感じがしてきました。動的型付けで遅延評価される点に目を瞑れば……!

主なリソース (予定)

REPL で関数を見る

Lambda 関数

nix-repl> let f = x: x + 1;
          in f 1
2

nix-repl> let f = x: y: x * y;
          in f 2 3
6

Attribute set を引数に取る関数

nix-repl> let f = { x }: x + 1;
          in f { x = 1; }
2

nix-repl> let f = { x, y }: x * y;
          in f { x = 2; y = 3; }
6

= は attribute set の上書きではなく和を作る

x.a = .. ; の後に x = { .. }; を書いてみます:

nix-repl> { x.a = "a"; x = { b = "b"; }; }
{ x = { ... }; }

おっと遅延評価だ。強制的に評価してみると:

nix-repl> { x.a = "a"; x = { b = "b"; }; }.x
{ a = "a"; b = "b"; }

= の厳密な解釈が気になります。

値の上書きはできない

Nix で書くのは式であって、逐次実行される手続きではないことが分かります:

nix-repl> { x.a = "a"; x = { a = "b"; }; }.x
error: attribute 'a' already defined at (string):1:20

       at «string»:1:3:

            1| { x.a = "a"; x = { a = "b"; }; }.x
             |   ^

:quit で REPL を閉じる

Haskell (ghci) と一緒だ……!:

nix-repl> :quit

configuraiton.nix の基本形式

Attribute set を引数に取って、その一部に対してマッチし、 attribute set を返す関数を書いていたことが分かります:

{ config, pkgs, ... }:

{
  name = value;
}
toyboot4etoyboot4e

Nix 言語は Nix パッケージマネジャ専用の DSL

Nix Reference Manual が非常に良さそうです。これを読んでいきます。

便利機能

  • Path が builtin (path interpolation も可)
  • inherit で値埋め込み
    (これは Rust みたく = .. を省いたら自動で inhreit になればいいのに?)
  • with 式で名前空間の一時塗り替え

import

わからん!

Derivation

yomuzo!

https://nixos.org/manual/nix/unstable/language/derivations.html

TODO: Nix で作るシェル環境

toyboot4etoyboot4e

雑多に

Nix の LSP

今は nil が最先端な気がします? NixOS モジュールの定義には飛べませんでしたが、ひとまず診断情報は出してくれました:

機能豊富みたいないので、ローカルパッケージでは本領発揮しそうです。

実装言語は Rust のようです。ちゃんと構文解析して lowering して名前解決しています。えらい……。 Analysis とか rust-analyzer っぽい命名だなと思ったら ra のコントリビューの人でした。

Nix Language overview

https://www.youtube.com/watch?v=eCapIx9heBw

  • 遅延評価: 1 つのパッケージを 2 回評価しない
  • Derivation: Build task
    Nix -> Derivation -> Nix store (at derivation hash)
  • derivation は環境設定が詳しすぎるので mkDerivation, runCommand などの代替を使うべき
toyboot4etoyboot4e

再挑戦する、かも……

nixpkgs に verification-helper を追加したい! 知識不足を補わなければです。

ローカルでのビルドには成功

動くには動くけれども、これを PR に投げて良いのか検証しなければなりません。

pkgs/development/python-modules/verification-helper/default.nix
{
  lib,
  buildPythonPackage,
  colorlog,
  fetchFromGitHub,
  importlab,
  online-judge-tools,
  pyyaml,
  setuptools,
  toml,
}:

buildPythonPackage rec {
  pname = "verification-helper";
  version = "5.6.0";
  pyproject = true;

  src = fetchFromGitHub {
    owner = "online-judge-tools";
    repo = "oj-verify";
    rev = "refs/tags/v${version}";
    sha256 = "sha256-Q7uI13kazajeYb3LRK7mMhx0V3hh7CVqnptmQksMLOA=";
  };

  build-system = [ setuptools ];

  # `propagatedBuildInputs` ではなく、ここに入れてしまって良い?
  # そもそもこれは何?
  dependencies = [
    colorlog
    importlab
    online-judge-tools
    pyyaml
    setuptools
    toml
  ];

  # これは必須みたい
  propagatedBuildInputs = [ setuptools ];

  # これは何?
  pythonImportsCheck = [
    "onlinejudge"
    "onlinejudge_command"
    "onlinejudge_api"
  ];

  # Requires internet access
  doCheck = false;

  meta = with lib; {
    description = "A testing framework for snippet libraries used in competitive programming.";
    mainProgram = "oj-verify";
    homepage = "https://github.com/online-judge-tools/verification-helper";
    license = licenses.mit;
    maintainers = with maintainers; [ toyboot4e ];
  };
}
$ nix-build -A python3Packages.verification-helper # 初回ビルドだと色々出る
/nix/store/hjw90nfiqhmjhl3170d2rb69qrcn9ph3-python3.12-verification-helper-5.6.0

正直、コントリビュータに丸投げすれば一撃なのは間違いありませんが、今回は自力で仕上げてみましょう。

メモ

  • nix-build -A <package>
    ローカルの nixpkgs の特定のパッケージをビルドする
  • pythonImportsCheck とは

いろいろ読んでみる

基本機能

  • inherits
  • extraArgs (だっけ?)
  • specialArgs
    NixOS modules が引数として取れる値になるらしい
toyboot4etoyboot4e

mozc_tool.desktop ファイルが欲しい

mozc_tool/run/current-system/sw/lib から消えていたので、そもそもちゃんと .desktop ファイルが生成されるように修正したい。

fork を作成する

fork の動作をローカルでテストする

  • 簡単な方法としては、 GitHub に push して Flakes で URL を設定する?
  • ローカルのファイルパスで動かしたい気が
toyboot4etoyboot4e

メモ

Slack / Discord のメモです。私は無断で転載しました

toyboot4etoyboot4e

/nix/store がストレージを圧迫している件

500 GB.. 600 GB.. 馬鹿な、まだ増えるだと!?

GC や旧世代削除は定期実行させている

他の件を探しに行きます。

nativeBuildInputs が原因?

以下のコマンドで GC roots, たぶん mark & sweep における mark の起点となるリンク一覧が得られるようです。

$ nix-store --gc --print-roots

結局 GC のせいでしょうか。nix-direnv で使った flakes が残っていました。 flake.nix の中に常に nativeBuildInputs を使っていたのが不味かったかもしれません。

また古代の home-manager もなぜか生き残っていました。どうしたんだお前……。

手荒に消してみる

ここで記録が止まっていたら、すべてオシャカになったということです。

https://nixos.org/guides/nix-pills/11-garbage-collector#cleanup-everything

$ /nix/var/nix/gcroots/auto
$ nix-collect-garbage -d

勝利!

528893 store paths deleted, 560739.82 MiB freed

消え杉にございます (560 GB).

toyboot4etoyboot4e

Nixify Haskell projects

haskell-flake (flake-parts の方) 単体だと何が起きているのか分からないので、こちらを追ってみます。

https://nixos.asia/en/nixify-haskell

(読む前) 実は devShell だけで十分?

Cabal は依存パッケージのロックファイルを生成できるため、 Nix を使わなくてもバージョン固定できます。それでも言語の依存パッケーを Nix で入れるメリットがあるのか気になっています。何か面白いことがあって欲しい!

nix run はネットワークと非接続の環境で実行されるため、 nix run したければ nix 化するしかないとか、そんなオチだったりするんでしょうか。みてみます。

公式を見ておく

  • haskellPackage は基本 Stackage のスナップショット (最新 LTS) + 追加パッケージ
  • (nixpkgs 上で pin された時の) Hackage 上の最新パッケージは <package>-<ver> の形で提供される (デフォルト (LTS) 側が追いつくと消える)
    • が、 nixpkgs 外での利用はおすすめしないらしい。あくまで nixpkgs 内で haskell アプリケーション等をビルドするためのものである
    • とはいえ pins するのも面倒だしな
  • デフォルトの ghc のパッケージセットのみ全体のテストが実行される
  • 各パッケージのデフォルト版のみビルドテストするが、他のバージョンは名前があるだけでビルドできない可能性がある
  • cabal.plan を元に自動的に依存パッケージを nix 化する仕組みが無いらしい? cabal2nix はあるので意味が取れていない
  • haskell.nix は nixpkgs と全く互換性が無いとか
  • インクルメンタルに ghc をビルドできるらしい。複数の derivation に分ければ確かに可能か?
  • ghcWithPackages は package db を GHC に注入するらしいが、これがパフォーマンス上のメリットがあるやつでは? Package db を調べたい。
  • cabal2nix で haskellPackeage.callPackage する例あり
  • hls は wrapper 版と直に触れるやつがある
  • あとは読んで無いけど下に Idris あり

https://nixos.org/manual/nixpkgs/stable/#haskell

チュートリアル

  • haskellPackages を overlay で拡張し、 callCabal2nix した自分のパッケージを挟む意味はある?
    nix run 用のセットアップをしてくれる?
  • haskellPackages.shellFor を使うと nix を使わずビルドするパッケージを指定できる他、たぶん依存パッケージ入りの ghc を設定してくれる?

む、ここでチュートリアルが終わってしまいました。 Stackage ではなく Hackage を使いたいですが、できるのかl

このスクラップは1ヶ月前にクローズされました