I'm working to understand as much as I can about Nix flakes. I'm puzzled by the fact that a nixpkgs
input is usually imported, and the imported value is called as a function. How does the result of import nixpkgs
map to code in the nixpkgs
flake?
It looks like this use of nixpkgs
is common practice in flakes:
# flake.nix
{
inputs = {
flake-utils.url = "github:numtide/flake-utils";
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
/* ... */
};
outputs = { self, flake-utils, nixpkgs /*, ... */ }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = (import nixpkgs) {
inherit system;
};
in
{
/* ... */
}
);
}
My understanding is that the nixpkgs
value in this flake's outputs
function is the attribute set produced by the nixpkgs
flake. I understand that flake output is a derivation, and a derivation can be imported. But how does the imported value become a function? I expected it to be an attribute set.
I see that the nixpkgs flake includes a lib
output. Is there some mechanism where an attribute with a lib
attribute path is callable? I have been looking for information on this, but I have not found anything.
If (import nixpkgs) {}
is effectively calling that lib
attribute, then how does importing differ from calling nixpkgs.lib
directly? From what I've read importing a derivation has some effect on either forcing evaluating, or not forcing evaluation of something. I don't understand the details yet.