Nix flake with packages for a list of systems and additional packages for only one of them

Hello everybody!

It is quite common to build packages in a flake for several systems:

{
  # […]
  outputs = { self, nixpkgs }:
    let
      supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ];

      forAllSystems = nixpkgs.lib.genAttrs supportedSystems;

      nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; });
    in {
      packages = forAllSystems (system:
        let
          pkgs = nixpkgsFor.${system};
        in {
          package_1 = {…};
          package_2 = {…};
          # […]
        });
    };
}

My question is: How would you add another package, lets say package_3 for only one of the systems in the list supportedSystem? Just updating it with // like this does not work:

# […]
      packages = forAllSystems (system:
        let
          pkgs = nixpkgsFor.${system};
        in {
          package_1 = {…};
          package_2 = {…};
          # […]
        }) // {
          "x86_64-linux" = {
            package_3 = {};
          };
        };
# […]

I tested that with playing in the nix repl:

packages = {"linux" = {"app_1" = {}; "app_2" = {};}; "osx" = {"app_1" = {}; "app_2" = {};};}
(packages // {"linux" = {"app_3" = {};};})."linux"

The reason is that it would then absolutely override the whole attribute x86_64-linux in the first argument of the //-operand. So some kind of a recursive // would be nice.

I am aware of https://stackoverflow.com/a/54505212 where the author self-defines a function for this. However I wonder if there is no dedicated library-function present for this. That would be surprising as you would expect this to be quite a common case that some of your packages are architecture-dependend and may not exist for every architecture or for just one of them.

Are you looking for lib.recursiveUpdate?

1 Like

Thank you very much! :slightly_smiling_face: