IMO NixOS is among the best of the bunch partially on account of precisely the lack of fhs (which is important, but complete purity isn’t necessary for the use case - the culture of it is sufficient). Most other IaC tools can’t reliably do the boot-on-tmpfs thing NixOS does so well, or inherently depend on containers to do anything, resulting in infrastructure you can’t actually deploy without first deploying infrastructure to deploy your infrastructure to.
Plus, among them, it’s basically the only one that is even remotely suited to desktop use. I find it’s also very good at low-maintenance small bare-metal server hosting. These use cases are largely overlooked by all the other IaC tools (with the notable exception of ansible, and maybe yocto for a specific subset of these use cases, but see above paragraph) - they tend to target big businesses and cloud deployments exclusively.
I’ve certainly not used all of them either, and I’m sure the number is orders of magnitude larger than 20, but NIxOS is the only one that has really met my needs.
Ok, long-form answer here because this is the second time this has come up, and so far nobody has voiced why nix-ld
is such a problem to me.
Personally, I think nix-ld
strikes a decent balance. It’s no worse than what NixOS does today - NixOS already deploys a shim dynamic linker to tell you why your binaries aren’t working. nix-ld
does exactly the same, unless you specify the NIX_LD
/NIX_LD_LIBRARY_PATH
variables, which require explicit setting because the NIX_LD
prefix doesn’t make them overlap with anything.
It beats buildFhsUserEnv
& co. for some use cases, because it doesn’t require writing a full nix package and doesn’t deploy into a container. This means:
-
I can run software that is allergic to containers with it.
-
I can get stuff to work without the time investment of writing a package by hand. Just put whatever libraries my binary complains about in a shell.nix
, run nix-shell
, and it works. This can be significantly faster than untangling an override of a package which internally uses buildFhsUserEnv
, but e.g. tries to run software downloaded at runtime which uses libraries not part of its normal closure.
-
There’s no separate build step that wraps binaries or anything, so I can just put a self-updating application (curse you, Von Neumann) in one of these shells and it’ll work as intended by its designer.
-
Finally, and most importantly to my mind, it helps users who are new to the ecosystem actually adopt NixOS without having to fully understand nix (the language) right off the bat. Putting a few libraries in shell.nix
is much easier to grok than using buildFhsUserEnv
(especially when you add nix-alien).
This may just be a weakness of the buildFhsUserEnv
API, to be fair, a simplified version of it could achieve similar things (and nix-alien basically provides that) - but then you run into issues with things that don’t like being containerized.
And what’s the trade-off? Well, a subtly different dynamic linker shim which users could abuse to break NixOS guarantees by setting a variable globally. It can’t interfere with builds, even if for some reason you put it somewhere that lacks sandboxing, since variables don’t propagate there, so there’s no risk of the contamination spreading even if abused this way. I don’t see how this is setting up users for failure, the caveat to its use is tiny.
On that note, perhaps your problem with nix-ld
isn’t actually nix-ld
, but the programs.nix-ld
NixOS module. For some reason we’re setting global variables with it, which does in fact completely break NixOS guarantees, and programs.nix-ld.enable
is so easy to just do without understanding anything that I’d call it a footgun. We really oughta stop providing footguns.