Skip to content

Conversation

@mildsunrise
Copy link

@mildsunrise mildsunrise commented Nov 29, 2025

This PR addresses two shortcomings in #222. rust-overlay works wonderfully if we use the targets argument:

pkgs.rustChannels.stable.rust.override { targets = [ "aarch64-unknown-none" ]; }

But if we request the same through the generic nixpkgs cross-compilation mechanism, it fails to evaluate entirely:

# equivalent to setting crossSystem:
let pkgs' = pkgs.pkgsCross.aarch64-embedded; in

pkgs'.buildPackages.rustChannels.stable.rust
error:
       … while evaluating 'strict' to select 'drvPath' on it
         at /builtin/derivation.nix:1:552:
       … while calling the 'derivationStrict' builtin
         at /builtin/derivation.nix:1:208:
       (stack trace truncated; use '--show-trace' to show the full trace)

       error: attribute '"*"' missing
       at rust-overlay.nix:81:75:
           80|       pkg = pkgs.${pkgname};
           81|       srcInfo = pkg.target.${toRustTargetCompat stdenv.targetPlatform} or pkg.target."*";
             |                                                                           ^
           82|       extensions = srcInfo.extensions or [];

Here I'm requesting rustChannels.stable.rust with hostPlatform still set to my platform, e.g. x86_64, and targetPlatform set to aarch64-unknown-none. The reason this fails is because we're trying to look up the extensions for pkg.rust.target.aarch64-unknown-none, instead of pkg.rust.target.x86_64-unknown-linux-gnu (which is what we'll actually fetch and use).

So this seems like a very clear typo; there is no situation where we'd want to look up extensions or components for the targetPlatform, it should always be the hostPlatform (matching the package we'll download and unpack). The reason this hasn't been spotted until now is likely that for many target platforms, like aarch64-multiplatform, the key did exist and the code succeeded (even if by looking at the wrong key).

However, fixing this is not entirely enough. It will now evaluate and build, but the resulting sysroot still lacks rust-std for aarch64-unknown-none (which we do get if we use override { targets = [ "aarch64-unknown-none" ]; }). From looking at #222 I see that the way this works is we fetch pkg.rust for BOTH platforms, and then we merge the two sysroots, and because of the order, the sysroot for the host platform ends up overriding most of the files (except for notably rust-std).

I find this very problematic: for once, it doesn't work for targets (like aarch64-unknown-none) that have rust-std but not a whole toolchain. I also very much doubt sysroots are designed to be merged like that; a sysroot should only be merged with its extensions, not other sysroots. It also consumes unnecessary disk space / bandwidth downloading the whole toolchain when just rust-std is enough.

So, the second commit makes the second Nix snippet behave identically to the first one: hostTargets now contains only hostPlatform, not the targetPlatform, which is instead added implicitly to the targets argument (assuming the platforms are different).

@mildsunrise mildsunrise changed the title Fix cross-compilation rust-overlay: Fix cross-compilation Dec 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant