Description
Suppose I have four flakes: A, B, C, and D. Flake A builds an executable, while flakes B, C, and D build libraries. There are two ABI-incompatible versions of D: D1 and D2. Suppose they have the following dependencies:
- A -> B
- A -> C
- B -> D1
- C -> D2
Because the program image of A has two ABI-incompatible versions of D, it could fail to link/segfault/otherwise be broken. This problem tends not to arise with legacy style use of Nixpkgs, since each Nixpkgs rev tends to have one version of each package (with a few exceptions). With flakes, this is no longer true, and I'm not aware of an ergonomic way to deal with this. If I understand flakes correctly, it seems that the author of a flake that depends on library-outputting flakes (like flake A) would need to recursively interrogate their flake input's inputs to avoid making a diamond like this (so that they know what .follows
directives to use in their inputs to avoid the problem). There are less catastrophic problems with such deeper flake dependency graphs too: if I have a big closure of dependency flakes that all take nixpkgs as an input, then it's a pain to add all the .follows
directives to my inputs, my inputs' inputs, my inputs' inputs' inputs, and so on if I want to e.g. use a single nixpkgs rev everywhere.
I'd propose the following mechanism to help with this problem: provide some way of collecting a flake's input closure, then pin one version of each unique flake in the closure in the flake.lock. This mechanism would fail in the case of conflicting shared dependencies that aren't direct inputs to the top-level flake, like D
in the example given above. In this case, one solution would be to just tell the user what .follows
directives they need to add to their flake inputs to achieve the one-version-of-each-dependency property. I think a better yet solution would be to enable this behavior in the flake itself, so that evaluation would fail if e.g. the author of A didn't specify a single version of D for B and C to use.
Without something like this, I don't see a way to avoid DLL hell with flakes.