Linux kernel will support $ORIGIN, sort of(fzakaria.com) |
Linux kernel will support $ORIGIN, sort of(fzakaria.com) |
https://fzakaria.com/2026/06/21/nix-needs-relocatable-binari...
> The loader in Linux however natively supports the variable $ORIGIN which translates to “the directory containing the executable.”
https://man7.org/linux/man-pages/man8/ld.so.8.html
But, if ld.so supports $ORIGIN already, why does the kernel needs to support it also? Or rather, why can't the kernel leverage ld.so and do this entirely on userspace?
On most Linux systems this is regrettably `glibc` (in a container where you get to choose everyone chooses the superior option of `musl`), on all Darwin systems this is `libstandard`.
This thread is more concerned with Linux, so you are probably dealing with `/lib64/ld-linux-x86-64.so.2`, which operates in userspace but is by convention and opacity quite clearly part of "the system".
The kernel modification is a much bigger, much weirder side effect of a weird Nix loyalty test around shebang lines in shell scripts, on which is has opted to be intentionally and violently incompatible with everything for no benefit other than incompatibility.
It’s fair to argue about whether those things are really important or whether nix does this in the best way, but to claim that the only benefit is incompatibility is just obvious nonsense.
Then, later, a couple of patches to make binfmt_misc more ergonomic. Seems like a good outcome.
Regarding shebangs, I've never understood why the kernel cannot resolve e.g. `#!sh` relative to PATH instead of CWD. Posix prescribes that you should look for `sh` in PATH and don't expect it to be in `/bin/sh`. And using `/usr/bin/env sh` has the same issue: what if coreutils is installed elsewhere.
glibc is what deals with PATH, not the shell. On Linux, it's execvp(3) in libc which is implemented in terms of execve(2) in the kernel, but POSIX doesn't make a distinction between syscalls and library functions, so a kernel could implement either or none directly.
Instead of looking for ways Nix could work with ensuring else they force everything else to be modified to work with Nix. You will constantly seem them trying to get projects to adapt a flake.nix or to replace bash scripts with a different shebang since they hardcode a single binary that is rare for people to use in the real world.
I have made appseed[0] (asciinema link[1]) which used zapps[2] which did a lot of tricks to achieve in end what this kernel patch could help in doing and hopefully more in the future!
My appseed project didn't work for large projects like OBS but I feel like the approach that this does could lead to mass adoption given that its now a kernel feature. It could in theory allow more portable binaries across Linux which is really cool :)
[0]: https://github.com/SerJaimeLannister/appseed
[1]: https://asciinema.org/a/zK0T3WXAxalMYCVUY1vp8FAv3
[2]: https://zapps.app/
bazel's wrong solution is $ORIGIN, Nix's wrong solution is "floating" CA / "realizations".
The technical debt / precedent argument doesn't apply: Nix never had this bug (for once), you the choices on this bug are 1. port the bazel bug to Nix 2. don't port the bug.
I predict... the bug is a shoe in, the bug lands eight days a week.
Disagreeing with you doesn't make something a rant. If it's not clear how deep my Nix expertise is I will demonstrate it to any level you like: I'm just as entitled to an opinion as you are and I would appreciate it if the nixpkgs community was a little less rude to anyone who disagrees with some dogma no matter their knowledge. The nixpkgs community is not regarded as healthy or friendly after an internecine faction war that split three ways twice, producing four implementations none of which work, and if that reputation is ever going to mend, it will be because less than every Nix person has precisely zero chill the nanosecond anyone disagrees with them about anything.
Besides, it allows for upgrades/downgrades to be done in a way that's much less error-prone.
There is much more value to be had in making glibc properly backward compatible so you can have a single one that can be used with everything than trying to make it so that you can swap everything around, creating extra complexity and compatibility risks.
You could only do that going forward though, and would be stuck, at least for a time, with the historic versions that still need extra handling. In an ideal world that wouldn't be needed, but in an ideal world you'd not need multiple versions of glibc at all so we aren't there.
Support in the kernel means that it will work even if applied to old packages that for some other reason need a held-back version of glibc. As mentioned elsewhere it also gives the feature to #! directives in scripts too.
- It would still not allow downgrades to work properly
- It would cause glibc/ld.so to have a harder time adding new features, as they now need to worry about incompatible versions being used together
Meanwhile, having different ld.so has many good use-cases, like simplifying development of ld.so itself, allowing them to swapped during updates in ways that are safer, etc...
And the eBPF binfmt support is a rather simple, generic mechanism that is likely to have many other use-cases beyond ld.so. So it's overall a pretty good resolution to the issue?
Other libraries on the system is far more hit and miss, but glibc is quite compatible.
The other way around is harder though, you can't take a program built against a newer glibc and run it on an older version. So you generally need to spin up a container with some LTS distro and build your binary in it if you want it to be maximally compatible. (However, zig apparently is able to deal with this by shipping a mapping between glibc versions and symbol versions and doing the linking themselves. You can even use zig to link rust code using cargo-zigbuild and get that benefit.)
But if you want to be maximally portable: static linking against musl. Though beware that many things are slower in musl, such as the allocator.
Nix has put in a ton of work to make their project work, and the assumptions in the rest of the ecosystem have been fighting every step of the way. And I would argue they've been changing it for the better, considering that if you were to just 'try to make nix work' you'd probably mainly come to the conclusion that it was impossible to make work sensibly due to the huge number of places where hardcoded relationships have been baked in.
[0] https://github.com/NixOS/nixpkgs/issues/420513 [1] https://github.com/NixOS/nixpkgs/issues/94228
There is an arrogance in the way of thinking that when you see everyone breaking your arbitrary rules you think to yourself "there is no way my rules are at fault, it's everyone else's fault for breaking them."
>due to the huge number of places where hardcoded relationships have been baked in.
And why are hardcoded relationships bad for developers or users of the operating system? "Because they break Nix" is not a good excuse. Plenty of other operating systems work just fine with such things hardcoded, I don't see developers complaining about these hardcoded things, and moving things around can only make things more confusing for the user.
To me it looks like Nix picked a poor design and instead of going back to the drawing board and trying to come up with a better design they have gone all in on trying to force their bad design to work.
How much work do you think iOS or Android spend on app packaging / installation per year. Despite having millions of more developers and billions of more users they spend orders of magnitude less than NixOS does.
Edit: I can't reply since I'm rate limited.
Debian already supports installing multiple php versions.
You can use the update-alternatives command to set which one is default for the php command.
Via your web server's config you can config which php version a site will use.
Nix is one such platform.
It's not really arrogance - it's just a different way to design a system. NixOS wants a few things:
1. An input-addressed dependency system
2. Easy and robust rollback/upgrades
3. Different versions of software/libraries/services coexisting on a single machine.
A lot of this is just impossible to have together with the way software were written, so NixOS made the changes necessary for them. When it became obvious it might be useful to other people, they upstreamed it.
I do agree with you that the whole `#!/usr/bin/env bash` shebang shenanigan is kinda ass (my personal nixos machine has a `/bin/bash` alias because there's not enough time in my life to care about this issue). But I also think that NixOS is right here, shebangs requiring a full path is just a terrible design in a multi-user world. If different users want to have a different bash implementation, they should be able to!
---
Fundamentally, I think the NixOS OS design is actually beautiful. It's taking most of what makes modern phone OS so reliable (read-only system, A/B partitions, etc...), and bringing their ideas in a shape that is coherent with desktop/server OS design.
$ python3 -c 'print("hi")'
hi
$ hash
hits command
1 /usr/bin/python3