Skip to content

Commit

Permalink
lib.systems: elaborate Rust metadata
Browse files Browse the repository at this point in the history
We need this stuff to be available in lib so make-derivation.nix can
access it to construct the Meson cross file.

This has a couple of other advantages:

 - It makes Rust less special.  Now figuring out what Rust calls a
   platform is the same as figuring out what Linux or QEMU call it.

 - We can unify the schema used to define Rust targets, and the schema
   used to access those values later.  Just like you can set "config"
   or "system" in a platform definition, and then access those same
   keys on the elaborated platform, you can now set "rustcTarget" in
   your crossSystem, and then access "stdenv.hostPlatform.rustcTarget"
   in your code.

"rustcTarget", "rustcTargetSpec", "cargoShortTarget", and
"cargoEnvVarTarget" have the "rustc" and "cargo" prefixes because
these are not exposed to code by the compiler, and are not
standardized.  The arch/os/etc. variables are all named to match the
forms in the Rust target spec JSON.

The new rust.target-family only takes a list, since we don't need to
worry about backwards compatibility when that name is used.

The old APIs are all still functional with no warning for now, so that
it's possible for external code to use a single API on both 23.05 and
23.11.  We can introduce the warnings once 23.05 is EOL, and make them
hard errors when 23.11 is EOL.
  • Loading branch information
alyssais committed Nov 9, 2023
1 parent fecd99b commit e3e57b8
Show file tree
Hide file tree
Showing 37 changed files with 211 additions and 219 deletions.
100 changes: 98 additions & 2 deletions lib/systems/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ rec {
elaborate = args': let
args = if lib.isString args' then { system = args'; }
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 {};

final = {
# Prefer to parse `config` as it is strictly more informative.
parsed = parse.mkSystemFromString (if args ? config then args.config else args.system);
Expand Down Expand Up @@ -159,9 +163,101 @@ rec {
({
linux-kernel = args.linux-kernel or {};
gcc = args.gcc or {};
rustc = args.rustc or {};
} // platforms.select final)
linux-kernel gcc rustc;
linux-kernel gcc;

# 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"
Expand Down
4 changes: 2 additions & 2 deletions pkgs/applications/blockchains/zcash/default.nix
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{ autoreconfHook, boost180, cargo, coreutils, curl, cxx-rs, db62, fetchFromGitHub
, git, hexdump, lib, libevent, libsodium, makeWrapper, rust, rustPlatform
, git, hexdump, lib, libevent, libsodium, makeWrapper, rustPlatform
, pkg-config, Security, stdenv, testers, tl-expected, utf8cpp, util-linux, zcash, zeromq
}:

Expand Down Expand Up @@ -57,7 +57,7 @@ rustPlatform.buildRustPackage.override { inherit stdenv; } rec {
configureFlags = [
"--disable-tests"
"--with-boost-libdir=${lib.getLib boost180}/lib"
"RUST_TARGET=${rust.toRustTargetSpec stdenv.hostPlatform}"
"RUST_TARGET=${stdenv.hostPlatform.rust.rustcTargetSpec}"
];

enableParallelBuilding = true;
Expand Down
3 changes: 1 addition & 2 deletions pkgs/applications/misc/effitask/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
, openssl
, gtk3
, stdenv
, rust
}:

rustPlatform.buildRustPackage rec {
Expand All @@ -28,7 +27,7 @@ rustPlatform.buildRustPackage rec {
# default installPhase don't install assets
installPhase = ''
runHook preInstall
make install PREFIX="$out" TARGET="target/${rust.toRustTarget stdenv.hostPlatform}/release/effitask"
make install PREFIX="$out" TARGET="target/${stdenv.hostPlatform.rust.rustcTarget}/release/effitask"
runHook postInstall
'';

Expand Down
6 changes: 3 additions & 3 deletions pkgs/applications/window-managers/cosmic/applets/default.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{ lib, stdenv, fetchFromGitHub, rust, rustPlatform
{ lib, stdenv, fetchFromGitHub, rustPlatform
, cargo, just, pkg-config, util-linuxMinimal
, dbus, glib, libxkbcommon, pulseaudio, wayland
}:
Expand Down Expand Up @@ -41,11 +41,11 @@ rustPlatform.buildRustPackage {

justFlags = [
"--set" "prefix" (placeholder "out")
"--set" "target" "${rust.lib.toRustTargetSpecShort stdenv.hostPlatform}/release"
"--set" "target" "${stdenv.hostPlatform.rust.cargoShortTarget}/release"
];

# Force linking to libwayland-client, which is always dlopen()ed.
"CARGO_TARGET_${rust.toRustTargetForUseInEnvVars stdenv.hostPlatform}_RUSTFLAGS" =
"CARGO_TARGET_${stdenv.hostPlatform.rust.cargoEnvVarTarget}_RUSTFLAGS" =
map (a: "-C link-arg=${a}") [
"-Wl,--push-state,--no-as-needed"
"-lwayland-client"
Expand Down
6 changes: 3 additions & 3 deletions pkgs/applications/window-managers/cosmic/panel/default.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{ lib, stdenv, fetchFromGitHub, cargo, just, pkg-config, rust, rustPlatform
{ lib, stdenv, fetchFromGitHub, cargo, just, pkg-config, rustPlatform
, libglvnd, libxkbcommon, wayland
}:

Expand Down Expand Up @@ -33,11 +33,11 @@ rustPlatform.buildRustPackage {

justFlags = [
"--set" "prefix" (placeholder "out")
"--set" "bin-src" "target/${rust.lib.toRustTargetSpecShort stdenv.hostPlatform}/release/cosmic-panel"
"--set" "bin-src" "target/${stdenv.hostPlatform.rust.cargoShortTarget}/release/cosmic-panel"
];

# Force linking to libEGL, which is always dlopen()ed.
"CARGO_TARGET_${rust.toRustTargetForUseInEnvVars stdenv.hostPlatform}_RUSTFLAGS" =
"CARGO_TARGET_${stdenv.hostPlatform.rust.cargoEnvVarTarget}_RUSTFLAGS" =
map (a: "-C link-arg=${a}") [
"-Wl,--push-state,--no-as-needed"
"-lEGL"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ rustPlatform.buildRustPackage {
(placeholder "out")
"--set"
"bin-src"
"target/${rust.lib.toRustTargetSpecShort stdenv.hostPlatform}/release/cosmic-settings"
"target/${stdenv.hostPlatform.rust.cargoShortTarget}/release/cosmic-settings"
];

meta = with lib; {
Expand Down
3 changes: 1 addition & 2 deletions pkgs/build-support/rust/build-rust-crate/build-crate.nix
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{ lib, stdenv
, mkRustcDepArgs, mkRustcFeatureArgs, needUnstableCLI
, rust
}:

{ crateName,
Expand All @@ -21,7 +20,7 @@
(mkRustcDepArgs dependencies crateRenames)
(mkRustcFeatureArgs crateFeatures)
] ++ lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
"--target" (rust.toRustTargetSpec stdenv.hostPlatform)
"--target" stdenv.hostPlatform.rust.rustcTargetSpec
] ++ lib.optionals (needUnstableCLI dependencies) [
"-Z" "unstable-options"
] ++ extraRustcOpts
Expand Down
10 changes: 5 additions & 5 deletions pkgs/build-support/rust/build-rust-crate/configure-crate.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{ lib, stdenv, rust, echo_colored, noisily, mkRustcDepArgs, mkRustcFeatureArgs }:
{ lib, stdenv, echo_colored, noisily, mkRustcDepArgs, mkRustcFeatureArgs }:
{
build
, buildDependencies
Expand Down Expand Up @@ -124,8 +124,8 @@ in ''
export CARGO_PKG_AUTHORS="${authors}"
export CARGO_PKG_DESCRIPTION="${crateDescription}"
export CARGO_CFG_TARGET_ARCH=${rust.toTargetArch stdenv.hostPlatform}
export CARGO_CFG_TARGET_OS=${rust.toTargetOs stdenv.hostPlatform}
export CARGO_CFG_TARGET_ARCH=${stdenv.hostPlatform.rust.platform.arch}
export CARGO_CFG_TARGET_OS=${stdenv.hostPlatform.rust.platform.os}
export CARGO_CFG_TARGET_FAMILY="unix"
export CARGO_CFG_UNIX=1
export CARGO_CFG_TARGET_ENV="gnu"
Expand All @@ -136,8 +136,8 @@ in ''
export CARGO_MANIFEST_DIR=$(pwd)
export DEBUG="${toString (!release)}"
export OPT_LEVEL="${toString optLevel}"
export TARGET="${rust.toRustTargetSpec stdenv.hostPlatform}"
export HOST="${rust.toRustTargetSpec stdenv.buildPlatform}"
export TARGET="${stdenv.hostPlatform.rust.rustcTargetSpec}"
export HOST="${stdenv.buildPlatform.rust.rustcTargetSpec}"
export PROFILE=${if release then "release" else "debug"}
export OUT_DIR=$(pwd)/target/build/${crateName}.out
export CARGO_PKG_VERSION_MAJOR=${lib.elemAt version 0}
Expand Down
11 changes: 3 additions & 8 deletions pkgs/build-support/rust/build-rust-crate/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
, fetchCrate
, pkgsBuildBuild
, rustc
, rust
, cargo
, jq
, libiconv
Expand Down Expand Up @@ -71,18 +70,14 @@ let
inherit (import ./log.nix { inherit lib; }) noisily echo_colored;

configureCrate = import ./configure-crate.nix {
inherit lib stdenv rust echo_colored noisily mkRustcDepArgs mkRustcFeatureArgs;
inherit lib stdenv echo_colored noisily mkRustcDepArgs mkRustcFeatureArgs;
};

buildCrate = import ./build-crate.nix {
inherit lib stdenv mkRustcDepArgs mkRustcFeatureArgs needUnstableCLI rust;
inherit lib stdenv mkRustcDepArgs mkRustcFeatureArgs needUnstableCLI;
};

installCrate = import ./install-crate.nix { inherit stdenv; };

# Allow access to the rust attribute set from inside buildRustCrate, which
# has a parameter that shadows the name.
rustAttrs = rust;
in

/* The overridable pkgs.buildRustCrate function.
Expand Down Expand Up @@ -310,7 +305,7 @@ crate_: lib.makeOverridable
depsMetadata = lib.foldl' (str: dep: str + dep.metadata) "" (dependencies ++ buildDependencies);
hashedMetadata = builtins.hashString "sha256"
(crateName + "-" + crateVersion + "___" + toString (mkRustcFeatureArgs crateFeatures) +
"___" + depsMetadata + "___" + rustAttrs.toRustTarget stdenv.hostPlatform);
"___" + depsMetadata + "___" + stdenv.hostPlatform.rust.rustcTarget);
in
lib.substring 0 10 hashedMetadata;

Expand Down
5 changes: 2 additions & 3 deletions pkgs/build-support/rust/build-rust-package/default.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{ lib
, importCargoLock
, fetchCargoTarball
, rust
, stdenv
, callPackage
, cargoBuildHook
Expand Down Expand Up @@ -78,13 +77,13 @@ let
sha256 = args.cargoSha256;
} // depsExtraArgs);

target = rust.toRustTargetSpec stdenv.hostPlatform;
target = stdenv.hostPlatform.rust.rustcTargetSpec;
targetIsJSON = lib.hasSuffix ".json" target;
useSysroot = targetIsJSON && !__internal_dontAddSysroot;

sysroot = callPackage ./sysroot { } {
inherit target;
shortTarget = rust.lib.toRustTargetSpecShort stdenv.hostPlatform;
shortTarget = stdenv.hostPlatform.rust.cargoShortTarget;
RUSTFLAGS = args.RUSTFLAGS or "";
originalCargoToml = src + /Cargo.toml; # profile info is later extracted
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{ lib, stdenv, rust, rustPlatform, buildPackages }:
{ lib, stdenv, rustPlatform, buildPackages }:

{ shortTarget, originalCargoToml, target, RUSTFLAGS }:

Expand Down Expand Up @@ -26,7 +26,7 @@ in rustPlatform.buildRustPackage {
done
export RUST_SYSROOT=$(rustc --print=sysroot)
host=${rust.toRustTarget stdenv.buildPlatform}
host=${stdenv.buildPlatform.rust.rustcTarget}
cp -r $RUST_SYSROOT/lib/rustlib/$host $out
'';

Expand Down
6 changes: 3 additions & 3 deletions pkgs/build-support/rust/hooks/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# This confusingly-named parameter indicates the *subdirectory of
# `target/` from which to copy the build artifacts. It is derived
# from a stdenv platform (or a JSON file).
, target ? rust.lib.toRustTargetSpecShort stdenv.hostPlatform
, target ? stdenv.hostPlatform.rust.cargoShortTarget
}:

{
Expand Down Expand Up @@ -65,10 +65,10 @@
diff = "${lib.getBin buildPackages.diffutils}/bin/diff";

cargoConfig = ''
[target."${rust.toRustTarget stdenv.buildPlatform}"]
[target."${stdenv.buildPlatform.rust.rustcTarget}"]
"linker" = "${rust.envVars.ccForBuild}"
${lib.optionalString (stdenv.buildPlatform.config != stdenv.hostPlatform.config) ''
[target."${rust.toRustTarget stdenv.hostPlatform}"]
[target."${stdenv.hostPlatform.rust.rustcTarget}"]
"linker" = "${rust.envVars.ccForHost}"
''}
"rustflags" = [ "-C", "target-feature=${if stdenv.hostPlatform.isStatic then "+" else "-"}crt-static" ]
Expand Down
Loading

0 comments on commit e3e57b8

Please sign in to comment.