Nix Overlays: Add attribute to “lib” and avoid “infinite recursion error”
The other day, I was about to add an attribute to pkgs.lib
using a nixpkgs overlay. There is a small and subtle pitfall when doing so, which made me create this short blog post.
A basic overlay looks like this:
(final: prev: { new_attribute = "foobar"; })
By looking at the architecture diagram, we see that both prev
and final
refer to what pkgs
is, just in different “generations” (or iteration steps) in the evaluation of the final
nixpkgs instance. So, when we want to add something to lib
, we must add it to prev.lib
to follow the intented usage of overlays.
As each nixpkgs
instance is recursive in the sense of that pkgs.pkgs.pkgs.pkgs.lib
is valid, once must be careful that you merge new functionality with prev.lib
and not prev.pkgs.lib
. Otherwise, you get an infinite recursion error. (I’m not exactly sure why it happens, but I know how to prevent it – that’s the sublte pitfall I encountered).
So, to properly extend pkgs.lib
in an overlay, do the following:
(final: prev: { // Caution: This may override existing properties! This only works if // you add or entirely replace top-level attributes of `pkgs.lib`. lib = prev.lib // {}; })
If you do it like this, i.e., lib = prev.lib
and not lib = prev.pkgs.lib
, you get rid of an infinite recursion error and the intented outcome. However, be aware that{ a = { b = "b";}; } // { a = { c = "c"; }; })
evaluates to { a = { c = "c"; }; }
.
So if your overlay is not strictly additive to the toplevel attributes of pkgs.lib
(or entirely replaces one), you need a deep merge.
0 Comments