【问题标题】:Nix overlays and override patternNix 覆盖和覆盖模式
【发布时间】:2019-12-18 07:40:08
【问题描述】:

我无法理解 Nix 叠加层和覆盖模式。我想要做的是在不复制/粘贴的情况下向 gdb 的“补丁”添加一些东西 整个推导。

来自Nix Pills 我有点看到覆盖只是模仿OOP,实际上它只是集合的另一个属性。但它是如何工作的呢?覆盖是从原始属性集到转换后的函数,它再次具有预定义的覆盖函数?

由于 Nix 是一种函数式语言,因此您也没有变量,只有绑定,您可以在不同的范围内进行映射。但这仍然不能解释叠加层是如何实现其“魔力”的。

通过 ~/.config/nixpkgs 我配置了一个测试覆盖,大致如下:

self: super:
  {
     test1 = super.gdb // { name = "test1"; buildInputs = [ super.curl ]; };
     test2 = super.gdb // { name = "test2"; buildInputs = [ super.coreutils ]; };
     test3 = super.gdb.override { pythonSupport = false; };
  };

我得到:

nix-repl> "${test1}"
"/nix/store/ib55xzrp60fmbf5dcswxy6v8hjjl0s34-gdb-8.3"

nix-repl> "${test2}"
"/nix/store/ib55xzrp60fmbf5dcswxy6v8hjjl0s34-gdb-8.3"

nix-repl> "${test3}"
"/nix/store/vqlrphs3a2jfw69v8kwk60vhdsadv3k5-gdb-8.3"

然后

$ nix-env -iA nixpkgs.test1
replacing old 'test1'
installing 'test1'

你能解释一下这些结果吗?我是否正确,覆盖只能改变“定义的接口” - 那是函数的所有参数,因为“补丁”不是 gdb 的参数,我将无法更改它?那么最好的选择是什么?

【问题讨论】:

  • 在 repl 中使用 // 运算符播放后,它似乎在派生上的工作方式与在属性集上的工作方式不同。但后来我想知道为什么我在 Nix Pills 中读到,原则上推导只是一个正常的集合。
  • 我不明白要问什么。也不清楚你对什么样的“行为”感到惊讶。
  • 在做 nix-instantiate(或类似的)之前,派生基本上只是一个具有特殊“类型”的属性集(至少根据 Nix Pills)。所以我应该能够创建一个更改了几个参数的新参数 - “new = old // ...” 然后让我感到困惑的是,当我尝试检查什么是新的时,它与旧的相同。像 test1 和 test2 有不同的 buildInputs(在名称旁边)所以我希望它们有一个完全不同的 nix 存储路径。但我想我的想法中的缺陷是“out”也是该属性集中的一个值(我不知何故认为这一切都会发生在“build”时)。
  • 在这种情况下,最好编辑问题/标题。但仅据我了解 - 哈希是基于输出而不是输入。

标签: nix


【解决方案1】:

我会写一个答案,以防其他人偶然发现。


编辑 21.8.2019:

https://nixos.org/nixpkgs/manual/#sec-overrides中描述了我真正想要的内容

overrideDerivationoverrideAttrs

overrideDerivation 基本上是“derivation (drv.drvAttrs // (f drv))”并且 overrideAttrs 在https://github.com/NixOS/nixpkgs/blob/master/pkgs/stdenv/generic/make-derivation.nix 中被定义为 mkDerivation 的一部分

然后我的代码看起来像:

gdb = super.gdb.overrideAttrs (oldAttrs: rec {
  patches = oldAttrs.patches ++ [
     (super.fetchpatch {
       name = "...";
       url = "...";
       sha256 = "...";
     })
 ];
});

问题标题具有误导性,源于我对推导的根本误解。叠加层的工作方式与宣传的完全一样。而且它们可能也没有那么神奇。只是一些递归,其中 endresult 是上一步的结果 // 最后一个覆盖函数的输出。

What is the purpose of nix-instantiate? What is a store-derivation?

如果我错了,请纠正我。

但基本上,当您评估 Nix 代码时,“派生函数”会将描述性属性集(名称、系统、构建器)转换为“实际派生”。 “实际派生”又是一个属性集,但诀窍在于它由存储中的 .drv 文件支持。所以在某种意义上,推导有副作用。 drv 对构建应该如何进行以及需要哪些依赖项进行编码。该文件的哈希值还确定了人工制品的目录名称(尽管尚未构建任何内容)。因此,nix 存储中的名称也隐含地取决于所有构建输入。

当我基于将现有派生组合在一起创建一种类似于科学怪人的新派生时,我所做的只是创建对同一个 .drv 文件的多个引用。就好像我正在复制一个指针,结果是让两个指针指向堆上的相同值。我能够更改一些元数据,但最终构建过程仍然相同。事实上,由于 Nix 是纯粹的,我敢打赌,甚至没有办法写入文件系统(更改 .drv 文件)——除非再次使用包装派生函数的东西。

另一方面,Override 允许您创建“新实例”。由于“输入模式”,Nix 中的每个包都是从依赖属性设置到最终调用“派生函数”的实际代码的函数。通过覆盖,您可以再次调用该函数,从而使“派生函数”获得不同的参数。

【讨论】:

    猜你喜欢
    • 2020-07-28
    • 1970-01-01
    • 2011-11-03
    • 2021-05-04
    • 1970-01-01
    • 1970-01-01
    • 2018-10-07
    • 2011-06-11
    • 2012-01-28
    相关资源
    最近更新 更多