diff --git a/doc/languages-frameworks/rust.section.md b/doc/languages-frameworks/rust.section.md index 66f821ea21a3..04b43b5c272f 100644 --- a/doc/languages-frameworks/rust.section.md +++ b/doc/languages-frameworks/rust.section.md @@ -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: - 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. For example: @@ -262,7 +262,7 @@ where they are known to differ. But there are ways to customize the argument: ```nix import { crossSystem = (import ).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 - `stdenv.hostPlatform.rust.rustcTarget` with its name, and - `stdenv.hostPlatform.rust.platform` with the value. The value will be - serialized to JSON in a file called - `${stdenv.hostPlatform.rust.rustcTarget}.json`, and the path of that file - will be used instead. + `stdenv.hostPlatform.rust.rustcTargetSpec` with the path to the custom + target specification JSON file. + + Note that some tools like Cargo and some crates like `cc` make use of the + 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: ```nix import { - crossSystem = (import ).systems.examples.armhf-embedded // { - rust.rustcTarget = "thumb-crazy"; - rust.platform = { - foo = ""; - bar = ""; - }; + crossSystem = { + config = "mips64el-unknown-linux-gnuabi64"; + # gcc = ...; # Config for C compiler omitted + rust.rustcTargetSpec = "${./rust}/mips64el_mips3-unknown-linux-gnuabi64.json"; }; } ``` @@ -297,12 +299,9 @@ where they are known to differ. But there are ways to customize the argument: will result in: ```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} When using `buildRustPackage`, the `checkPhase` is enabled by default and runs diff --git a/lib/systems/default.nix b/lib/systems/default.nix index 534af380738d..b4f6c13feafa 100644 --- a/lib/systems/default.nix +++ b/lib/systems/default.nix @@ -417,66 +417,75 @@ let // args // { rust = rust // { - # Once args.rustc.platform.target-family is deprecated and - # removed, there will no longer be any need to modify any - # values from args.rust.platform, so we can drop all the - # "args ? rust" etc. checks, and merge args.rust.platform in - # /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 + platform = + rust.platform or ( + if lib.hasSuffix ".json" (rust.rustcTargetSpec or "") then + lib.importJSON rust.rustcTargetSpec else - final.parsed.cpu.name; + { } + ) - # https://doc.rust-lang.org/reference/conditional-compilation.html#target_os - os = - if rust ? platform then - rust.platform.os or "none" - else if final.isDarwin then - "macos" - else if final.isWasm && !final.isWasi then - "unknown" # Needed for {wasm32,wasm64}-unknown-unknown. - else - final.parsed.kernel.name; + # Once args.rustc.platform.target-family is deprecated and + # removed, there will no longer be any need to modify any + # values from args.rust.platform, so we can drop all the + # "args ? rust" etc. checks, and merge args.rust.platform in + # /after/. + // { + # 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 + final.parsed.cpu.name; - # https://doc.rust-lang.org/reference/conditional-compilation.html#target_family - target-family = - if args ? rust.platform.target-family then - args.rust.platform.target-family - else if args ? rustc.platform.target-family then - ( - # Since https://github.com/rust-lang/rust/pull/84072 - # `target-family` is a list instead of single value. - 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"; + # https://doc.rust-lang.org/reference/conditional-compilation.html#target_os + os = + if rust ? platform then + rust.platform.os or "none" + else if final.isDarwin then + "macos" + else if final.isWasm && !final.isWasi then + "unknown" # Needed for {wasm32,wasm64}-unknown-unknown. + else + final.parsed.kernel.name; - # https://doc.rust-lang.org/reference/conditional-compilation.html#target_vendor - vendor = - let - inherit (final.parsed) vendor; - in - rust.platform.vendor or { - "w64" = "pc"; - } - .${vendor.name} or vendor.name; - }; + # https://doc.rust-lang.org/reference/conditional-compilation.html#target_family + target-family = + if args ? rust.platform.target-family then + args.rust.platform.target-family + else if args ? rustc.platform.target-family then + ( + # Since https://github.com/rust-lang/rust/pull/84072 + # `target-family` is a list instead of single value. + 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 - # because rust has slightly different naming conventions than we do. - rustcTarget = + # https://doc.rust-lang.org/reference/conditional-compilation.html#target_vendor + vendor = + 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 inherit (final.parsed) cpu kernel abi; cpu_ = @@ -497,28 +506,29 @@ let "gnu" else 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 # TODO: deprecate args.rustc in favour of args.rust after 23.05 is EOL. - args.rust.rustcTarget or args.rustc.config or ( - # 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.rustcTarget` to override it. - if final.isWasi then - "${cpu_}-wasip1" + args.rust.rustcTargetSpec or args.rustc.config or ( + if rust ? platform then + # TODO: This breaks cc-rs and thus std support, so maybe remove support? + builtins.toFile (rust.rustcTarget or inferred + ".json") (toJSON rust.platform) 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 - # containing the custom target spec. - rustcTargetSpec = - rust.rustcTargetSpec or ( - if rust ? platform then - builtins.toFile (final.rust.rustcTarget + ".json") (toJSON rust.platform) - else - final.rust.rustcTarget - ); + # Do not use rustcTarget. Use rustcTargetSpec or cargoShortTarget. + # TODO: Remove all in-tree usages, and deprecate + rustcTarget = rust.rustcTarget or final.rust.cargoShortTarget; # The name of the rust target if it is standard, or the # basename of the file containing the custom target spec,