Nix-darwin: why isn't my `packageOverrides` working?

Hello all,

I just made my first PR to nixpkgs (issue update: now merged)! It’s patching libvirt to be able to use EFI VM images on aarch64-darwin machines.

I’m confused as to why this patch doesn’t do anything when I place it in my nix-darwin config under nixpkgs.config.packageOverrides:

  nixpkgs = {
    config = {
      packageOverrides = pkgs: {
        libvirt = unstable.libvirt.overrideAttrs (old: {
          mesonFlags = old.mesonFlags ++ [ "-Dqemu_datadir=${unstable.qemu}/share/qemu" ];
          postPatch = old.postPatch + ''
            sed -i '/domaincapstest/d' tests/
            sed -i '/qemufirmwaretest/d' tests/
            sed -i '/qemuvhostusertest/d' tests/
environment.systemPackages = with unstable; [ pkgs.libvirt ];

Other package overrides have seemed work when placed there, but with this setup the extra build flag isn’t set:

$ nix show-derivation $(which virsh) | grep qemu_datadir
$ echo $?

However, if I put the override into environment.systemPackages directly, it works as expected:

environment.systemPackages = with unstable; [
        (old: {
          mesonFlags = old.mesonFlags ++ [ "-Dqemu_datadir=${unstable.qemu}/share/qemu" ];
          postPatch = old.postPatch + ''
            sed -i '/domaincapstest/d' tests/
            sed -i '/qemufirmwaretest/d' tests/
            sed -i '/qemuvhostusertest/d' tests/
$ nix show-derivation $(which virsh) | grep qemu_datadir
      "mesonFlags": "--sysconfdir=/var/lib -Dinstall_prefix=/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9 -Dlocalstatedir=/var -Drunstatedir=/run -Dinit_script=none -Dapparmor=disabled -Dattr=disabled -Daudit=disabled -Dbash_completion=enabled -Dblkid=disabled -Dcapng=disabled -Dcurl=enabled -Ddocs=enabled -Dexpensive_tests=enabled -Dfirewalld=disabled -Dfirewalld_zone=disabled -Dfuse=disabled -Dglusterfs=disabled -Dhost_validate=enabled -Dlibiscsi=disabled -Dlibnl=disabled -Dlibpcap=enabled -Dlibssh2=enabled -Dlogin_shell=disabled -Dnss=disabled -Dnumactl=disabled -Dnumad=disabled -Dpciaccess=disabled -Dpolkit=disabled -Dreadline=enabled -Dsecdriver_apparmor=disabled -Dtests=enabled -Dudev=disabled -Dyajl=enabled -Ddriver_ch=disabled -Ddriver_esx=enabled -Ddriver_interface=disabled -Ddriver_libvirtd=enabled -Ddriver_libxl=disabled -Ddriver_lxc=disabled -Ddriver_network=enabled -Ddriver_openvz=disabled -Ddriver_qemu=enabled -Ddriver_remote=enabled -Ddriver_secrets=enabled -Ddriver_test=enabled -Ddriver_vbox=enabled -Ddriver_vmware=enabled -Dstorage_dir=enabled -Dstorage_disk=disabled -Dstorage_fs=disabled -Dstorage_gluster=disabled -Dstorage_iscsi=disabled -Dstorage_iscsi_direct=disabled -Dstorage_lvm=disabled -Dstorage_mpath=disabled -Dstorage_rbd=disabled -Dstorage_scsi=enabled -Dstorage_vstorage=disabled -Dstorage_zfs=disabled -Dqemu_datadir=/nix/store/dyzfcnf6r3zh5qhbx1blf2vw2r301cjb-qemu-7.1.0/share/qemu",

Reading other issues, is my override being applied early but then overridden somewhere else? If so, how might I have figured that out on my own?

Thanks as always for all the help!

1 Like
environment.systemPackages = with unstable; [ pkgs.libvirt ];

You used with. That pkgs doesn’t refer to your regular pkgs variable; it refers to unstable.pkgs. This is why friends don’t let friends use with; not even once.

Really? I assumed that everything else (e.g. bare foo) in that block referred to, but that explicitly using pkgs.libvirt would ensure that I was referring to the “global” pkgs.

EDIT: So within that block, how do I refer to the “global” / outer scope pkgs?

Actually, I forgot one quirk about Nix syntax, and you might be right (depending on what your file looks like). Local variable names always take priority over “environmental” variable names that come from things like with or scopedImport. This is regardless of which type comes closer in scope. e.g. to mimic the way pkgs works:

  x = { x = x; y = "foo"; };
  z = { x = z; y = "bar"; };
in with z; x.y

This evaluates to "foo", even though z.x.y would be "bar". So I guess if pkgs is a local variable and not an environmental one (if it’s at the top of your file like { pkgs, ... }: then it is local), then it should work as you expected. If you don’t have any local pkgs binding though, then the only one there is unstable.pkgs

Still, with makes things like this very confusing so I still recommend avoiding it.

Removing with and manually specifying for everything else didn’t change anything.

Adding abort to my packageOverrides doesn’t change anything, so it seems like it’s not even being evaluated.

As additional context, the above is from my darwin-configuration.nix, which starts by accepting pkgs and is being called from a flake that calls it with specialArgs = { pkgs = unstable; }.

I wonder if that’s the problem? It’s being overridden?

It ended up being more a pain to sort out than I expected.

@ElvishJerricco ended up being on the right track for part of the issue; apparently unstable has a pkgs attribute. I couldn’t figure out why completely removing pkgs from the configuration arguments didn’t result in an error here:

{ config
, lib
, specialArgs
, options
, modulesPath
, stable
, darwinPkgs
, unstable
with unstable; [ pkgs.libvirt ];

pkgs should have been undefined! Ends up it was picking up unstable.pkgs :man_facepalming:

Temporarily removing the with unstable helped reveal this issue, and appropriately gave me an error about missing pkgs as expected.

I eventually figured out that I could inspect the derivation like so, and it properly showed my override:

$ nix show-derivation ~/.dotfiles/?submodules=1#darwinConfigurations.$(hostname -s).pkgs.libvirt | less

Realizing that I could do inspect pkgs even though

  • I hadn’t defined pkgs anywhere
  • I wasn’t passing pkgs as an argument into the config
  • and I wasn’t accepting ... in my arguments (so there shouldn’t be anything “hiding”)

suggested that pkgs was magically being passed in somehow, somewhere. I still haven’t figured out where or how – maybe something here?

Anyway, all I had to do was to accept pkgs as an argument, no other changes to my flake (and not passing it in explicitly from the flake anywhere), and my overrides started working. The diff is pretty uninspiring:

diff --git a/darwin-configuration.nix b/darwin-configuration.nix
index 4f7319c..e63a689 100644
--- a/darwin-configuration.nix
+++ b/darwin-configuration.nix
@@ -1,4 +1,5 @@
-{ config
+{ pkgs
+, config
 , lib
 , specialArgs
 , options