lib.systems: rust: Make rustcTargetSpec the primary entrypoint (#446668)

This commit is contained in:
Alyssa Ross 2026-03-07 08:22:44 +00:00 committed by GitHub
commit bd0c7ad05a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 98 additions and 89 deletions

View file

@ -254,7 +254,7 @@ By default, it takes the `stdenv.hostPlatform.config` and replaces components
where they are known to differ. But there are ways to customize the argument: where they are known to differ. But there are ways to customize the argument:
- To choose a different target by name, define - To choose a different target by name, define
`stdenv.hostPlatform.rust.rustcTarget` as that name (a string), and that `stdenv.hostPlatform.rust.rustcTargetSpec` as that name (a string), and that
name will be used instead. name will be used instead.
For example: For example:
@ -262,7 +262,7 @@ where they are known to differ. But there are ways to customize the argument:
```nix ```nix
import <nixpkgs> { import <nixpkgs> {
crossSystem = (import <nixpkgs/lib>).systems.examples.armhf-embedded // { crossSystem = (import <nixpkgs/lib>).systems.examples.armhf-embedded // {
rust.rustcTarget = "thumbv7em-none-eabi"; rust.rustcTargetSpec = "thumbv7em-none-eabi";
}; };
} }
``` ```
@ -274,22 +274,24 @@ where they are known to differ. But there are ways to customize the argument:
``` ```
- To pass a completely custom target, define - To pass a completely custom target, define
`stdenv.hostPlatform.rust.rustcTarget` with its name, and `stdenv.hostPlatform.rust.rustcTargetSpec` with the path to the custom
`stdenv.hostPlatform.rust.platform` with the value. The value will be target specification JSON file.
serialized to JSON in a file called
`${stdenv.hostPlatform.rust.rustcTarget}.json`, and the path of that file Note that some tools like Cargo and some crates like `cc` make use of the
will be used instead. file name of the target JSON. Therefore, do not use
`./path/to/target-spec.json` directly, because it will be renamed by Nix.
Instead, place it a directory and use `"${./path/to/dir}/target-spec.json"`.
The directory should contain only this one file, to avoid unrelated changes
causing unnecessary rebuilds.
For example: For example:
```nix ```nix
import <nixpkgs> { import <nixpkgs> {
crossSystem = (import <nixpkgs/lib>).systems.examples.armhf-embedded // { crossSystem = {
rust.rustcTarget = "thumb-crazy"; config = "mips64el-unknown-linux-gnuabi64";
rust.platform = { # gcc = ...; # Config for C compiler omitted
foo = ""; rust.rustcTargetSpec = "${./rust}/mips64el_mips3-unknown-linux-gnuabi64.json";
bar = "";
};
}; };
} }
``` ```
@ -297,12 +299,9 @@ where they are known to differ. But there are ways to customize the argument:
will result in: will result in:
```shell ```shell
--target /nix/store/asdfasdfsadf-thumb-crazy.json # contains {"foo":"","bar":""} --target /nix/store/...-rust/mips64el_mips3-unknown-linux-gnuabi64.json
``` ```
Note that currently custom targets aren't compiled with `std`, so `cargo test`
will fail. This can be ignored by adding `doCheck = false;` to your derivation.
### Running package tests {#running-package-tests} ### Running package tests {#running-package-tests}
When using `buildRustPackage`, the `checkPhase` is enabled by default and runs When using `buildRustPackage`, the `checkPhase` is enabled by default and runs

View file

@ -417,66 +417,75 @@ let
// args // args
// { // {
rust = rust // { rust = rust // {
# Once args.rustc.platform.target-family is deprecated and platform =
# removed, there will no longer be any need to modify any rust.platform or (
# values from args.rust.platform, so we can drop all the if lib.hasSuffix ".json" (rust.rustcTargetSpec or "") then
# "args ? rust" etc. checks, and merge args.rust.platform in lib.importJSON rust.rustcTargetSpec
# /after/.
platform = rust.platform or { } // {
# https://doc.rust-lang.org/reference/conditional-compilation.html#target_arch
arch =
if rust ? platform then
rust.platform.arch
else if final.isAarch32 then
"arm"
else if final.isMips64 then
"mips64" # never add "el" suffix
else if final.isPower64 then
"powerpc64" # never add "le" suffix
else else
final.parsed.cpu.name; { }
)
# https://doc.rust-lang.org/reference/conditional-compilation.html#target_os # Once args.rustc.platform.target-family is deprecated and
os = # removed, there will no longer be any need to modify any
if rust ? platform then # values from args.rust.platform, so we can drop all the
rust.platform.os or "none" # "args ? rust" etc. checks, and merge args.rust.platform in
else if final.isDarwin then # /after/.
"macos" // {
else if final.isWasm && !final.isWasi then # https://doc.rust-lang.org/reference/conditional-compilation.html#target_arch
"unknown" # Needed for {wasm32,wasm64}-unknown-unknown. arch =
else if rust ? platform then
final.parsed.kernel.name; rust.platform.arch
else if final.isAarch32 then
"arm"
else if final.isMips64 then
"mips64" # never add "el" suffix
else if final.isPower64 then
"powerpc64" # never add "le" suffix
else
final.parsed.cpu.name;
# https://doc.rust-lang.org/reference/conditional-compilation.html#target_family # https://doc.rust-lang.org/reference/conditional-compilation.html#target_os
target-family = os =
if args ? rust.platform.target-family then if rust ? platform then
args.rust.platform.target-family rust.platform.os or "none"
else if args ? rustc.platform.target-family then else if final.isDarwin then
( "macos"
# Since https://github.com/rust-lang/rust/pull/84072 else if final.isWasm && !final.isWasi then
# `target-family` is a list instead of single value. "unknown" # Needed for {wasm32,wasm64}-unknown-unknown.
let else
f = args.rustc.platform.target-family; final.parsed.kernel.name;
in
if isList f then f else [ f ]
)
else
optional final.isUnix "unix" ++ optional final.isWindows "windows" ++ optional final.isWasm "wasm";
# https://doc.rust-lang.org/reference/conditional-compilation.html#target_vendor # https://doc.rust-lang.org/reference/conditional-compilation.html#target_family
vendor = target-family =
let if args ? rust.platform.target-family then
inherit (final.parsed) vendor; args.rust.platform.target-family
in else if args ? rustc.platform.target-family then
rust.platform.vendor or { (
"w64" = "pc"; # Since https://github.com/rust-lang/rust/pull/84072
} # `target-family` is a list instead of single value.
.${vendor.name} or vendor.name; let
}; f = args.rustc.platform.target-family;
in
if isList f then f else [ f ]
)
else
optional final.isUnix "unix" ++ optional final.isWindows "windows" ++ optional final.isWasm "wasm";
# The name of the rust target, even if it is custom. Adjustments are # https://doc.rust-lang.org/reference/conditional-compilation.html#target_vendor
# because rust has slightly different naming conventions than we do. vendor =
rustcTarget = let
inherit (final.parsed) vendor;
in
rust.platform.vendor or {
"w64" = "pc";
}
.${vendor.name} or vendor.name;
};
# The name of the rust target if it is standard, or the json file
# containing the custom target spec. Adjustments are because rust has
# slightly different naming conventions than we do.
rustcTargetSpec =
let let
inherit (final.parsed) cpu kernel abi; inherit (final.parsed) cpu kernel abi;
cpu_ = cpu_ =
@ -497,28 +506,29 @@ let
"gnu" "gnu"
else else
abi.name; abi.name;
inferred =
if final.isWasi then
# Rust uses `wasm32-wasip?` rather than `wasm32-unknown-wasi`.
# We cannot know which subversion does the user want, and
# currently use WASI 0.1 as default for compatibility. Custom
# users can set `rust.rustcTargetSpec` to override it.
"${cpu_}-wasip1"
else
"${cpu_}-${vendor_}-${kernel.name}${optionalString (abi.name != "unknown") "-${abi_}"}";
in in
# TODO: deprecate args.rustc in favour of args.rust after 23.05 is EOL. # TODO: deprecate args.rustc in favour of args.rust after 23.05 is EOL.
args.rust.rustcTarget or args.rustc.config or ( args.rust.rustcTargetSpec or args.rustc.config or (
# Rust uses `wasm32-wasip?` rather than `wasm32-unknown-wasi`. if rust ? platform then
# We cannot know which subversion does the user want, and # TODO: This breaks cc-rs and thus std support, so maybe remove support?
# currently use WASI 0.1 as default for compatibility. Custom builtins.toFile (rust.rustcTarget or inferred + ".json") (toJSON rust.platform)
# users can set `rust.rustcTarget` to override it.
if final.isWasi then
"${cpu_}-wasip1"
else else
"${cpu_}-${vendor_}-${kernel.name}${optionalString (abi.name != "unknown") "-${abi_}"}" args.rust.rustcTarget or inferred
); );
# The name of the rust target if it is standard, or the json file # Do not use rustcTarget. Use rustcTargetSpec or cargoShortTarget.
# containing the custom target spec. # TODO: Remove all in-tree usages, and deprecate
rustcTargetSpec = rustcTarget = rust.rustcTarget or final.rust.cargoShortTarget;
rust.rustcTargetSpec or (
if rust ? platform then
builtins.toFile (final.rust.rustcTarget + ".json") (toJSON rust.platform)
else
final.rust.rustcTarget
);
# The name of the rust target if it is standard, or the # The name of the rust target if it is standard, or the
# basename of the file containing the custom target spec, # basename of the file containing the custom target spec,