Using the same nixosConfiguration for different build systems

I’m converting my nix code from flake-utils to flake-parts. The code generates images for flashing on aarch64-linux devices. Those devices are described in the top-level flake.nix in the nixosConfigurations attribute.

flake-utils was adding the (build) system name to nixosConfigurations, which was breaking nix flake check. But apart from that, everything looked neat and simple. The system value was available inside the nixosConfiguration definition, which used it for individual configurations:

pkgs = import nixpkgs {inherit system;};
cross-config = modules:
  pkgs.pkgsCross.aarch64-multiplatform.nixos {imports = modules;};

With flake-parts (or if I just stop using flake-utils), system is no longer visible in nixosConfiguration. That leaves me with several options, neither of which is very appealing.

  1. Use separate configurations based on the build system. For instance, devkit splits into x86_64-linux-devkit and aarch64-linux-devkit. That’s what flake-utils was doing behind the scenes, but now it becomes visible and misleading, as x86_64-linux-devkit is an image for aarch64-linux built on an x86_64-linux machine.

  2. Limit the build system to x86_64-linux. That would interfere with our plan to use Asahi Linux (aarch64-linux) for the build eventually.

  3. Use impure build so I can do simply import nixpkgs; without specifying the build system.

I hope to find some way do define nixosConfigurations without depending on system. That would be the best.

I’ve made a GitHub repository specifically for this topic to illustrate what I’m trying to do:

You can see what I have originally. That’s a greatly simplified example, of course, but it shows the issues I’m trying to fix: https://github.com/proski/flake-os-demo/tree/main/flake-utils-original

I’m going to add similar directories to illustrate the approaches I have tried so far.

After spending a lot of time on different approaches, I realized a simple fact. nixosConfiguration is too rigid. It doesn’t accept any information about the build system, whether it’s the host platform or the build platform. The host platform is known, but the build platform can only be recovered using means that are considered impure.

Indeed, let’s consider the packages output after flake-parts expansion:

packages.devkit.aarch64-linux = nixosConfigurations.devkit.config.system.build.toplevel;
packages.devkit.x86_64-linux = nixosConfigurations.devkit.config.system.build.toplevel;

Two attributes are assigned the same value. The right hand side is not aware of the left hand side, of pkgs, system etc.

At this point, my best option is probably to stop using nixosConfiguration, as it’s too rigid for my use case.

I can only use nixosConfiguration if I solve one of the following problems, but I’m not too optimistic:

  • Find a way to pass the build system to the derivation (toplevel is this case).
  • Find a way to get the build platform the way it’s not considered impure.