Right now the only way to specify runtime dependencies is to hard-code an implementation using something like makeWrapper. Although, there are a lot of cases I think it would be useful to encode that a specific file must exist or that a specific binary must exist in $PATH, without tying down the package to a specific implementation.
It even applies much more broadly, you could e.g. delay choosing a libc implementation, or a docker/container runner, or a Python implementation, for an application. Conceptually you’d want to build a derivation against an API, then decide on an implementation of that API in a separate derivation. You can then only build the first derivation once, then have a (cheap) build for each combination with an implementation.
Requiring something in $PATH etc is kinda annoying IMHO because it breaks expectations for things like nix run. However you can do a two-level, where the wrapper is in a separate derivation, so you don’t have to rebuild the ‘base’ to change the ‘wrapper’. IIUC things like neovim and clang already use this approach.
xdg-utils is already a good concrete example of this as apps which open URLs assume xdg-open will be on the path, and they can call xdg-open https://example.org/ to open it. handlr was already linked as an example replacement.
That’s true for most cases, but I think it makes sense in certain circumstances. I feel like for nix run we could just give the same kind of error message pointing out that a runtime dependency is missing.
For certain common tools which one might want to replace, like xdg-open, it seems to me like nixpkgs config, combined with the two-level structure @dramforever suggested, is the right way to handle it. That way you can set in one place what you want to use for that, but you still keep the self-contained nature of a nix derivation closure.
Yep, I think that’s the ideal, but the problem comes when there’s no good default, and it makes more sense to take what the user set on $PATH.
For example, I mentioned doing the exact same thing for texlab (that it should depend on a TeX distribution), but the other reviewers decided against it because they mentioned that many users may have a different TeX distribution installed, and expect that to be used instead:
For these situations I’m suggesting that we have some other mechanism to determine when these dependencies are satisfied, instead of just leaving the dependency off altogether.
Another similar existing example is /run/opengl-drivers. Packages build against mesa, and then at runtime depend on whatever is symlinked in /run/opengl-drivers.
Yeah, but that hook can’t actually verify that /run/opengl-drivers actually exists in the final system profile during build time, it will just fail to load the library at runtime.
Do you think it would help to have some formal way to describe these runtime impurities like what I mentioned in the main description though? Right now we assume these exist at runtime and fail at runtime if they don’t, but I feel like we could verify this earlier during profile generation.
The problem is c-style dynamic linking. There’s only so much we can do when an environment “assumes” that libraries will be co-located with everything else.
Part of the problem is that even nixos doesn’t actually know for sure what’s in PATH at runtime. It comes from multiple sources, including home-manager and nix-env for user-installed stuff.
Part of the overall philosophy of the nix ecosystem is to use build-time resolution of resources wherever possible. This philosophy isn’t incidental. It’s an important part of getting many of the benefits we get from it. PATH lookups are an exception to this philosophy, because you don’t want to reboot just to get a new package installed, but this doesn’t seem like it qualifies for an exception to me. If the current UX is bad, we need to make the build-time resolution’s configuration process easier, not start trying to guarantee runtime resolution will work. It can’t even be done in environments like nix-env and nix profile anyway… not without a major overhaul to the architecture of nix itself, which I would view as quite detrimental.
With CA derivations, it might be possible to add a hardware drivers stub, and then people don’t have to rely on any runtime hacks to find the more specific hardware libraries.
The stub is just there so that the actual drivers only have a single downstream package. This should make it cheap for the contents to be replaced with something else without having to rebuild the actual immediate downstream dependencies.