https://nixos.org/guides/nix-pills/nixpkgs-overriding-packages.html says
17.3. Fixed point
...
nix-repl> fix = f: let result = f result; in result nix-repl> pkgs = self: { a = 3; b = 4; c = self.a+self.b; } nix-repl> fix pkgs { a = 3; b = 4; c = 7; }...
17.3.1. Overriding a set with fixed point
Given that self.a and self.b refer to the passed set and not to the literal set in the function, we're able to override both a and b and get a new value for c :
nix-repl> overrides = { a = 1; b = 2; } nix-repl> let newpkgs = pkgs (newpkgs // overrides); in newpkgs { a = 3; b = 4; c = 3; } nix-repl> let newpkgs = pkgs (newpkgs // overrides); in newpkgs // overrides { a = 1; b = 2; c = 3; }In the first case we computed pkgs with the overrides, in the second case we also included the overriden attributes in the result.
17.4. Overriding nixpkgs packages
We've seen how to override attributes in a set such that they get recursively picked by dependant attributes. This approach can be used for derivations too, after all nixpkgs is a giant set of attributes that depend on each other.
To do this, nixpkgs offers config.packageOverrides . So nixpkgs returns a fixed point of the package set, and packageOverrides is used to inject the overrides.
Create a config.nix file like this somewhere:
{ packageOverrides = pkgs: { graphviz = pkgs.graphviz.override { withXorg = false; }; }; }Now we can build e.g. asciidoc-full and it will automatically use the overridden graphviz:
nix-repl> pkgs = import <nixpkgs> { config = import ./config.nix; } nix-repl> :b pkgs.asciidoc-fullNote how we pass the config with packageOverrides when importing nixpkgs . Then pkgs.asciidoc-full is a derivation that has graphviz input ( pkgs.asciidoc is the lighter version and doesn't use graphviz at all).
Since there's no version of asciidoc with graphviz without X support in the binary cache, Nix will recompile the needed stuff for you.
17.6. Conclusion
Nix applications will depend on specific versions of libraries, hence the reason why we have to recompile asciidoc to use the new graphviz library.
The newly built asciidoc will depend on the new graphviz, and old asciidoc will keep using the old graphviz undisturbed.
What does it mean by "override attributes in a set such that they get recursively picked by dependant attributes"? Could you explain that in terms of the example in 17.3.1?
What does it mean by "nixpkgs returns a fixed point of the package set"?
Isn't a fixed point something belonging to a function? How is the package set a function?
Why does nixpkgs return a fixed point? Is nixpkgs something similar to the example
let newpkgs = pkgs (newpkgs // overrides); in newpkgsin 17.3.1.?
What does it mean by "packageOverrides is used to inject the overrides"?
Why "Then pkgs.asciidoc-full is a derivation that has graphviz input"?
Why "The newly built asciidoc will depend on the new graphviz", and "old asciidoc will keep using the old graphviz undisturbed"?
First question
The term "dependent attribute" does not have a particularly strict or standard definition. In this context it means an attribute in a set whose value depends on one or more of the other values in the set. Here is the
pkgsfunction from section 17.3 of that document:Since that attribute
cis defined to be the sum ofaandb, you could saycis a dependent attribute.When we have our final set, we could override the value of
ausing the//operator in Nix, but that would only changeawithout changing any of the attributes that depend on it, likec.What we would like to do is find a way to override
ain such a way thatcstill isa + bin the final set. And furthermore, any attribute that depends oncshould use the new value of c, and so on. That's why the word "recursively" was used in that sentence you're asking about. We want to find a way to "override attributes in a set such that they get recursively picked by dependent attributes".This is achieved at the end of section 17.3.1. Note that
aandbwere successfully changed to 1 and 2, and these overridden new values were used to recomputec(1+2 = 3).Second question
The sentence "nixpkgs returns a fixed point of the package set" is an example of hasty, inaccurate writing. There is no such thing as a "fixed point" of a set, because a "fixed point" is a property of a function, not a set. I will rephrase what the author was trying to say. nixpkgs is a Nix function that you can get by writing
import <nixpkgs>or similar. When you pass a set to this function with your configuration parameters, the function returns a set of packages, usually calledpkgs.The packages set was generated in a special way to help you override parts of it. nixpkgs makes a big complicated function that takes a packages set, modifies it, and returns a new package set. Then nixpkgs finds the fix point of that function, and returns it. Somewhere in nixpkgs there should be some code that will be similar to the last line of section 17.3.1 (
let newpkgs = pkgs (newpkgs // overrides); in newpkgs // overrides). That code computes the fix point of a function that takes a set of packagesnewpkgsand then applies the user-specified overrides and applies the originalpkgsfunction to it.Third question
I know the passive voice can be confusing in the sentence "packageOverrides is used to inject the overrides", but you just have to read the full context and then it makes sense. When you call nixpkgs, you can pass an argument named
configto it, which should be a set. Theconfigset can contain an attribute namedpackageOverridesthat lets you tell nixpkgs how you want to override the packages. There is nothing deep here, this part of the document is just defining the API that allows you to tell Nixpkgs what you want it to do.There is nothing particularly special or meaningful about the word "inject" here, but maybe that word was used because your function will be integrated into the large complicated function I talked about above, which nixpkgs will compute the fixed point of.
Fourth question
You're asking why "pkgs.asciidoc-full is a derivation that has graphviz input".
Well, a derivation is a piece of software built by Nix. A derivation can depend on other derivations. For instance, an application can depend on a library to do some computations or generate some graphics. Apparently asciidoc-full depends on graphviz. You can see the definition of the asciidoc package here:
https://github.com/NixOS/nixpkgs/blob/master/pkgs/tools/typesetting/asciidoc/default.nix
Note that it is a big function, and
graphvizis one of the arguments to it.Fifth question
Suppose you had previously built asciidoc using Nix. Maybe you installed it in your user environment, or maybe you just started a shell with
nix-shell -p asciidoc. We will call this the old asciidoc.Then later you make a new Nix expression where you are overriding the definition of
graphvizin the package set. You can build asciidoc using this new Nix expression and you will get a new piece of software we can call new asciidoc. This new asciidoc uses your modified version of graphviz, and the old asciidoc will keep using the normal version of graphviz. Each version of graphviz you made has a unique path in the Nix store, and each version of asciidoc you made has a reference to that path, ensuring that it loads the same version of graphviz that it was built with. That is one of great parts of Nix compared to a lot of other package management systems: it is easy and natural to have multiple versions of a library installed at once, being used by different pieces of software.