Why is cross compilation failing for `armv7l-linux` but not for `aarch64-linux`?

I decided to reactivate my old raspberrypi 2 (armv7), the way i did with my raspi 4s (aarch64) before and to my surprise the usual nix build .#...sdImage failed with:

error: Cannot build '/nix/store/2h1bf9z321kib4wc46g0zhgnjhkh35hb-bootstrap-tools.drv'.
       Reason: required system or feature not available
       Required system: 'armv7l-linux' with features {}
       Current system: 'x86_64-linux' with features {benchmark, big-parallel, flakes, kvm, nix-command, nixos-test}
[ ... many more successive deps failing ]

My nixos host is:

$ nix-info 
system: "x86_64-linux", multi-user?: yes, version: nix-env (Nix) 2.33.3, channels(root): "nixos", nixpkgs: /nix/store/zkrz054gvl1dcxkw25d8lgx8l10px665-source

With binfmt enabled for both foreign platforms

$ head /proc/sys/fs/binfmt_misc/*
==> /proc/sys/fs/binfmt_misc/aarch64-linux <==
enabled
interpreter /run/binfmt/aarch64-linux
flags: P
offset 0
magic 7f454c460201010000000000000000000200b700
mask ffffffffffffff00ffffffffffff00fffeffffff

==> /proc/sys/fs/binfmt_misc/armv7l-linux <==
enabled
interpreter /run/binfmt/armv7l-linux
flags: P
offset 0
magic 7f454c4601010100000000000000000002002800
mask ffffffffffffff00ffffffffffff00fffeffffff

==> /proc/sys/fs/binfmt_misc/status <==
enabled

For tinkering, I have created a minimal flake to reproduce the issue:

{
  inputs.nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";

  outputs =
    { self, nixpkgs }:
    let
      system = "x86_64-linux";
      pkgs = nixpkgs.legacyPackages.${system};

      mkNixos =
        platform: image:
        nixpkgs.lib.nixosSystem {
          modules = [
            (
              { modulesPath, ... }:
              {
                imports = [ "${modulesPath}/installer/sd-card/${image}" ];
                nixpkgs = {
                  hostPlatform = platform;
                  config.allowBroken = true; # pkgs.efivar is marked broken for armv7l
                  config.allowUnsupportedSystem = true; # pkgs.uboot-rpi_0_w_defconfig-2025.10 not supported for armv7l
                };
              }
            )
          ];
        };
    in
    {
      nixosConfigurations = {
        host_1 = mkNixos "aarch64-linux" "sd-image-aarch64-new-kernel.nix";
        host_2 = mkNixos "armv7l-linux" "sd-image-armv7l-multiplatform.nix";
        host_3 = mkNixos "armv7l-linux" "sd-image-raspberrypi.nix";
      };

      devShells.${system}.default = pkgs.mkShell {
        shellHook =
          let
            buildAlias =
              n: "alias build_${n}='nix build .#nixosConfigurations.host_${n}.config.system.build.sdImage'";
          in
          ''
            set -x
            ${buildAlias "1"}
            ${buildAlias "2"}
            ${buildAlias "3"}
            set +x
          '';
      };
    };
}

Building host_1 works as expected, host_2 and host_3 yield the error above. The same behavior occurs with nixpkgs?ref=nixos-25.11.

I don’t know how to proceed from here. Maybe (a) the armv7l nixosConfiguration is broken in an exotic way, or (b) the nix build command doesn’t work as told to, or (c) my local boot.binfmt.emulatedSystems is somehow incorrect but only for armv7l-linux.
I can’t even find the build logs or turn on verbosity for leads to why bootstrap-tools is getting build with my host arch and not target arch.

Your config isn’t cross-compiling, it’s just emulating. For cross-compilation, set buildPlatform to the platform of your build host (e.g. x86_64-linux). I cross-compile armv7l-linux this way.

1 Like

Thank you for the hint, this really did the trick! I totally forgot!
Yea I know it’s emulated compilation, I used the term “cross” loosely.

I got the misguided impression from “cross” compiling aarch64 for my rpi4s on my x86 desktop, that I don’t need to set nixpkgs.buildPlatform. When it’s not set, buildPlatform defaults to hostPlatform (I just checked for all hosts) but still, somehow nix build works with a conflicting hostPlatform = “aarch64-linux” on my x86 desktop.
The question is still unanswered.

I do have a reason, why I am not setting buildPlatform. All my raspis nixosConfigurations get initially build on my x86 desktop and then run on SD cards in those raspis. From there on, an auto-update service pulls their nixosConfiguration form a remote flake (the same I have locally on my desktop) and get build natively. So setting buildPlatform = “x86_64-linux” inside a raspi nixosConfiguration will lead to the reversed conflict I have described above.
I remember tinkering around this issue and was relieved when I found out, I can somehow ignore buildPlatform. Now, when i tried armv7l-linux, it came back to bite me.

Maybe I have to live with setting buildPlatform temporarily for that initial build and not push it to the remote flake.

What die you set it to?

My nixos x86 desktop runs with boot.binfmt.emulatedSystems = [ “aarch64-linux” “armv7l-linux” ].

Does it need a reboot to take effect?

Run head /proc/sys/fs/binfmt_misc/* to check what emulation is live.

Could it be linked to extra-platforms option in /etc/nix/nix.conf?

On my x86_64-linux desktop is nix.settings.extra-platforms = [ “aarch64-linux” “armv7l-linux” “i686-linux”] active, which gets correctly set in /etc/nix/nix.conf

Would it work if you give the system to nix build ?
Something like:

nix build --system armv7l-linux .#nixosConfigurations.host_2.config.system.build.sdImage

Though, that wouldn’t explain why the aarch64-linux build succeed.

Adding this to my system configuration made it work for me.

  nix.settings.system-features = [ "gccarch-armv7-a" ];
1 Like