Consider, for example, the suggested home manager configuration here, particularly this chunk:
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.jdoe = import ./home.nix;
}
This looks like an ordinary function call, but that’s not how it is actually treated. home-manager.nixosModules.home-manager
resolves to the module here and, as such, it’s expecting arguments like config
, pkgs
, lib
, etc. In any other context, the “function application” above would raise an error—but not when this code is used with lib.nixosSystem
.
I am aware that the module system is responsible for calling modules with the arguments they’re expecting (see this thread for instance). But usually, I see the modules
or imports
arguments used to list modules by themselves (in the form of functions), not modules that have options passed to them like the code above. I’m trying to figure out how this option-passing mechanism works.
So my question is, what exactly happens to the attribute set shown above? How does the module become aware of these options?
There is clearly some magic happening here. For instance, I can replace the code with this
home-manager.nixosModules.home-manager {} {} {} {} {} {}
and I do not get an error, which means this code is not being treated like a function application. I am particularly disturbed that if I try to factor the original code like this
nixosConfigurations = let hm = home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.jdoe = import ./home.nix;
}; in {
hostname = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
hm
];
}
then I get this error
error: anonymous function at /nix/store/27g251cjy32c69j4zwz0xlf1imym255n-source/nixos/default.nix:1:1 called without required argument 'lib'
The last error makes perfect sense: I’m trying to call a function without its required arguments. But I’m disturbed that I don’t get this error with the original example. Clearly, some combination of laziness and reflection is being used to take the original code and… do something else.
What exactly is happening here?