编写本地 nix 包
composing local nix packages
我想 运行 一个安装了以下软件包的 nix-shell:
- aspell
- aspellDicts.en
- 你好
我不能简单地做: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
所以我的解决方案有效,但能否以更简洁的惯用方式实现这一结果?
您需要构建 foo
吗? foo
你会用到什么?
假设您只想通过 nix-shell
使用 shell 而不想 build/install 使用 nix-build
或 nix-env -i
任何东西,这应该可行。
以下shell.nix
with import <nixpkgs> {};
with pkgs;
let
myAspell = aspellWithDicts (d: [d.en]);
in
stdenv.mkDerivation {
name = "myShell";
buildInputs = [myAspell hello];
shellHooks = ''
echo Im in $name.
echo aspell is locate at ${myAspell}
echo hello is locate at ${hello}
'';
}
会给你一个 shell 和 aspell
和 hello
$ nix-shell
Im in myShell.
aspell is locate at /nix/store/zcclppbibcg4nfkis6zqml8cnrlnx00b-aspell-env
hello is locate at /nix/store/gas2p68jqbzgb7zr96y5nc8j7nk61kkk-hello-2.10
如果是这种情况,foo
有一些代码可以构建和安装。
foo/default.nix
中的 mkDerivation
必须有 src
字段,可以是 src = ./.;
或类似 fetchurl
或 fetchFromGithub
的字段(参见 document 例如)。
然后您可以使用 callPackages
或 import
(取决于 nix 表达式的编写方式)和 foo/default.nix
作为参数,将 foo
提供的内容用于这个shell.
如果您尝试构建此 shell.nix
(或 foo/default.nix
),它将因缺少 src
而失败
$ nix-build shell.nix
these derivations will be built:
/nix/store/20h8cva19irq8vn39i72j8iz40ivijhr-myShell.drv
building path(s) ‘/nix/store/r1f6qpxz91h5jkj7hzrmaymmzi9h1yml-myShell’
unpacking sources
variable $src or $srcs should point to the source
builder for ‘/nix/store/20h8cva19irq8vn39i72j8iz40ivijhr-myShell.drv’ failed with exit code 1
error: build of ‘/nix/store/20h8cva19irq8vn39i72j8iz40ivijhr-myShell.drv’ failed
为了使这段代码更加地道,我有以下建议:
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
。这样 reader 可以轻松确定变量的来源。
我确实在尝试不熟悉的包或功能时使用它,因为那时维护不是问题。
pkgs/aspell-with-dicts/default.nix
除非你希望你的 aspell 实例化是你想要重用的东西,否则在你使用它的地方构建它可能更容易。
如果您确实希望重用包的特定配置,您可能希望通过在覆盖层中构建它来使其成为第一个 class 包。
就是这样。我认为最重要的一点是避免 <nixpkgs>
,除此之外,它已经非常地道了。
我不知道你神秘的foo
是什么,但如果它是开源的,请考虑将其上游到NixPkgs。根据我的经验,Nix 有一个非常热情的社区。
我想 运行 一个安装了以下软件包的 nix-shell:
- aspell
- aspellDicts.en
- 你好
我不能简单地做: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
所以我的解决方案有效,但能否以更简洁的惯用方式实现这一结果?
您需要构建 foo
吗? foo
你会用到什么?
假设您只想通过 nix-shell
使用 shell 而不想 build/install 使用 nix-build
或 nix-env -i
任何东西,这应该可行。
以下shell.nix
with import <nixpkgs> {};
with pkgs;
let
myAspell = aspellWithDicts (d: [d.en]);
in
stdenv.mkDerivation {
name = "myShell";
buildInputs = [myAspell hello];
shellHooks = ''
echo Im in $name.
echo aspell is locate at ${myAspell}
echo hello is locate at ${hello}
'';
}
会给你一个 shell 和 aspell
和 hello
$ nix-shell
Im in myShell.
aspell is locate at /nix/store/zcclppbibcg4nfkis6zqml8cnrlnx00b-aspell-env
hello is locate at /nix/store/gas2p68jqbzgb7zr96y5nc8j7nk61kkk-hello-2.10
如果是这种情况,foo
有一些代码可以构建和安装。
foo/default.nix
中的 mkDerivation
必须有 src
字段,可以是 src = ./.;
或类似 fetchurl
或 fetchFromGithub
的字段(参见 document 例如)。
然后您可以使用 callPackages
或 import
(取决于 nix 表达式的编写方式)和 foo/default.nix
作为参数,将 foo
提供的内容用于这个shell.
如果您尝试构建此 shell.nix
(或 foo/default.nix
),它将因缺少 src
$ nix-build shell.nix
these derivations will be built:
/nix/store/20h8cva19irq8vn39i72j8iz40ivijhr-myShell.drv
building path(s) ‘/nix/store/r1f6qpxz91h5jkj7hzrmaymmzi9h1yml-myShell’
unpacking sources
variable $src or $srcs should point to the source
builder for ‘/nix/store/20h8cva19irq8vn39i72j8iz40ivijhr-myShell.drv’ failed with exit code 1
error: build of ‘/nix/store/20h8cva19irq8vn39i72j8iz40ivijhr-myShell.drv’ failed
为了使这段代码更加地道,我有以下建议:
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
。这样 reader 可以轻松确定变量的来源。
我确实在尝试不熟悉的包或功能时使用它,因为那时维护不是问题。
pkgs/aspell-with-dicts/default.nix
除非你希望你的 aspell 实例化是你想要重用的东西,否则在你使用它的地方构建它可能更容易。
如果您确实希望重用包的特定配置,您可能希望通过在覆盖层中构建它来使其成为第一个 class 包。
就是这样。我认为最重要的一点是避免 <nixpkgs>
,除此之外,它已经非常地道了。
我不知道你神秘的foo
是什么,但如果它是开源的,请考虑将其上游到NixPkgs。根据我的经验,Nix 有一个非常热情的社区。