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. Usingpkgs.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 thestdenv.mkDerivation
function, not the generated, raw Nix derivation. Thus, usingoverrideDerivation
will not work in this case, as it overrides only the attributes of the final derivation. It is for this reason thatoverrideAttrs
should be preferred in (almost) all cases tooverrideDerivation
, i.e. to allow usingstdenv.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
vsnativeBuildInputs
), 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 asstdenv.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 rg
ing 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?