nixpkgs/pkgs/build-support/rust/build-rust-package/default.nix
Alyssa Ross cd6818baf7
rustPlatform: forward unpack hooks to cargo fetch
Sometimes it's more ergonomic to set up the build environment in
hooks, to add to the default behaviour rather than replacing it.  It's
very surprising that the fetcher works fine with a custom unpackPhase,
but not with custom preUnpack or postUnpack.

Packages that use preUnpack or postUnpack and Cargo FODs seem to be
very rare.  I searched Nixpkgs for files containing one of
"cargoHash", "cargoDeps", and "cargoSha256", and one of "preUnpack" or
"postUnpack", and only found two such packages:
python3.pkgs.tokenizers and rustdesk.  Neither of their Cargo FOD
hashes are affected by this change.  So if that's any indication,
we're unlikely to be breaking many out-of-tree hashes with these
changes either.
2023-03-14 00:26:11 +00:00

164 lines
4.4 KiB
Nix

{ lib
, importCargoLock
, fetchCargoTarball
, rust
, stdenv
, callPackage
, cargoBuildHook
, cargoCheckHook
, cargoInstallHook
, cargoNextestHook
, cargoSetupHook
, cargo
, cargo-auditable
, cargo-auditable-cargo-wrapper
, rustc
, libiconv
, windows
}:
{ name ? "${args.pname}-${args.version}"
# Name for the vendored dependencies tarball
, cargoDepsName ? name
, src ? null
, srcs ? null
, preUnpack ? null
, unpackPhase ? null
, postUnpack ? null
, cargoPatches ? []
, patches ? []
, sourceRoot ? null
, logLevel ? ""
, buildInputs ? []
, nativeBuildInputs ? []
, cargoUpdateHook ? ""
, cargoDepsHook ? ""
, buildType ? "release"
, meta ? {}
, cargoLock ? null
, cargoVendorDir ? null
, checkType ? buildType
, buildNoDefaultFeatures ? false
, checkNoDefaultFeatures ? buildNoDefaultFeatures
, buildFeatures ? [ ]
, checkFeatures ? buildFeatures
, useNextest ? false
, auditable ? false # TODO: change to true
, depsExtraArgs ? {}
# 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 && cargoLock == null
-> !(args ? cargoSha256 && args.cargoSha256 != null) && !(args ? cargoHash && args.cargoHash != null)
-> throw "cargoSha256, cargoHash, cargoVendorDir, or cargoLock must be set";
assert buildType == "release" || buildType == "debug";
let
cargoDeps =
if cargoVendorDir != null then null
else if cargoLock != null then importCargoLock cargoLock
else fetchCargoTarball ({
inherit src srcs sourceRoot preUnpack unpackPhase postUnpack cargoUpdateHook;
name = cargoDepsName;
patches = cargoPatches;
} // lib.optionalAttrs (args ? cargoHash) {
hash = args.cargoHash;
} // lib.optionalAttrs (args ? cargoSha256) {
sha256 = args.cargoSha256;
} // depsExtraArgs);
target = rust.toRustTargetSpec stdenv.hostPlatform;
targetIsJSON = lib.hasSuffix ".json" target;
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
(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
};
in
# 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);
stdenv.mkDerivation ((removeAttrs args [ "depsExtraArgs" "cargoUpdateHook" "cargoLock" ]) // lib.optionalAttrs useSysroot {
RUSTFLAGS = "--sysroot ${sysroot} " + (args.RUSTFLAGS or "");
} // {
inherit buildAndTestSubdir cargoDeps;
cargoBuildType = buildType;
cargoCheckType = checkType;
cargoBuildNoDefaultFeatures = buildNoDefaultFeatures;
cargoCheckNoDefaultFeatures = checkNoDefaultFeatures;
cargoBuildFeatures = buildFeatures;
cargoCheckFeatures = checkFeatures;
patchRegistryDeps = ./patch-registry-deps;
nativeBuildInputs = nativeBuildInputs ++ lib.optionals auditable [
(cargo-auditable-cargo-wrapper.override {
inherit cargo cargo-auditable;
})
] ++ [
cargoBuildHook
(if useNextest then cargoNextestHook else cargoCheckHook)
cargoInstallHook
cargoSetupHook
rustc
];
buildInputs = buildInputs
++ lib.optionals stdenv.hostPlatform.isDarwin [ libiconv ]
++ lib.optionals 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
runHook postConfigure
'';
doCheck = args.doCheck or true;
strictDeps = true;
meta = {
# default to Rust's platforms
platforms = rustc.meta.platforms;
} // meta;
})