我想运行安装了以下软件包的nix-shell:
我不能简单地这样做:
nix-shell -p aspell aspellDicts.en hello --pure
,因为这将无法正确安装aspell词典。 Nix提供了一个aspellWithDict
函数,该函数可用于构建带有字典的aspell:nix-build -E 'with import <nixpkgs> {}; aspellWithDicts (d: [d.en])'
我想将此构建的结果用作另一个本地包(foo)中的依赖项。这就是我目前正在实现的方式:
./pkgs/aspell-with-dicts/default.nix:
with import <nixpkgs> {};
aspellWithDicts (d: [d.en])
./pkgs/foo/default.nix:
{stdenv, aspellWithDicts, hello}:
stdenv.mkDerivation rec {
name = "foo";
buildInputs = [ aspellWithDicts hello ];
}
./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;
};
}
运行 shell 程序按预期方式工作:
nix-shell ./custom-packages.nix -A foo --pure
因此,我的解决方案有效,但是能否以更简洁的惯用方式实现这一结果?
最佳答案
为了使此代码更惯用,我有以下建议:callPackage
使用pkgs.callPackage
函数。它将处理传递推导所需的参数。这就是为什么NixPkgs中的许多文件看起来像{ dependency, ...}: something
的原因。第一个参数是要向其注入(inject)依赖项的函数,第二个参数是可用于手动传递某些依赖项的属性集。
通过使用callPackage
,您不需要import <nixpkgs> {}
,因此您的代码将更易于在新的上下文中使用<nixpkgs>
无法使用,并且它的求值速度更快,因为它只需要评估NixPkgs固定点一次。
(当然,您必须先输入import <nixpkgs>
才能上手,但此后就不需要了。)with
在pkgs/aspell-with-dicts/default.nix
中,您可以使用with
关键字,这是可以的,但是在这种情况下,它实际上并没有增加值(value)。我更喜欢显式地引用变量,因此,当它被使用一次或两次时,更喜欢阅读pkgs.something
;如果更经常使用,则更喜欢阅读inherit (pkgs) something
。这样,读者可以轻松确定变量的来源。
在尝试不熟悉的软件包或功能时,我确实会使用它,因为那时的维护不是问题。pkgs/aspell-with-dicts/default.nix
除非您期望自己的aspell实例是要重用的东西,否则在使用它的地方构造它可能会更容易。
如果您确实希望重用某个程序包的特定配置,则可能需要通过将其构造为覆盖图来使其成为一流的程序包。
就是这样。我认为最重要的一点是避免使用<nixpkgs>
,除此之外,它已经非常惯用了。
我不知道您的神秘foo
是什么,但是如果它是开源的,请考虑将其上游到NixPkgs中。根据我的经验,Nix有一个非常热情的社区。
关于nix - 组成本地nix包,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47591632/