It’s a question of goals. Is the goal to make the computer like the nix expression or the nix expression like the computer. Nix picks the former over the later exclusively.
That’s the point. If you generate the expression ad-hoc, it’s subject to random change and not reproducible. Hardware may change, bugs may cause changes in reporting, etc.
NixOS prioritizes reproducibility; taking that snapshot of what the hardware looks like and making it static ensures that your configuration is set up for a specific system and produces an OS precisely for that system, every time, rather than different systems producing different OSes every time you evaluate.
The theory is that it matters less that sometimes a misconfigured system will fail to boot than that you can’t reliably tell whether your configuration is broken or if the hardware generation layer is randomly failing to do its job.
I don’t think dynamic generation is really feasible with nix anyway, you’d have to do something very hacky with nixos-rebuild.
I don’t even think dynamic gen is possible at the nixos-rebuild stage, since hardware often gets switched out when the system is off. The generation would have to happen at boot.
Just to be clear - I am not pushing for a dynamic nix expression rebuild that magically works at boot.
(Although I am wondering how different the expression is between systems really are for systems to boot. Basically how specialized the expression really is. But I digress…)
But shouldn’t it be possible to compare what the nix expression was built for with the expected status quo and show the differences if found?
You could totally have nixos-rebuild have a step where it will print the generated HW config and compare the configuration fragment and warn you that the system may not boot again.
But it can only be an advisory warning as people can do extremely complicated things, e.g. boot on a system via kexec which cannot lead to simple heuristics as “are you going to reboot on the right disk?” works.
Simple:
You have a system which boots over the NVMe bus.
You have a system which boots over the SATA bus.
This is going to lead in different kernel modules being required in the initrd.
In my case I used nixos-anyware to install the base system.
So it sounds like the during the build for the new system (before the reboot) it would be the ideal time. It is already on the machine in question - and it should be able to break the build and tell me this will not work.
The build could run the generate hardware config and compare what is contained in the nix expression. And fail if it is (too) different.
Did I understand that correctly?
Learning question:
Couldn’t both kernel modules be included in the nix expression?
And during runtime it just picks the one found/needed?
Isn’t that what happens via systemd-udevd?
Or is this different for the initrd?
I don’t see that necessarily changing the nix expression yet.
Yep, whatever you use doesn’t matter. It all trickle down to the same flavor of Nix magic that builds a toplevel and install it. Nix is made to inspect configurations, as long as you have the original .nix or some metadata left behind, you can “re-inspect” things and compare to what should have been the hardware configuration.
You can certainly take the union of every possible things you need, do note though there exists hardware configuration that can collide. An installer does exactly what you say, because its role is to work without knowing the target system hardware configuration in advance.
But do note that this can sometimes not work, more examples:
kernel 6.18 has a regression that makes old systems not complete boot
kernel 6.18 is required to boot newest AMD CPUs
you can choose either nvidia or nouveau to boot the graphical stack of an nVidia graphical card, but both are mutually exclusive; some systems may live better with one or the other.
You cannot always get away with putting ALL the modules.
Yes, systemd-udevd, systemd-kmod does many of these things. But certain modules might need to be loaded before they exist and are ready. You cannot always use runtime detection if you need runtime detection to start the runtime detection process.