Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rust: hooks: fix cross compilation #247442

Merged
merged 5 commits into from Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions pkgs/build-support/rust/hooks/cargo-build-hook.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,8 @@ cargoBuildHook() {

(
set -x
env \
"CC_@rustBuildPlatform@=@ccForBuild@" \
"CXX_@rustBuildPlatform@=@cxxForBuild@" \
"CC_@rustTargetPlatform@=@ccForHost@" \
"CXX_@rustTargetPlatform@=@cxxForHost@" \
cargo build -j $NIX_BUILD_CORES \
--target @rustTargetPlatformSpec@ \
@setEnv@ cargo build -j $NIX_BUILD_CORES \
--target @rustHostPlatformSpec@ \
--frozen \
${cargoBuildProfileFlag} \
${cargoBuildNoDefaultFeaturesFlag} \
Expand Down
2 changes: 1 addition & 1 deletion pkgs/build-support/rust/hooks/cargo-check-hook.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ cargoCheckHook() {
fi

argstr="${cargoCheckProfileFlag} ${cargoCheckNoDefaultFeaturesFlag} ${cargoCheckFeaturesFlag}
--target @rustTargetPlatformSpec@ --frozen ${cargoTestFlags}"
--target @rustHostPlatformSpec@ --frozen ${cargoTestFlags}"

(
set -x
Expand Down
4 changes: 2 additions & 2 deletions pkgs/build-support/rust/hooks/cargo-install-hook.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cargoInstallPostBuildHook() {
echo "Executing cargoInstallPostBuildHook"

releaseDir=target/@shortTarget@/$cargoBuildType
releaseDir=target/@targetSubdirectory@/$cargoBuildType
tmpDir="${releaseDir}-tmp";

mkdir -p $tmpDir
Expand All @@ -21,7 +21,7 @@ cargoInstallHook() {

# rename the output dir to a architecture independent one

releaseDir=target/@shortTarget@/$cargoBuildType
releaseDir=target/@targetSubdirectory@/$cargoBuildType
tmpDir="${releaseDir}-tmp";

mapfile -t targets < <(find "$NIX_BUILD_TOP" -type d | grep "${tmpDir}$")
Expand Down
2 changes: 1 addition & 1 deletion pkgs/build-support/rust/hooks/cargo-nextest-hook.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ cargoNextestHook() {
fi

argstr="${cargoCheckProfileFlag} ${cargoCheckNoDefaultFeaturesFlag} ${cargoCheckFeaturesFlag}
--target @rustTargetPlatformSpec@ --frozen ${cargoTestFlags}"
--target @rustHostPlatformSpec@ --frozen ${cargoTestFlags}"

(
set -x
Expand Down
42 changes: 21 additions & 21 deletions pkgs/build-support/rust/hooks/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
, rust
, rustc
, stdenv

# 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; see below).
, target ? rust.toRustTargetSpec stdenv.hostPlatform
}:

Expand All @@ -17,24 +21,17 @@ let

# see https://github.com/rust-lang/cargo/blob/964a16a28e234a3d397b2a7031d4ab4a428b1391/src/cargo/core/compiler/compile_kind.rs#L151-L168
# the "${}" is needed to transform the path into a /nix/store path before baseNameOf
shortTarget = if targetIsJSON then
targetSubdirectory = if targetIsJSON then
(lib.removeSuffix ".json" (builtins.baseNameOf "${target}"))
else target;
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++";
rustBuildPlatform = rust.toRustTarget stdenv.buildPlatform;
rustTargetPlatform = rust.toRustTarget stdenv.hostPlatform;
rustTargetPlatformSpec = rust.toRustTargetSpec stdenv.hostPlatform;

in {
cargoBuildHook = callPackage ({ }:
makeSetupHook {
name = "cargo-build-hook.sh";
propagatedBuildInputs = [ cargo ];
substitutions = {
inherit ccForBuild ccForHost cxxForBuild cxxForHost
rustBuildPlatform rustTargetPlatform rustTargetPlatformSpec;
inherit (rust.envVars) rustHostPlatformSpec setEnv;
};
} ./cargo-build-hook.sh) {};

Expand All @@ -43,7 +40,7 @@ in {
name = "cargo-check-hook.sh";
propagatedBuildInputs = [ cargo ];
substitutions = {
inherit rustTargetPlatformSpec;
inherit (rust.envVars) rustHostPlatformSpec;
};
} ./cargo-check-hook.sh) {};

Expand All @@ -52,7 +49,7 @@ in {
name = "cargo-install-hook.sh";
propagatedBuildInputs = [ ];
substitutions = {
inherit shortTarget;
inherit targetSubdirectory;
};
} ./cargo-install-hook.sh) {};

Expand All @@ -61,7 +58,7 @@ in {
name = "cargo-nextest-hook.sh";
propagatedBuildInputs = [ cargo cargo-nextest ];
substitutions = {
inherit rustTargetPlatformSpec;
inherit (rust.envVars) rustHostPlatformSpec;
};
} ./cargo-nextest-hook.sh) {};

Expand All @@ -78,23 +75,26 @@ in {

cargoConfig = ''
[target."${rust.toRustTarget stdenv.buildPlatform}"]
"linker" = "${ccForBuild}"
${lib.optionalString (stdenv.buildPlatform.config != stdenv.hostPlatform.config) ''
[target."${shortTarget}"]
"linker" = "${ccForHost}"
"linker" = "${rust.envVars.ccForBuild}"
${lib.optionalString (stdenv.hostPlatform.config != stdenv.targetPlatform.config) ''
[target."${rust.toRustTarget stdenv.targetPlatform}"]
"linker" = "${rust.envVars.ccForTarget}"
''}
"rustflags" = [ "-C", "target-feature=${if stdenv.hostPlatform.isStatic then "+" else "-"}crt-static" ]
'';
};
} ./cargo-setup-hook.sh) {};

maturinBuildHook = callPackage ({ }:
maturinBuildHook = callPackage ({ pkgsHostTarget }:
makeSetupHook {
name = "maturin-build-hook.sh";
propagatedBuildInputs = [ cargo maturin rustc ];
propagatedBuildInputs = [
pkgsHostTarget.maturin
pkgsHostTarget.cargo
pkgsHostTarget.rustc
];
substitutions = {
inherit ccForBuild ccForHost cxxForBuild cxxForHost
rustBuildPlatform rustTargetPlatform rustTargetPlatformSpec;
inherit (rust.envVars) rustTargetPlatformSpec setEnv;
};
} ./maturin-build-hook.sh) {};

Expand Down
7 changes: 1 addition & 6 deletions pkgs/build-support/rust/hooks/maturin-build-hook.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@ maturinBuildHook() {

(
set -x
env \
"CC_@rustBuildPlatform@=@ccForBuild@" \
"CXX_@rustBuildPlatform@=@cxxForBuild@" \
"CC_@rustTargetPlatform@=@ccForHost@" \
"CXX_@rustTargetPlatform@=@cxxForHost@" \
maturin build \
@setEnv@ maturin build \
--jobs=$NIX_BUILD_CORES \
--frozen \
--target @rustTargetPlatformSpec@ \
Expand Down
77 changes: 76 additions & 1 deletion pkgs/build-support/rust/lib/default.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{ lib }:
{ lib
, stdenv
, buildPackages
, targetPackages
}:

rec {
# https://doc.rust-lang.org/reference/conditional-compilation.html#target_arch
Expand Down Expand Up @@ -59,8 +63,79 @@ rec {
then builtins.toFile (toRustTarget platform + ".json") (builtins.toJSON platform.rustc.platform)
else toRustTarget platform;

# 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
#
toRustTargetForUseInEnvVars = platform:
lib.strings.replaceStrings ["-"] ["_"]
(lib.strings.toUpper
(toRustTarget platform));

# Returns true if the target is no_std
# https://github.com/rust-lang/rust/blob/2e44c17c12cec45b6a682b1e53a04ac5b5fcc9d2/src/bootstrap/config.rs#L415-L421
IsNoStdTarget = platform: let rustTarget = toRustTarget platform; in
builtins.any (t: lib.hasInfix t rustTarget) ["-none" "nvptx" "switch" "-uefi"];

# 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 = toRustTarget stdenv.buildPlatform;
rustBuildPlatformSpec = toRustTargetSpec stdenv.buildPlatform;
rustHostPlatform = toRustTarget stdenv.hostPlatform;
rustHostPlatformSpec = toRustTargetSpec stdenv.hostPlatform;
rustTargetPlatform = toRustTarget stdenv.targetPlatform;
rustTargetPlatformSpec = toRustTargetSpec stdenv.targetPlatform;
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_${toRustTargetForUseInEnvVars stdenv.targetPlatform}=${ccForTarget}" \
"CXX_${toRustTargetForUseInEnvVars stdenv.targetPlatform}=${cxxForTarget}" \
"CARGO_TARGET_${toRustTargetForUseInEnvVars stdenv.targetPlatform}_LINKER=${ccForTarget}" \
'' + ''
"CC_${toRustTargetForUseInEnvVars stdenv.hostPlatform}=${ccForHost}" \
"CXX_${toRustTargetForUseInEnvVars stdenv.hostPlatform}=${cxxForHost}" \
"CARGO_TARGET_${toRustTargetForUseInEnvVars stdenv.hostPlatform}_LINKER=${ccForHost}" \
'' + ''
"CC_${toRustTargetForUseInEnvVars stdenv.buildPlatform}=${ccForBuild}" \
"CXX_${toRustTargetForUseInEnvVars stdenv.buildPlatform}=${cxxForBuild}" \
"CARGO_TARGET_${toRustTargetForUseInEnvVars stdenv.buildPlatform}_LINKER=${ccForBuild}" \
"CARGO_BUILD_TARGET=${rustBuildPlatform}" \
"HOST_CC=${buildPackages.stdenv.cc}/bin/cc" \
"HOST_CXX=${buildPackages.stdenv.cc}/bin/c++" \
'';
};
}
1 change: 1 addition & 0 deletions pkgs/development/compilers/rust/1_72.nix
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

{ stdenv, lib
, buildPackages
, targetPackages
, newScope, callPackage
, CoreFoundation, Security, SystemConfiguration
, pkgsBuildTarget, pkgsBuildBuild, pkgsBuildHost
Expand Down
5 changes: 3 additions & 2 deletions pkgs/development/compilers/rust/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
}:
{ stdenv, lib
, buildPackages
, targetPackages
, newScope, callPackage
, CoreFoundation, Security, SystemConfiguration
, pkgsBuildBuild
Expand All @@ -21,15 +22,15 @@

let
# Use `import` to make sure no packages sneak in here.
lib' = import ../../../build-support/rust/lib { inherit lib; };
lib' = import ../../../build-support/rust/lib { inherit lib stdenv buildPackages targetPackages; };
# Allow faster cross compiler generation by reusing Build artifacts
fastCross = (stdenv.buildPlatform == stdenv.hostPlatform) && (stdenv.hostPlatform != stdenv.targetPlatform);
in
{
lib = lib';

# Backwards compat before `lib` was factored out.
inherit (lib') toTargetArch toTargetOs toRustTarget toRustTargetSpec IsNoStdTarget;
inherit (lib') toTargetArch toTargetOs toRustTarget toRustTargetSpec IsNoStdTarget toRustTargetForUseInEnvVars envVars;

# This just contains tools for now. But it would conceivably contain
# libraries too, say if we picked some default/recommended versions to build
Expand Down
6 changes: 3 additions & 3 deletions pkgs/development/libraries/libdovi/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,19 @@ rustPlatform.buildRustPackage rec {

buildPhase = ''
runHook preBuild
cargo cbuild -j $NIX_BUILD_CORES --release --frozen --prefix=${placeholder "out"} --target ${rustTargetPlatformSpec}
${rust.envVars.setEnv} cargo cbuild -j $NIX_BUILD_CORES --release --frozen --prefix=${placeholder "out"} --target ${rustTargetPlatformSpec}
runHook postBuild
'';

installPhase = ''
runHook preInstall
cargo cinstall -j $NIX_BUILD_CORES --release --frozen --prefix=${placeholder "out"} --target ${rustTargetPlatformSpec}
${rust.envVars.setEnv} cargo cinstall -j $NIX_BUILD_CORES --release --frozen --prefix=${placeholder "out"} --target ${rustTargetPlatformSpec}
runHook postInstall
'';

checkPhase = ''
runHook preCheck
cargo ctest -j $NIX_BUILD_CORES --release --frozen --prefix=${placeholder "out"} --target ${rustTargetPlatformSpec}
${rust.envVars.setEnv} cargo ctest -j $NIX_BUILD_CORES --release --frozen --prefix=${placeholder "out"} --target ${rustTargetPlatformSpec}
runHook postCheck
'';

Expand Down
4 changes: 2 additions & 2 deletions pkgs/development/libraries/libimagequant/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ rustPlatform.buildRustPackage rec {

postBuild = ''
pushd imagequant-sys
cargo cbuild --release --frozen --prefix=${placeholder "out"} --target ${rustTargetPlatformSpec}
${rust.envVars.setEnv} cargo cbuild --release --frozen --prefix=${placeholder "out"} --target ${rustTargetPlatformSpec}
popd
'';

postInstall = ''
pushd imagequant-sys
cargo cinstall --release --frozen --prefix=${placeholder "out"} --target ${rustTargetPlatformSpec}
${rust.envVars.setEnv} cargo cinstall --release --frozen --prefix=${placeholder "out"} --target ${rustTargetPlatformSpec}
popd
'';

Expand Down
23 changes: 2 additions & 21 deletions pkgs/tools/video/rav1e/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,6 @@
let
rustTargetPlatformSpec = rust.toRustTargetSpec stdenv.hostPlatform;

# TODO: if another package starts using cargo-c (seems likely),
# factor this out into a makeCargoChook expression in
# pkgs/build-support/rust/hooks/default.nix
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++";
rustBuildPlatform = rust.toRustTarget stdenv.buildPlatform;
rustTargetPlatform = rust.toRustTarget stdenv.hostPlatform;
setEnvVars = ''
env \
"CC_${rustBuildPlatform}"="${ccForBuild}" \
"CXX_${rustBuildPlatform}"="${cxxForBuild}" \
"CC_${rustTargetPlatform}"="${ccForHost}" \
"CXX_${rustTargetPlatform}"="${cxxForHost}" \
'';

in rustPlatform.buildRustPackage rec {
pname = "rav1e";
version = "0.6.6";
Expand Down Expand Up @@ -64,13 +47,11 @@ in rustPlatform.buildRustPackage rec {
checkType = "debug";

postBuild = ''
${setEnvVars} \
cargo cbuild --release --frozen --prefix=${placeholder "out"} --target ${rustTargetPlatformSpec}
${rust.envVars.setEnv} cargo cbuild --release --frozen --prefix=${placeholder "out"} --target ${rustTargetPlatformSpec}
'';

postInstall = ''
${setEnvVars} \
cargo cinstall --release --frozen --prefix=${placeholder "out"} --target ${rustTargetPlatformSpec}
${rust.envVars.setEnv} cargo cinstall --release --frozen --prefix=${placeholder "out"} --target ${rustTargetPlatformSpec}
'';

meta = with lib; {
Expand Down