Skip to content

Commit

Permalink
lib.systems.elaborate: fix passing rust
Browse files Browse the repository at this point in the history
Usually, attributes passed explicitly to elaborate take precedence
over the elaborated ones, but since we also elaborate the nested
"rust" attrset, we need to push that one level down, so the rest of
"rust" is still filled in if you just pass
{ rust = { config = ... } }.

I've had to drop the assertion that checked that at most one of "rust"
and "rustc" was part of the un-elaborated system, because doing this
broke passing an elaborated system in, which should be idempotent.

For the same reason, I've also had to make it possible for
rust.rustcTargetSpec to be passed in.  Otherwise, on the second call,
since platform was filled in by the first, the custom target file
would be constructed.  The only other way to avoid this would be to
compare the platform attrs to all built in Rust targets to check it
wasn't one of those, and that isn't feasible.

Fixes: e3e57b8 ("lib.systems: elaborate Rust metadata")
  • Loading branch information
alyssais committed Nov 19, 2023
1 parent 4584687 commit 886c892
Showing 1 changed file with 92 additions and 92 deletions.
184 changes: 92 additions & 92 deletions lib/systems/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ rec {
else args';

# TODO: deprecate args.rustc in favour of args.rust after 23.05 is EOL.
rust = assert !(args ? rust && args ? rustc); args.rust or args.rustc or {};
rust = args.rust or args.rustc or {};

final = {
# Prefer to parse `config` as it is strictly more informative.
Expand Down Expand Up @@ -169,96 +169,6 @@ rec {
# TODO: remove after 23.05 is EOL, with an error pointing to the rust.* attrs.
rustc = args.rustc or {};

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
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 final.parsed.kernel.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 builtins.isList f then f else [ f ]
)
else lib.optional final.isUnix "unix"
++ lib.optional final.isWindows "windows";

# 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, even if it is custom. Adjustments are
# because rust has slightly different naming conventions than we do.
rustcTarget = let
inherit (final.parsed) cpu kernel abi;
cpu_ = rust.platform.arch or {
"armv7a" = "armv7";
"armv7l" = "armv7";
"armv6l" = "arm";
"armv5tel" = "armv5te";
"riscv64" = "riscv64gc";
}.${cpu.name} or cpu.name;
vendor_ = final.rust.platform.vendor;
in rust.config
or "${cpu_}-${vendor_}-${kernel.name}${lib.optionalString (abi.name != "unknown") "-${abi.name}"}";

# The name of the rust target if it is standard, or the json file
# containing the custom target spec.
rustcTargetSpec =
/**/ if rust ? platform
then builtins.toFile (final.rust.rustcTarget + ".json") (builtins.toJSON rust.platform)
else final.rust.rustcTarget;

# The name of the rust target if it is standard, or the
# basename of the file containing the custom target spec,
# without the .json extension.
#
# This is the name used by Cargo for target subdirectories.
cargoShortTarget =
lib.removeSuffix ".json" (baseNameOf "${final.rust.rustcTargetSpec}");

# When used as part of an environment variable name, triples are
# uppercased and have all hyphens replaced by underscores:
#
# https://github.com/rust-lang/cargo/pull/9169
# https://github.com/rust-lang/cargo/issues/8285#issuecomment-634202431
cargoEnvVarTarget =
lib.strings.replaceStrings ["-"] ["_"]
(lib.strings.toUpper final.rust.cargoShortTarget);

# True if the target is no_std
# https://github.com/rust-lang/rust/blob/2e44c17c12cec45b6a682b1e53a04ac5b5fcc9d2/src/bootstrap/config.rs#L415-L421
isNoStdTarget =
builtins.any (t: lib.hasInfix t final.rust.rustcTarget) ["-none" "nvptx" "switch" "-uefi"];
};

linuxArch =
if final.isAarch32 then "arm"
else if final.isAarch64 then "arm64"
Expand Down Expand Up @@ -356,7 +266,97 @@ rec {

}) // mapAttrs (n: v: v final.parsed) inspect.predicates
// mapAttrs (n: v: v final.gcc.arch or "default") architectures.predicates
// args;
// 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
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 final.parsed.kernel.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 builtins.isList f then f else [ f ]
)
else lib.optional final.isUnix "unix"
++ lib.optional final.isWindows "windows";

# 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, even if it is custom. Adjustments are
# because rust has slightly different naming conventions than we do.
rustcTarget = let
inherit (final.parsed) cpu kernel abi;
cpu_ = rust.platform.arch or {
"armv7a" = "armv7";
"armv7l" = "armv7";
"armv6l" = "arm";
"armv5tel" = "armv5te";
"riscv64" = "riscv64gc";
}.${cpu.name} or cpu.name;
vendor_ = final.rust.platform.vendor;
in rust.config
or "${cpu_}-${vendor_}-${kernel.name}${lib.optionalString (abi.name != "unknown") "-${abi.name}"}";

# 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") (builtins.toJSON rust.platform)
else final.rust.rustcTarget);

# The name of the rust target if it is standard, or the
# basename of the file containing the custom target spec,
# without the .json extension.
#
# This is the name used by Cargo for target subdirectories.
cargoShortTarget =
lib.removeSuffix ".json" (baseNameOf "${final.rust.rustcTargetSpec}");

# When used as part of an environment variable name, triples are
# uppercased and have all hyphens replaced by underscores:
#
# https://github.com/rust-lang/cargo/pull/9169
# https://github.com/rust-lang/cargo/issues/8285#issuecomment-634202431
cargoEnvVarTarget =
lib.strings.replaceStrings ["-"] ["_"]
(lib.strings.toUpper final.rust.cargoShortTarget);

# True if the target is no_std
# https://github.com/rust-lang/rust/blob/2e44c17c12cec45b6a682b1e53a04ac5b5fcc9d2/src/bootstrap/config.rs#L415-L421
isNoStdTarget =
builtins.any (t: lib.hasInfix t final.rust.rustcTarget) ["-none" "nvptx" "switch" "-uefi"];
};
};
in assert final.useAndroidPrebuilt -> final.isAndroid;
assert lib.foldl
(pass: { assertion, message }:
Expand Down

0 comments on commit 886c892

Please sign in to comment.