编写本地 nix 包

b73*_*b73 5 nixos nix

我想运行一个安装了以下软件包的 nix-shell:

  • 阿斯佩尔
  • aspellDicts.en
  • 你好

我不能简单地做:nix-shell -p aspell aspellDicts.en hello --pure因为这将无法正确安装 aspell 词典。Nix 提供了一个aspellWithDict函数,可用于使用字典构建 aspell:

nix-build -E 'with import <nixpkgs> {}; aspellWithDicts (d: [d.en])'
Run Code Online (Sandbox Code Playgroud)

我想将此构建的结果用作另一个本地包 (foo) 中的依赖项。这就是我目前实现这一目标的方式:

./pkgs/aspell-with-dicts/default.nix:

with import <nixpkgs> {};

aspellWithDicts (d: [d.en])
Run Code Online (Sandbox Code Playgroud)

./pkgs/foo/default.nix:

{stdenv, aspellWithDicts, hello}:

stdenv.mkDerivation rec {
    name = "foo";
    buildInputs = [ aspellWithDicts hello ];
}
Run Code Online (Sandbox Code Playgroud)

./custom-packages.nix:

{ system ? builtins.currentSystem }:

let
  pkgs = import <nixpkgs> { inherit system; };

in

rec {
  aspellWithDicts = import ./pkgs/aspell-with-dicts;

  foo = import ./pkgs/foo {
    aspellWithDicts = aspellWithDicts;
    hello = pkgs.hello;
    stdenv = pkgs.stdenv;
  };
}
Run Code Online (Sandbox Code Playgroud)

运行 shell 按预期工作: nix-shell ./custom-packages.nix -A foo --pure

所以我的解决方案有效,但是这个结果可以以更简洁的惯用方式实现吗?

Rob*_*ing 2

为了使这段代码更加地道,我有以下建议:

callPackage

使用该pkgs.callPackage功能。它将负责传递您的推导所需的参数。这就是为什么 NixPkgs 中的许多文件看起来像{ dependency, ...}: something. 第一个参数是您想要注入依赖项的函数,第二个参数是一个属性集,您可以使用它手动传递一些依赖项。

通过使用callPackage,您不需要这样做import <nixpkgs> {},因此您的代码将更容易在<nixpkgs>无法使用的新上下文中使用,并且评估速度会更快一些,因为它只需评估 NixPkgs 固定点一次。

(当然,你必须import <nixpkgs>先开始一次,但之后就没有必要了。)

with

pkgs/aspell-with-dicts/default.nix您使用with关键字时,这是可以的,但在这种情况下它并没有真正增加价值。我更喜欢明确地引用变量,因此更喜欢pkgs.something在使用一次或两次时或者inherit (pkgs) something使用更频繁时阅读。这样读者可以很容易地确定变量来自哪里。

当尝试不熟悉的软件包或功能时,我确实会使用它,因为那时维护就不是问题了。

pkgs/aspell-with-dicts/default.nix

除非您期望 aspell 的实例化是您想要重用的东西,否则在您使用它的地方构建它可能会更容易。

如果您确实希望重用包的特定配置,您可能希望通过在覆盖层中构造它来使其成为一流包。


就是这样。我认为最重要的一点是避免<nixpkgs>,除此之外它已经很惯用了。

我不知道你的神秘foo是什么,但如果它是开源的,请考虑将其上游到 NixPkgs 中。根据我的经验,尼克斯有一个非常热情的社区。