summary refs log tree commit diff
path: root/pkgs/build-support/rust
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2021-08-04 10:43:07 +0000
committerAlyssa Ross <hi@alyssa.is>2021-08-04 10:43:07 +0000
commit62614cbef7da005c1eda8c9400160f6bcd6546b8 (patch)
treec2630f69080637987b68acb1ee8676d2681fe304 /pkgs/build-support/rust
parentd9c82ed3044c72cecf01c6ea042489d30914577c (diff)
parente24069138dfec3ef94f211f1da005bb5395adc11 (diff)
downloadnixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar
nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar.gz
nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar.bz2
nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar.lz
nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar.xz
nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.tar.zst
nixpkgs-62614cbef7da005c1eda8c9400160f6bcd6546b8.zip
Merge branch 'nixpkgs-update' into master
Diffstat (limited to 'pkgs/build-support/rust')
-rw-r--r--pkgs/build-support/rust/build-rust-crate/build-crate.nix15
-rw-r--r--pkgs/build-support/rust/build-rust-crate/configure-crate.nix13
-rw-r--r--pkgs/build-support/rust/build-rust-crate/default.nix28
-rw-r--r--pkgs/build-support/rust/build-rust-crate/test/default.nix72
-rw-r--r--pkgs/build-support/rust/default-crate-overrides.nix79
-rw-r--r--pkgs/build-support/rust/default.nix252
-rw-r--r--pkgs/build-support/rust/fetchCargoTarball.nix21
-rw-r--r--pkgs/build-support/rust/fetchcrate.nix7
-rw-r--r--pkgs/build-support/rust/hooks/cargo-build-hook.sh41
-rw-r--r--pkgs/build-support/rust/hooks/cargo-check-hook.sh46
-rw-r--r--pkgs/build-support/rust/hooks/cargo-install-hook.sh49
-rw-r--r--pkgs/build-support/rust/hooks/cargo-setup-hook.sh86
-rw-r--r--pkgs/build-support/rust/hooks/default.nix95
-rw-r--r--pkgs/build-support/rust/hooks/maturin-build-hook.sh39
-rw-r--r--pkgs/build-support/rust/import-cargo-lock.nix175
-rw-r--r--pkgs/build-support/rust/sysroot/Cargo.lock29
-rw-r--r--pkgs/build-support/rust/sysroot/cargo.py45
-rw-r--r--pkgs/build-support/rust/sysroot/default.nix41
-rwxr-xr-xpkgs/build-support/rust/sysroot/update-lockfile.sh21
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/basic/Cargo.lock83
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/basic/Cargo.toml8
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/basic/default.nix18
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/basic/src/main.rs9
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/default.nix8
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/git-dependency-no-rev/Cargo.lock79
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/git-dependency-no-rev/Cargo.toml8
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/git-dependency-no-rev/default.nix21
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/git-dependency-no-rev/src/main.rs9
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/git-dependency/Cargo.lock79
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/git-dependency/Cargo.toml8
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/git-dependency/default.nix21
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/git-dependency/src/main.rs9
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/maturin/Cargo.lock682
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/maturin/default.nix43
34 files changed, 1991 insertions, 248 deletions
diff --git a/pkgs/build-support/rust/build-rust-crate/build-crate.nix b/pkgs/build-support/rust/build-rust-crate/build-crate.nix
index 142109cef49..3441e2c5e7b 100644
--- a/pkgs/build-support/rust/build-rust-crate/build-crate.nix
+++ b/pkgs/build-support/rust/build-rust-crate/build-crate.nix
@@ -9,13 +9,14 @@
 
   let
     baseRustcOpts =
-      [(if release then "-C opt-level=3" else "-C debuginfo=2")]
-      ++ ["-C codegen-units=$NIX_BUILD_CORES"]
-      ++ ["--remap-path-prefix=$NIX_BUILD_TOP=/" ]
-      ++ [(mkRustcDepArgs dependencies crateRenames)]
-      ++ [(mkRustcFeatureArgs crateFeatures)]
-      ++ extraRustcOpts
-      ++ lib.optional (stdenv.hostPlatform != stdenv.buildPlatform) "--target ${rust.toRustTarget stdenv.hostPlatform} -C linker=${stdenv.hostPlatform.config}-gcc"
+      [
+        (if release then "-C opt-level=3" else "-C debuginfo=2")
+        "-C codegen-units=$NIX_BUILD_CORES"
+        "--remap-path-prefix=$NIX_BUILD_TOP=/"
+        (mkRustcDepArgs dependencies crateRenames)
+        (mkRustcFeatureArgs crateFeatures)
+      ] ++ extraRustcOpts
+      ++ lib.optional (stdenv.hostPlatform != stdenv.buildPlatform) "--target ${rust.toRustTargetSpec stdenv.hostPlatform} -C linker=${stdenv.hostPlatform.config}-gcc"
       # since rustc 1.42 the "proc_macro" crate is part of the default crate prelude
       # https://github.com/rust-lang/cargo/commit/4d64eb99a4#diff-7f98585dbf9d30aa100c8318e2c77e79R1021-R1022
       ++ lib.optional (lib.elem "proc-macro" crateType) "--extern proc_macro"
diff --git a/pkgs/build-support/rust/build-rust-crate/configure-crate.nix b/pkgs/build-support/rust/build-rust-crate/configure-crate.nix
index a95b356646e..d1010ac1adb 100644
--- a/pkgs/build-support/rust/build-rust-crate/configure-crate.nix
+++ b/pkgs/build-support/rust/build-rust-crate/configure-crate.nix
@@ -1,4 +1,4 @@
-{ lib, stdenv, echo_colored, noisily, mkRustcDepArgs, mkRustcFeatureArgs }:
+{ lib, stdenv, rust, echo_colored, noisily, mkRustcDepArgs, mkRustcFeatureArgs }:
 {
   build
 , buildDependencies
@@ -17,7 +17,6 @@
 , libName
 , libPath
 , release
-, target_os
 , verbose
 , workspace_member }:
 let version_ = lib.splitString "-" crateVersion;
@@ -124,8 +123,8 @@ in ''
   export CARGO_PKG_AUTHORS="${authors}"
   export CARGO_PKG_DESCRIPTION="${crateDescription}"
 
-  export CARGO_CFG_TARGET_ARCH=${stdenv.hostPlatform.parsed.cpu.name}
-  export CARGO_CFG_TARGET_OS=${target_os}
+  export CARGO_CFG_TARGET_ARCH=${rust.toTargetArch stdenv.hostPlatform}
+  export CARGO_CFG_TARGET_OS=${rust.toTargetOs stdenv.hostPlatform}
   export CARGO_CFG_TARGET_FAMILY="unix"
   export CARGO_CFG_UNIX=1
   export CARGO_CFG_TARGET_ENV="gnu"
@@ -136,8 +135,8 @@ in ''
   export CARGO_MANIFEST_DIR=$(pwd)
   export DEBUG="${toString (!release)}"
   export OPT_LEVEL="${toString optLevel}"
-  export TARGET="${stdenv.hostPlatform.config}"
-  export HOST="${stdenv.hostPlatform.config}"
+  export TARGET="${rust.toRustTargetSpec stdenv.hostPlatform}"
+  export HOST="${rust.toRustTargetSpec stdenv.buildPlatform}"
   export PROFILE=${if release then "release" else "debug"}
   export OUT_DIR=$(pwd)/target/build/${crateName}.out
   export CARGO_PKG_VERSION_MAJOR=${lib.elemAt version 0}
@@ -145,7 +144,7 @@ in ''
   export CARGO_PKG_VERSION_PATCH=${lib.elemAt version 2}
   export CARGO_PKG_VERSION_PRE="${versionPre}"
   export CARGO_PKG_HOMEPAGE="${crateHomepage}"
-  export NUM_JOBS=1
+  export NUM_JOBS=$NIX_BUILD_CORES
   export RUSTC="rustc"
   export RUSTDOC="rustdoc"
 
diff --git a/pkgs/build-support/rust/build-rust-crate/default.nix b/pkgs/build-support/rust/build-rust-crate/default.nix
index d559aba1616..e605c9550e5 100644
--- a/pkgs/build-support/rust/build-rust-crate/default.nix
+++ b/pkgs/build-support/rust/build-rust-crate/default.nix
@@ -4,15 +4,10 @@
 # This can be useful for deploying packages with NixOps, and to share
 # binary dependencies between projects.
 
-{ lib, stdenv, defaultCrateOverrides, fetchCrate, rustc, rust, cargo, jq }:
+{ lib, stdenv, defaultCrateOverrides, fetchCrate, pkgsBuildBuild, rustc, rust
+, cargo, jq }:
 
 let
-    # This doesn't appear to be officially documented anywhere yet.
-    # See https://github.com/rust-lang-nursery/rust-forge/issues/101.
-    target_os = if stdenv.hostPlatform.isDarwin
-      then "macos"
-      else stdenv.hostPlatform.parsed.kernel.name;
-
     # Create rustc arguments to link against the given list of dependencies
     # and renames.
     #
@@ -51,7 +46,7 @@ let
    inherit (import ./log.nix { inherit lib; }) noisily echo_colored;
 
    configureCrate = import ./configure-crate.nix {
-     inherit lib stdenv echo_colored noisily mkRustcDepArgs mkRustcFeatureArgs;
+     inherit lib stdenv rust echo_colored noisily mkRustcDepArgs mkRustcFeatureArgs;
    };
 
    buildCrate = import ./build-crate.nix {
@@ -59,6 +54,10 @@ let
    };
 
    installCrate = import ./install-crate.nix { inherit stdenv; };
+
+   # Allow access to the rust attribute set from inside buildRustCrate, which
+   # has a parameter that shadows the name.
+   rustAttrs = rust;
 in
 
 /* The overridable pkgs.buildRustCrate function.
@@ -83,6 +82,8 @@ in
    # A list of rust/cargo features to enable while building the crate.
    # Example: [ "std" "async" ]
    , features
+   # Additional native build inputs for building this crate.
+   , nativeBuildInputs
    # Additional build inputs for building this crate.
    #
    # Example: [ pkgs.openssl ]
@@ -188,12 +189,13 @@ let crate = crate_ // (lib.attrByPath [ crate_.crateName ] (attr: {}) crateOverr
     dependencies_ = dependencies;
     buildDependencies_ = buildDependencies;
     processedAttrs = [
-      "src" "buildInputs" "crateBin" "crateLib" "libName" "libPath"
+      "src" "nativeBuildInputs" "buildInputs" "crateBin" "crateLib" "libName" "libPath"
       "buildDependencies" "dependencies" "features" "crateRenames"
       "crateName" "version" "build" "authors" "colors" "edition"
       "buildTests"
     ];
     extraDerivationAttrs = builtins.removeAttrs crate processedAttrs;
+    nativeBuildInputs_ = nativeBuildInputs;
     buildInputs_ = buildInputs;
     extraRustcOpts_ = extraRustcOpts;
     buildTests_ = buildTests;
@@ -225,7 +227,8 @@ stdenv.mkDerivation (rec {
     src = crate.src or (fetchCrate { inherit (crate) crateName version sha256; });
     name = "rust_${crate.crateName}-${crate.version}${lib.optionalString buildTests_ "-test"}";
     version = crate.version;
-    depsBuildBuild = [ rust stdenv.cc cargo jq ];
+    depsBuildBuild = [ pkgsBuildBuild.stdenv.cc ];
+    nativeBuildInputs = [ rust stdenv.cc cargo jq ] ++ (crate.nativeBuildInputs or []) ++ nativeBuildInputs_;
     buildInputs = (crate.buildInputs or []) ++ buildInputs_;
     dependencies = map lib.getLib dependencies_;
     buildDependencies = map lib.getLib buildDependencies_;
@@ -251,7 +254,7 @@ stdenv.mkDerivation (rec {
       depsMetadata = lib.foldl' (str: dep: str + dep.metadata) "" (dependencies ++ buildDependencies);
       hashedMetadata = builtins.hashString "sha256"
         (crateName + "-" + crateVersion + "___" + toString (mkRustcFeatureArgs crateFeatures) +
-          "___" + depsMetadata);
+          "___" + depsMetadata + "___" + rustAttrs.toRustTarget stdenv.hostPlatform);
       in lib.substring 0 10 hashedMetadata;
 
     build = crate.build or "";
@@ -279,7 +282,7 @@ stdenv.mkDerivation (rec {
       inherit crateName buildDependencies completeDeps completeBuildDeps crateDescription
               crateFeatures crateRenames libName build workspace_member release libPath crateVersion
               extraLinkFlags extraRustcOpts
-              crateAuthors crateHomepage verbose colors target_os;
+              crateAuthors crateHomepage verbose colors;
     };
     buildPhase = buildCrate {
       inherit crateName dependencies
@@ -301,6 +304,7 @@ stdenv.mkDerivation (rec {
   verbose = crate_.verbose or true;
   extraRustcOpts = [];
   features = [];
+  nativeBuildInputs = [];
   buildInputs = [];
   crateOverrides = defaultCrateOverrides;
   preUnpack = crate_.preUnpack or "";
diff --git a/pkgs/build-support/rust/build-rust-crate/test/default.nix b/pkgs/build-support/rust/build-rust-crate/test/default.nix
index 112aa72fec7..65c8880b134 100644
--- a/pkgs/build-support/rust/build-rust-crate/test/default.nix
+++ b/pkgs/build-support/rust/build-rust-crate/test/default.nix
@@ -1,4 +1,5 @@
 { lib
+, buildPackages
 , buildRustCrate
 , callPackage
 , releaseTools
@@ -10,13 +11,14 @@
 }:
 
 let
-  mkCrate = args: let
+  mkCrate = buildRustCrate: args: let
     p = {
       crateName = "nixtestcrate";
       version = "0.1.0";
       authors = [ "Test <test@example.com>" ];
     } // args;
   in buildRustCrate p;
+  mkHostCrate = mkCrate buildRustCrate;
 
   mkCargoToml =
     { name, crateVersion ? "0.1.0", path ? "Cargo.toml" }:
@@ -68,15 +70,15 @@ let
   mkLib = name: mkFile name "pub fn test() -> i32 { return 23; }";
 
   mkTest = crateArgs: let
-    crate = mkCrate (builtins.removeAttrs crateArgs ["expectedTestOutput"]);
+    crate = mkHostCrate (builtins.removeAttrs crateArgs ["expectedTestOutput"]);
     hasTests = crateArgs.buildTests or false;
     expectedTestOutputs = crateArgs.expectedTestOutputs or null;
-    binaries = map (v: ''"${v.name}"'') (crateArgs.crateBin or []);
+    binaries = map (v: lib.escapeShellArg v.name) (crateArgs.crateBin or []);
     isLib = crateArgs ? libName || crateArgs ? libPath;
     crateName = crateArgs.crateName or "nixtestcrate";
     libName = crateArgs.libName or crateName;
 
-    libTestBinary = if !isLib then null else mkCrate {
+    libTestBinary = if !isLib then null else mkHostCrate {
       crateName = "run-test-${crateName}";
       dependencies = [ crate ];
       src = mkBinExtern "src/main.rs" libName;
@@ -89,18 +91,27 @@ let
       runCommand "run-buildRustCrate-${crateName}-test" {
         nativeBuildInputs = [ crate ];
       } (if !hasTests then ''
-          ${lib.concatStringsSep "\n" binaries}
+          ${lib.concatMapStringsSep "\n" (binary:
+            # Can't actually run the binary when cross-compiling
+            (lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) "type ") + binary
+          ) binaries}
           ${lib.optionalString isLib ''
               test -e ${crate}/lib/*.rlib || exit 1
-              ${libTestBinary}/bin/run-test-${crateName}
+              ${lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) "test -x "} \
+                ${libTestBinary}/bin/run-test-${crateName}
           ''}
           touch $out
-        '' else ''
+        '' else if stdenv.hostPlatform == stdenv.buildPlatform then ''
           for file in ${crate}/tests/*; do
             $file 2>&1 >> $out
           done
           set -e
           ${lib.concatMapStringsSep "\n" (o: "grep '${o}' $out || {  echo 'output \"${o}\" not found in:'; cat $out; exit 23; }") expectedTestOutputs}
+        '' else ''
+          for file in ${crate}/tests/*; do
+            test -x "$file"
+          done
+          touch "$out"
         ''
       );
 
@@ -109,7 +120,7 @@ let
 
        `name` is used as part of the derivation name that performs the checking.
 
-       `crateArgs` is passed to `mkCrate` to build the crate with `buildRustCrate`.
+       `crateArgs` is passed to `mkHostCrate` to build the crate with `buildRustCrate`.
 
        `expectedFiles` contains a list of expected file paths in the output. E.g.
        `[ "./bin/my_binary" ]`.
@@ -124,7 +135,7 @@ let
       assert (builtins.isList expectedFiles);
 
       let
-        crate = mkCrate (builtins.removeAttrs crateArgs ["expectedTestOutput"]);
+        crate = mkHostCrate (builtins.removeAttrs crateArgs ["expectedTestOutput"]);
         crateOutput = if output == null then crate else crate."${output}";
         expectedFilesFile = writeTextFile {
           name = "expected-files-${name}";
@@ -135,12 +146,18 @@ let
         };
       in
       runCommand "assert-outputs-${name}" {
-      } ''
+      } (''
       local actualFiles=$(mktemp)
 
       cd "${crateOutput}"
-      find . -type f | sort >$actualFiles
-      diff -q ${expectedFilesFile} $actualFiles >/dev/null || {
+      find . -type f \
+        | sort \
+      ''
+      # sed out the hash because it differs per platform
+      + ''
+        | sed -E -e 's/-[0-9a-fA-F]{10}\.rlib/-HASH.rlib/g' \
+        > "$actualFiles"
+      diff -q ${expectedFilesFile} "$actualFiles" > /dev/null || {
         echo -e "\033[0;1;31mERROR: Difference in expected output files in ${crateOutput} \033[0m" >&2
         echo === Got:
         sed -e 's/^/  /' $actualFiles
@@ -153,7 +170,7 @@ let
         exit 1
       }
       touch $out
-      ''
+      '')
       ;
 
   in rec {
@@ -188,17 +205,17 @@ let
       crateBinRename1 = {
         crateBin = [{ name = "my-binary-rename1"; }];
         src = mkBinExtern "src/main.rs" "foo_renamed";
-        dependencies = [ (mkCrate { crateName = "foo"; src = mkLib "src/lib.rs"; }) ];
+        dependencies = [ (mkHostCrate { crateName = "foo"; src = mkLib "src/lib.rs"; }) ];
         crateRenames = { "foo" = "foo_renamed"; };
       };
       crateBinRename2 = {
         crateBin = [{ name = "my-binary-rename2"; }];
         src = mkBinExtern "src/main.rs" "foo_renamed";
-        dependencies = [ (mkCrate { crateName = "foo"; libName = "foolib"; src = mkLib "src/lib.rs"; }) ];
+        dependencies = [ (mkHostCrate { crateName = "foo"; libName = "foolib"; src = mkLib "src/lib.rs"; }) ];
         crateRenames = { "foo" = "foo_renamed"; };
       };
       crateBinRenameMultiVersion = let
-        crateWithVersion = version: mkCrate {
+        crateWithVersion = version: mkHostCrate {
           crateName = "my_lib";
           inherit version;
           src = mkFile "src/lib.rs" ''
@@ -307,7 +324,7 @@ let
           fn main() {}
         '';
         dependencies = [
-          (mkCrate {
+          (mkHostCrate {
             crateName = "somerlib";
             type = [ "rlib" ];
             src = mkLib "src/lib.rs";
@@ -315,7 +332,7 @@ let
         ];
       };
       buildScriptDeps = let
-        depCrate = boolVal: mkCrate {
+        depCrate = buildRustCrate: boolVal: mkCrate buildRustCrate {
           crateName = "bar";
           src = mkFile "src/lib.rs" ''
             pub const baz: bool = ${boolVal};
@@ -339,8 +356,8 @@ let
             '')
           ];
         };
-        buildDependencies = [ (depCrate "true") ];
-        dependencies = [ (depCrate "false") ];
+        buildDependencies = [ (depCrate buildPackages.buildRustCrate "true") ];
+        dependencies = [ (depCrate buildRustCrate "false") ];
         buildTests = true;
         expectedTestOutputs = [ "test baz_false ... ok" ];
       };
@@ -373,7 +390,7 @@ let
       # Regression test for https://github.com/NixOS/nixpkgs/pull/88054
       # Build script output should be rewritten as valid env vars.
       buildScriptIncludeDirDeps = let
-        depCrate = mkCrate {
+        depCrate = mkHostCrate {
           crateName = "bar";
           src = symlinkJoin {
             name = "build-script-and-include-dir-bar";
@@ -460,7 +477,7 @@ let
             mkdir -p $out/lib
             # Note: On darwin (which defaults to clang) we have to add
             # `-undefined dynamic_lookup` as otherwise the compilation fails.
-            cc -shared \
+            $CC -shared \
               ${lib.optionalString stdenv.isDarwin "-undefined dynamic_lookup"} \
               -o $out/lib/${name}${stdenv.hostPlatform.extensions.sharedLibrary} ${src}
           '';
@@ -519,6 +536,7 @@ let
           };
       procMacroInPrelude = {
         procMacro = true;
+        edition = "2018";
         src = symlinkJoin {
           name = "proc-macro-in-prelude";
           paths = [
@@ -582,7 +600,7 @@ let
       };
       expectedFiles = [
         "./nix-support/propagated-build-inputs"
-        "./lib/libtest_lib-042a1fdbef.rlib"
+        "./lib/libtest_lib-HASH.rlib"
         "./lib/link"
       ];
     };
@@ -599,7 +617,7 @@ let
       };
       expectedFiles = [
         "./nix-support/propagated-build-inputs"
-        "./lib/libtest_lib-042a1fdbef.rlib"
+        "./lib/libtest_lib-HASH.rlib"
         "./lib/link"
       ];
     };
@@ -608,9 +626,11 @@ let
       pkg = brotliCrates.brotli_2_5_0 {};
     in runCommand "run-brotli-test-cmd" {
       nativeBuildInputs = [ pkg ];
-    } ''
+    } (if stdenv.hostPlatform == stdenv.buildPlatform then ''
       ${pkg}/bin/brotli -c ${pkg}/bin/brotli > /dev/null && touch $out
-    '';
+    '' else ''
+      test -x '${pkg}/bin/brotli' && touch $out
+    '');
     allocNoStdLibTest = let
       pkg = brotliCrates.alloc_no_stdlib_1_3_0 {};
     in runCommand "run-alloc-no-stdlib-test-cmd" {
diff --git a/pkgs/build-support/rust/default-crate-overrides.nix b/pkgs/build-support/rust/default-crate-overrides.nix
index 1c4fe9daead..61cec2a6aba 100644
--- a/pkgs/build-support/rust/default-crate-overrides.nix
+++ b/pkgs/build-support/rust/default-crate-overrides.nix
@@ -1,6 +1,7 @@
-{ stdenv, pkgconfig, curl, darwin, libiconv, libgit2, libssh2,
+{ lib, stdenv, pkg-config, curl, darwin, libiconv, libgit2, libssh2,
   openssl, sqlite, zlib, dbus, dbus-glib, gdk-pixbuf, cairo, python3,
-  libsodium, postgresql, gmp, foundationdb, ... }:
+  libsodium, postgresql, gmp, foundationdb, capnproto, nettle, clang,
+  llvmPackages, ... }:
 
 let
   inherit (darwin.apple_sdk.frameworks) CoreFoundation Security;
@@ -10,24 +11,31 @@ in
     buildInputs = [ cairo ];
   };
 
+  capnp-rpc = attrs: {
+    nativeBuildInputs = [ capnproto ];
+  };
+
   cargo = attrs: {
     buildInputs = [ openssl zlib curl ]
-      ++ stdenv.lib.optionals stdenv.isDarwin [ CoreFoundation Security libiconv ];
+      ++ lib.optionals stdenv.isDarwin [ CoreFoundation Security libiconv ];
   };
 
   libz-sys = attrs: {
-    buildInputs = [ pkgconfig zlib ];
+    nativeBuildInputs = [ pkg-config ];
+    buildInputs = [ zlib ];
     extraLinkFlags = ["-L${zlib.out}/lib"];
   };
 
   curl-sys = attrs: {
-    buildInputs = [ pkgconfig zlib curl ];
+    nativeBuildInputs = [ pkg-config ];
+    buildInputs = [ zlib curl ];
     propagatedBuildInputs = [ curl zlib ];
     extraLinkFlags = ["-L${zlib.out}/lib"];
   };
 
   dbus = attrs: {
-    buildInputs = [ pkgconfig dbus ];
+    nativeBuildInputs = [ pkg-config ];
+    buildInputs = [ dbus ];
   };
 
   foundationdb-sys = attrs: {
@@ -62,19 +70,29 @@ in
 
   libgit2-sys = attrs: {
     LIBGIT2_SYS_USE_PKG_CONFIG = true;
-    buildInputs = [ pkgconfig openssl zlib libgit2 ];
+    nativeBuildInputs = [ pkg-config ];
+    buildInputs = [ openssl zlib libgit2 ];
   };
 
   libsqlite3-sys = attrs: {
-    buildInputs = [ pkgconfig sqlite ];
+    nativeBuildInputs = [ pkg-config ];
+    buildInputs = [ sqlite ];
   };
 
   libssh2-sys = attrs: {
-    buildInputs = [ pkgconfig openssl zlib libssh2 ];
+    nativeBuildInputs = [ pkg-config ];
+    buildInputs = [ openssl zlib libssh2 ];
   };
 
   libdbus-sys = attrs: {
-    buildInputs = [ pkgconfig dbus ];
+    nativeBuildInputs = [ pkg-config ];
+    buildInputs = [ dbus ];
+  };
+
+  nettle-sys = attrs: {
+    nativeBuildInputs = [ pkg-config ];
+    buildInputs = [ nettle clang ];
+    LIBCLANG_PATH = "${llvmPackages.libclang.lib}/lib";
   };
 
   openssl = attrs: {
@@ -82,11 +100,13 @@ in
   };
 
   openssl-sys = attrs: {
-    buildInputs = [ pkgconfig openssl ];
+    nativeBuildInputs = [ pkg-config ];
+    buildInputs = [ openssl ];
   };
 
   pq-sys = attr: {
-    buildInputs = [ pkgconfig postgresql ];
+    nativeBuildInputs = [ pkg-config ];
+    buildInputs = [ postgresql ];
   };
 
   rink = attrs: {
@@ -98,12 +118,43 @@ in
     propagatedBuildInputs = [ Security ];
   };
 
+  sequoia-openpgp = attrs: {
+    buildInputs = [ gmp ];
+  };
+
+  sequoia-openpgp-ffi = attrs: {
+    buildInputs = [ gmp ];
+  };
+
+  sequoia-ipc = attrs: {
+    buildInputs = [ gmp ];
+  };
+
+  sequoia-guide = attrs: {
+    buildInputs = [ gmp ];
+  };
+
+  sequoia-store = attrs: {
+    nativeBuildInputs = [ capnproto ];
+    buildInputs = [ sqlite gmp ];
+  };
+
+  sequoia-sq = attrs: {
+    buildInputs = [ sqlite gmp ];
+  };
+
+  sequoia-tool = attrs: {
+    nativeBuildInputs = [ capnproto ];
+    buildInputs = [ sqlite gmp ];
+  };
+
   serde_derive = attrs: {
-    buildInputs = stdenv.lib.optional stdenv.isDarwin Security;
+    buildInputs = lib.optional stdenv.isDarwin Security;
   };
 
   thrussh-libsodium = attrs: {
-    buildInputs = [ pkgconfig libsodium ];
+    nativeBuildInputs = [ pkg-config ];
+    buildInputs = [ libsodium ];
   };
 
   xcb = attrs: {
diff --git a/pkgs/build-support/rust/default.nix b/pkgs/build-support/rust/default.nix
index c292b8ea4d4..be983af1c11 100644
--- a/pkgs/build-support/rust/default.nix
+++ b/pkgs/build-support/rust/default.nix
@@ -1,17 +1,35 @@
 { stdenv
+, lib
 , buildPackages
 , cacert
-, cargo
-, diffutils
+, cargoBuildHook
+, cargoCheckHook
+, cargoInstallHook
+, cargoSetupHook
 , fetchCargoTarball
+, importCargoLock
+, runCommandNoCC
+, rustPlatform
+, callPackage
+, remarshal
 , git
 , rust
 , rustc
+, libiconv
 , windows
 }:
 
 { name ? "${args.pname}-${args.version}"
-, cargoSha256 ? "unset"
+
+  # SRI hash
+, cargoHash ? ""
+
+  # Legacy hash
+, cargoSha256 ? ""
+
+  # Name for the vendored dependencies tarball
+, cargoDepsName ? name
+
 , src ? null
 , srcs ? null
 , unpackPhase ? null
@@ -23,12 +41,15 @@
 , nativeBuildInputs ? []
 , cargoUpdateHook ? ""
 , cargoDepsHook ? ""
-, cargoBuildFlags ? []
 , buildType ? "release"
 , meta ? {}
-, target ? null
+, cargoLock ? null
 , 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
@@ -37,59 +58,74 @@
 , buildAndTestSubdir ? null
 , ... } @ args:
 
-assert cargoVendorDir == null -> cargoSha256 != "unset";
+assert cargoVendorDir == null && cargoLock == null -> cargoSha256 == "" && cargoHash == ""
+  -> throw "cargoSha256, cargoHash, cargoVendorDir, or cargoLock must be set";
 assert buildType == "release" || buildType == "debug";
 
 let
 
-  cargoDeps = if cargoVendorDir == null
-    then fetchCargoTarball {
-        inherit name src srcs sourceRoot unpackPhase cargoUpdateHook;
-        patches = cargoPatches;
-        sha256 = cargoSha256;
-      }
+  cargoDeps =
+    if cargoVendorDir == null
+    then if cargoLock != null then importCargoLock cargoLock
+    else 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 = cargoSha256 != "unset";
-
-  # Some cargo builds include build hooks that modify their own vendor
-  # dependencies. This copies the vendor directory into the build tree and makes
-  # it writable. If we're using a tarball, the unpackFile hook already handles
-  # this for us automatically.
-  setupVendorDir = if cargoVendorDir == null
-    then (''
-      unpackFile "$cargoDeps"
-      cargoDepsCopy=$(stripHash $cargoDeps)
-    '')
-    else ''
-      cargoDepsCopy="$sourceRoot/${cargoVendorDir}"
-    '';
-
-  rustTarget = if target == null then rust.toRustTarget stdenv.hostPlatform 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++";
-  releaseDir = "target/${rustTarget}/${buildType}";
-  tmpDir = "${releaseDir}-tmp";
-
-  # Specify the stdenv's `diff` by abspath to ensure that the user's build
-  # inputs do not cause us to find the wrong `diff`.
-  # The `.nativeDrv` stanza works like nativeBuildInputs and ensures cross-compiling has the right version available.
-  diff = "${diffutils.nativeDrv or diffutils}/bin/diff";
+  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
 
-stdenv.mkDerivation (args // {
-  inherit cargoDeps;
+# 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" "cargoLock" ]) // lib.optionalAttrs useSysroot {
+  RUSTFLAGS = "--sysroot ${sysroot} " + (args.RUSTFLAGS or "");
+} // {
+  inherit buildAndTestSubdir cargoDeps;
+
+  cargoBuildType = buildType;
+
+  cargoCheckType = checkType;
 
   patchRegistryDeps = ./patch-registry-deps;
 
-  nativeBuildInputs = nativeBuildInputs ++ [ cacert git cargo rustc ];
-  buildInputs = buildInputs ++ stdenv.lib.optional stdenv.hostPlatform.isMinGW windows.pthreads;
+  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;
 
@@ -99,146 +135,18 @@ stdenv.mkDerivation (args // {
   postUnpack = ''
     eval "$cargoDepsHook"
 
-    ${setupVendorDir}
-
-    mkdir .cargo
-    config="$(pwd)/$cargoDepsCopy/.cargo/config";
-    if [[ ! -e $config ]]; then
-      config=${./fetchcargo-default-config.toml};
-    fi;
-    substitute $config .cargo/config \
-      --subst-var-by vendor "$(pwd)/$cargoDepsCopy"
-
-    cat >> .cargo/config <<'EOF'
-    [target."${rust.toRustTarget stdenv.buildPlatform}"]
-    "linker" = "${ccForBuild}"
-    ${stdenv.lib.optionalString (stdenv.buildPlatform.config != stdenv.hostPlatform.config) ''
-    [target."${rustTarget}"]
-    "linker" = "${ccForHost}"
-    ${# https://github.com/rust-lang/rust/issues/46651#issuecomment-433611633
-      stdenv.lib.optionalString (stdenv.hostPlatform.isMusl && stdenv.hostPlatform.isAarch64) ''
-    "rustflags" = [ "-C", "target-feature=+crt-static", "-C", "link-arg=-lgcc" ]
-    ''}
-    ''}
-    EOF
-
     export RUST_LOG=${logLevel}
   '' + (args.postUnpack or "");
 
-  # After unpacking and applying patches, check that the Cargo.lock matches our
-  # src package. Note that we do this after the patchPhase, because the
-  # patchPhase may create the Cargo.lock if upstream has not shipped one.
-  postPatch = (args.postPatch or "") + stdenv.lib.optionalString validateCargoDeps ''
-    cargoDepsLockfile=$NIX_BUILD_TOP/$cargoDepsCopy/Cargo.lock
-    srcLockfile=$NIX_BUILD_TOP/$sourceRoot/Cargo.lock
-
-    echo "Validating consistency between $srcLockfile and $cargoDepsLockfile"
-    if ! ${diff} $srcLockfile $cargoDepsLockfile; then
-
-      # If the diff failed, first double-check that the file exists, so we can
-      # give a friendlier error msg.
-      if ! [ -e $srcLockfile ]; then
-        echo "ERROR: Missing Cargo.lock from src. Expected to find it at: $srcLockfile"
-        echo "Hint: You can use the cargoPatches attribute to add a Cargo.lock manually to the build."
-        exit 1
-      fi
-
-      if ! [ -e $cargoDepsLockfile ]; then
-        echo "ERROR: Missing lockfile from cargo vendor. Expected to find it at: $cargoDepsLockfile"
-        exit 1
-      fi
-
-      echo
-      echo "ERROR: cargoSha256 is out of date"
-      echo
-      echo "Cargo.lock is not the same in $cargoDepsCopy"
-      echo
-      echo "To fix the issue:"
-      echo '1. Use "0000000000000000000000000000000000000000000000000000" as the cargoSha256 value'
-      echo "2. Build the derivation and wait it to fail with a hash mismatch"
-      echo "3. Copy the 'got: sha256:' value back into the cargoSha256 field"
-      echo
-
-      exit 1
-    fi
-  '' + ''
-    unset cargoDepsCopy
-  '';
-
   configurePhase = args.configurePhase or ''
     runHook preConfigure
     runHook postConfigure
   '';
 
-  buildPhase = with builtins; args.buildPhase or ''
-    ${stdenv.lib.optionalString (buildAndTestSubdir != null) "pushd ${buildAndTestSubdir}"}
-    runHook preBuild
-
-    (
-    set -x
-    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 \
-        ${stdenv.lib.optionalString (buildType == "release") "--release"} \
-        --target ${rustTarget} \
-        --frozen ${concatStringsSep " " cargoBuildFlags}
-    )
-
-    runHook postBuild
-
-    ${stdenv.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
-    argstr = "${stdenv.lib.optionalString (checkType == "release") "--release"} --target ${rustTarget} --frozen";
-  in ''
-    ${stdenv.lib.optionalString (buildAndTestSubdir != null) "pushd ${buildAndTestSubdir}"}
-    runHook preCheck
-    echo "Running cargo test ${argstr} -- ''${checkFlags} ''${checkFlagsArray+''${checkFlagsArray[@]}}"
-    cargo test ${argstr} -- ''${checkFlags} ''${checkFlagsArray+"''${checkFlagsArray[@]}"}
-    runHook postCheck
-    ${stdenv.lib.optionalString (buildAndTestSubdir != null) "popd"}
-  '');
-
   doCheck = args.doCheck or true;
 
   strictDeps = true;
 
-  inherit releaseDir tmpDir;
-
-  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
-
-    xargs -r cp -t $out/bin <<< $bins
-    find $tmpDir \
-      -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 = {
diff --git a/pkgs/build-support/rust/fetchCargoTarball.nix b/pkgs/build-support/rust/fetchCargoTarball.nix
index dff5d99da9e..3b36554e707 100644
--- a/pkgs/build-support/rust/fetchCargoTarball.nix
+++ b/pkgs/build-support/rust/fetchCargoTarball.nix
@@ -1,4 +1,4 @@
-{ stdenv, cacert, git, cargo, python3 }:
+{ lib, stdenv, cacert, git, cargo, python3 }:
 let cargo-vendor-normalise = stdenv.mkDerivation {
   name = "cargo-vendor-normalise";
   src = ./cargo-vendor-normalise.py;
@@ -21,12 +21,18 @@ in
 , src ? null
 , srcs ? []
 , patches ? []
-, sourceRoot
-, sha256
+, sourceRoot ? ""
+, hash ? ""
+, sha256 ? ""
 , cargoUpdateHook ? ""
 , ...
 } @ args:
-stdenv.mkDerivation ({
+
+let hash_ =
+  if hash != "" then { outputHashAlgo = null; outputHash = hash; }
+  else if sha256 != "" then { outputHashAlgo = "sha256"; outputHash = sha256; }
+  else throw "fetchCargoTarball requires a hash for ${name}";
+in stdenv.mkDerivation ({
   name = "${name}-vendor.tar.gz";
   nativeBuildInputs = [ cacert git cargo-vendor-normalise cargo ];
 
@@ -40,7 +46,7 @@ stdenv.mkDerivation ({
         echo
         echo "ERROR: The Cargo.lock file doesn't exist"
         echo
-        echo "Cargo.lock is needed to make sure that cargoSha256 doesn't change"
+        echo "Cargo.lock is needed to make sure that cargoHash/cargoSha256 doesn't change"
         echo "when the registry is updated."
         echo
 
@@ -72,10 +78,9 @@ stdenv.mkDerivation ({
         -czf $out $name
   '';
 
-  outputHashAlgo = "sha256";
-  outputHash = sha256;
+  inherit (hash_) outputHashAlgo outputHash;
 
-  impureEnvVars = stdenv.lib.fetchers.proxyImpureEnvVars;
+  impureEnvVars = lib.fetchers.proxyImpureEnvVars;
 } // (builtins.removeAttrs args [
   "name" "sha256" "cargoUpdateHook"
 ]))
diff --git a/pkgs/build-support/rust/fetchcrate.nix b/pkgs/build-support/rust/fetchcrate.nix
index 95dfd38b12a..4e6c38b032c 100644
--- a/pkgs/build-support/rust/fetchcrate.nix
+++ b/pkgs/build-support/rust/fetchcrate.nix
@@ -1,10 +1,13 @@
 { lib, fetchurl, unzip }:
 
-{ crateName
+{ crateName ? args.pname
+, pname ? null
 , version
 , sha256
 , ... } @ args:
 
+assert pname == null || pname == crateName;
+
 lib.overrideDerivation (fetchurl ({
 
   name = "${crateName}-${version}.tar.gz";
@@ -30,6 +33,6 @@ lib.overrideDerivation (fetchurl ({
       fi
       mv "$unpackDir/$fn" "$out"
     '';
-} // removeAttrs args [ "crateName" "version" ]))
+} // removeAttrs args [ "crateName" "pname" "version" ]))
 # Hackety-hack: we actually need unzip hooks, too
 (x: {nativeBuildInputs = x.nativeBuildInputs++ [unzip];})
diff --git a/pkgs/build-support/rust/hooks/cargo-build-hook.sh b/pkgs/build-support/rust/hooks/cargo-build-hook.sh
new file mode 100644
index 00000000000..c10120c5aa1
--- /dev/null
+++ b/pkgs/build-support/rust/hooks/cargo-build-hook.sh
@@ -0,0 +1,41 @@
+declare -a cargoBuildFlags
+
+cargoBuildHook() {
+    echo "Executing cargoBuildHook"
+
+    runHook preBuild
+
+    if [ ! -z "${buildAndTestSubdir-}" ]; then
+        pushd "${buildAndTestSubdir}"
+    fi
+
+    if [ "${cargoBuildType}" != "debug" ]; then
+        cargoBuildProfileFlag="--${cargoBuildType}"
+    fi
+
+    (
+    set -x
+    env \
+      "CC_@rustBuildPlatform@=@ccForBuild@" \
+      "CXX_@rustBuildPlatform@=@cxxForBuild@" \
+      "CC_@rustTargetPlatform@=@ccForHost@" \
+      "CXX_@rustTargetPlatform@=@cxxForHost@" \
+      cargo build -j $NIX_BUILD_CORES \
+        --target @rustTargetPlatformSpec@ \
+        --frozen \
+        ${cargoBuildProfileFlag} \
+        ${cargoBuildFlags}
+    )
+
+    if [ ! -z "${buildAndTestSubdir-}" ]; then
+        popd
+    fi
+
+    runHook postBuild
+
+    echo "Finished cargoBuildHook"
+}
+
+if [ -z "${dontCargoBuild-}" ] && [ -z "${buildPhase-}" ]; then
+  buildPhase=cargoBuildHook
+fi
diff --git a/pkgs/build-support/rust/hooks/cargo-check-hook.sh b/pkgs/build-support/rust/hooks/cargo-check-hook.sh
new file mode 100644
index 00000000000..f0339afb38f
--- /dev/null
+++ b/pkgs/build-support/rust/hooks/cargo-check-hook.sh
@@ -0,0 +1,46 @@
+declare -a checkFlags
+declare -a cargoTestFlags
+
+cargoCheckHook() {
+    echo "Executing cargoCheckHook"
+
+    runHook preCheck
+
+    if [[ -n "${buildAndTestSubdir-}" ]]; then
+        pushd "${buildAndTestSubdir}"
+    fi
+
+    if [[ -z ${dontUseCargoParallelTests-} ]]; then
+        threads=$NIX_BUILD_CORES
+    else
+        threads=1
+    fi
+
+    if [ "${cargoBuildType}" != "debug" ]; then
+        cargoBuildProfileFlag="--${cargoBuildType}"
+    fi
+
+    argstr="${cargoBuildProfileFlag} --target @rustTargetPlatformSpec@ --frozen ${cargoTestFlags}";
+
+    (
+        set -x
+        cargo test \
+              -j $NIX_BUILD_CORES \
+              ${argstr} -- \
+              --test-threads=${threads} \
+              ${checkFlags} \
+              ${checkFlagsArray+"${checkFlagsArray[@]}"}
+    )
+
+    if [[ -n "${buildAndTestSubdir-}" ]]; then
+        popd
+    fi
+
+    echo "Finished cargoCheckHook"
+
+    runHook postCheck
+}
+
+if [ -z "${dontCargoCheck-}" ] && [ -z "${checkPhase-}" ]; then
+  checkPhase=cargoCheckHook
+fi
diff --git a/pkgs/build-support/rust/hooks/cargo-install-hook.sh b/pkgs/build-support/rust/hooks/cargo-install-hook.sh
new file mode 100644
index 00000000000..69ce7266936
--- /dev/null
+++ b/pkgs/build-support/rust/hooks/cargo-install-hook.sh
@@ -0,0 +1,49 @@
+cargoInstallPostBuildHook() {
+    echo "Executing cargoInstallPostBuildHook"
+
+    releaseDir=target/@shortTarget@/$cargoBuildType
+    tmpDir="${releaseDir}-tmp";
+
+    mkdir -p $tmpDir
+    cp -r ${releaseDir}/* $tmpDir/
+    bins=$(find $tmpDir \
+      -maxdepth 1 \
+      -type f \
+      -executable ! \( -regex ".*\.\(so.[0-9.]+\|so\|a\|dylib\)" \))
+
+    echo "Finished cargoInstallPostBuildHook"
+}
+
+cargoInstallHook() {
+    echo "Executing cargoInstallHook"
+
+    runHook preInstall
+
+    # rename the output dir to a architecture independent one
+
+    releaseDir=target/@shortTarget@/$cargoBuildType
+    tmpDir="${releaseDir}-tmp";
+
+    mapfile -t targets < <(find "$NIX_BUILD_TOP" -type d | grep "${tmpDir}$")
+    for target in "${targets[@]}"; do
+      rm -rf "$target/../../${cargoBuildType}"
+      ln -srf "$target" "$target/../../"
+    done
+    mkdir -p $out/bin $out/lib
+
+    xargs -r cp -t $out/bin <<< $bins
+    find $tmpDir \
+      -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
+
+    echo "Finished cargoInstallHook"
+}
+
+
+if [ -z "${dontCargoInstall-}" ] && [ -z "${installPhase-}" ]; then
+  installPhase=cargoInstallHook
+  postBuildHooks+=(cargoInstallPostBuildHook)
+fi
diff --git a/pkgs/build-support/rust/hooks/cargo-setup-hook.sh b/pkgs/build-support/rust/hooks/cargo-setup-hook.sh
new file mode 100644
index 00000000000..842e66b5170
--- /dev/null
+++ b/pkgs/build-support/rust/hooks/cargo-setup-hook.sh
@@ -0,0 +1,86 @@
+cargoSetupPostUnpackHook() {
+    echo "Executing cargoSetupPostUnpackHook"
+
+    # Some cargo builds include build hooks that modify their own vendor
+    # dependencies. This copies the vendor directory into the build tree and makes
+    # it writable. If we're using a tarball, the unpackFile hook already handles
+    # this for us automatically.
+    if [ -z $cargoVendorDir ]; then
+        unpackFile "$cargoDeps"
+        export cargoDepsCopy=$(stripHash $cargoDeps)
+    else
+      cargoDepsCopy="$sourceRoot/${cargoRoot:+$cargoRoot/}${cargoVendorDir}"
+    fi
+
+    if [ ! -d .cargo ]; then
+        mkdir .cargo
+    fi
+
+    config="$(pwd)/$cargoDepsCopy/.cargo/config";
+    if [[ ! -e $config ]]; then
+      config=@defaultConfig@
+    fi;
+
+    tmp_config=$(mktemp)
+    substitute $config $tmp_config \
+      --subst-var-by vendor "$(pwd)/$cargoDepsCopy"
+    cat ${tmp_config} >> .cargo/config
+
+    cat >> .cargo/config <<'EOF'
+    @rustTarget@
+EOF
+
+    echo "Finished cargoSetupPostUnpackHook"
+}
+
+# After unpacking and applying patches, check that the Cargo.lock matches our
+# src package. Note that we do this after the patchPhase, because the
+# patchPhase may create the Cargo.lock if upstream has not shipped one.
+cargoSetupPostPatchHook() {
+    echo "Executing cargoSetupPostPatchHook"
+
+    cargoDepsLockfile="$NIX_BUILD_TOP/$cargoDepsCopy/Cargo.lock"
+    srcLockfile="$NIX_BUILD_TOP/$sourceRoot/${cargoRoot:+$cargoRoot/}/Cargo.lock"
+
+    echo "Validating consistency between $srcLockfile and $cargoDepsLockfile"
+    if ! @diff@ $srcLockfile $cargoDepsLockfile; then
+
+      # If the diff failed, first double-check that the file exists, so we can
+      # give a friendlier error msg.
+      if ! [ -e $srcLockfile ]; then
+        echo "ERROR: Missing Cargo.lock from src. Expected to find it at: $srcLockfile"
+        echo "Hint: You can use the cargoPatches attribute to add a Cargo.lock manually to the build."
+        exit 1
+      fi
+
+      if ! [ -e $cargoDepsLockfile ]; then
+        echo "ERROR: Missing lockfile from cargo vendor. Expected to find it at: $cargoDepsLockfile"
+        exit 1
+      fi
+
+      echo
+      echo "ERROR: cargoSha256 is out of date"
+      echo
+      echo "Cargo.lock is not the same in $cargoDepsCopy"
+      echo
+      echo "To fix the issue:"
+      echo '1. Use "0000000000000000000000000000000000000000000000000000" as the cargoSha256 value'
+      echo "2. Build the derivation and wait for it to fail with a hash mismatch"
+      echo "3. Copy the 'got: sha256:' value back into the cargoSha256 field"
+      echo
+
+      exit 1
+    fi
+
+    unset cargoDepsCopy
+
+    echo "Finished cargoSetupPostPatchHook"
+}
+
+if [ -z "${dontCargoSetupPostUnpack-}" ]; then
+  postUnpackHooks+=(cargoSetupPostUnpackHook)
+fi
+
+if [ -z ${cargoVendorDir-} ]; then
+  postPatchHooks+=(cargoSetupPostPatchHook)
+fi
diff --git a/pkgs/build-support/rust/hooks/default.nix b/pkgs/build-support/rust/hooks/default.nix
new file mode 100644
index 00000000000..d86c9ebaed8
--- /dev/null
+++ b/pkgs/build-support/rust/hooks/default.nix
@@ -0,0 +1,95 @@
+{ buildPackages
+, callPackage
+, cargo
+, diffutils
+, lib
+, makeSetupHook
+, maturin
+, rust
+, rustc
+, stdenv
+, target ? rust.toRustTargetSpec stdenv.hostPlatform
+}:
+
+let
+  targetIsJSON = lib.hasSuffix ".json" target;
+
+  # 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;
+  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";
+      deps = [ cargo ];
+      substitutions = {
+        inherit ccForBuild ccForHost cxxForBuild cxxForHost
+          rustBuildPlatform rustTargetPlatform rustTargetPlatformSpec;
+      };
+    } ./cargo-build-hook.sh) {};
+
+  cargoCheckHook = callPackage ({ }:
+    makeSetupHook {
+      name = "cargo-check-hook.sh";
+      deps = [ cargo ];
+      substitutions = {
+        inherit rustTargetPlatformSpec;
+      };
+    } ./cargo-check-hook.sh) {};
+
+  cargoInstallHook = callPackage ({ }:
+    makeSetupHook {
+      name = "cargo-install-hook.sh";
+      deps = [ ];
+      substitutions = {
+        inherit shortTarget;
+      };
+    } ./cargo-install-hook.sh) {};
+
+  cargoSetupHook = callPackage ({ }:
+    makeSetupHook {
+      name = "cargo-setup-hook.sh";
+      deps = [ ];
+      substitutions = {
+        defaultConfig = ../fetchcargo-default-config.toml;
+
+        # Specify the stdenv's `diff` by abspath to ensure that the user's build
+        # inputs do not cause us to find the wrong `diff`.
+        # The `.nativeDrv` stanza works like nativeBuildInputs and ensures cross-compiling has the right version available.
+        diff = "${diffutils.nativeDrv or diffutils}/bin/diff";
+
+        # Target platform
+        rustTarget = ''
+          [target."${rust.toRustTarget stdenv.buildPlatform}"]
+          "linker" = "${ccForBuild}"
+          ${lib.optionalString (stdenv.buildPlatform.config != stdenv.hostPlatform.config) ''
+            [target."${shortTarget}"]
+            "linker" = "${ccForHost}"
+            ${# https://github.com/rust-lang/rust/issues/46651#issuecomment-433611633
+            lib.optionalString (stdenv.hostPlatform.isMusl && stdenv.hostPlatform.isAarch64) ''
+              "rustflags" = [ "-C", "target-feature=+crt-static", "-C", "link-arg=-lgcc" ]
+            ''}
+          ''}
+        '';
+      };
+    } ./cargo-setup-hook.sh) {};
+
+  maturinBuildHook = callPackage ({ }:
+    makeSetupHook {
+      name = "maturin-build-hook.sh";
+      deps = [ cargo maturin rustc ];
+      substitutions = {
+        inherit ccForBuild ccForHost cxxForBuild cxxForHost
+          rustBuildPlatform rustTargetPlatform rustTargetPlatformSpec;
+      };
+    } ./maturin-build-hook.sh) {};
+}
diff --git a/pkgs/build-support/rust/hooks/maturin-build-hook.sh b/pkgs/build-support/rust/hooks/maturin-build-hook.sh
new file mode 100644
index 00000000000..7e2599d9224
--- /dev/null
+++ b/pkgs/build-support/rust/hooks/maturin-build-hook.sh
@@ -0,0 +1,39 @@
+maturinBuildHook() {
+    echo "Executing maturinBuildHook"
+
+    runHook preBuild
+
+    if [ ! -z "${buildAndTestSubdir-}" ]; then
+        pushd "${buildAndTestSubdir}"
+    fi
+
+    (
+    set -x
+    env \
+      "CC_@rustBuildPlatform@=@ccForBuild@" \
+      "CXX_@rustBuildPlatform@=@cxxForBuild@" \
+      "CC_@rustTargetPlatform@=@ccForHost@" \
+      "CXX_@rustTargetPlatform@=@cxxForHost@" \
+      maturin build \
+        --cargo-extra-args="-j $NIX_BUILD_CORES --frozen" \
+        --target @rustTargetPlatformSpec@ \
+        --manylinux off \
+        --strip \
+        --release \
+        ${maturinBuildFlags-}
+    )
+
+    runHook postBuild
+
+    if [ ! -z "${buildAndTestSubdir-}" ]; then
+        popd
+    fi
+
+    # Move the wheel to dist/ so that regular Python tooling can find it.
+    mkdir -p dist
+    mv target/wheels/*.whl dist/
+
+    echo "Finished maturinBuildHook"
+}
+
+buildPhase=maturinBuildHook
diff --git a/pkgs/build-support/rust/import-cargo-lock.nix b/pkgs/build-support/rust/import-cargo-lock.nix
new file mode 100644
index 00000000000..83f4e0df4f2
--- /dev/null
+++ b/pkgs/build-support/rust/import-cargo-lock.nix
@@ -0,0 +1,175 @@
+{ fetchgit, fetchurl, lib, runCommand, cargo, jq }:
+
+{
+  # Cargo lock file
+  lockFile
+
+  # Hashes for git dependencies.
+, outputHashes ? {}
+}:
+
+let
+  # Parse a git source into different components.
+  parseGit = src:
+    let
+      parts = builtins.match ''git\+([^?]+)(\?rev=(.*))?#(.*)?'' src;
+      rev = builtins.elemAt parts 2;
+    in
+      if parts == null then null
+      else {
+        url = builtins.elemAt parts 0;
+        sha = builtins.elemAt parts 3;
+      } // lib.optionalAttrs (rev != null) { inherit rev; };
+
+  packages = (builtins.fromTOML (builtins.readFile lockFile)).package;
+
+  # There is no source attribute for the source package itself. But
+  # since we do not want to vendor the source package anyway, we can
+  # safely skip it.
+  depPackages = (builtins.filter (p: p ? "source") packages);
+
+  # Create dependent crates from packages.
+  #
+  # Force evaluation of the git SHA -> hash mapping, so that an error is
+  # thrown if there are stale hashes. We cannot rely on gitShaOutputHash
+  # being evaluated otherwise, since there could be no git dependencies.
+  depCrates = builtins.deepSeq (gitShaOutputHash) (builtins.map mkCrate depPackages);
+
+  # Map package name + version to git commit SHA for packages with a git source.
+  namesGitShas = builtins.listToAttrs (
+    builtins.map nameGitSha (builtins.filter (pkg: lib.hasPrefix "git+" pkg.source) depPackages)
+  );
+
+  nameGitSha = pkg: let gitParts = parseGit pkg.source; in {
+    name = "${pkg.name}-${pkg.version}";
+    value = gitParts.sha;
+  };
+
+  # Convert the attrset provided through the `outputHashes` argument to a
+  # a mapping from git commit SHA -> output hash.
+  #
+  # There may be multiple different packages with different names
+  # originating from the same git repository (typically a Cargo
+  # workspace). By using the git commit SHA as a universal identifier,
+  # the user does not have to specify the output hash for every package
+  # individually.
+  gitShaOutputHash = lib.mapAttrs' (nameVer: hash:
+    let
+      unusedHash = throw "A hash was specified for ${nameVer}, but there is no corresponding git dependency.";
+      rev = namesGitShas.${nameVer} or unusedHash; in {
+      name = rev;
+      value = hash;
+    }) outputHashes;
+
+  # We can't use the existing fetchCrate function, since it uses a
+  # recursive hash of the unpacked crate.
+  fetchCrate = pkg:
+    assert lib.assertMsg (pkg ? checksum) ''
+      Package ${pkg.name} does not have a checksum.
+      Please note that the Cargo.lock format where checksums used to be listed
+      under [metadata] is not supported.
+      If that is the case, running `cargo update` with a recent toolchain will
+      automatically update the format along with the crate's depenendencies.
+    '';
+    fetchurl {
+      name = "crate-${pkg.name}-${pkg.version}.tar.gz";
+      url = "https://crates.io/api/v1/crates/${pkg.name}/${pkg.version}/download";
+      sha256 = pkg.checksum;
+    };
+
+  # Fetch and unpack a crate.
+  mkCrate = pkg:
+    let
+      gitParts = parseGit pkg.source;
+    in
+      if pkg.source == "registry+https://github.com/rust-lang/crates.io-index" then
+      let
+        crateTarball = fetchCrate pkg;
+      in runCommand "${pkg.name}-${pkg.version}" {} ''
+        mkdir $out
+        tar xf "${crateTarball}" -C $out --strip-components=1
+
+        # Cargo is happy with largely empty metadata.
+        printf '{"files":{},"package":"${pkg.checksum}"}' > "$out/.cargo-checksum.json"
+      ''
+      else if gitParts != null then
+      let
+        missingHash = throw ''
+          No hash was found while vendoring the git dependency ${pkg.name}-${pkg.version}. You can add
+          a hash through the `outputHashes` argument of `importCargoLock`:
+
+          outputHashes = {
+            "${pkg.name}-${pkg.version}" = "<hash>";
+          };
+
+          If you use `buildRustPackage`, you can add this attribute to the `cargoLock`
+          attribute set.
+        '';
+        sha256 = gitShaOutputHash.${gitParts.sha} or missingHash;
+        tree = fetchgit {
+          inherit sha256;
+          inherit (gitParts) url;
+          rev = gitParts.sha; # The commit SHA is always available.
+        };
+      in runCommand "${pkg.name}-${pkg.version}" {} ''
+        tree=${tree}
+        if grep --quiet '\[workspace\]' "$tree/Cargo.toml"; then
+          # If the target package is in a workspace, find the crate path
+          # using `cargo metadata`.
+          crateCargoTOML=$(${cargo}/bin/cargo metadata --format-version 1 --no-deps --manifest-path $tree/Cargo.toml | \
+            ${jq}/bin/jq -r '.packages[] | select(.name == "${pkg.name}") | .manifest_path')
+
+            if [[ ! -z $crateCargoTOML ]]; then
+              tree=$(dirname $crateCargoTOML)
+            else
+              >&2 echo "Cannot find path for crate '${pkg.name}-${pkg.version}' in the Cargo workspace in: $tree"
+              exit 1
+            fi
+        fi
+
+        cp -prvd "$tree/" $out
+        chmod u+w $out
+
+        # Cargo is happy with empty metadata.
+        printf '{"files":{},"package":null}' > "$out/.cargo-checksum.json"
+
+        # Set up configuration for the vendor directory.
+        cat > $out/.cargo-config <<EOF
+        [source."${gitParts.url}"]
+        git = "${gitParts.url}"
+        ${lib.optionalString (gitParts ? rev) "rev = \"${gitParts.rev}\""}
+        replace-with = "vendored-sources"
+        EOF
+      ''
+      else throw "Cannot handle crate source: ${pkg.source}";
+
+  vendorDir = runCommand "cargo-vendor-dir" {} ''
+    mkdir -p $out/.cargo
+
+    ln -s ${lockFile} $out/Cargo.lock
+
+    cat > $out/.cargo/config <<EOF
+    [source.crates-io]
+    replace-with = "vendored-sources"
+
+    [source.vendored-sources]
+    directory = "cargo-vendor-dir"
+    EOF
+
+    declare -A keysSeen
+
+    for crate in ${toString depCrates}; do
+      # Link the crate directory, removing the output path hash from the destination.
+      ln -s "$crate" $out/$(basename "$crate" | cut -c 34-)
+
+      if [ -e "$crate/.cargo-config" ]; then
+        key=$(sed 's/\[source\."\(.*\)"\]/\1/; t; d' < "$crate/.cargo-config")
+        if [[ -z ''${keysSeen[$key]} ]]; then
+          keysSeen[$key]=1
+          cat "$crate/.cargo-config" >> $out/.cargo/config
+        fi
+      fi
+    done
+  '';
+in
+  vendorDir
diff --git a/pkgs/build-support/rust/sysroot/Cargo.lock b/pkgs/build-support/rust/sysroot/Cargo.lock
new file mode 100644
index 00000000000..61fcef61744
--- /dev/null
+++ b/pkgs/build-support/rust/sysroot/Cargo.lock
@@ -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",
+]
diff --git a/pkgs/build-support/rust/sysroot/cargo.py b/pkgs/build-support/rust/sysroot/cargo.py
new file mode 100644
index 00000000000..09f6fba6d1c
--- /dev/null
+++ b/pkgs/build-support/rust/sysroot/cargo.py
@@ -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)
diff --git a/pkgs/build-support/rust/sysroot/default.nix b/pkgs/build-support/rust/sysroot/default.nix
new file mode 100644
index 00000000000..4db7cf0dc39
--- /dev/null
+++ b/pkgs/build-support/rust/sysroot/default.nix
@@ -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
+  '';
+}
diff --git a/pkgs/build-support/rust/sysroot/update-lockfile.sh b/pkgs/build-support/rust/sysroot/update-lockfile.sh
new file mode 100755
index 00000000000..83d29832384
--- /dev/null
+++ b/pkgs/build-support/rust/sysroot/update-lockfile.sh
@@ -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"
+
+
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/basic/Cargo.lock b/pkgs/build-support/rust/test/import-cargo-lock/basic/Cargo.lock
new file mode 100644
index 00000000000..fd1b5e42ad3
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/basic/Cargo.lock
@@ -0,0 +1,83 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "basic"
+version = "0.1.0"
+dependencies = [
+ "rand",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "getrandom"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.94"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+
+[[package]]
+name = "rand"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/basic/Cargo.toml b/pkgs/build-support/rust/test/import-cargo-lock/basic/Cargo.toml
new file mode 100644
index 00000000000..f555bb0de62
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/basic/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "basic"
+version = "0.1.0"
+authors = ["Daniël de Kok <me@danieldk.eu>"]
+edition = "2018"
+
+[dependencies]
+rand = "0.8"
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/basic/default.nix b/pkgs/build-support/rust/test/import-cargo-lock/basic/default.nix
new file mode 100644
index 00000000000..d595b58109a
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/basic/default.nix
@@ -0,0 +1,18 @@
+{ rustPlatform }:
+
+rustPlatform.buildRustPackage {
+  pname = "basic";
+  version = "0.1.0";
+
+  src = ./.;
+
+  cargoLock = {
+    lockFile = ./Cargo.lock;
+  };
+
+  doInstallCheck = true;
+
+  installCheckPhase = ''
+    $out/bin/basic
+  '';
+}
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/basic/src/main.rs b/pkgs/build-support/rust/test/import-cargo-lock/basic/src/main.rs
new file mode 100644
index 00000000000..50b4ed799e4
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/basic/src/main.rs
@@ -0,0 +1,9 @@
+use rand::Rng;
+
+fn main() {
+    let mut rng = rand::thread_rng();
+
+    // Always draw zero :).
+    let roll: u8 = rng.gen_range(0..1);
+    assert_eq!(roll, 0);
+}
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/default.nix b/pkgs/build-support/rust/test/import-cargo-lock/default.nix
new file mode 100644
index 00000000000..2dd525a8ac3
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/default.nix
@@ -0,0 +1,8 @@
+{ callPackage }:
+
+{
+  basic = callPackage ./basic { };
+  gitDependency = callPackage ./git-dependency { };
+  gitDependencyNoRev = callPackage ./git-dependency-no-rev { };
+  maturin = callPackage ./maturin { };
+}
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-no-rev/Cargo.lock b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-no-rev/Cargo.lock
new file mode 100644
index 00000000000..54b9c7c5739
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-no-rev/Cargo.lock
@@ -0,0 +1,79 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "getrandom"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "git-dependency-no-rev"
+version = "0.1.0"
+dependencies = [
+ "rand",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.94"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+
+[[package]]
+name = "rand"
+version = "0.8.3"
+source = "git+https://github.com/rust-random/rand.git#f0e01ee0a7257753cc51b291f62666f4765923ef"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.0"
+source = "git+https://github.com/rust-random/rand.git#f0e01ee0a7257753cc51b291f62666f4765923ef"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.2"
+source = "git+https://github.com/rust-random/rand.git#f0e01ee0a7257753cc51b291f62666f4765923ef"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.3.0"
+source = "git+https://github.com/rust-random/rand.git#f0e01ee0a7257753cc51b291f62666f4765923ef"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-no-rev/Cargo.toml b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-no-rev/Cargo.toml
new file mode 100644
index 00000000000..770dfb86f52
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-no-rev/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "git-dependency-no-rev"
+version = "0.1.0"
+authors = ["Daniël de Kok <me@danieldk.eu>"]
+edition = "2018"
+
+[dependencies]
+rand = { git = "https://github.com/rust-random/rand.git" }
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-no-rev/default.nix b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-no-rev/default.nix
new file mode 100644
index 00000000000..fc36edc4077
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-no-rev/default.nix
@@ -0,0 +1,21 @@
+{ rustPlatform }:
+
+rustPlatform.buildRustPackage {
+  pname = "git-dependency-no-rev";
+  version = "0.1.0";
+
+  src = ./.;
+
+  cargoLock = {
+    lockFile = ./Cargo.lock;
+    outputHashes = {
+      "rand-0.8.3" = "0ya2hia3cn31qa8894s3av2s8j5bjwb6yq92k0jsnlx7jid0jwqa";
+    };
+  };
+
+  doInstallCheck = true;
+
+  installCheckPhase = ''
+    $out/bin/git-dependency-no-rev
+  '';
+}
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-no-rev/src/main.rs b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-no-rev/src/main.rs
new file mode 100644
index 00000000000..50b4ed799e4
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-no-rev/src/main.rs
@@ -0,0 +1,9 @@
+use rand::Rng;
+
+fn main() {
+    let mut rng = rand::thread_rng();
+
+    // Always draw zero :).
+    let roll: u8 = rng.gen_range(0..1);
+    assert_eq!(roll, 0);
+}
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/git-dependency/Cargo.lock b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency/Cargo.lock
new file mode 100644
index 00000000000..50600ef4caa
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency/Cargo.lock
@@ -0,0 +1,79 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "getrandom"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "git-dependency"
+version = "0.1.0"
+dependencies = [
+ "rand",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.94"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+
+[[package]]
+name = "rand"
+version = "0.8.3"
+source = "git+https://github.com/rust-random/rand.git?rev=0.8.3#6ecbe2626b2cc6110a25c97b1702b347574febc7"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.0"
+source = "git+https://github.com/rust-random/rand.git?rev=0.8.3#6ecbe2626b2cc6110a25c97b1702b347574febc7"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.1"
+source = "git+https://github.com/rust-random/rand.git?rev=0.8.3#6ecbe2626b2cc6110a25c97b1702b347574febc7"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.3.0"
+source = "git+https://github.com/rust-random/rand.git?rev=0.8.3#6ecbe2626b2cc6110a25c97b1702b347574febc7"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/git-dependency/Cargo.toml b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency/Cargo.toml
new file mode 100644
index 00000000000..11ee8b1763e
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "git-dependency"
+version = "0.1.0"
+authors = ["Daniël de Kok <me@danieldk.eu>"]
+edition = "2018"
+
+[dependencies]
+rand = { git = "https://github.com/rust-random/rand.git", rev = "0.8.3" }
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/git-dependency/default.nix b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency/default.nix
new file mode 100644
index 00000000000..17276c5f5c3
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency/default.nix
@@ -0,0 +1,21 @@
+{ rustPlatform }:
+
+rustPlatform.buildRustPackage {
+  pname = "git-dependency";
+  version = "0.1.0";
+
+  src = ./.;
+
+  cargoLock = {
+    lockFile = ./Cargo.lock;
+    outputHashes = {
+      "rand-0.8.3" = "0l3p174bpwia61vcvxz5mw65a13ri3wy94z04xrnyy5lzciykz4f";
+    };
+  };
+
+  doInstallCheck = true;
+
+  installCheckPhase = ''
+    $out/bin/git-dependency
+  '';
+}
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/git-dependency/src/main.rs b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency/src/main.rs
new file mode 100644
index 00000000000..50b4ed799e4
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency/src/main.rs
@@ -0,0 +1,9 @@
+use rand::Rng;
+
+fn main() {
+    let mut rng = rand::thread_rng();
+
+    // Always draw zero :).
+    let roll: u8 = rng.gen_range(0..1);
+    assert_eq!(roll, 0);
+}
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/maturin/Cargo.lock b/pkgs/build-support/rust/test/import-cargo-lock/maturin/Cargo.lock
new file mode 100644
index 00000000000..5e698d4ff73
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/maturin/Cargo.lock
@@ -0,0 +1,682 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "ahash"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e"
+
+[[package]]
+name = "assert_approx_eq"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c07dab4369547dbe5114677b33fbbf724971019f3818172d59a97a61c774ffd"
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "bitflags"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+
+[[package]]
+name = "byteorder"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "const_fn"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6"
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
+dependencies = [
+ "cfg-if",
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d"
+dependencies = [
+ "cfg-if",
+ "const_fn",
+ "crossbeam-utils",
+ "lazy_static",
+ "memoffset",
+ "scopeguard",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
+dependencies = [
+ "autocfg",
+ "cfg-if",
+ "lazy_static",
+]
+
+[[package]]
+name = "ctor"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8f45d9ad417bcef4817d614a501ab55cdd96a6fdb24f49aab89a54acfd66b19"
+dependencies = [
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "either"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+
+[[package]]
+name = "getrandom"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "ghost"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
+
+[[package]]
+name = "hashbrown"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
+dependencies = [
+ "ahash",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "indoc"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47741a8bc60fb26eb8d6e0238bbb26d8575ff623fdc97b1a2c00c050b9684ed8"
+dependencies = [
+ "indoc-impl",
+ "proc-macro-hack",
+]
+
+[[package]]
+name = "indoc-impl"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0"
+dependencies = [
+ "proc-macro-hack",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "unindent",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "inventory"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f0f7efb804ec95e33db9ad49e4252f049e37e8b0a4652e3cd61f7999f2eff7f"
+dependencies = [
+ "ctor",
+ "ghost",
+ "inventory-impl",
+]
+
+[[package]]
+name = "inventory-impl"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75c094e94816723ab936484666968f5b58060492e880f3c8d00489a1e244fa51"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "itoa"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
+
+[[package]]
+name = "lock_api"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312"
+dependencies = [
+ "scopeguard",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num-bigint"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e9a41747ae4633fce5adffb4d2e81ffc5e89593cb19917f8fb2cc5ff76507bf"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-complex"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
+dependencies = [
+ "instant",
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
+dependencies = [
+ "cfg-if",
+ "instant",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "winapi",
+]
+
+[[package]]
+name = "paste"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880"
+dependencies = [
+ "paste-impl",
+ "proc-macro-hack",
+]
+
+[[package]]
+name = "paste-impl"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6"
+dependencies = [
+ "proc-macro-hack",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+
+[[package]]
+name = "proc-macro-hack"
+version = "0.5.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "proptest"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12e6c80c1139113c28ee4670dc50cc42915228b51f56a9e407f0ec60f966646f"
+dependencies = [
+ "bitflags",
+ "byteorder",
+ "lazy_static",
+ "num-traits",
+ "quick-error",
+ "rand",
+ "rand_chacha",
+ "rand_xorshift",
+ "regex-syntax",
+]
+
+[[package]]
+name = "pyo3"
+version = "0.13.2"
+dependencies = [
+ "assert_approx_eq",
+ "cfg-if",
+ "ctor",
+ "hashbrown",
+ "indoc",
+ "inventory",
+ "libc",
+ "num-bigint",
+ "num-complex",
+ "parking_lot",
+ "paste",
+ "proptest",
+ "pyo3",
+ "pyo3-macros",
+ "rustversion",
+ "serde",
+ "serde_json",
+ "trybuild",
+ "unindent",
+]
+
+[[package]]
+name = "pyo3-macros"
+version = "0.13.2"
+dependencies = [
+ "pyo3-macros-backend",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pyo3-macros-backend"
+version = "0.13.2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "quick-error"
+version = "1.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
+
+[[package]]
+name = "quote"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+dependencies = [
+ "getrandom",
+ "libc",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "rand_xorshift"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "rayon"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
+dependencies = [
+ "autocfg",
+ "crossbeam-deque",
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
+dependencies = [
+ "crossbeam-channel",
+ "crossbeam-deque",
+ "crossbeam-utils",
+ "lazy_static",
+ "num_cpus",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
+
+[[package]]
+name = "rustapi-module"
+version = "0.1.0"
+dependencies = [
+ "pyo3",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd"
+
+[[package]]
+name = "ryu"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "serde"
+version = "1.0.123"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.123"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.62"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea1c6153794552ea7cf7cf63b1231a25de00ec90db326ba6264440fa08e31486"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
+
+[[package]]
+name = "syn"
+version = "1.0.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "toml"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "trybuild"
+version = "1.0.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99471a206425fba51842a9186315f32d91c56eadc21ea4c21f847b59cf778f8b"
+dependencies = [
+ "glob",
+ "lazy_static",
+ "serde",
+ "serde_json",
+ "termcolor",
+ "toml",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+
+[[package]]
+name = "unindent"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
+
+[[package]]
+name = "wasi"
+version = "0.9.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "word-count"
+version = "0.1.0"
+dependencies = [
+ "pyo3",
+ "rayon",
+]
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/maturin/default.nix b/pkgs/build-support/rust/test/import-cargo-lock/maturin/default.nix
new file mode 100644
index 00000000000..af0de596b38
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/maturin/default.nix
@@ -0,0 +1,43 @@
+{ lib
+, fetchFromGitHub
+, python3
+, rustPlatform
+}:
+
+python3.pkgs.buildPythonPackage rec {
+  pname = "word-count";
+  version = "0.13.2";
+
+  format = "pyproject";
+
+  src = fetchFromGitHub {
+    owner = "PyO3";
+    repo = "pyo3";
+    rev = "v${version}";
+    hash = "sha256-NOMrrfo8WjlPhtGxWUOPJS/UDDdbLQRCXR++Zd6JmIA=";
+  };
+
+  cargoDeps = rustPlatform.importCargoLock {
+    lockFile = ./Cargo.lock;
+  };
+
+  postPatch = ''
+    cp ${./Cargo.lock} Cargo.lock
+  '';
+
+  buildAndTestSubdir = "examples/word-count";
+
+  nativeBuildInputs = with rustPlatform; [
+    cargoSetupHook
+    maturinBuildHook
+  ];
+
+  pythonImportsCheck = [ "word_count" ];
+
+  meta = with lib; {
+    description = "PyO3 word count example";
+    homepage = "https://github.com/PyO3/pyo3";
+    license = licenses.asl20;
+    maintainers = [ maintainers.danieldk ];
+  };
+}