build-support/rust: Organize

- `toRustTarget` and friends pulled out from rust tools into rust
   library. Since they don't depend on any packages they can be more
   widely useable.

 - `build-rust-package` gets its own directory

 - `fetch-cargo-tarball` gets its own directory

(cherry picked from commit 18ed048c7b27e288a6c9ba894790a7e67ed5080d)
This commit is contained in:
John Ericson
2021-11-07 20:03:11 +00:00
parent 96cf5a2b2d
commit 67aa63e5e2
11 changed files with 50 additions and 34 deletions
@@ -0,0 +1,151 @@
{ stdenv
, lib
, buildPackages
, cacert
, cargoBuildHook
, cargoCheckHook
, cargoInstallHook
, cargoSetupHook
, fetchCargoTarball
, runCommandNoCC
, rustPlatform
, callPackage
, remarshal
, git
, rust
, rustc
, libiconv
, windows
}:
{ name ? "${args.pname}-${args.version}"
# SRI hash
, cargoHash ? ""
# Legacy hash
, cargoSha256 ? ""
# Name for the vendored dependencies tarball
, cargoDepsName ? name
, src ? null
, srcs ? null
, unpackPhase ? null
, cargoPatches ? []
, patches ? []
, sourceRoot ? null
, logLevel ? ""
, buildInputs ? []
, nativeBuildInputs ? []
, cargoUpdateHook ? ""
, cargoDepsHook ? ""
, buildType ? "release"
, meta ? {}
, cargoVendorDir ? null
, checkType ? buildType
, 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 -> !(cargoSha256 == "" && cargoHash == "");
assert buildType == "release" || buildType == "debug";
let
cargoDeps = if cargoVendorDir == null
then fetchCargoTarball ({
inherit src srcs sourceRoot unpackPhase cargoUpdateHook;
name = cargoDepsName;
hash = cargoHash;
patches = cargoPatches;
sha256 = cargoSha256;
} // depsExtraArgs)
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 == "");
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"]) // lib.optionalAttrs useSysroot {
RUSTFLAGS = "--sysroot ${sysroot} " + (args.RUSTFLAGS or "");
} // {
inherit buildAndTestSubdir cargoDeps;
cargoBuildType = buildType;
cargoCheckType = checkType;
patchRegistryDeps = ./patch-registry-deps;
nativeBuildInputs = nativeBuildInputs ++ [
cacert
git
cargoBuildHook
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;
passthru = { inherit cargoDeps; } // (args.passthru or {});
meta = {
# default to Rust's platforms
platforms = rustc.meta.platforms;
} // meta;
})
@@ -0,0 +1,8 @@
for dir in pkg-config-*; do
[ -d "$dir" ] || continue
echo "Patching pkg-config registry dep"
substituteInPlace "$dir/src/lib.rs" \
--replace '"/usr"' '"'"$NIX_STORE"'/"'
done
@@ -0,0 +1,29 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "alloc"
version = "0.0.0"
dependencies = [
"compiler_builtins",
"core",
]
[[package]]
name = "compiler_builtins"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cd0782e0a7da7598164153173e5a5d4d9b1da094473c98dce0ff91406112369"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "core"
version = "0.0.0"
[[package]]
name = "rustc-std-workspace-core"
version = "1.99.0"
dependencies = [
"core",
]
@@ -0,0 +1,45 @@
import os
import toml
rust_src = os.environ['RUSTC_SRC']
orig_cargo = os.environ['ORIG_CARGO'] if 'ORIG_CARGO' in os.environ else None
base = {
'package': {
'name': 'alloc',
'version': '0.0.0',
'authors': ['The Rust Project Developers'],
'edition': '2018',
},
'dependencies': {
'compiler_builtins': {
'version': '0.1.0',
'features': ['rustc-dep-of-std', 'mem'],
},
'core': {
'path': os.path.join(rust_src, 'libcore'),
},
},
'lib': {
'name': 'alloc',
'path': os.path.join(rust_src, 'liballoc/lib.rs'),
},
'patch': {
'crates-io': {
'rustc-std-workspace-core': {
'path': os.path.join(rust_src, 'tools/rustc-std-workspace-core'),
},
},
},
}
if orig_cargo is not None:
with open(orig_cargo, 'r') as f:
src = toml.loads(f.read())
if 'profile' in src:
base['profile'] = src['profile']
out = toml.dumps(base)
with open('Cargo.toml', 'x') as f:
f.write(out)
@@ -0,0 +1,41 @@
{ stdenv, rust, rustPlatform, buildPackages }:
{ shortTarget, originalCargoToml, target, RUSTFLAGS }:
let
cargoSrc = stdenv.mkDerivation {
name = "cargo-src";
preferLocalBuild = true;
phases = [ "installPhase" ];
installPhase = ''
RUSTC_SRC=${rustPlatform.rustcSrc.override { minimalContent = false; }} ORIG_CARGO=${originalCargoToml} \
${buildPackages.python3.withPackages (ps: with ps; [ toml ])}/bin/python3 ${./cargo.py}
mkdir -p $out
cp Cargo.toml $out/Cargo.toml
cp ${./Cargo.lock} $out/Cargo.lock
'';
};
in rustPlatform.buildRustPackage {
inherit target RUSTFLAGS;
name = "custom-sysroot";
src = cargoSrc;
RUSTC_BOOTSTRAP = 1;
__internal_dontAddSysroot = true;
cargoSha256 = "0y6dqfhsgk00y3fv5bnjzk0s7i30nwqc1rp0xlrk83hkh80x81mw";
doCheck = false;
installPhase = ''
export LIBS_DIR=$out/lib/rustlib/${shortTarget}/lib
mkdir -p $LIBS_DIR
for f in target/${shortTarget}/release/deps/*.{rlib,rmeta}; do
cp $f $LIBS_DIR
done
export RUST_SYSROOT=$(rustc --print=sysroot)
host=${rust.toRustTarget stdenv.buildPlatform}
cp -r $RUST_SYSROOT/lib/rustlib/$host $out
'';
}
@@ -0,0 +1,21 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p python3 python3.pkgs.toml cargo
set -e
HERE=$(dirname "${BASH_SOURCE[0]}")
NIXPKGS_ROOT="$HERE/../../../.."
# https://unix.stackexchange.com/a/84980/390173
tempdir=$(mktemp -d 2>/dev/null || mktemp -d -t 'update-lockfile')
cd "$tempdir"
nix-build -E "with import (/. + \"${NIXPKGS_ROOT}\") {}; pkgs.rustPlatform.rustcSrc.override { minimalContent = false; }"
RUSTC_SRC="$(pwd)/result" python3 "$HERE/cargo.py"
RUSTC_BOOTSTRAP=1 cargo build || echo "Build failure is expected. All that's needed is the lockfile."
cp Cargo.lock "$HERE"
rm -rf "$tempdir"