如何使用定点来覆盖 nixpkgs 包?

How is fixed point used for overriding nixpkgs packages?

提问人:Tim 提问时间:11/15/2023 最后编辑:Tim 更新时间:11/16/2023 访问量:58

问:

https://nixos.org/guides/nix-pills/nixpkgs-overriding-packages.html

17.3. 固定点

...

nix-repl> fix = f: let result = f result; in result
nix-repl> pkgs = self: { a = 3; b = 4; c = self.a+self.b; }
nix-repl> fix pkgs
{ a = 3; b = 4; c = 7; }

...

17.3.1. 用定点覆盖集合

鉴于 self.a 和 self.b 引用传递的集合,而不是 函数中的文字集,我们能够覆盖 a 和 b 并得到 c 的新值:

nix-repl> overrides = { a = 1; b = 2; }
nix-repl> let newpkgs = pkgs (newpkgs // overrides); in newpkgs
{ a = 3; b = 4; c = 3; }
nix-repl> let newpkgs = pkgs (newpkgs // overrides); in newpkgs // overrides
{ a = 1; b = 2; c = 3; }

在第一种情况下,我们计算了带有覆盖的 pkgs,在第二种情况下 案例中,我们还在结果中包含了覆盖的属性。

17.4. 覆盖 nixpkgs 软件包

我们已经了解了如何覆盖集合中的属性,以便它们被依赖属性递归地选取。这种方法可以是 也用于推导,毕竟 nixpkgs 是一个巨大的集合 相互依赖的属性。

为此,nixpkgs 提供了 config.packageOverrides 。所以 nixpkgs 返回包集的固定点packageOverrides 为 用于注入覆盖

在某处创建一个 config.nix 文件,如下所示:

{
  packageOverrides = pkgs: {
    graphviz = pkgs.graphviz.override { withXorg = false; };
  };
}

现在我们可以构建例如 asciidoc-full,它将自动使用 覆盖的 graphviz:

nix-repl> pkgs = import <nixpkgs> { config = import ./config.nix; }
nix-repl> :b pkgs.asciidoc-full

注意我们在导入时如何使用 packageOverrides 传递配置 尼克斯 .那么 pkgs.asciidoc-full 是一个派生,它有 图形可视化输入 ( pkgs.asciidoc 是较轻的版本,而不是 完全使用graphviz)。

由于没有 Graph viz 的 asciidoc 版本没有 X 支持 在二进制缓存中,Nix 会为你重新编译需要的东西。

17.6. 结论

Nix 应用程序将依赖于特定版本的库,因此 我们之所以要重新编译 ASCIIDoc 才能使用新的 graphviz 图书馆。

新建的 asciidoc 将依赖于新的 graphviz,而旧的 asciidoc 将继续不受干扰地使用旧的 graphviz

“覆盖集合中的属性,以便它们被依赖属性递归选取”是什么意思?您能用 17.3.1 中的示例来解释一下吗?

“nixpkgs 返回包集的固定点”是什么意思?

  • 固定点不是属于函数的东西吗?包是如何设置函数的?

  • 为什么 nixpkgs 返回一个定点?nixpkgs 是否类似于 17.3.1 中的示例?let newpkgs = pkgs (newpkgs // overrides); in newpkgs

“packageOverrides 用于注入覆盖”是什么意思?

为什么“那么 pkgs.asciidoc-full 是具有图形可视化输入的派生”?

为什么“新建的 asciidoc 将依赖于新的图形可视化”,而“旧的 asciidoc 将继续不受干扰地使用旧的图形可视化”?

功能编程 NIX Nixos

评论


答:

1赞 David Grayson 11/16/2023 #1

第一个问题

术语“从属属性”没有特别严格或标准的定义。在此上下文中,它表示集合中的属性,其值取决于集合中的一个或多个其他值。以下是该文档第 17.3 节中的函数:pkgs

pkgs = self: { a = 3; b = 4; c = self.a + self.b; }

由于该属性被定义为 和 的总和,因此可以说是一个依赖属性。cabc

当我们得到最终集合时,我们可以覆盖在 Nix 中使用运算符的值,但这只会改变而不改变任何依赖于它的属性,比如 .a//ac

我们想做的是找到一种方法来覆盖,这种方式仍然在最后一集中。此外,任何依赖于的属性都应使用新值 c,依此类推。这就是为什么在你问的那句话中使用了“递归”这个词。我们希望找到一种方法来“覆盖集合中的属性,以便它们被依赖属性递归地选取”。aca + bc

这是在第 17.3.1 节末尾实现的。请注意,和已成功更改为 1 和 2,并且这些被覆盖的新值用于重新计算 (1+2 = 3)。abc

第二个问题

句子“nixpkgs 返回包集的固定点”是仓促、不准确写作的一个例子。没有集合的“不动点”这样的东西,因为“不动点”是函数的属性,而不是集合。我将改写作者想说的话。nixpkgs 是一个 Nix 函数,您可以通过编写或类似方式获得。当您将一个集合与配置参数一起传递给此函数时,该函数将返回一组包,通常称为 。import <nixpkgs>pkgs

包集是以一种特殊方式生成的,以帮助您覆盖其中的某些部分。nixpkgs 做了一个非常复杂的函数,它接受一个包集,修改它,然后返回一个新的包集。然后 nixpkgs 找到该函数的固定点,并返回它。在 nixpkgs 的某个地方,应该有一些代码类似于第 17.3.1 节的最后一行 ()。该代码计算一个函数的固定点,该函数采用一组包,然后应用用户指定的重写,并将原始函数应用于该函数。let newpkgs = pkgs (newpkgs // overrides); in newpkgs // overridesnewpkgspkgs

第三个问题

我知道被动语态在“packageOverrides 用于注入覆盖”这句话中可能会令人困惑,但你只需要阅读完整的上下文,然后它就有意义了。调用 nixpkgs 时,可以传递一个名为它的参数,该参数应该是一个集合。该集可以包含一个名为的属性,该属性允许您告诉 nixpkgs 您希望如何覆盖包。这里没有什么深奥的东西,文档的这一部分只是定义了一个 API,它允许你告诉 Nixpkgs 你希望它做什么。configconfigpackageOverrides

这里的“注入”这个词没有什么特别或有意义的,但也许使用了这个词,因为你的函数将被集成到我上面谈到的大型复杂函数中,nixpkgs 将计算它的不动点。

第四个问题

你问为什么“pkgs.asciidoc-full 是具有图形可视化输入的派生”。

好吧,派生是 Nix 构建的软件。派生可以依赖于其他派生。例如,应用程序可以依赖库来执行一些计算或生成一些图形。显然 asciidoc-full 取决于 graphviz。您可以在此处查看 asciidoc 包的定义:

https://github.com/NixOS/nixpkgs/blob/master/pkgs/tools/typesetting/asciidoc/default.nix

请注意,它是一个很大的函数,并且是它的参数之一。graphviz

第五个问题

假设您之前使用 Nix 构建了 asciidoc。也许您将其安装在用户环境中,或者您刚刚使用 启动了一个 shell。我们称之为旧的 asciidocnix-shell -p asciidoc

然后,稍后创建一个新的 Nix 表达式,其中将覆盖包集中的定义。您可以使用这个新的 Nix 表达式构建 asciidoc,您将获得一个新软件,我们可以称之为新 asciidoc。这个新的 asciidoc 使用您修改后的 graphviz 版本,旧的 asciidoc 将继续使用普通版本的 graphviz。您制作的每个版本的 graphviz 在 Nix store 中都有一个唯一的路径,并且您制作的每个 asciidoc 版本都有对该路径的引用,确保它加载的 graphviz 版本与构建时使用的相同版本。与许多其他软件包管理系统相比,这是 Nix 的重要部分之一:同时安装多个版本的库,由不同的软件使用是简单而自然的。graphviz

评论

0赞 Tim 11/23/2023
谢谢。"...“不动点”是函数的属性,而不是集合。我将改写作者想说的话。nixpkgs 是一个 Nix 函数,您可以通过编写 import <nixpkgs> 或类似内容来获得。当您将一个集合与配置参数一起传递给此函数时,该函数将返回一组包,通常称为 pkgs。将pkgs计算为定点的“函数”是什么?它在 pkgs/top-levels/all-packages.nix 中吗?
0赞 David Grayson 11/23/2023
这是其中的一部分,但要完全理解它,您必须阅读 nixpkgs 的顶级 default.nix 及其引用的所有代码。这就是您在执行时导入的内容。代码实际上非常复杂,我无法确切地找到最终函数的定义位置,但它必须在那里的某个地方。import <nixpkgs>