Overriding Package breaking pkgsi686Linux

First off, I know what I’m doing is very outside the norm. I’m doing a global stdenv changing overlay, but for a few packages I’d like to still use the original derivation so I don’t get a cache miss and need to recompile large programs (electron) or deal with some build / test problems. My approach is as follows:

nixpkgs.overlays = let
  nixpkgs-unoptimized = import inputs.nixpkgs {
    inherit (pkgs) system;
  };
in [
  (self: super: {
    stdenv = (super.addAttrsToDerivation {} super.stdenv).override (old: {
        # Disclaimer: This is very simplified from my actual code to avoid too much confusion on the problem.
        mkDerivationFromStdenv = extendMkDerivationArgs old (args:
          let
            updateMarch = super.stdenv.system == "x86_64-linux";
            updateFunction = flags: flags + " -O3 " + (if updateMarch then " -march=znver4 -mtune=znver4 " else "");
          in
            if (lib.strings.hasInfix "bootstrap" old.name) then {} else
              (lib.attrsets.optionalAttrs (args ? "NIX_CFLAGS_COMPILE") {
                NIX_CFLAGS_COMPILE = updateFunction (toString(args.NIX_CFLAGS_COMPILE));
              }) // (lib.attrsets.optionalAttrs (!(args ? "NIX_CFLAGS_COMPILE") || ((args.env or {}) ? "NIX_CFLAGS_LINK")) {
                env = (args.env or {}) // lib.attrsets.optionalAttrs (!(args ? "NIX_CFLAGS_COMPILE")) {
                  NIX_CFLAGS_COMPILE = updateFunction (toString(args.env.NIX_CFLAGS_COMPILE or ""));
                };
              }));
      });

   electron = nixpkgs-unoptimized.pkgs.electron;
   # There are a bunch more packages I do the override this way here too
   libavif = nixpkgs-unoptimized.pkgs.libavif;
    })
  ];

After making that override, if I open up nix repl I get the following response:

> :lf .
> nixosConfigurations.framework.pkgs.pkgsi686Linux.libavif.system
"x86_64-linux"

This should be “i686-linux” like all other packages in pkgsi686Linux. This isn’t really a problem for electron, but I have a few libraries that are used by 32-bit programs that are overridden in this way and those programs fail to build due to the dependency actually being a 64-bit library and not a 32-bit one.

I got further, but it looks like the inputs for the builds are coming from the normal pkgs set instead of the i686 set.

useUnoptimized = super: pkgs: lib.lists.foldr (a: b: (lib.attrsets.setAttrByPath [a] (lib.attrsets.getAttrFromPath [a] nixpkgs-unoptimized.pkgs)) // b) { } pkgs
      // {
        pkgsi686Linux = super.pkgsi686Linux // lib.lists.foldr (a: b: (lib.attrsets.setAttrByPath [a] (lib.attrsets.getAttrFromPath [a] nixpkgs-unoptimized.pkgs.pkgsi686Linux)) // b) { } pkgs;
      };

And then I use it as an overlay:

(final: super: (useUnoptimized super [ "nodejs" "electron" "firefox" "firefox-bin" "webkitgtk" "dav1d"]))

I can see this problem in nix repl:

> lf .
> nixosConfigurations.framework.pkgs.pkgsi686Linux.libavif.system
"i686-linux"
> nixosConfigurations.framework.pkgs.pkgsi686Linux.libavif.buildInputs
[ ... /nix/store/apbdpiqvazqp96s2a6d6qch9z4zg19aj-dav1d-1.4.1.drv ... ]
> nixosConfigurations.framework.pkgs.dav1d
«derivation /nix/store/apbdpiqvazqp96s2a6d6qch9z4zg19aj-dav1d-1.4.1.drv»
> nixosConfigurations.framework.pkgs.pkgsi686Linux.dav1d
«derivation /nix/store/2pbjzrhjpylysqjhiqcxhpnjc8ghvz92-dav1d-1.4.1.drv»

So the system is set correctly, but the inputs are coming from the wrong package set

I’ve come up with a fully working solution, albeit a bit hacky.

nixpkgs.overlays = let
  useUnoptimized-x64 = super: pkgs: lib.lists.foldr (a: b: (lib.attrsets.setAttrByPath [a] (lib.attrsets.getAttrFromPath [a] nixpkgs-unoptimized.pkgs)) // b) { } pkgs;
  useUnoptimized-i686 = super: pkgs: lib.lists.foldr (a: b: (lib.attrsets.setAttrByPath [a] (lib.attrsets.getAttrFromPath [a] nixpkgs-unoptimized-i686.pkgs)) // b) { } pkgs;
  useUnoptimized = super: pkgs: if (super.stdenv.system == "x86_64-linux") then (useUnoptimized-x64 super pkgs) else (useUnoptimized-i686 super pkgs);

  useUnoptimizedHaskell-x64 = super: pkgs: lib.lists.foldr (a: b: (lib.attrsets.setAttrByPath [a] (lib.attrsets.getAttrFromPath [a] nixpkgs-unoptimized.pkgs.haskellPackages)) // b) { } pkgs;
  useUnoptimizedHaskell-i686 = super: pkgs: lib.lists.foldr (a: b: (lib.attrsets.setAttrByPath [a] (lib.attrsets.getAttrFromPath [a] nixpkgs-unoptimized-i686.pkgs.haskellPackages)) // b) { } pkgs;
  useUnoptimizedHaskell = super: pkgs: {
    haskellPackages = super.haskellPackages.override{
      overrides = (new: old: (if (super.stdenv.system == "x86_64-linux") then (useUnoptimizedHaskell-x64 super pkgs) else (useUnoptimizedHaskell-i686 super pkgs)));
    };
  };
in [
  <other overlays>
  (final: super: (useUnoptimized super [
      # These are here because they can be very slow to build
      "nodejs"
      "electron"
      "electron_29"
      "firefox"
      "firefox-bin"
      "webkitgtk"
      "webkitgtk_4_1"
      "webkitgtk_5_0"
      "webkitgtk_6_0"
      # Build failure - 5/8/2024
      "dav1d"
      # Test failure if too many builds are happening at once
      "fprintd"]))
  (final: super: (useUnoptimizedHaskell super [
      # Test failure - 5/8/2024
      "crypton"
      # Test failure - 5/8/2024
      "cryptonite"]))
];

I had to do some other hacks for Haskell packages that failed

1 Like