While writing this I discovered I was mostly reinventing the wheel of @zimbatm’s nixpkgs-unfree, but I think discussing the essence of the technique might be useful for others.
Recently, my team has been using flakes to package individual python libraries for re-use. One difficulty we encountered it that if we enable cudaSupport
in nixpkgs, there wasn’t an easy way to propagate that to our dependencies. Using inputs.<a>.inputs.nixpkgs.follows
would bring in the unconfigured nixpkgs. So a dependency might bring in pytorch without cuda enabled, but the toplevel flake might request it with cuda, the two versions would conflict and the build would fail.
To work-around this we came up with small hack. We set up a small flake to pull in nixpkgs, reimport with our config, and re-export it in a format that works for our dependencies as the legacyPackages
output of the flake. It looks like this
{
description = "Flake for nixpkgs with GPU stuff set up";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-24.11";
};
outputs = { self, nixpkgs,
}:
let
pkgs = import nixpkgs {
system = "x86_64-linux";
config = { cudaSupport = true; };
in {
legacyPackages.x86_64-linux = pkgs;
};
}
additional config can be added as well such as allowUnfree
or cudaCapabilities
.
The nice part of this approach is that this flake can follow
nixpkgs from the top-level flake, where dependencies can follow this flake, so the the top-level flake can still handle version pinning.
A dependent project flake would look like:
{
description = "A GPU project";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-24.11";
nixpkgs-gpu.url = "github:<our>/<repo-for-this>";
nixpkgs-gpu.inputs.nixpkgs.follows = "nixpkgs";
another-dep = "github:<our>/<package-repo>";
another-dep.inputs.nixpkgs.follows = "nixpkgs-gpu";
};
outputs = { self, nixpkgs, nixpkgs-gpu, another-dep }:
let pkgs = nixpkgs-gpu.legacyPackages.x86_64-linux; in
{
....
};
}
This strategy doesn’t work if the other dependencies try to import nixpkgs
but that is not recommended any longer anyway (nixpkgs-unfree has solved this)
If you’re in a situation like we were, using nixpkgs-unfree directly, or forking it so you can make your own configuration changes is probably superior to the approach we used.