nixpkgs/pkgs/build-support/rust/lib/default.nix
Alyssa Ross e3e57b8f18 lib.systems: elaborate Rust metadata
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.
2023-11-09 10:02:24 +01:00

81 lines
3.7 KiB
Nix

{ lib
, stdenv
, buildPackages
, targetPackages
}:
rec {
# These environment variables must be set when using `cargo-c` and
# several other tools which do not deal well with cross
# compilation. The symptom of the problem they fix is errors due
# to buildPlatform CFLAGS being passed to the
# hostPlatform-targeted compiler -- for example, `-m64` being
# passed on a build=x86_64/host=aarch64 compilation.
envVars = let
ccForBuild = "${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}cc";
cxxForBuild = "${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}c++";
ccForHost = "${stdenv.cc}/bin/${stdenv.cc.targetPrefix}cc";
cxxForHost = "${stdenv.cc}/bin/${stdenv.cc.targetPrefix}c++";
# Unfortunately we must use the dangerous `targetPackages` here
# because hooks are artificially phase-shifted one slot earlier
# (they go in nativeBuildInputs, so the hostPlatform looks like
# a targetPlatform to them).
ccForTarget = "${targetPackages.stdenv.cc}/bin/${targetPackages.stdenv.cc.targetPrefix}cc";
cxxForTarget = "${targetPackages.stdenv.cc}/bin/${targetPackages.stdenv.cc.targetPrefix}c++";
rustBuildPlatform = stdenv.buildPlatform.rust.rustcTarget;
rustBuildPlatformSpec = stdenv.buildPlatform.rust.rustcTargetSpec;
rustHostPlatform = stdenv.hostPlatform.rust.rustcTarget;
rustHostPlatformSpec = stdenv.hostPlatform.rust.rustcTargetSpec;
rustTargetPlatform = stdenv.targetPlatform.rust.rustcTarget;
rustTargetPlatformSpec = stdenv.targetPlatform.rust.rustcTargetSpec;
in {
inherit
ccForBuild cxxForBuild rustBuildPlatform rustBuildPlatformSpec
ccForHost cxxForHost rustHostPlatform rustHostPlatformSpec
ccForTarget cxxForTarget rustTargetPlatform rustTargetPlatformSpec;
# Prefix this onto a command invocation in order to set the
# variables needed by cargo.
#
setEnv = ''
env \
''
# Due to a bug in how splicing and targetPackages works, in
# situations where targetPackages is irrelevant
# targetPackages.stdenv.cc is often simply wrong. We must omit
# the following lines when rustTargetPlatform collides with
# rustHostPlatform.
+ lib.optionalString (rustTargetPlatform != rustHostPlatform) ''
"CC_${stdenv.targetPlatform.rust.cargoEnvVarTarget}=${ccForTarget}" \
"CXX_${stdenv.targetPlatform.rust.cargoEnvVarTarget}=${cxxForTarget}" \
"CARGO_TARGET_${stdenv.targetPlatform.rust.cargoEnvVarTarget}_LINKER=${ccForTarget}" \
'' + ''
"CC_${stdenv.hostPlatform.rust.cargoEnvVarTarget}=${ccForHost}" \
"CXX_${stdenv.hostPlatform.rust.cargoEnvVarTarget}=${cxxForHost}" \
"CARGO_TARGET_${stdenv.hostPlatform.rust.cargoEnvVarTarget}_LINKER=${ccForHost}" \
'' + ''
"CC_${stdenv.buildPlatform.rust.cargoEnvVarTarget}=${ccForBuild}" \
"CXX_${stdenv.buildPlatform.rust.cargoEnvVarTarget}=${cxxForBuild}" \
"CARGO_TARGET_${stdenv.buildPlatform.rust.cargoEnvVarTarget}_LINKER=${ccForBuild}" \
"CARGO_BUILD_TARGET=${rustBuildPlatform}" \
"HOST_CC=${buildPackages.stdenv.cc}/bin/cc" \
"HOST_CXX=${buildPackages.stdenv.cc}/bin/c++" \
'';
};
} // lib.mapAttrs (old: new: platform:
# TODO: enable warning after 23.05 is EOL.
# lib.warn "`rust.${old} platform` is deprecated. Use `platform.rust.${new}` instead."
lib.getAttrFromPath new platform.rust)
{
toTargetArch = [ "platform" "arch" ];
toTargetOs = [ "platform" "os" ];
toTargetFamily = [ "platform" "target-family" ];
toTargetVendor = [ "platform" "vendor" ];
toRustTarget = [ "rustcTarget" ];
toRustTargetSpec = [ "rustcTargetSpec" ];
toRustTargetSpecShort = [ "cargoShortTarget" ];
toRustTargetForUseInEnvVars = [ "cargoEnvVarTarget" ];
IsNoStdTarget = [ "isNoStdTarget" ];
}