nixpkgs/pkgs/build-support/rust/default.nix

205 lines
6.3 KiB
Nix
Raw Normal View History

{ stdenv
2021-01-24 00:40:18 +00:00
, lib
, buildPackages
, cacert
, cargo
, cargoSetupHook
, fetchCargoTarball
, runCommandNoCC
, rustPlatform
, callPackage
, remarshal
, git
, rust
, rustc
, windows
}:
{ name ? "${args.pname}-${args.version}"
# SRI hash
, cargoHash ? ""
# Legacy hash
, cargoSha256 ? ""
, src ? null
, srcs ? null
, unpackPhase ? null
, cargoPatches ? []
, patches ? []
, sourceRoot ? null
, logLevel ? ""
, buildInputs ? []
2018-11-21 01:47:45 +00:00
, nativeBuildInputs ? []
, cargoUpdateHook ? ""
, cargoDepsHook ? ""
2017-04-15 09:14:55 +00:00
, cargoBuildFlags ? []
, buildType ? "release"
, meta ? {}
, target ? rust.toRustTargetSpec stdenv.hostPlatform
2018-02-20 09:59:26 +00:00
, cargoVendorDir ? null
, checkType ? buildType
2020-09-23 10:01:05 +00:00
, depsExtraArgs ? {}
, cargoParallelTestThreads ? true
# Toggles whether a custom sysroot is created when the target is a .json file.
, __internal_dontAddSysroot ? false
# Needed to `pushd`/`popd` into a subdir of a tarball if this subdir
# contains a Cargo.toml, but isn't part of a workspace (which is e.g. the
# case for `rustfmt`/etc from the `rust-sources).
# Otherwise, everything from the tarball would've been built/tested.
, buildAndTestSubdir ? null
, ... } @ args:
assert cargoVendorDir == null -> !(cargoSha256 == "" && cargoHash == "");
assert buildType == "release" || buildType == "debug";
2018-02-20 09:59:26 +00:00
let
2018-02-20 09:59:26 +00:00
cargoDeps = if cargoVendorDir == null
2020-09-23 10:01:05 +00:00
then fetchCargoTarball ({
inherit name src srcs sourceRoot unpackPhase cargoUpdateHook;
hash = cargoHash;
patches = cargoPatches;
2018-02-20 09:59:26 +00:00
sha256 = cargoSha256;
2020-09-23 10:01:05 +00:00
} // depsExtraArgs)
2018-02-20 09:59:26 +00:00
else null;
# If we have a cargoSha256 fixed-output derivation, validate it at build time
# against the src fixed-output derivation to check consistency.
validateCargoDeps = !(cargoHash == "" && cargoSha256 == "");
2021-01-24 00:40:18 +00:00
targetIsJSON = lib.hasSuffix ".json" target;
2020-10-17 07:45:27 +00:00
useSysroot = targetIsJSON && !__internal_dontAddSysroot;
# 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
2021-01-24 00:40:18 +00:00
(lib.removeSuffix ".json" (builtins.baseNameOf "${target}"))
else target;
sysroot = (callPackage ./sysroot {}) {
inherit target shortTarget;
RUSTFLAGS = args.RUSTFLAGS or "";
originalCargoToml = src + /Cargo.toml; # profile info is later extracted
};
2018-11-21 01:47:45 +00:00
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++";
releaseDir = "target/${shortTarget}/${buildType}";
tmpDir = "${releaseDir}-tmp";
in
2020-10-17 07:47:14 +00:00
# Tests don't currently work for `no_std`, and all custom sysroots are currently built without `std`.
# See https://os.phil-opp.com/testing/ for more information.
assert useSysroot -> !(args.doCheck or true);
2021-01-24 00:40:18 +00:00
stdenv.mkDerivation ((removeAttrs args ["depsExtraArgs"]) // lib.optionalAttrs useSysroot {
RUSTFLAGS = "--sysroot ${sysroot} " + (args.RUSTFLAGS or "");
} // {
inherit cargoDeps;
patchRegistryDeps = ./patch-registry-deps;
nativeBuildInputs = nativeBuildInputs ++ [ cacert git cargo cargoSetupHook rustc ];
2021-01-24 00:40:18 +00:00
buildInputs = buildInputs ++ lib.optional stdenv.hostPlatform.isMinGW windows.pthreads;
patches = cargoPatches ++ patches;
PKG_CONFIG_ALLOW_CROSS =
if stdenv.buildPlatform != stdenv.hostPlatform then 1 else 0;
postUnpack = ''
eval "$cargoDepsHook"
export RUST_LOG=${logLevel}
'' + (args.postUnpack or "");
configurePhase = args.configurePhase or ''
runHook preConfigure
2018-11-21 01:47:45 +00:00
runHook postConfigure
'';
2017-04-15 09:14:55 +00:00
buildPhase = with builtins; args.buildPhase or ''
2021-01-24 00:40:18 +00:00
${lib.optionalString (buildAndTestSubdir != null) "pushd ${buildAndTestSubdir}"}
runHook preBuild
(
set -x
2018-11-21 01:47:45 +00:00
env \
"CC_${rust.toRustTarget stdenv.buildPlatform}"="${ccForBuild}" \
"CXX_${rust.toRustTarget stdenv.buildPlatform}"="${cxxForBuild}" \
"CC_${rust.toRustTarget stdenv.hostPlatform}"="${ccForHost}" \
"CXX_${rust.toRustTarget stdenv.hostPlatform}"="${cxxForHost}" \
cargo build -j $NIX_BUILD_CORES \
2021-01-24 00:40:18 +00:00
${lib.optionalString (buildType == "release") "--release"} \
--target ${target} \
2018-11-21 01:47:45 +00:00
--frozen ${concatStringsSep " " cargoBuildFlags}
)
runHook postBuild
2021-01-24 00:40:18 +00:00
${lib.optionalString (buildAndTestSubdir != null) "popd"}
# This needs to be done after postBuild: packages like `cargo` do a pushd/popd in
# the pre/postBuild-hooks that need to be taken into account before gathering
# all binaries to install.
mkdir -p $tmpDir
cp -r $releaseDir/* $tmpDir/
bins=$(find $tmpDir \
-maxdepth 1 \
-type f \
-executable ! \( -regex ".*\.\(so.[0-9.]+\|so\|a\|dylib\)" \))
'';
checkPhase = args.checkPhase or (let
2021-01-24 00:40:18 +00:00
argstr = "${lib.optionalString (checkType == "release") "--release"} --target ${target} --frozen";
threads = if cargoParallelTestThreads then "$NIX_BUILD_CORES" else "1";
in ''
2021-01-24 00:40:18 +00:00
${lib.optionalString (buildAndTestSubdir != null) "pushd ${buildAndTestSubdir}"}
runHook preCheck
2020-05-06 21:25:01 +00:00
echo "Running cargo test ${argstr} -- ''${checkFlags} ''${checkFlagsArray+''${checkFlagsArray[@]}}"
cargo test -j $NIX_BUILD_CORES ${argstr} -- --test-threads=${threads} ''${checkFlags} ''${checkFlagsArray+"''${checkFlagsArray[@]}"}
runHook postCheck
2021-01-24 00:40:18 +00:00
${lib.optionalString (buildAndTestSubdir != null) "popd"}
'');
doCheck = args.doCheck or true;
strictDeps = true;
inherit releaseDir tmpDir;
2018-11-21 01:47:45 +00:00
installPhase = args.installPhase or ''
runHook preInstall
# rename the output dir to a architecture independent one
mapfile -t targets < <(find "$NIX_BUILD_TOP" -type d | grep '${tmpDir}$')
for target in "''${targets[@]}"; do
rm -rf "$target/../../${buildType}"
ln -srf "$target" "$target/../../"
done
mkdir -p $out/bin $out/lib
2018-11-21 01:47:45 +00:00
xargs -r cp -t $out/bin <<< $bins
find $tmpDir \
2018-11-21 01:47:45 +00:00
-maxdepth 1 \
-regex ".*\.\(so.[0-9.]+\|so\|a\|dylib\)" \
-print0 | xargs -r -0 cp -t $out/lib
rmdir --ignore-fail-on-non-empty $out/lib $out/bin
runHook postInstall
'';
passthru = { inherit cargoDeps; } // (args.passthru or {});
meta = {
# default to Rust's platforms
platforms = rustc.meta.platforms;
} // meta;
})