This is what Bazel does and definitely can work. But, there are significant downsides to it. For instance-
- Cannot move binaries after they’ve been linked. Since everything is relative you have to move the whole tree along with it. Things like multiple outputs would not work correctly.
- There is no way to specify to build systems that $ORIGIN linking should be used. Nixpkgs tries to defer as much as possible to the package’s build system. These usually expect a hardcoded path in the form of
--prefix
and similar. No build system that I’m aware of cares about “$ORIGIN”. - $ORIGIN does not work on macOS or probably any other system but Linux (`$ORIGIN` in RPATH on macOS · Issue #4480 · bazelbuild/bazel · GitHub). It sounds like there are close parallels in macOS, but there is no certainty the behavior will be the same. With absolute paths, we are pretty sure this works on any Unix system.
- Larger rpaths can reduce reproducibility. Each rpath is looked up by the linker in order, so having lots of them like Bazel does can harm reproducible execution. If the library exists in one rpath for one system but not another, we may have different versions of libraries being used. With Nix’s absolute hash+name scheme, we can be certain that all binaries use the same libraries, and those same libraries are included in the closure.
- Adding on to that, the fundamental difference here is how Nix’s idea of “closure” vs. Bazel’s idea of “runfiles”. Nix’s closures are automatically managed, while runfiles are manually managed. This benefits Nix users by not making them care about what is used at runtime, only what absolute path references are transitively included matter. On the other hand, you end up relying on the absolute Nix store path. Nix cares about both build time and run time while Bazel only really care about build time.