We’ve had two chapters covering two different ways to override packages, but we still haven’t actually been able to override any packages. But this chapter is about overriding, so maybe it will tell us how to use the features from chapters 2 and 3?

This is a very curious presentation order.

Chapter 4. Overriding

The function override is usually available for all the derivations in the nixpkgs expression (pkgs).

What do you mean usually available?

It is used to override the arguments passed to a function.

So packages that aren’t functions, maybe? This seems to just be a way to supply arguments to functions.

The manual gives this example:

pkgs.foo.override { arg1 = val1; arg2 = val2; ... }

And says:

pkgs.foo is the result of a function call with some default arguments, usually a derivation. Using pkgs.foo.override will call the same function with the given new arguments.

Weird. Okay. I don’t… I am very curious where override comes from. I assumed it was added in the return value of mkDerivation. But clearly it’s something else – mkDerivation couldn’t know that a package was a function call. Is this something added by callPackage? That would be crazy, right? Surely when the Nix manual explained callPackage it would have mentioned something about this, if that were the case.

Next we learn about overrideAttrs, which behaves the way that I assumed override behaved – allows me to change things like name or what have you. Actually slightly more complicated: it’s a function from old attributes to – no, not new attributes! that would be crazy! – to a set that will apply diffs (?) to the attributes? How do I use this to remove an attribute?

helloWithDebug = pkgs.hello.overrideAttrs (oldAttrs: rec {
  separateDebugInfo = true;
});

Why isn’t it just a function from old to new? Why this weird implicit patch situation? We have the // operator!

And the manual actually explains where overrideAttrs comes from:

This function is available on all derivations produced by the stdenv.mkDerivation function

But there’s still no mention of where override comes from.

Then we get this interesting warning:

Note: Note that separateDebugInfo is processed only by the stdenv.mkDerivation function, not the generated, raw Nix derivation. Thus, using overrideDerivation will not work in this case, as it overrides only the attributes of the final derivation. It is for this reason that overrideAttrs should be preferred in (almost) all cases to overrideDerivation, i.e. to allow using stdenv.mkDerivation to process input arguments, as well as the fact that it is easier to use (you can use the same attribute names you see in your Nix code, instead of the ones generated (e.g. buildInputs vs nativeBuildInputs), and it involves less typing).

Ooookay. I don’t know what overrideDerivation is. So that’s a very weird note to include here.

Ah, but the next section explains it. It says:

This function is available on all derivations defined using the makeOverridable function. Most standard derivation-producing functions, such as stdenv.mkDerivation, are defined using this function, which means most packages in the nixpkgs expression, pkgs, have this function.

Okay. But makeOverridable is not where we get the override function, right?

No: the next section contradicts that. makeOverridable provides override. So my theory that callPackage calls this… is maybe plausible?

Alright. That’s the end of the chapter. Let’s try to find out if callPackage calls makeOverridable.

Where is that function defined?

I find in ~/src/nixpkgs/lib/customisation.nix

  /* Call the package function in the file `fn' with the required
    arguments automatically.  The function is called with the
    arguments `args', but any missing arguments are obtained from
    `autoArgs'.  This function is intended to be partially
    parameterised, e.g.,

      callPackage = callPackageWith pkgs;
      pkgs = {
        libfoo = callPackage ./foo.nix { };
        libbar = callPackage ./bar.nix { };
      };

    If the `libbar' function expects an argument named `libfoo', it is
    automatically passed as an argument.  Overrides or missing
    arguments can be supplied in `args', e.g.

      libbar = callPackage ./bar.nix {
        libfoo = null;
        enableX11 = true;
      };
  */
  callPackageWith = autoArgs: fn: args:
    let
      f = if lib.isFunction fn then fn else import fn;
      auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs;
    in makeOverridable f (auto // args);

However, I can’t find anywhere that actually does the thing in the comment – I can’t find the callPackage = callPackageWith pkgs line, or anything plausibly close. But surely it is out there, and I am just not rging hard enough.

Gosh, what font makes backticks reasonably pair with the single quote character?

Anyway, yes, it appears that callPackage calls makeOverridable. Question answered.

I wish the manual just said that instead of “packages usually have an override function.” It makes me think maybe there is another common pattern that would result in that.

I don’t think I’m going to try any of this out; I don’t really know what I would override. But I feel like I know where to start if I run into a broken package.


  • Why doesn’t overrideAttrs just transform a set into a new set?
  • How can I use overrideAttrs to remove an attribute?