I’ve been digging through the Nix source trying to find where exactly overlays get applied to derivations. I see that they get imported in pkgs/top-level/impure.nix
and eventually get passed to the stdenv stages, but I don’t see the exact place where they end up interacting with the system.
Can someone please enlighten me?
The heart of the overlays can be found in stage.nix, where the package set is accumulated by performing a fold:
# The complete chain of package set builders, applied from top to bottom
toFix = lib.foldl' (lib.flip lib.extends) (self: {}) ([
stdenvBootstappingAndPlatforms
stdenvBootstappingAndPlatforms
stdenvAdapters
stdenvAdapters
trivialBuilders
trivialBuilders
allPackages
allPackages
aliases
aliases
stdenvOverrides
stdenvOverrides
configOverrides
configOverrides
] ++ overlays);
# Use `overridePackages` to easily override this package set.
in
# Warning: this function is very expensive and must not be used
# Return the complete set of packages.
# from within the nixpkgs repository.
lib.fix toFix
first the boostrap + normal nixpkg package set is constructed. Then the overlays are applied, creating a final package set. The fix function forces the chain of overlays to be resolved. An example is given in fixed-points.nix:
# Compute the fixed point of the given function `f`, which is usually an
# attribute set that expects its final, non-recursive representation as an
# argument:
#
# f = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }
#
# Nix evaluates this recursion until all references to `self` have been
# resolved. At that point, the final result is returned and `f x = x` holds:
#
# nix-repl> fix f
# { bar = "bar"; foo = "foo"; foobar = "foobar"; }
#
# Type: fix :: (a -> a) -> a
#
# See https://en.wikipedia.org/wiki/Fixed-point_combinator for further
# details.
fix = f: let x = f x; in x;