summary refs log tree commit diff
path: root/pkgs/build-support
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2020-01-26 22:39:25 +0000
committerAlyssa Ross <hi@alyssa.is>2020-01-26 22:39:25 +0000
commitbd2ad77e38991af0d7a3a5d82bd3f41a077ce401 (patch)
treed1e26d039eb5004eb7c836aafff259cc198626d4 /pkgs/build-support
parente5d8381542a8d084371d26013fab199f52474be7 (diff)
parentad3f0d9829119b611350a9be1c226fb625f1f310 (diff)
downloadnixpkgs-bd2ad77e38991af0d7a3a5d82bd3f41a077ce401.tar
nixpkgs-bd2ad77e38991af0d7a3a5d82bd3f41a077ce401.tar.gz
nixpkgs-bd2ad77e38991af0d7a3a5d82bd3f41a077ce401.tar.bz2
nixpkgs-bd2ad77e38991af0d7a3a5d82bd3f41a077ce401.tar.lz
nixpkgs-bd2ad77e38991af0d7a3a5d82bd3f41a077ce401.tar.xz
nixpkgs-bd2ad77e38991af0d7a3a5d82bd3f41a077ce401.tar.zst
nixpkgs-bd2ad77e38991af0d7a3a5d82bd3f41a077ce401.zip
Merge remote-tracking branch 'nixpkgs/master' into master
Diffstat (limited to 'pkgs/build-support')
-rw-r--r--pkgs/build-support/docker-slim/default.nix67
-rw-r--r--pkgs/build-support/docker/default.nix18
-rwxr-xr-xpkgs/build-support/docker/store-path-to-layer.sh37
-rw-r--r--pkgs/build-support/fetchurl/mirrors.nix4
-rw-r--r--pkgs/build-support/libredirect/libredirect.c4
-rw-r--r--pkgs/build-support/rust/build-rust-crate/build-crate.nix35
-rw-r--r--pkgs/build-support/rust/build-rust-crate/default.nix44
-rw-r--r--pkgs/build-support/rust/build-rust-crate/install-crate.nix23
-rw-r--r--pkgs/build-support/rust/build-rust-crate/lib.sh27
-rw-r--r--pkgs/build-support/rust/build-rust-crate/test/default.nix140
-rw-r--r--pkgs/build-support/rust/default.nix4
11 files changed, 349 insertions, 54 deletions
diff --git a/pkgs/build-support/docker-slim/default.nix b/pkgs/build-support/docker-slim/default.nix
new file mode 100644
index 00000000000..6004898f08e
--- /dev/null
+++ b/pkgs/build-support/docker-slim/default.nix
@@ -0,0 +1,67 @@
+{ stdenv
+, buildGoPackage
+, fetchFromGitHub
+, makeWrapper
+}:
+
+let
+
+  version = "1.26.1";
+  rev = "2ec04e169b12a87c5286aa09ef44eac1cea2c7a1";
+
+in buildGoPackage rec {
+  pname = "docker-slim";
+  inherit version;
+
+  goPackagePath = "github.com/docker-slim/docker-slim";
+
+  src = fetchFromGitHub {
+    owner = "docker-slim";
+    repo = "docker-slim";
+    inherit rev;
+    # fetchzip yields a different hash on Darwin because `use-case-hack`
+    sha256 =
+      if stdenv.isDarwin
+      then "0j72rn6qap78qparrnslxm3yv83mzy1yc7ha0crb4frwkzmspyvf"
+      else "01bjb14z7yblm7qdqrx1j2pw5x5da7a6np4rkzay931gly739gbh";
+  };
+
+  subPackages = [ "cmd/docker-slim" "cmd/docker-slim-sensor" ];
+
+  nativeBuildInputs = [
+    makeWrapper
+  ];
+
+  # docker-slim vendorized logrus files in different directories, which
+  # conflicts on case-sensitive filesystems
+  preBuild = stdenv.lib.optionalString stdenv.isLinux ''
+    mv go/src/${goPackagePath}/vendor/github.com/Sirupsen/logrus/* \
+      go/src/${goPackagePath}/vendor/github.com/sirupsen/logrus/
+  '';
+
+  buildFlagsArray =
+    let
+      ldflags = "-ldflags=-s -w " +
+                "-X ${goPackagePath}/pkg/version.appVersionTag=${version} " +
+                "-X ${goPackagePath}/pkg/version.appVersionRev=${rev}";
+    in
+      [ ldflags ];
+
+  # docker-slim tries to create its state dir next to the binary (inside the nix
+  # store), so we set it to use the working directory at the time of invocation
+  postInstall = ''
+    wrapProgram "$bin/bin/docker-slim" --add-flags '--state-path "$(pwd)"'
+  '';
+
+  meta = with stdenv.lib; {
+    description = "Minify and secure Docker containers";
+    homepage = "https://dockersl.im/";
+    license = licenses.asl20;
+    maintainers = with maintainers; [ filalex77 marsam mbrgm ];
+    # internal/app/sensor/monitors/ptrace/monitor.go:151:16: undefined:
+    #     system.CallNumber
+    # internal/app/sensor/monitors/ptrace/monitor.go:161:15: undefined:
+    #     system.CallReturnValue
+    badPlatforms = [ "aarch64-linux" ];
+  };
+}
diff --git a/pkgs/build-support/docker/default.nix b/pkgs/build-support/docker/default.nix
index e10ff269950..3fcae13e20d 100644
--- a/pkgs/build-support/docker/default.nix
+++ b/pkgs/build-support/docker/default.nix
@@ -325,7 +325,6 @@ rec {
         | jshon -d config \
         | jshon -s "1970-01-01T00:00:01Z" -i created > generic.json
 
-
       # WARNING!
       # The following code is fiddly w.r.t. ensuring every layer is
       # created, and that no paths are missed. If you change the
@@ -625,7 +624,22 @@ rec {
           -i "$imageName" > image/repositories
 
         echo "Cooking the image..."
-        tar -C image --dereference --hard-dereference --sort=name --mtime="@$SOURCE_DATE_EPOCH" --owner=0 --group=0  --mode=a-w --xform s:'^./':: -c . | pigz -nT > $out
+        # tar exits with an exit code of 1 if files changed while it was
+        # reading them. It considers a change in the number of hard links
+        # to be a "change", which can cause this to fail if images are being
+        # built concurrently and the auto-optimise-store nix option is turned on.
+        # Since the contents of these files will not change, we can reasonably
+        # ignore this exit code.
+        set +e
+        tar -C image --dereference --hard-dereference --sort=name \
+          --mtime="@$SOURCE_DATE_EPOCH" --owner=0 --group=0  \
+          --mode=a-w --xform s:'^./':: --use-compress-program='pigz -nT' \
+          --warning=no-file-changed -cf $out .
+        RET=$?
+        if [ $RET -ne 0 ] && [ $RET -ne 1 ]; then
+          exit $RET
+        fi
+        set -e
 
         echo "Finished."
       '';
diff --git a/pkgs/build-support/docker/store-path-to-layer.sh b/pkgs/build-support/docker/store-path-to-layer.sh
index bcad9e83e06..c808abab7a8 100755
--- a/pkgs/build-support/docker/store-path-to-layer.sh
+++ b/pkgs/build-support/docker/store-path-to-layer.sh
@@ -5,16 +5,43 @@ set -eu
 layerNumber=$1
 shift
 
+storePath="$1"
+shift
+
 layerPath="./layers/$layerNumber"
-echo "Creating layer #$layerNumber for $@"
+echo "Creating layer #$layerNumber for $storePath"
 
 mkdir -p "$layerPath"
-tar --no-recursion -rf "$layerPath/layer.tar" \
+
+# Make sure /nix and /nix/store appear first in the archive.
+# We create the directories here and use them because
+# when there are other things being added to the
+# nix store, tar could fail, saying,
+# "tar: /nix/store: file changed as we read it"
+mkdir -p nix/store
+tar -cf "$layerPath/layer.tar"  \
     --mtime="@$SOURCE_DATE_EPOCH" \
-    --owner=0 --group=0 /nix /nix/store
-tar -rpf "$layerPath/layer.tar" --hard-dereference --sort=name \
+    --owner=0 --group=0 \
+    --transform='s,nix,/nix,' \
+    nix
+
+# We change into the /nix/store in order to avoid a similar
+# "file changed as we read it" error as above. Namely,
+# if we use the absolute path of /nix/store/123-pkg
+# and something new is added to the nix store while tar
+# is running, it will detect a change to /nix/store and
+# fail. Instead, if we cd into the nix store and copy
+# the relative nix store path, tar will ignore changes
+# to /nix/store. In order to create the correct structure
+# in the tar file, we transform the relative nix store
+# path to the absolute store path.
+n=$(basename "$storePath")
+tar -C /nix/store -rpf "$layerPath/layer.tar" \
+    --hard-dereference --sort=name \
     --mtime="@$SOURCE_DATE_EPOCH" \
-    --owner=0 --group=0 "$@"
+    --owner=0 --group=0 \
+    --transform="s,$n,/nix/store/$n," \
+    $n
 
 # Compute a checksum of the tarball.
 tarhash=$(tarsum < $layerPath/layer.tar)
diff --git a/pkgs/build-support/fetchurl/mirrors.nix b/pkgs/build-support/fetchurl/mirrors.nix
index c0e115bca28..a0a61f7cc50 100644
--- a/pkgs/build-support/fetchurl/mirrors.nix
+++ b/pkgs/build-support/fetchurl/mirrors.nix
@@ -425,8 +425,8 @@
 
   # Maven Central
   maven = [
-    http://repo1.maven.org/maven2/
-    http://central.maven.org/maven2/
+    https://repo1.maven.org/maven2/
+    https://central.maven.org/maven2/
   ];
 
   # Alsa Project
diff --git a/pkgs/build-support/libredirect/libredirect.c b/pkgs/build-support/libredirect/libredirect.c
index d31b7551e94..e7f74c736ab 100644
--- a/pkgs/build-support/libredirect/libredirect.c
+++ b/pkgs/build-support/libredirect/libredirect.c
@@ -61,7 +61,11 @@ static const char * rewrite(const char * path, char * buf)
 
 static int open_needs_mode(int flags)
 {
+#ifdef O_TMPFILE
     return (flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE;
+#else
+    return flags & O_CREAT;
+#endif
 }
 
 /* The following set of Glibc library functions is very incomplete -
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 9f1930fa62b..dec49d24f52 100644
--- a/pkgs/build-support/rust/build-rust-crate/build-crate.nix
+++ b/pkgs/build-support/rust/build-rust-crate/build-crate.nix
@@ -4,6 +4,7 @@
   crateFeatures, crateRenames, libName, release, libPath,
   crateType, metadata, crateBin, hasCrateBin,
   extraRustcOpts, verbose, colors,
+  buildTests
 }:
 
   let
@@ -30,6 +31,7 @@
       baseRustcOpts
     );
 
+    build_bin = if buildTests then "build_bin_test" else "build_bin";
   in ''
     runHook preBuild
     ${echo_build_heading colors}
@@ -48,14 +50,15 @@
     setup_link_paths
 
     if [[ -e "$LIB_PATH" ]]; then
-       build_lib $LIB_PATH
+       build_lib "$LIB_PATH"
+       ${lib.optionalString buildTests ''build_lib_test "$LIB_PATH"''}
     elif [[ -e src/lib.rs ]]; then
        build_lib src/lib.rs
-    elif [[ -e "src/$LIB_NAME.rs" ]]; then
-       build_lib src/$LIB_NAME.rs
+       ${lib.optionalString buildTests "build_lib_test src/lib.rs"}
     fi
 
 
+
     ${lib.optionalString (lib.length crateBin > 0) (lib.concatMapStringsSep "\n" (bin: ''
       mkdir -p target/bin
       BIN_NAME='${bin.name or crateName}'
@@ -65,19 +68,39 @@
       '' else ''
         BIN_PATH='${bin.path}'
       ''}
-      build_bin "$BIN_NAME" "$BIN_PATH"
+        ${build_bin} "$BIN_NAME" "$BIN_PATH"
     '') crateBin)}
 
+    ${lib.optionalString buildTests ''
+    # When tests are enabled build all the files in the `tests` directory as
+    # test binaries.
+    if [ -d tests ]; then
+      # find all the .rs files (or symlinks to those) in the tests directory, no subdirectories
+      find tests -maxdepth 1 \( -type f -o -type l \) -a -name '*.rs' -print0 | while IFS= read -r -d ''' file; do
+        mkdir -p target/bin
+        build_bin_test_file "$file"
+      done
+
+      # find all the subdirectories of tests/ that contain a main.rs file as
+      # that is also a test according to cargo
+      find tests/ -mindepth 1 -maxdepth 2 \( -type f -o -type l \) -a -name 'main.rs' -print0 | while IFS= read -r -d ''' file; do
+        mkdir -p target/bin
+        build_bin_test_file "$file"
+      done
+
+    fi
+    ''}
+
     # If crateBin is empty and hasCrateBin is not set then we must try to
     # detect some kind of bin target based on some files that might exist.
     ${lib.optionalString (lib.length crateBin == 0 && !hasCrateBin) ''
       if [[ -e src/main.rs ]]; then
         mkdir -p target/bin
-        build_bin ${crateName} src/main.rs
+        ${build_bin} ${crateName} src/main.rs
       fi
       for i in src/bin/*.rs; do #*/
         mkdir -p target/bin
-        build_bin "$(basename $i .rs)" "$i"
+        ${build_bin} "$(basename $i .rs)" "$i"
       done
     ''}
     # Remove object files to avoid "wrong ELF type"
diff --git a/pkgs/build-support/rust/build-rust-crate/default.nix b/pkgs/build-support/rust/build-rust-crate/default.nix
index d5d6bf30b7c..2885b2aef51 100644
--- a/pkgs/build-support/rust/build-rust-crate/default.nix
+++ b/pkgs/build-support/rust/build-rust-crate/default.nix
@@ -39,12 +39,12 @@ let
      inherit lib stdenv echo_build_heading noisily mkRustcDepArgs rust;
    };
 
-   installCrate = import ./install-crate.nix;
+   installCrate = import ./install-crate.nix { inherit stdenv; };
 in
 
 crate_: lib.makeOverridable ({ rust, release, verbose, features, buildInputs, crateOverrides,
   dependencies, buildDependencies, crateRenames,
-  extraRustcOpts,
+  extraRustcOpts, buildTests,
   preUnpack, postUnpack, prePatch, patches, postPatch,
   preConfigure, postConfigure, preBuild, postBuild, preInstall, postInstall }:
 
@@ -55,10 +55,12 @@ let crate = crate_ // (lib.attrByPath [ crate_.crateName ] (attr: {}) crateOverr
       "src" "buildInputs" "crateBin" "crateLib" "libName" "libPath"
       "buildDependencies" "dependencies" "features" "crateRenames"
       "crateName" "version" "build" "authors" "colors" "edition"
+      "buildTests"
     ];
-    extraDerivationAttrs = lib.filterAttrs (n: v: ! lib.elem n processedAttrs) crate;
+    extraDerivationAttrs = builtins.removeAttrs crate processedAttrs;
     buildInputs_ = buildInputs;
     extraRustcOpts_ = extraRustcOpts;
+    buildTests_ = buildTests;
 
     # take a list of crates that we depend on and override them to fit our overrides, rustc, release, …
     makeDependencies = map (dep: lib.getLib (dep.override { inherit release verbose crateOverrides; }));
@@ -72,13 +74,23 @@ in
 stdenv.mkDerivation (rec {
 
     inherit (crate) crateName;
-    inherit preUnpack postUnpack prePatch patches postPatch preConfigure postConfigure preBuild postBuild preInstall postInstall;
-
-    src = if lib.hasAttr "src" crate then
-        crate.src
-      else
-        fetchCrate { inherit (crate) crateName version sha256; };
-    name = "rust_${crate.crateName}-${crate.version}";
+    inherit
+      preUnpack
+      postUnpack
+      prePatch
+      patches
+      postPatch
+      preConfigure
+      postConfigure
+      preBuild
+      postBuild
+      preInstall
+      postInstall
+      buildTests
+    ;
+
+    src = crate.src or (fetchCrate { inherit (crate) crateName version sha256; });
+    name = "rust_${crate.crateName}-${crate.version}${lib.optionalString buildTests_ "-test"}";
     depsBuildBuild = [ rust stdenv.cc ];
     buildInputs = (crate.buildInputs or []) ++ buildInputs_;
     dependencies = makeDependencies dependencies_;
@@ -122,6 +134,7 @@ stdenv.mkDerivation (rec {
       ++ extraRustcOpts_
       ++ (lib.optional (edition != null) "--edition ${edition}");
 
+
     configurePhase = configureCrate {
       inherit crateName buildDependencies completeDeps completeBuildDeps crateDescription
               crateFeatures crateRenames libName build workspace_member release libPath crateVersion
@@ -132,12 +145,14 @@ stdenv.mkDerivation (rec {
       inherit crateName dependencies
               crateFeatures crateRenames libName release libPath crateType
               metadata hasCrateBin crateBin verbose colors
-              extraRustcOpts;
+              extraRustcOpts buildTests;
     };
-    installPhase = installCrate crateName metadata;
+    installPhase = installCrate crateName metadata buildTests;
 
-    outputs = [ "out" "lib" ];
-    outputDev = [ "lib" ];
+    # depending on the test setting we are either producing something with bins
+    # and libs or just test binaries
+    outputs = if buildTests then [ "out" ] else [ "out" "lib" ];
+    outputDev = if buildTests then [ "out" ] else  [ "lib" ];
 
 } // extraDerivationAttrs
 )) {
@@ -162,4 +177,5 @@ stdenv.mkDerivation (rec {
   dependencies = crate_.dependencies or [];
   buildDependencies = crate_.buildDependencies or [];
   crateRenames = crate_.crateRenames or {};
+  buildTests = crate_.buildTests or false;
 }
diff --git a/pkgs/build-support/rust/build-rust-crate/install-crate.nix b/pkgs/build-support/rust/build-rust-crate/install-crate.nix
index 934c3a03176..5ba7b69bedc 100644
--- a/pkgs/build-support/rust/build-rust-crate/install-crate.nix
+++ b/pkgs/build-support/rust/build-rust-crate/install-crate.nix
@@ -1,5 +1,6 @@
-crateName: metadata:
-''
+{ stdenv }:
+crateName: metadata: buildTests:
+if !buildTests then ''
   runHook preInstall
   # always create $out even if we do not have binaries. We are detecting binary targets during compilation, if those are missing there is no way to only have $lib
   mkdir $out
@@ -29,4 +30,22 @@ crateName: metadata:
     fi
   fi
   runHook postInstall
+'' else
+# for tests we just put them all in the output. No execution.
+''
+  runHook preInstall
+
+  mkdir -p $out/tests
+  if [ -e target/bin ]; then
+    find target/bin/ -type f -executable -exec cp {} $out/tests \;
+  fi
+  if [ -e target/lib ]; then
+    find target/lib/ -type f \! -name '*.rlib' \
+      -a \! -name '*${stdenv.hostPlatform.extensions.sharedLibrary}' \
+      -a \! -name '*.d' \
+      -executable \
+      -print0 | xargs --no-run-if-empty --null install --target $out/tests;
+  fi
+
+  runHook postInstall
 ''
diff --git a/pkgs/build-support/rust/build-rust-crate/lib.sh b/pkgs/build-support/rust/build-rust-crate/lib.sh
index 24c712468ea..d4d9317496f 100644
--- a/pkgs/build-support/rust/build-rust-crate/lib.sh
+++ b/pkgs/build-support/rust/build-rust-crate/lib.sh
@@ -13,6 +13,7 @@ build_lib() {
     $BUILD_OUT_DIR \
     $EXTRA_BUILD \
     $EXTRA_FEATURES \
+    $EXTRA_RUSTC_FLAGS \
     --color $colors
 
   EXTRA_LIB=" --extern $CRATE_NAME=target/lib/lib$CRATE_NAME-$metadata.rlib"
@@ -22,9 +23,10 @@ build_lib() {
 }
 
 build_bin() {
-  crate_name=$1
-  crate_name_=$(echo $crate_name | tr '-' '_')
-  main_file=""
+  local crate_name=$1
+  local crate_name_=$(echo $crate_name | tr '-' '_')
+  local main_file=""
+
   if [[ ! -z $2 ]]; then
     main_file=$2
   fi
@@ -43,6 +45,7 @@ build_bin() {
     $BUILD_OUT_DIR \
     $EXTRA_BUILD \
     $EXTRA_FEATURES \
+    $EXTRA_RUSTC_FLAGS \
     --color ${colors} \
 
   if [ "$crate_name_" != "$crate_name" ]; then
@@ -50,6 +53,24 @@ build_bin() {
   fi
 }
 
+build_lib_test() {
+    local file="$1"
+    EXTRA_RUSTC_FLAGS="--test $EXTRA_RUSTC_FLAGS" build_lib "$1" "$2"
+}
+
+build_bin_test() {
+    local crate="$1"
+    local file="$2"
+    EXTRA_RUSTC_FLAGS="--test $EXTRA_RUSTC_FLAGS" build_bin "$1" "$2"
+}
+
+build_bin_test_file() {
+    local file="$1"
+    local derived_crate_name="${file//\//_}"
+    derived_crate_name="${derived_crate_name%.rs}"
+    build_bin_test "$derived_crate_name" "$file"
+}
+
 setup_link_paths() {
   EXTRA_LIB=""
   if [[ -e target/link_ ]]; then
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 4a90cf442a4..aefa279fc5e 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,4 @@
-{ lib, buildRustCrate, runCommand, writeTextFile, symlinkJoin, callPackage }:
+{ lib, buildRustCrate, runCommand, writeTextFile, symlinkJoin, callPackage, releaseTools }:
 let
   mkCrate = args: let
       p = {
@@ -29,10 +29,30 @@ let
     }
   '';
 
+  mkTestFile = name: functionName: mkFile name ''
+    #[cfg(test)]
+    #[test]
+    fn ${functionName}() {
+      assert!(true);
+    }
+  '';
+  mkTestFileWithMain = name: functionName: mkFile name ''
+    #[cfg(test)]
+    #[test]
+    fn ${functionName}() {
+      assert!(true);
+    }
+
+    fn main() {}
+  '';
+
+
   mkLib = name: mkFile name "pub fn test() -> i32 { return 23; }";
 
   mkTest = crateArgs: let
-    crate = mkCrate crateArgs;
+    crate = mkCrate (builtins.removeAttrs crateArgs ["expectedTestOutput"]);
+    hasTests = crateArgs.buildTests or false;
+    expectedTestOutputs = crateArgs.expectedTestOutputs or null;
     binaries = map (v: ''"${v.name}"'') (crateArgs.crateBin or []);
     isLib = crateArgs ? libName || crateArgs ? libPath;
     crateName = crateArgs.crateName or "nixtestcrate";
@@ -44,23 +64,45 @@ let
       src = mkBinExtern "src/main.rs" libName;
     };
 
-    in runCommand "run-buildRustCrate-${crateName}-test" {
-      nativeBuildInputs = [ crate ];
-    } ''
-      ${lib.concatStringsSep "\n" binaries}
-      ${lib.optionalString isLib ''
-          test -e ${crate}/lib/*.rlib || exit 1
-          ${libTestBinary}/bin/run-test-${crateName}
-      ''}
-      touch $out
-  '';
+    in
+      assert expectedTestOutputs != null -> hasTests;
+      assert hasTests -> expectedTestOutputs != null;
+
+      runCommand "run-buildRustCrate-${crateName}-test" {
+        nativeBuildInputs = [ crate ];
+      } (if !hasTests then ''
+          ${lib.concatStringsSep "\n" binaries}
+          ${lib.optionalString isLib ''
+              test -e ${crate}/lib/*.rlib || exit 1
+              ${libTestBinary}/bin/run-test-${crateName}
+          ''}
+          touch $out
+        '' else ''
+          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}
+        ''
+      );
+
   in rec {
 
   tests = let
     cases = {
       libPath =  { libPath = "src/my_lib.rs"; src = mkLib "src/my_lib.rs"; };
       srcLib =  { src = mkLib "src/lib.rs"; };
-      customLibName =  { libName = "test_lib"; src = mkLib "src/test_lib.rs"; };
+
+      # This used to be supported by cargo but as of 1.40.0 I can't make it work like that with just cargo anymore.
+      # This might be a regression or deprecated thing they finally removed…
+      # customLibName =  { libName = "test_lib"; src = mkLib "src/test_lib.rs"; };
+      # rustLibTestsCustomLibName = {
+      #   libName = "test_lib";
+      #   src = mkTestFile "src/test_lib.rs" "foo";
+      #   buildTests = true;
+      #   expectedTestOutputs = [ "test foo ... ok" ];
+      # };
+
       customLibNameAndLibPath =  { libName = "test_lib"; libPath = "src/best-lib.rs"; src = mkLib "src/best-lib.rs"; };
       crateBinWithPath =  { crateBin = [{ name = "test_binary1"; path = "src/foobar.rs"; }]; src = mkBin "src/foobar.rs"; };
       crateBinNoPath1 =  { crateBin = [{ name = "my-binary2"; }]; src = mkBin "src/my_binary2.rs"; };
@@ -85,6 +127,65 @@ let
         dependencies = [ (mkCrate { crateName = "foo"; libName = "foolib"; src = mkLib "src/lib.rs"; }) ];
         crateRenames = { "foo" = "foo_renamed"; };
       };
+      rustLibTestsDefault = {
+        src = mkTestFile "src/lib.rs" "baz";
+        buildTests = true;
+        expectedTestOutputs = [ "test baz ... ok" ];
+      };
+      rustLibTestsCustomLibPath = {
+        libPath = "src/test_path.rs";
+        src = mkTestFile "src/test_path.rs" "bar";
+        buildTests = true;
+        expectedTestOutputs = [ "test bar ... ok" ];
+      };
+      rustLibTestsCustomLibPathWithTests = {
+        libPath = "src/test_path.rs";
+        src = symlinkJoin {
+          name = "rust-lib-tests-custom-lib-path-with-tests-dir";
+          paths = [
+            (mkTestFile "src/test_path.rs" "bar")
+            (mkTestFile "tests/something.rs" "something")
+          ];
+        };
+        buildTests = true;
+        expectedTestOutputs = [
+          "test bar ... ok"
+          "test something ... ok"
+        ];
+      };
+      rustBinTestsCombined = {
+        src = symlinkJoin {
+          name = "rust-bin-tests-combined";
+          paths = [
+            (mkTestFileWithMain "src/main.rs" "src_main")
+            (mkTestFile "tests/foo.rs" "tests_foo")
+            (mkTestFile "tests/bar.rs" "tests_bar")
+          ];
+        };
+        buildTests = true;
+        expectedTestOutputs = [
+          "test src_main ... ok"
+          "test tests_foo ... ok"
+          "test tests_bar ... ok"
+        ];
+      };
+      rustBinTestsSubdirCombined = {
+        src = symlinkJoin {
+          name = "rust-bin-tests-subdir-combined";
+          paths = [
+            (mkTestFileWithMain "src/main.rs" "src_main")
+            (mkTestFile "tests/foo/main.rs" "tests_foo")
+            (mkTestFile "tests/bar/main.rs" "tests_bar")
+          ];
+        };
+        buildTests = true;
+        expectedTestOutputs = [
+          "test src_main ... ok"
+          "test tests_foo ... ok"
+          "test tests_bar ... ok"
+        ];
+      };
+
     };
     brotliCrates = (callPackage ./brotli-crates.nix {});
   in lib.mapAttrs (key: value: mkTest (value // lib.optionalAttrs (!value?crateName) { crateName = key; })) cases // {
@@ -110,9 +211,12 @@ let
       test -e ${pkg}/bin/brotli-decompressor && touch $out
     '';
   };
-  test = runCommand "run-buildRustCrate-tests" {
-    nativeBuildInputs = builtins.attrValues tests;
-  } "
-    touch $out
-  ";
+  test = releaseTools.aggregate {
+    name = "buildRustCrate-tests";
+    meta = {
+      description = "Test cases for buildRustCrate";
+      maintainers = [ lib.maintainers.andir ];
+    };
+    constituents = builtins.attrValues tests;
+  };
 }
diff --git a/pkgs/build-support/rust/default.nix b/pkgs/build-support/rust/default.nix
index f9cf8f1f0c1..4089436c0e0 100644
--- a/pkgs/build-support/rust/default.nix
+++ b/pkgs/build-support/rust/default.nix
@@ -100,9 +100,9 @@ stdenv.mkDerivation (args // {
   '' + stdenv.lib.optionalString verifyCargoDeps ''
     if ! diff source/Cargo.lock $cargoDeps/Cargo.lock ; then
       echo
-      echo "ERROR: cargoSha256 is out of date."
+      echo "ERROR: cargoSha256 is out of date"
       echo
-      echo "Cargo.lock is not the same in $cargoDeps."
+      echo "Cargo.lock is not the same in $cargoDeps"
       echo
       echo "To fix the issue:"
       echo '1. Use "1111111111111111111111111111111111111111111111111111" as the cargoSha256 value'