Nix 不会触发 coreutils 的重建

Nix does not trigger rebuild of coreutils

我在 Devuan GNU/Linux 系统 (x86_64) 上使用 运行ning Nix,并遵循 ~/.nixpkgs/config.nix,如 Nix Pills 中所述:

{
  packageOverrides = pkgs: {
    coreutils = pkgs.coreutils.override {
      aclSupport = false;
      attrSupport = false;
      selinuxSupport = false;
    };
    coreutils2 = pkgs.coreutils.override {
      aclSupport = false;
      attrSupport = false;
      selinuxSupport = false;
    };
    w3m = pkgs.w3m.override {
      graphicsSupport = false;
      imlib2 = null;
      x11Support = false;
      mouseSupport = true;
    };
  };
}

但是当我 运行 nix-env -iA nixpkgs.coreutils 时,Nix 安装了 coreutils 的库存版本,并启用了可选功能:

$ nix-env -iA nixpkgs.coreutils
replacing old 'coreutils-8.31'
installing 'coreutils-8.31'
$ ldd /home/iu/.nix-profile/bin/ls |grep libattr
        libattr.so.1 => /nix/store/5xwmn6ai8c42j84k6gdzja0lnkdi3c60-attr-2.4.48/lib/libattr.so.1
(0x00007f0354e7f000)

但是如果我通过其他名称引用相同的推导(引用透明):

$ nix-env -iA nixpkgs.coreutils2

Nix 开始从源代码重建,结果生成二进制文件,编译后没有 可选功能,正如要求的那样。更神秘的是,w3m 的重写构建选项起作用并且 do 触发重建。

此外,我注意到 gnutar 也有同样的奇怪行为。这与 coreutilsgnutar 对 Nix 本身至关重要这一事实有某种关系吗?我怎样才能按预期的方式制作 coreutils

发生这种情况是因为 one final overlay 是在叠加层之后应用的。 (您正在使用 packageOverrides,这实际上成为第一个用户覆盖)

引用commit

The stdenvOverrides overlay is used to bring packages forward during bootstrapping via stdenv.overrides. These packages have already had the overlays applied to them in the previous boostrapping stage. If stdenvOverrides is not last in the overlays stack, all remaining overlays will windup being applied again to these packages.

gnutar也由此覆盖设置。

$ nix repl '<nixpkgs>'
nix-repl> lib.attrNames (stdenv.overrides pkgs pkgs)
[ "acl" "attr" "bash" "binutils" "binutils-unwrapped" "bzip2" "coreutils" "diffutils" "findutils" "gawk" "gcc" "glibc" "gnugrep" "gnumake" "gnupatch" "gnused" "gnutar" "gzip" "patchelf" "pcre" "xz" "zlib" ]

"good" 消息是您可以使用普通叠加层来配置最后一个叠加层。它很复杂但有效:

nix-repl> (import <nixpkgs> { overlays = [ (self: super: { stdenv = super.stdenv // { overrides = self2: super2: super.stdenv.overrides self2 super2 // { coreutils = "put your coreutils here"; }; }; }) ]; }).coreutils
"put your coreutils here"

我建议使用覆盖而不是 packageOverrides 以确保在最后一个 "user" 覆盖中发生这种情况。 所以你的覆盖将类似于:

_: super:
let
  coreutils = pkgs.coreutils.override {
    aclSupport = false;
    attrSupport = false;
    selinuxSupport = false;
  };
in
{
  # Overrides for stuff from stdenv go here. They're applied last
  # so we use the same stdenv for builds but a custom coreutils etc for
  # our system. This allows use to still use cache.nixos.org.
  stdenv = super.stdenv // {
    overrides = self2: super2: super.stdenv.overrides self2 super2 // {
      inherit coreutils;
    };
  };

  w3m = ...;
}