about summary refs log tree commit diff
path: root/pkgs/build-support
diff options
context:
space:
mode:
authorJustin Bedo <cu@cua0.org>2023-04-06 08:51:55 +1000
committerJustin Bedo <cu@cua0.org>2023-04-06 08:51:55 +1000
commit2231a9c89a14d92879feafee21cf6bf72523fa11 (patch)
treeddaf1b7411f24744449cfd1cd56eac40a4ab5eec /pkgs/build-support
parenta9dd7b9e841ac110d30576a5c128255a0088935f (diff)
parentc2f2239d92f2e7c853ff5b48701d179fec2ea7d4 (diff)
Merge remote-tracking branch 'origin/master' into r-updates
Diffstat (limited to 'pkgs/build-support')
-rw-r--r--pkgs/build-support/alternatives/lapack/default.nix3
-rw-r--r--pkgs/build-support/bintools-wrapper/default.nix16
-rw-r--r--pkgs/build-support/bintools-wrapper/ld-wrapper.sh21
-rw-r--r--pkgs/build-support/build-bazel-package/default.nix35
-rw-r--r--pkgs/build-support/build-fhs-userenv-bubblewrap/buildFHSEnv.nix (renamed from pkgs/build-support/build-fhs-userenv-bubblewrap/env.nix)6
-rw-r--r--pkgs/build-support/build-fhs-userenv-bubblewrap/default.nix48
-rw-r--r--pkgs/build-support/build-fhs-userenv/default.nix12
-rw-r--r--pkgs/build-support/build-graalvm-native-image/default.nix3
-rw-r--r--pkgs/build-support/cc-wrapper/add-hardening.sh27
-rw-r--r--pkgs/build-support/cc-wrapper/default.nix10
-rw-r--r--pkgs/build-support/coq/default.nix2
-rw-r--r--pkgs/build-support/coq/meta-fetch/default.nix8
-rw-r--r--pkgs/build-support/docker/default.nix2
-rwxr-xr-xpkgs/build-support/docker/nix-prefetch-docker2
-rw-r--r--pkgs/build-support/dotnet/build-dotnet-module/default.nix19
-rw-r--r--pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-fixup-hook.sh3
-rwxr-xr-xpkgs/build-support/dotnet/nuget-to-nix/nuget-to-nix.sh7
-rw-r--r--pkgs/build-support/fetchdocker/default.nix2
-rw-r--r--pkgs/build-support/make-desktopitem/default.nix2
-rw-r--r--pkgs/build-support/ocaml/dune.nix2
-rw-r--r--pkgs/build-support/release/nix-build.nix2
-rw-r--r--pkgs/build-support/rust/build-rust-package/sysroot/default.nix9
-rw-r--r--pkgs/build-support/rust/fetch-cargo-tarball/default.nix11
-rw-r--r--pkgs/build-support/rust/fetchcrate.nix8
-rw-r--r--pkgs/build-support/rust/hooks/cargo-setup-hook.sh10
-rw-r--r--pkgs/build-support/rust/hooks/default.nix3
-rw-r--r--pkgs/build-support/rust/import-cargo-lock.nix15
-rw-r--r--pkgs/build-support/rust/replace-workspace-values.py103
-rw-r--r--pkgs/build-support/rust/sysroot/Cargo.lock6
-rw-r--r--pkgs/build-support/rust/sysroot/src.nix2
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/default.nix7
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/git-dependency-workspace-inheritance/crate.toml6
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/git-dependency-workspace-inheritance/default.nix7
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/git-dependency-workspace-inheritance/want.toml12
-rw-r--r--pkgs/build-support/rust/test/import-cargo-lock/git-dependency-workspace-inheritance/workspace.toml5
-rw-r--r--pkgs/build-support/setup-hooks/multiple-outputs.sh11
-rw-r--r--pkgs/build-support/setup-hooks/patch-shebangs.sh14
-rw-r--r--pkgs/build-support/setup-hooks/reproducible-builds.sh3
-rw-r--r--pkgs/build-support/setup-hooks/separate-debug-info.sh3
-rw-r--r--pkgs/build-support/setup-hooks/wrap-gapps-hook/default.nix32
-rw-r--r--pkgs/build-support/trivial-builders.nix13
-rw-r--r--pkgs/build-support/trivial-builders/test/references.nix2
-rw-r--r--pkgs/build-support/writers/default.nix4
43 files changed, 393 insertions, 125 deletions
diff --git a/pkgs/build-support/alternatives/lapack/default.nix b/pkgs/build-support/alternatives/lapack/default.nix
index 9886a035e4ec2..cbc7bf25c7978 100644
--- a/pkgs/build-support/alternatives/lapack/default.nix
+++ b/pkgs/build-support/alternatives/lapack/default.nix
@@ -35,6 +35,9 @@ stdenv.mkDerivation {
     implementation = lapackImplementation;
   };
 
+  # TODO: drop this forced rebuild, as it was needed just once.
+  rebuild_salt = if stdenv.isDarwin && stdenv.isx86_64 then "J4AQ" else null;
+
   dontBuild = true;
   dontConfigure = true;
   unpackPhase = "src=$PWD";
diff --git a/pkgs/build-support/bintools-wrapper/default.nix b/pkgs/build-support/bintools-wrapper/default.nix
index 6e33f6189a4af..00375db220fe9 100644
--- a/pkgs/build-support/bintools-wrapper/default.nix
+++ b/pkgs/build-support/bintools-wrapper/default.nix
@@ -25,7 +25,9 @@
 , nativeTools, noLibc ? false, nativeLibc, nativePrefix ? ""
 , propagateDoc ? bintools != null && bintools ? man
 , extraPackages ? [], extraBuildCommands ? ""
-, isGNU ? bintools.isGNU or false, isLLVM ? bintools.isLLVM or false
+, isGNU ? bintools.isGNU or false
+, isLLVM ? bintools.isLLVM or false
+, isCCTools ? bintools.isCCTools or false
 , buildPackages ? {}
 , targetPackages ? {}
 , useMacosReexportHack ? false
@@ -139,6 +141,7 @@ stdenv.mkDerivation {
         local dst="$1"
         local wrapper="$2"
         export prog="$3"
+        export use_response_file_by_default=${if isCCTools then "1" else "0"}
         substituteAll "$wrapper" "$out/bin/$dst"
         chmod +x "$out/bin/$dst"
       }
@@ -183,7 +186,9 @@ stdenv.mkDerivation {
       done
 
     '' + (if !useMacosReexportHack then ''
-      wrap ${targetPrefix}ld ${./ld-wrapper.sh} ''${ld:-$ldPath/${targetPrefix}ld}
+      if [ -e ''${ld:-$ldPath/${targetPrefix}ld} ]; then
+        wrap ${targetPrefix}ld ${./ld-wrapper.sh} ''${ld:-$ldPath/${targetPrefix}ld}
+      fi
     '' else ''
       ldInner="${targetPrefix}ld-reexport-delegate"
       wrap "$ldInner" ${./macos-sierra-reexport-hack.bash} ''${ld:-$ldPath/${targetPrefix}ld}
@@ -191,10 +196,9 @@ stdenv.mkDerivation {
       unset ldInner
     '') + ''
 
-      for variant in ld.gold ld.bfd ld.lld; do
-        local underlying=$ldPath/${targetPrefix}$variant
-        [[ -e "$underlying" ]] || continue
-        wrap ${targetPrefix}$variant ${./ld-wrapper.sh} $underlying
+      for variant in $ldPath/${targetPrefix}ld.*; do
+        basename=$(basename "$variant")
+        wrap $basename ${./ld-wrapper.sh} $variant
       done
     '';
 
diff --git a/pkgs/build-support/bintools-wrapper/ld-wrapper.sh b/pkgs/build-support/bintools-wrapper/ld-wrapper.sh
index 86a7416022010..0d832bc4a67a0 100644
--- a/pkgs/build-support/bintools-wrapper/ld-wrapper.sh
+++ b/pkgs/build-support/bintools-wrapper/ld-wrapper.sh
@@ -232,8 +232,11 @@ fi
 
 # Only add --build-id if this is a final link. FIXME: should build gcc
 # with --enable-linker-build-id instead?
+#
+# Note: `lld` interprets `--build-id` to mean `--build-id=fast`; GNU ld defaults
+# to SHA1.
 if [ "$NIX_SET_BUILD_ID_@suffixSalt@" = 1 ] && ! (( "$relocatable" )); then
-    extraAfter+=(--build-id)
+    extraAfter+=(--build-id="${NIX_BUILD_ID_STYLE:-sha1}")
 fi
 
 
@@ -250,10 +253,18 @@ fi
 
 PATH="$path_backup"
 # Old bash workaround, see above.
-@prog@ \
-    ${extraBefore+"${extraBefore[@]}"} \
-    ${params+"${params[@]}"} \
-    ${extraAfter+"${extraAfter[@]}"}
+
+if (( "${NIX_LD_USE_RESPONSE_FILE:-@use_response_file_by_default@}" >= 1 )); then
+    @prog@ @<(printf "%q\n" \
+        ${extraBefore+"${extraBefore[@]}"} \
+        ${params+"${params[@]}"} \
+        ${extraAfter+"${extraAfter[@]}"})
+else
+    @prog@ \
+        ${extraBefore+"${extraBefore[@]}"} \
+        ${params+"${params[@]}"} \
+        ${extraAfter+"${extraAfter[@]}"}
+fi
 
 if [ -e "@out@/nix-support/post-link-hook" ]; then
     source @out@/nix-support/post-link-hook
diff --git a/pkgs/build-support/build-bazel-package/default.nix b/pkgs/build-support/build-bazel-package/default.nix
index a3f331b23cb89..ab2014ea6a63f 100644
--- a/pkgs/build-support/build-bazel-package/default.nix
+++ b/pkgs/build-support/build-bazel-package/default.nix
@@ -10,7 +10,7 @@ args@{
 , bazelBuildFlags ? []
 , bazelTestFlags ? []
 , bazelFetchFlags ? []
-, bazelTarget
+, bazelTargets
 , bazelTestTargets ? []
 , buildAttrs
 , fetchAttrs
@@ -69,11 +69,11 @@ let
     '';
 in
 stdenv.mkDerivation (fBuildAttrs // {
-  inherit name bazelFlags bazelBuildFlags bazelTestFlags bazelFetchFlags bazelTarget bazelTestTargets;
+  inherit name bazelFlags bazelBuildFlags bazelTestFlags bazelFetchFlags bazelTargets bazelTestTargets;
 
   deps = stdenv.mkDerivation (fFetchAttrs // {
     name = "${name}-deps.tar.gz";
-    inherit bazelFlags bazelBuildFlags bazelTestFlags bazelFetchFlags bazelTarget bazelTestTargets;
+    inherit bazelFlags bazelBuildFlags bazelTestFlags bazelFetchFlags bazelTargets bazelTestTargets;
 
     impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ fFetchAttrs.impureEnvVars or [];
 
@@ -94,21 +94,18 @@ stdenv.mkDerivation (fBuildAttrs // {
     buildPhase = fFetchAttrs.buildPhase or ''
       runHook preBuild
 
-      # See footnote called [USER and BAZEL_USE_CPP_ONLY_TOOLCHAIN variables].
-      # We disable multithreading for the fetching phase since it can lead to timeouts with many dependencies/threads:
-      # https://github.com/bazelbuild/bazel/issues/6502
-      BAZEL_USE_CPP_ONLY_TOOLCHAIN=1 \
-      USER=homeless-shelter \
-      bazel \
-        --batch \
-        --output_base="$bazelOut" \
-        --output_user_root="$bazelUserRoot" \
-        ${if fetchConfigured then "build --nobuild" else "fetch"} \
-        --loading_phase_threads=1 \
-        $bazelFlags \
-        $bazelFetchFlags \
-        ${bazelTarget} \
-        ${lib.strings.concatStringsSep " " bazelTestTargets}
+      ${
+        bazelCmd {
+          cmd = if fetchConfigured then "build --nobuild" else "fetch";
+          additionalFlags = [
+            # We disable multithreading for the fetching phase since it can lead to timeouts with many dependencies/threads:
+            # https://github.com/bazelbuild/bazel/issues/6502
+            "--loading_phase_threads=1"
+            "$bazelFetchFlags"
+          ];
+          targets = bazelTargets ++ bazelTestTargets;
+        }
+      }
 
       runHook postBuild
     '';
@@ -232,7 +229,7 @@ stdenv.mkDerivation (fBuildAttrs // {
       bazelCmd {
         cmd = "build";
         additionalFlags = bazelBuildFlags;
-        targets = [bazelTarget];
+        targets = bazelTargets;
       }
     }
     runHook postBuild
diff --git a/pkgs/build-support/build-fhs-userenv-bubblewrap/env.nix b/pkgs/build-support/build-fhs-userenv-bubblewrap/buildFHSEnv.nix
index c4d967a11c699..0d98c0a2bc645 100644
--- a/pkgs/build-support/build-fhs-userenv-bubblewrap/env.nix
+++ b/pkgs/build-support/build-fhs-userenv-bubblewrap/buildFHSEnv.nix
@@ -1,6 +1,6 @@
 { stdenv, lib, buildEnv, writeText, writeShellScriptBin, pkgs, pkgsi686Linux }:
 
-{ name, profile ? ""
+args@{ name, profile ? ""
 , targetPkgs ? pkgs: [], multiPkgs ? pkgs: []
 , extraBuildCommands ? "", extraBuildCommandsMulti ? ""
 , extraOutputsToInstall ? []
@@ -216,4 +216,8 @@ in stdenv.mkDerivation {
   '';
   preferLocalBuild = true;
   allowSubstitutes = false;
+
+  passthru = {
+    inherit args multiPaths targetPaths;
+  };
 }
diff --git a/pkgs/build-support/build-fhs-userenv-bubblewrap/default.nix b/pkgs/build-support/build-fhs-userenv-bubblewrap/default.nix
index 048233d728c47..ce807b932a197 100644
--- a/pkgs/build-support/build-fhs-userenv-bubblewrap/default.nix
+++ b/pkgs/build-support/build-fhs-userenv-bubblewrap/default.nix
@@ -2,6 +2,7 @@
 
 args @ {
   name
+, version ? null
 , runScript ? "bash"
 , extraInstallCommands ? ""
 , meta ? {}
@@ -19,14 +20,15 @@ args @ {
 
 with builtins;
 let
-  buildFHSEnv = callPackage ./env.nix { };
+  buildFHSEnv = callPackage ./buildFHSEnv.nix { };
 
-  env = buildFHSEnv (removeAttrs args [
+  fhsenv = buildFHSEnv (removeAttrs args [
     "runScript" "extraInstallCommands" "meta" "passthru" "extraBwrapArgs" "dieWithParent"
     "unshareUser" "unshareCgroup" "unshareUts" "unshareNet" "unsharePid" "unshareIpc"
+    "version"
   ]);
 
-  etcBindFlags = let
+  etcBindEntries = let
     files = [
       # NixOS Compatibility
       "static"
@@ -69,8 +71,7 @@ let
       "ca-certificates"
       "pki"
     ];
-  in concatStringsSep "\n  "
-  (map (file: "--ro-bind-try $(${coreutils}/bin/readlink -m /etc/${file}) /etc/${file}") files);
+  in map (path: "/etc/${path}") files;
 
   # Create this on the fly instead of linking from /nix
   # The container might have to modify it and re-run ldconfig if there are
@@ -99,24 +100,25 @@ let
   '';
 
   bwrapCmd = { initArgs ? "" }: ''
-    blacklist=(/nix /dev /proc /etc)
+    ignored=(/nix /dev /proc /etc)
     ro_mounts=()
     symlinks=()
-    for i in ${env}/*; do
+    etc_ignored=()
+    for i in ${fhsenv}/*; do
       path="/''${i##*/}"
       if [[ $path == '/etc' ]]; then
         :
       elif [[ -L $i ]]; then
         symlinks+=(--symlink "$(${coreutils}/bin/readlink "$i")" "$path")
-        blacklist+=("$path")
+        ignored+=("$path")
       else
         ro_mounts+=(--ro-bind "$i" "$path")
-        blacklist+=("$path")
+        ignored+=("$path")
       fi
     done
 
-    if [[ -d ${env}/etc ]]; then
-      for i in ${env}/etc/*; do
+    if [[ -d ${fhsenv}/etc ]]; then
+      for i in ${fhsenv}/etc/*; do
         path="/''${i##*/}"
         # NOTE: we're binding /etc/fonts and /etc/ssl/certs from the host so we
         # don't want to override it with a path from the FHS environment.
@@ -124,14 +126,26 @@ let
           continue
         fi
         ro_mounts+=(--ro-bind "$i" "/etc$path")
+        etc_ignored+=("/etc$path")
       done
     fi
 
+    for i in ${lib.escapeShellArgs etcBindEntries}; do
+      if [[ "''${etc_ignored[@]}" =~ "$i" ]]; then
+        continue
+      fi
+      if [[ -L $i ]]; then
+        symlinks+=(--symlink "$(${coreutils}/bin/readlink "$i")" "$i")
+      else
+        ro_mounts+=(--ro-bind-try "$i" "$i")
+      fi
+    done
+
     declare -a auto_mounts
     # loop through all directories in the root
     for dir in /*; do
-      # if it is a directory and it is not in the blacklist
-      if [[ -d "$dir" ]] && [[ ! "''${blacklist[@]}" =~ "$dir" ]]; then
+      # if it is a directory and it is not ignored
+      if [[ -d "$dir" ]] && [[ ! "''${ignored[@]}" =~ "$dir" ]]; then
         # add it to the mount list
         auto_mounts+=(--bind "$dir" "$dir")
       fi
@@ -179,7 +193,6 @@ let
       --symlink /etc/ld.so.cache ${pkgsi686Linux.glibc}/etc/ld.so.cache \
       --ro-bind ${pkgsi686Linux.glibc}/etc/rpc ${pkgsi686Linux.glibc}/etc/rpc \
       --remount-ro ${pkgsi686Linux.glibc}/etc \
-      ${etcBindFlags}
       "''${ro_mounts[@]}"
       "''${symlinks[@]}"
       "''${auto_mounts[@]}"
@@ -192,7 +205,11 @@ let
 
   bin = writeShellScriptBin name (bwrapCmd { initArgs = ''"$@"''; });
 
-in runCommandLocal name {
+  versionStr = lib.optionalString (version != null) ("-" + version);
+
+  nameAndVersion = name + versionStr;
+
+in runCommandLocal nameAndVersion {
   inherit meta;
 
   passthru = passthru // {
@@ -204,6 +221,7 @@ in runCommandLocal name {
       echo >&2 ""
       exit 1
     '';
+    inherit args fhsenv;
   };
 } ''
   mkdir -p $out/bin
diff --git a/pkgs/build-support/build-fhs-userenv/default.nix b/pkgs/build-support/build-fhs-userenv/default.nix
index e7db6a75297d1..6f0adfb4e08cb 100644
--- a/pkgs/build-support/build-fhs-userenv/default.nix
+++ b/pkgs/build-support/build-fhs-userenv/default.nix
@@ -1,11 +1,11 @@
-{ callPackage, runCommandLocal, writeScript, stdenv, coreutils }:
+{ lib, callPackage, runCommandLocal, writeScript, stdenv, coreutils }:
 
 let buildFHSEnv = callPackage ./env.nix { }; in
 
-args@{ name, runScript ? "bash", extraInstallCommands ? "", meta ? {}, passthru ? {}, ... }:
+args@{ name, version ? null, runScript ? "bash", extraInstallCommands ? "", meta ? {}, passthru ? {}, ... }:
 
 let
-  env = buildFHSEnv (removeAttrs args [ "runScript" "extraInstallCommands" "meta" "passthru" ]);
+  env = buildFHSEnv (removeAttrs args [ "version" "runScript" "extraInstallCommands" "meta" "passthru" ]);
 
   chrootenv = callPackage ./chrootenv {};
 
@@ -23,7 +23,11 @@ let
     exec ${run} "$@"
   '';
 
-in runCommandLocal name {
+  versionStr = lib.optionalString (version != null) ("-" + version);
+
+  nameAndVersion = name + versionStr;
+
+in runCommandLocal nameAndVersion {
   inherit meta;
 
   passthru = passthru // {
diff --git a/pkgs/build-support/build-graalvm-native-image/default.nix b/pkgs/build-support/build-graalvm-native-image/default.nix
index 3bf675b5d2083..c3c4a7b1e57b2 100644
--- a/pkgs/build-support/build-graalvm-native-image/default.nix
+++ b/pkgs/build-support/build-graalvm-native-image/default.nix
@@ -34,6 +34,9 @@ let
     "dontUnpack"
     "LC_ALL"
     "meta"
+    "buildPhase"
+    "nativeBuildInputs"
+    "installPhase"
   ];
 in
 stdenv.mkDerivation ({
diff --git a/pkgs/build-support/cc-wrapper/add-hardening.sh b/pkgs/build-support/cc-wrapper/add-hardening.sh
index b23fda1fed756..b1aa01355b137 100644
--- a/pkgs/build-support/cc-wrapper/add-hardening.sh
+++ b/pkgs/build-support/cc-wrapper/add-hardening.sh
@@ -12,8 +12,17 @@ done
 # Remove unsupported flags.
 for flag in @hardening_unsupported_flags@; do
   unset -v "hardeningEnableMap[$flag]"
+  # fortify being unsupported implies fortify3 is unsupported
+  if [[ "$flag" = 'fortify' ]] ; then
+    unset -v "hardeningEnableMap['fortify3']"
+  fi
 done
 
+# make fortify and fortify3 mutually exclusive
+if [[ -n "${hardeningEnableMap[fortify3]-}" ]]; then
+  unset -v "hardeningEnableMap['fortify']"
+fi
+
 if (( "${NIX_DEBUG:-0}" >= 1 )); then
   declare -a allHardeningFlags=(fortify stackprotector pie pic strictoverflow format)
   declare -A hardeningDisableMap=()
@@ -36,11 +45,23 @@ fi
 
 for flag in "${!hardeningEnableMap[@]}"; do
   case $flag in
-    fortify)
-      if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling fortify >&2; fi
+    fortify | fortify3)
       # Use -U_FORTIFY_SOURCE to avoid warnings on toolchains that explicitly
       # set -D_FORTIFY_SOURCE=0 (like 'clang -fsanitize=address').
-      hardeningCFlags+=('-O2' '-U_FORTIFY_SOURCE' '-D_FORTIFY_SOURCE=2')
+      hardeningCFlags+=('-O2' '-U_FORTIFY_SOURCE')
+      case $flag in
+        fortify)
+          if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling fortify >&2; fi
+          hardeningCFlags+=('-D_FORTIFY_SOURCE=2')
+        ;;
+        fortify3)
+          if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling fortify3 >&2; fi
+          hardeningCFlags+=('-D_FORTIFY_SOURCE=3')
+        ;;
+        *)
+          # Ignore unsupported.
+          ;;
+      esac
       ;;
     stackprotector)
       if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling stackprotector >&2; fi
diff --git a/pkgs/build-support/cc-wrapper/default.nix b/pkgs/build-support/cc-wrapper/default.nix
index 6520c04f5e8a8..d2a1ed39ee07f 100644
--- a/pkgs/build-support/cc-wrapper/default.nix
+++ b/pkgs/build-support/cc-wrapper/default.nix
@@ -9,7 +9,6 @@
 , lib
 , stdenvNoCC
 , cc ? null, libc ? null, bintools, coreutils ? null, shell ? stdenvNoCC.shell
-, gccForLibs ? null
 , zlib ? null
 , nativeTools, noLibc ? false, nativeLibc, nativePrefix ? ""
 , propagateDoc ? cc != null && cc ? man
@@ -18,6 +17,9 @@
 , isGNU ? false, isClang ? cc.isClang or false, gnugrep ? null
 , buildPackages ? {}
 , libcxx ? null
+, gccForLibs ? if useCcForLibs then cc else null
+# same as `gccForLibs`, but generalized beyond clang
+, useCcForLibs ? isClang
 }:
 
 with lib;
@@ -61,7 +63,7 @@ let
   expand-response-params =
     lib.optionalString ((buildPackages.stdenv.hasCC or false) && buildPackages.stdenv.cc != "/dev/null") (import ../expand-response-params { inherit (buildPackages) stdenv; });
 
-  useGccForLibs = isClang
+  useGccForLibs = useCcForLibs
     && libcxx == null
     && !stdenv.targetPlatform.isDarwin
     && !(stdenv.targetPlatform.useLLVM or false)
@@ -226,6 +228,10 @@ stdenv.mkDerivation {
 
       if [ -e $ccPath/cpp ]; then
         wrap ${targetPrefix}cpp $wrapper $ccPath/cpp
+    '' + lib.optionalString (hostPlatform != targetPlatform) ''
+      elif [ -e $ccPath/${targetPrefix}cpp ]; then
+        wrap ${targetPrefix}cpp $wrapper $ccPath/${targetPrefix}cpp
+    '' + ''
       fi
     ''
 
diff --git a/pkgs/build-support/coq/default.nix b/pkgs/build-support/coq/default.nix
index e26504a66f10a..eb045ddf6865a 100644
--- a/pkgs/build-support/coq/default.nix
+++ b/pkgs/build-support/coq/default.nix
@@ -52,7 +52,7 @@ let
       inherit release releaseRev;
       location = { inherit domain owner repo; };
     } // optionalAttrs (args?fetcher) {inherit fetcher;});
-  fetched = fetch (if !isNull version then version else defaultVersion);
+  fetched = fetch (if version != null then version else defaultVersion);
   display-pkg = n: sep: v:
     let d = displayVersion.${n} or (if sep == "" then ".." else true); in
     n + optionalString (v != "" && v != null) (switch d [
diff --git a/pkgs/build-support/coq/meta-fetch/default.nix b/pkgs/build-support/coq/meta-fetch/default.nix
index d5fe31c6ccf7d..82c29fb760b78 100644
--- a/pkgs/build-support/coq/meta-fetch/default.nix
+++ b/pkgs/build-support/coq/meta-fetch/default.nix
@@ -8,13 +8,13 @@ let
         fmt = if args?sha256 then "zip" else "tarball";
         pr  = match "^#(.*)$" rev;
         url = switch-if [
-          { cond = isNull pr && !isNull (match "^github.*" domain);
+          { cond = pr == null && (match "^github.*" domain) != null;
             out = "https://${domain}/${owner}/${repo}/archive/${rev}.${ext}"; }
-          { cond = !isNull pr && !isNull (match "^github.*" domain);
+          { cond = pr != null && (match "^github.*" domain) != null;
             out = "https://api.${domain}/repos/${owner}/${repo}/${fmt}/pull/${head pr}/head"; }
-          { cond = isNull pr && !isNull (match "^gitlab.*" domain);
+          { cond = pr == null && (match "^gitlab.*" domain) != null;
             out = "https://${domain}/${owner}/${repo}/-/archive/${rev}/${repo}-${rev}.${ext}"; }
-          { cond = !isNull (match "(www.)?mpi-sws.org" domain);
+          { cond = (match "(www.)?mpi-sws.org" domain) != null;
             out = "https://www.mpi-sws.org/~${owner}/${repo}/download/${repo}-${rev}.${ext}";}
         ] (throw "meta-fetch: no fetcher found for domain ${domain} on ${rev}");
         fetch = x: if args?sha256 then fetchzip (x // { inherit sha256; }) else fetchTarball x;
diff --git a/pkgs/build-support/docker/default.nix b/pkgs/build-support/docker/default.nix
index 7fa5aeafc8e3d..5f48fb9f7bdbe 100644
--- a/pkgs/build-support/docker/default.nix
+++ b/pkgs/build-support/docker/default.nix
@@ -190,7 +190,7 @@ rec {
       cat > /etc/pam.d/other <<EOF
     account sufficient pam_unix.so
     auth sufficient pam_rootok.so
-    password requisite pam_unix.so nullok sha512
+    password requisite pam_unix.so nullok yescrypt
     session required pam_unix.so
     EOF
     fi
diff --git a/pkgs/build-support/docker/nix-prefetch-docker b/pkgs/build-support/docker/nix-prefetch-docker
index 5798ab5984f17..f551d37cda96f 100755
--- a/pkgs/build-support/docker/nix-prefetch-docker
+++ b/pkgs/build-support/docker/nix-prefetch-docker
@@ -38,7 +38,7 @@ get_image_digest(){
         imageTag="latest"
     fi
 
-    skopeo --insecure-policy --tmpdir=$TMPDIR inspect "docker://$imageName:$imageTag" | jq '.Digest' -r
+    skopeo --override-os "${os}" --override-arch "${arch}" --insecure-policy --tmpdir=$TMPDIR inspect "docker://$imageName:$imageTag" | jq '.Digest' -r
 }
 
 get_name() {
diff --git a/pkgs/build-support/dotnet/build-dotnet-module/default.nix b/pkgs/build-support/dotnet/build-dotnet-module/default.nix
index 311eb2b293e5e..8858d4e9877dd 100644
--- a/pkgs/build-support/dotnet/build-dotnet-module/default.nix
+++ b/pkgs/build-support/dotnet/build-dotnet-module/default.nix
@@ -121,11 +121,13 @@ let
   # this contains all the nuget packages that are implicitly referenced by the dotnet
   # build system. having them as separate deps allows us to avoid having to regenerate
   # a packages dependencies when the dotnet-sdk version changes
-  sdkDeps = dotnet-sdk.packages;
+  sdkDeps = lib.lists.flatten [ dotnet-sdk.packages ];
 
-  sdkSource = mkNugetSource {
-    name = "dotnet-sdk-${dotnet-sdk.version}-source";
-    deps = [ sdkDeps ];
+  sdkSource = let
+    version = dotnet-sdk.version or (lib.concatStringsSep "-" dotnet-sdk.versions);
+  in mkNugetSource {
+    name = "dotnet-sdk-${version}-source";
+    deps = sdkDeps;
   };
 
   nuget-source = symlinkJoin {
@@ -174,7 +176,7 @@ stdenvNoCC.mkDerivation (args // {
           # Note that toString is necessary here as it results in the path at
           # eval time (i.e. to the file in your local Nixpkgs checkout) rather
           # than the Nix store path of the path after it's been imported.
-          if lib.isPath nugetDeps && !lib.hasPrefix "/nix/store/" (toString nugetDeps)
+          if lib.isPath nugetDeps && !lib.hasPrefix "${builtins.storeDir}/" (toString nugetDeps)
           then toString nugetDeps
           else ''$(mktemp -t "${pname}-deps-XXXXXX.nix")'';
       in
@@ -271,7 +273,12 @@ stdenvNoCC.mkDerivation (args // {
 
         echo "Writing lockfile..."
         echo -e "# This file was automatically generated by passthru.fetch-deps.\n# Please dont edit it manually, your changes might get overwritten!\n" > "$depsFile"
-        nuget-to-nix "$tmp/nuget_pkgs" "${sdkDeps}" >> "$depsFile"
+
+        excluded_sources="${lib.concatStringsSep " " sdkDeps}"
+        for excluded_source in ''${excluded_sources[@]}; do
+          ls "$excluded_source" >> "$tmp/excluded_list"
+        done
+        nuget-to-nix "$tmp/nuget_pkgs" "$tmp/excluded_list" >> "$depsFile"
         echo "Succesfully wrote lockfile to $depsFile"
       '';
   } // args.passthru or { };
diff --git a/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-fixup-hook.sh b/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-fixup-hook.sh
index 59df9b319afba..27885238ef7bf 100644
--- a/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-fixup-hook.sh
+++ b/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-fixup-hook.sh
@@ -1,5 +1,6 @@
 # Inherit arguments from the derivation
-makeWrapperArgs=( ${makeWrapperArgs-} )
+declare -a derivationMakeWrapperArgs="( ${makeWrapperArgs-} )"
+makeWrapperArgs=( "${derivationMakeWrapperArgs[@]}" )
 
 # First argument is the executable you want to wrap,
 # the second is the destination for the wrapper.
diff --git a/pkgs/build-support/dotnet/nuget-to-nix/nuget-to-nix.sh b/pkgs/build-support/dotnet/nuget-to-nix/nuget-to-nix.sh
index 390c96751facd..ce2a7070ea31e 100755
--- a/pkgs/build-support/dotnet/nuget-to-nix/nuget-to-nix.sh
+++ b/pkgs/build-support/dotnet/nuget-to-nix/nuget-to-nix.sh
@@ -7,14 +7,15 @@ export PATH="@binPath@"
 export LC_ALL=C
 
 if [ $# -eq 0 ]; then
-  >&2 echo "Usage: $0 <packages directory> [path to excluded package source] > deps.nix"
+  >&2 echo "Usage: $0 <packages directory> [path to a file with a list of excluded packages] > deps.nix"
   exit 1
 fi
 
 pkgs=$1
 tmp=$(realpath "$(mktemp -td nuget-to-nix.XXXXXX)")
 trap 'rm -r "$tmp"' EXIT
-excluded_source=$(realpath "${2:-$tmp/empty}")
+
+excluded_list=$(realpath "${2:-/dev/null}")
 
 export DOTNET_NOLOGO=1
 export DOTNET_CLI_TELEMETRY_OPTOUT=1
@@ -37,7 +38,7 @@ for package in *; do
   for version in *; do
     id=$(xq -r .package.metadata.id "$version/$package".nuspec)
 
-    if [[ -e "$excluded_source/$id.$version".nupkg ]]; then
+    if grep -qxF "$id.$version.nupkg" "$excluded_list"; then
       continue
     fi
 
diff --git a/pkgs/build-support/fetchdocker/default.nix b/pkgs/build-support/fetchdocker/default.nix
index 57d2e4ad82d2d..ef6132bfe3a5a 100644
--- a/pkgs/build-support/fetchdocker/default.nix
+++ b/pkgs/build-support/fetchdocker/default.nix
@@ -3,7 +3,7 @@ let
   stripScheme =
     builtins.replaceStrings [ "https://" "http://" ] [ "" "" ];
   stripNixStore =
-    s: lib.removePrefix "/nix/store/" s;
+    s: lib.removePrefix "${builtins.storeDir}/" s;
 in
 { name
 , registry         ? "https://registry-1.docker.io/v2/"
diff --git a/pkgs/build-support/make-desktopitem/default.nix b/pkgs/build-support/make-desktopitem/default.nix
index af314aa338c86..ccceb23256b6f 100644
--- a/pkgs/build-support/make-desktopitem/default.nix
+++ b/pkgs/build-support/make-desktopitem/default.nix
@@ -89,7 +89,7 @@ let
   renderSection = sectionName: attrs:
     lib.pipe attrs [
       (lib.mapAttrsToList renderLine)
-      (builtins.filter (v: !isNull v))
+      (builtins.filter (v: v != null))
       (builtins.concatStringsSep "\n")
       (section: ''
         [${sectionName}]
diff --git a/pkgs/build-support/ocaml/dune.nix b/pkgs/build-support/ocaml/dune.nix
index 81f1010e467cb..7b602e2507d51 100644
--- a/pkgs/build-support/ocaml/dune.nix
+++ b/pkgs/build-support/ocaml/dune.nix
@@ -32,7 +32,7 @@ stdenv.mkDerivation ({
     runHook preInstall
     dune install --prefix $out --libdir $OCAMLFIND_DESTDIR ${pname} \
      ${if lib.versionAtLeast Dune.version "2.9"
-       then "--docdir $out/share/doc --man $out/share/man"
+       then "--docdir $out/share/doc --mandir $out/share/man"
        else ""}
     runHook postInstall
   '';
diff --git a/pkgs/build-support/release/nix-build.nix b/pkgs/build-support/release/nix-build.nix
index 0498232d4d623..83e521bb65c74 100644
--- a/pkgs/build-support/release/nix-build.nix
+++ b/pkgs/build-support/release/nix-build.nix
@@ -140,7 +140,7 @@ stdenv.mkDerivation (
       (lib.optional doCoverityAnalysis args.cov-build) ++
       (lib.optional doCoverityAnalysis args.xz);
 
-    lcovFilter = ["/nix/store/*"] ++ lcovFilter;
+    lcovFilter = ["${builtins.storeDir}/*"] ++ lcovFilter;
 
     inherit lcovExtraTraceFiles;
 
diff --git a/pkgs/build-support/rust/build-rust-package/sysroot/default.nix b/pkgs/build-support/rust/build-rust-package/sysroot/default.nix
index 1e0b901105cd8..a6d53056d9c7c 100644
--- a/pkgs/build-support/rust/build-rust-package/sysroot/default.nix
+++ b/pkgs/build-support/rust/build-rust-package/sysroot/default.nix
@@ -1,10 +1,10 @@
-{ stdenv, rust, rustPlatform, buildPackages }:
+{ lib, stdenv, rust, rustPlatform, buildPackages }:
 
 { shortTarget, originalCargoToml, target, RUSTFLAGS }:
 
 let
   cargoSrc = import ../../sysroot/src.nix {
-    inherit stdenv rustPlatform buildPackages originalCargoToml;
+    inherit lib stdenv rustPlatform buildPackages originalCargoToml;
   };
 in rustPlatform.buildRustPackage {
   inherit target RUSTFLAGS;
@@ -14,7 +14,7 @@ in rustPlatform.buildRustPackage {
 
   RUSTC_BOOTSTRAP = 1;
   __internal_dontAddSysroot = true;
-  cargoSha256 = "0y6dqfhsgk00y3fv5bnjzk0s7i30nwqc1rp0xlrk83hkh80x81mw";
+  cargoSha256 = "sha256-zgkwevitxsu1C4OgGTsqNSc0gDxaNXYK1WPbfER48d0=";
 
   doCheck = false;
 
@@ -29,4 +29,7 @@ in rustPlatform.buildRustPackage {
     host=${rust.toRustTarget stdenv.buildPlatform}
     cp -r $RUST_SYSROOT/lib/rustlib/$host $out
   '';
+
+  # allows support for cross-compilation
+  meta.platforms = lib.platforms.all;
 }
diff --git a/pkgs/build-support/rust/fetch-cargo-tarball/default.nix b/pkgs/build-support/rust/fetch-cargo-tarball/default.nix
index 36ab931697410..adbfe98d81039 100644
--- a/pkgs/build-support/rust/fetch-cargo-tarball/default.nix
+++ b/pkgs/build-support/rust/fetch-cargo-tarball/default.nix
@@ -76,6 +76,17 @@ in stdenv.mkDerivation ({
     # Override the `http.cainfo` option usually specified in `.cargo/config`.
     export CARGO_HTTP_CAINFO=${cacert}/etc/ssl/certs/ca-bundle.crt
 
+    if grep '^source = "git' Cargo.lock; then
+        echo
+        echo "ERROR: The Cargo.lock contains git dependencies"
+        echo
+        echo "This is currently not supported in the fixed-output derivation fetcher."
+        echo "Use cargoLock.lockFile / importCargoLock instead."
+        echo
+
+        exit 1
+    fi
+
     cargo vendor $name --respect-source-config | cargo-vendor-normalise > $CARGO_CONFIG
 
     # Create an empty vendor directory when there is no dependency to vendor
diff --git a/pkgs/build-support/rust/fetchcrate.nix b/pkgs/build-support/rust/fetchcrate.nix
index 53219b2d06296..09f5e7805e166 100644
--- a/pkgs/build-support/rust/fetchcrate.nix
+++ b/pkgs/build-support/rust/fetchcrate.nix
@@ -1,15 +1,17 @@
-{ lib, fetchzip }:
+{ lib, fetchzip, fetchurl }:
 
 { crateName ? args.pname
 , pname ? null
 , version
+, unpack ? true
 , ...
 } @ args:
 
 assert pname == null || pname == crateName;
 
-fetchzip ({
+(if unpack then fetchzip else fetchurl) ({
   name = "${crateName}-${version}.tar.gz";
   url = "https://crates.io/api/v1/crates/${crateName}/${version}/download";
+} // lib.optionalAttrs unpack {
   extension = "tar.gz";
-} // removeAttrs args [ "crateName" "pname" "version" ])
+} // removeAttrs args [ "crateName" "pname" "version" "unpack" ])
diff --git a/pkgs/build-support/rust/hooks/cargo-setup-hook.sh b/pkgs/build-support/rust/hooks/cargo-setup-hook.sh
index 90a81d68b5200..693c0b08759ea 100644
--- a/pkgs/build-support/rust/hooks/cargo-setup-hook.sh
+++ b/pkgs/build-support/rust/hooks/cargo-setup-hook.sh
@@ -1,14 +1,18 @@
 cargoSetupPostUnpackHook() {
     echo "Executing cargoSetupPostUnpackHook"
 
-    export NIX_LDFLAGS+=" @aarch64LinuxGccWorkaround@"
-
     # 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"
+        if [ -d "$cargoDeps" ]; then
+            local dest=$(stripHash "$cargoDeps")
+            cp -Lr --reflink=auto -- "$cargoDeps" "$dest"
+            chmod -R +644 -- "$dest"
+        else
+            unpackFile "$cargoDeps"
+        fi
         export cargoDepsCopy="$(realpath "$(stripHash $cargoDeps)")"
     else
         cargoDepsCopy="$(realpath "$(pwd)/$sourceRoot/${cargoRoot:+$cargoRoot/}${cargoVendorDir}")"
diff --git a/pkgs/build-support/rust/hooks/default.nix b/pkgs/build-support/rust/hooks/default.nix
index b4034120103ed..168224e39b359 100644
--- a/pkgs/build-support/rust/hooks/default.nix
+++ b/pkgs/build-support/rust/hooks/default.nix
@@ -108,9 +108,6 @@ in {
           host-config = true
           target-applies-to-host = true
         '';
-
-        # https://github.com/NixOS/nixpkgs/issues/201254
-        aarch64LinuxGccWorkaround = lib.optionalString (stdenv.isLinux && stdenv.isAarch64 && stdenv.cc.isGNU) "-lgcc";
       };
     } ./cargo-setup-hook.sh) {};
 
diff --git a/pkgs/build-support/rust/import-cargo-lock.nix b/pkgs/build-support/rust/import-cargo-lock.nix
index 9ff9c2f6289c1..0e1da7ce5f524 100644
--- a/pkgs/build-support/rust/import-cargo-lock.nix
+++ b/pkgs/build-support/rust/import-cargo-lock.nix
@@ -1,4 +1,4 @@
-{ fetchgit, fetchurl, lib, runCommand, cargo, jq }:
+{ fetchgit, fetchurl, lib, writers, python3Packages, runCommand, cargo, jq }:
 
 {
   # Cargo lock file
@@ -93,6 +93,11 @@ let
       sha256 = checksum;
     };
 
+  # Replaces values inherited by workspace members.
+  replaceWorkspaceValues = writers.writePython3 "replace-workspace-values"
+    { libraries = with python3Packages; [ tomli tomli-w ]; flakeIgnore = [ "E501" ]; }
+    (builtins.readFile ./replace-workspace-values.py);
+
   # Fetch and unpack a crate.
   mkCrate = pkg:
     let
@@ -133,6 +138,7 @@ let
               inherit (gitParts) url;
               rev = gitParts.sha;
               allRefs = true;
+              submodules = true;
             }
           else
             missingHash;
@@ -168,9 +174,14 @@ let
         echo Found crate ${pkg.name} at $crateCargoTOML
         tree=$(dirname $crateCargoTOML)
 
-        cp -prvd "$tree/" $out
+        cp -prvL "$tree/" $out
         chmod u+w $out
 
+        if grep -q workspace "$out/Cargo.toml"; then
+          chmod u+w "$out/Cargo.toml"
+          ${replaceWorkspaceValues} "$out/Cargo.toml" "${tree}/Cargo.toml"
+        fi
+
         # Cargo is happy with empty metadata.
         printf '{"files":{},"package":null}' > "$out/.cargo-checksum.json"
 
diff --git a/pkgs/build-support/rust/replace-workspace-values.py b/pkgs/build-support/rust/replace-workspace-values.py
new file mode 100644
index 0000000000000..f5108f840b336
--- /dev/null
+++ b/pkgs/build-support/rust/replace-workspace-values.py
@@ -0,0 +1,103 @@
+# This script implements the workspace inheritance mechanism described
+# here: https://doc.rust-lang.org/cargo/reference/workspaces.html#the-package-table
+#
+# Please run `mypy --strict`, `black`, and `isort --profile black` on this after editing, thanks!
+
+import sys
+from typing import Any
+
+import tomli
+import tomli_w
+
+
+def load_file(path: str) -> dict[str, Any]:
+    with open(path, "rb") as f:
+        return tomli.load(f)
+
+
+def replace_key(
+    workspace_manifest: dict[str, Any], table: dict[str, Any], section: str, key: str
+) -> bool:
+    if "workspace" in table[key] and table[key]["workspace"] is True:
+        print("replacing " + key)
+
+        replaced = table[key]
+        del replaced["workspace"]
+
+        workspace_copy = workspace_manifest[section][key]
+
+        if section == "dependencies":
+            crate_features = replaced.get("features")
+
+            if type(workspace_copy) is str:
+                replaced["version"] = workspace_copy
+            else:
+                replaced.update(workspace_copy)
+
+                merged_features = (crate_features or []) + (
+                    workspace_copy.get("features") or []
+                )
+
+                if len(merged_features) > 0:
+                    # Dictionaries are guaranteed to be ordered (https://stackoverflow.com/a/7961425)
+                    replaced["features"] = list(dict.fromkeys(merged_features))
+        elif section == "package":
+            table[key] = replaced = workspace_copy
+
+        return True
+
+    return False
+
+
+def replace_dependencies(
+    workspace_manifest: dict[str, Any], root: dict[str, Any]
+) -> bool:
+    changed = False
+
+    for key in ["dependencies", "dev-dependencies", "build-dependencies"]:
+        if key in root:
+            for k in root[key].keys():
+                changed |= replace_key(workspace_manifest, root[key], "dependencies", k)
+
+    return changed
+
+
+def main() -> None:
+    top_cargo_toml = load_file(sys.argv[2])
+
+    if "workspace" not in top_cargo_toml:
+        # If top_cargo_toml is not a workspace manifest, then this script was probably
+        # ran on something that does not actually use workspace dependencies
+        print(f"{sys.argv[2]} is not a workspace manifest, doing nothing.")
+        return
+
+    crate_manifest = load_file(sys.argv[1])
+    workspace_manifest = top_cargo_toml["workspace"]
+
+    if "workspace" in crate_manifest:
+        return
+
+    changed = False
+
+    for key in crate_manifest["package"].keys():
+        changed |= replace_key(
+            workspace_manifest, crate_manifest["package"], "package", key
+        )
+
+    changed |= replace_dependencies(workspace_manifest, crate_manifest)
+
+    if "target" in crate_manifest:
+        for key in crate_manifest["target"].keys():
+            changed |= replace_dependencies(
+                workspace_manifest, crate_manifest["target"][key]
+            )
+
+    if not changed:
+        return
+
+    with open(sys.argv[1], "wb") as f:
+        tomli_w.dump(crate_manifest, f)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/pkgs/build-support/rust/sysroot/Cargo.lock b/pkgs/build-support/rust/sysroot/Cargo.lock
index 6ec6da6ae6e28..d9b0c25d02f2b 100644
--- a/pkgs/build-support/rust/sysroot/Cargo.lock
+++ b/pkgs/build-support/rust/sysroot/Cargo.lock
@@ -1,5 +1,7 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
+version = 3
+
 [[package]]
 name = "alloc"
 version = "0.0.0"
@@ -10,9 +12,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.52"
+version = "0.1.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6591c2442ee984e2b264638a8b5e7ae44fd47b32d28e3a08e2e9c3cdb0c2fb0"
+checksum = "f867ce54c09855ccd135ad4a50c777182a0c7af5ff20a8f537617bd648b10d50"
 dependencies = [
  "rustc-std-workspace-core",
 ]
diff --git a/pkgs/build-support/rust/sysroot/src.nix b/pkgs/build-support/rust/sysroot/src.nix
index 3d11b62dd3156..664702e82c31b 100644
--- a/pkgs/build-support/rust/sysroot/src.nix
+++ b/pkgs/build-support/rust/sysroot/src.nix
@@ -19,7 +19,7 @@ stdenv.mkDerivation {
   + ''
     ${buildPackages.python3.withPackages (ps: with ps; [ toml ])}/bin/python3 ${./cargo.py}
     mkdir -p $out/src
-    touch $out/src/lib.rs
+    echo '#![no_std]' > $out/src/lib.rs
     cp Cargo.toml $out/Cargo.toml
     cp ${./Cargo.lock} $out/Cargo.lock
   '';
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/default.nix b/pkgs/build-support/rust/test/import-cargo-lock/default.nix
index 74be68b2c3564..f399107eb9821 100644
--- a/pkgs/build-support/rust/test/import-cargo-lock/default.nix
+++ b/pkgs/build-support/rust/test/import-cargo-lock/default.nix
@@ -1,4 +1,4 @@
-{ callPackage }:
+{ callPackage, writers, python3Packages }:
 
 # Build like this from nixpkgs root:
 # $ nix-build -A tests.importCargoLock
@@ -12,4 +12,9 @@
   gitDependencyBranch = callPackage ./git-dependency-branch { };
   maturin = callPackage ./maturin { };
   v1 = callPackage ./v1 { };
+  gitDependencyWorkspaceInheritance = callPackage ./git-dependency-workspace-inheritance {
+    replaceWorkspaceValues = writers.writePython3 "replace-workspace-values"
+      { libraries = with python3Packages; [ tomli tomli-w ]; flakeIgnore = [ "E501" ]; }
+      (builtins.readFile ../../replace-workspace-values.py);
+  };
 }
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-workspace-inheritance/crate.toml b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-workspace-inheritance/crate.toml
new file mode 100644
index 0000000000000..a50855706dff7
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-workspace-inheritance/crate.toml
@@ -0,0 +1,6 @@
+[package]
+version = { workspace = true }
+
+[dependencies]
+foo = { workspace = true, features = ["cat"] }
+bar = "1.0.0"
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-workspace-inheritance/default.nix b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-workspace-inheritance/default.nix
new file mode 100644
index 0000000000000..138b7179b95fd
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-workspace-inheritance/default.nix
@@ -0,0 +1,7 @@
+{ replaceWorkspaceValues, runCommand }:
+
+runCommand "git-dependency-workspace-inheritance-test" { } ''
+  cp --no-preserve=mode ${./crate.toml} "$out"
+  ${replaceWorkspaceValues} "$out" ${./workspace.toml}
+  diff -u "$out" ${./want.toml}
+''
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-workspace-inheritance/want.toml b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-workspace-inheritance/want.toml
new file mode 100644
index 0000000000000..3c11228e97c2f
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-workspace-inheritance/want.toml
@@ -0,0 +1,12 @@
+[package]
+version = "1.0.0"
+
+[dependencies]
+bar = "1.0.0"
+
+[dependencies.foo]
+features = [
+    "cat",
+    "meow",
+]
+version = "1.0.0"
diff --git a/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-workspace-inheritance/workspace.toml b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-workspace-inheritance/workspace.toml
new file mode 100644
index 0000000000000..c58112a782d03
--- /dev/null
+++ b/pkgs/build-support/rust/test/import-cargo-lock/git-dependency-workspace-inheritance/workspace.toml
@@ -0,0 +1,5 @@
+[workspace.package]
+version = "1.0.0"
+
+[workspace.dependencies]
+foo = { version = "1.0.0", features = ["meow"] }
diff --git a/pkgs/build-support/setup-hooks/multiple-outputs.sh b/pkgs/build-support/setup-hooks/multiple-outputs.sh
index 3a318933f138d..8a62c57dbd071 100644
--- a/pkgs/build-support/setup-hooks/multiple-outputs.sh
+++ b/pkgs/build-support/setup-hooks/multiple-outputs.sh
@@ -13,13 +13,14 @@ postFixupHooks+=(_multioutPropagateDev)
 # specific to this function's use case, which is setting up the output variables.
 _assignFirst() {
     local varName="$1"
+    local _var
     local REMOVE=REMOVE # slightly hacky - we allow REMOVE (i.e. not a variable name)
     shift
-    for var in "$@"; do
-        if [ -n "${!var-}" ]; then eval "${varName}"="${var}"; return; fi
+    for _var in "$@"; do
+        if [ -n "${!_var-}" ]; then eval "${varName}"="${_var}"; return; fi
     done
     echo
-    echo "error: _assignFirst: could not find a non-empty variable to assign to ${varName}."
+    echo "error: _assignFirst: could not find a non-empty variable whose name to assign to ${varName}."
     echo "       The following variables were all unset or empty:"
     echo "           $*"
     if [ -z "${out:-}" ]; then
@@ -138,9 +139,9 @@ moveToOutput() {
 
             # remove empty directories, printing iff at least one gets removed
             local srcParent="$(readlink -m "$srcPath/..")"
-            if rmdir "$srcParent"; then
+            if [ -n "$(find "$srcParent" -maxdepth 0 -type d -empty 2>/dev/null)" ]; then
                 echo "Removing empty $srcParent/ and (possibly) its parents"
-                rmdir -p --ignore-fail-on-non-empty "$(readlink -m "$srcParent/..")" \
+                rmdir -p --ignore-fail-on-non-empty "$srcParent" \
                     2> /dev/null || true # doesn't ignore failure for some reason
             fi
         done
diff --git a/pkgs/build-support/setup-hooks/patch-shebangs.sh b/pkgs/build-support/setup-hooks/patch-shebangs.sh
index a26113abea88e..9a48440debec3 100644
--- a/pkgs/build-support/setup-hooks/patch-shebangs.sh
+++ b/pkgs/build-support/setup-hooks/patch-shebangs.sh
@@ -62,15 +62,21 @@ patchShebangs() {
         fi
 
         if [[ "$oldPath" == *"/bin/env" ]]; then
+            if [[ $arg0 == "-S" ]]; then
+                arg0=${args%% *}
+                args=${args#* }
+                newPath="$(PATH="${!pathName}" command -v "env" || true)"
+                args="-S $(PATH="${!pathName}" command -v "$arg0" || true) $args"
+
             # Check for unsupported 'env' functionality:
-            # - options: something starting with a '-'
+            # - options: something starting with a '-' besides '-S'
             # - environment variables: foo=bar
-            if [[ $arg0 == "-"* || $arg0 == *"="* ]]; then
+            elif [[ $arg0 == "-"* || $arg0 == *"="* ]]; then
                 echo "$f: unsupported interpreter directive \"$oldInterpreterLine\" (set dontPatchShebangs=1 and handle shebang patching yourself)" >&2
                 exit 1
+            else
+                newPath="$(PATH="${!pathName}" command -v "$arg0" || true)"
             fi
-
-            newPath="$(PATH="${!pathName}" command -v "$arg0" || true)"
         else
             if [[ -z $oldPath ]]; then
                 # If no interpreter is specified linux will use /bin/sh. Set
diff --git a/pkgs/build-support/setup-hooks/reproducible-builds.sh b/pkgs/build-support/setup-hooks/reproducible-builds.sh
index 7b52f84df67b4..5e27ce8a25fec 100644
--- a/pkgs/build-support/setup-hooks/reproducible-builds.sh
+++ b/pkgs/build-support/setup-hooks/reproducible-builds.sh
@@ -3,7 +3,8 @@
 # derivation and not easily collide with other builds.
 # We also truncate the hash so that it cannot cause reference cycles.
 NIX_CFLAGS_COMPILE="${NIX_CFLAGS_COMPILE:-} -frandom-seed=$(
-    outbase="${out##*/}"
+    randSeed=${NIX_OUTPATH_USED_AS_RANDOM_SEED:-$out}
+    outbase="${randSeed##*/}"
     randomseed="${outbase:0:10}"
     echo $randomseed
 )"
diff --git a/pkgs/build-support/setup-hooks/separate-debug-info.sh b/pkgs/build-support/setup-hooks/separate-debug-info.sh
index 3c8c9c294c3e2..ca651b4393a11 100644
--- a/pkgs/build-support/setup-hooks/separate-debug-info.sh
+++ b/pkgs/build-support/setup-hooks/separate-debug-info.sh
@@ -11,6 +11,9 @@ _separateDebugInfo() {
     local dst="${debug:-$out}"
     if [ "$prefix" = "$dst" ]; then return 0; fi
 
+    # in case there is nothing to strip, don't fail the build
+    mkdir -p "$dst"
+
     dst="$dst/lib/debug/.build-id"
 
     # Find executables and dynamic libraries.
diff --git a/pkgs/build-support/setup-hooks/wrap-gapps-hook/default.nix b/pkgs/build-support/setup-hooks/wrap-gapps-hook/default.nix
index 99633a3c7c9af..3c5199be31322 100644
--- a/pkgs/build-support/setup-hooks/wrap-gapps-hook/default.nix
+++ b/pkgs/build-support/setup-hooks/wrap-gapps-hook/default.nix
@@ -17,16 +17,6 @@ makeSetupHook {
   propagatedBuildInputs = [
     # We use the wrapProgram function.
     makeWrapper
-  ] ++ lib.optionals (!stdenv.isDarwin) [
-    # It is highly probable that a program will use GSettings,
-    # at minimum through GTK file chooser dialogue.
-    # Let’s add a GIO module for “dconf” GSettings backend
-    # to avoid falling back to “memory” backend. This is
-    # required for GSettings-based settings to be persisted.
-    # Unfortunately, it also requires the user to have dconf
-    # D-Bus service enabled globally (e.g. through a NixOS module).
-    dconf.lib
-
   ] ++ lib.optionals isGraphical [
     # TODO: remove this, packages should depend on GTK explicitly.
     gtk3
@@ -35,13 +25,25 @@ makeSetupHook {
   ];
 
   # depsTargetTargetPropagated will essentially be buildInputs when wrapGAppsHook is placed into nativeBuildInputs
-  # the librsvg above should be removed but kept to not break anything that implicitly depended on its binaries
+  # the librsvg and gtk3 above should be removed but kept to not break anything that implicitly depended on its binaries
   depsTargetTargetPropagated = assert (lib.assertMsg (!targetPackages ? raw) "wrapGAppsHook must be in nativeBuildInputs"); lib.optionals isGraphical [
     # librsvg provides a module for gdk-pixbuf to allow rendering
     # SVG icons. Most icon themes are SVG-based and so are some
     # graphics in GTK (e.g. cross for closing window in window title bar)
     # so it is pretty much required for applications using GTK.
     librsvg
+
+    # TODO: remove this, packages should depend on GTK explicitly.
+    gtk3
+  ] ++ lib.optionals (!stdenv.isDarwin) [
+    # It is highly probable that a program will use GSettings,
+    # at minimum through GTK file chooser dialogue.
+    # Let’s add a GIO module for “dconf” GSettings backend
+    # to avoid falling back to “memory” backend. This is
+    # required for GSettings-based settings to be persisted.
+    # Unfortunately, it also requires the user to have dconf
+    # D-Bus service enabled globally (e.g. through a NixOS module).
+    dconf.lib
   ];
   passthru = {
     tests = let
@@ -56,6 +58,7 @@ makeSetupHook {
 
         src = sample-project;
 
+        strictDeps = true;
         nativeBuildInputs = [ wrapGAppsHook ];
 
         installFlags = [ "bin-foo" "libexec-bar" ];
@@ -86,6 +89,8 @@ makeSetupHook {
 
         src = sample-project;
 
+        strictDeps = true;
+
         installFlags = [ "typelib-Mahjong" ];
       };
 
@@ -95,6 +100,7 @@ makeSetupHook {
 
         src = sample-project;
 
+        strictDeps = true;
         nativeBuildInputs = [
           gobject-introspection
           wrapGAppsHook
@@ -126,6 +132,8 @@ makeSetupHook {
 
         src = sample-project;
 
+        strictDeps = true;
+
         makeFlags = [
           "LIBDIR=${placeholder "lib"}/lib"
         ];
@@ -139,6 +147,7 @@ makeSetupHook {
 
         src = sample-project;
 
+        strictDeps = true;
         nativeBuildInputs = [
           gobject-introspection
           wrapGAppsHook
@@ -169,6 +178,7 @@ makeSetupHook {
 
         src = sample-project;
 
+        strictDeps = true;
         nativeBuildInputs = [
           gobject-introspection
           wrapGAppsHook
diff --git a/pkgs/build-support/trivial-builders.nix b/pkgs/build-support/trivial-builders.nix
index d8b4ae5dd97f8..2a4e93f82dffe 100644
--- a/pkgs/build-support/trivial-builders.nix
+++ b/pkgs/build-support/trivial-builders.nix
@@ -132,13 +132,12 @@ rec {
     , destination ? ""   # relative path appended to $out eg "/bin/foo"
     , checkPhase ? ""    # syntax checks, e.g. for scripts
     , meta ? { }
+    , allowSubstitutes ? false
+    , preferLocalBuild ? true
     }:
     runCommand name
-      { inherit text executable checkPhase meta;
+      { inherit text executable checkPhase meta allowSubstitutes preferLocalBuild;
         passAsFile = [ "text" ];
-        # Pointless to do this on a remote machine.
-        preferLocalBuild = true;
-        allowSubstitutes = false;
       }
       ''
         target=$out${lib.escapeShellArg destination}
@@ -324,6 +323,8 @@ rec {
       inherit name;
       executable = true;
       destination = "/bin/${name}";
+      allowSubstitutes = true;
+      preferLocalBuild = false;
       text = ''
         #!${runtimeShell}
         set -o errexit
@@ -511,8 +512,8 @@ rec {
       ''
         mkdir -p $out
         for i in $(cat $pathsPath); do
-          ${lndir}/bin/lndir $i $out
-        done 2>&1 | sed 's/^/symlinkJoin: warning: keeping existing file: /'
+          ${lndir}/bin/lndir -silent $i $out
+        done
         ${postBuild}
       '';
 
diff --git a/pkgs/build-support/trivial-builders/test/references.nix b/pkgs/build-support/trivial-builders/test/references.nix
index 3e1eb16eecd0b..7c8ea83f3c8bf 100644
--- a/pkgs/build-support/trivial-builders/test/references.nix
+++ b/pkgs/build-support/trivial-builders/test/references.nix
@@ -45,10 +45,8 @@ testers.nixosTest {
       """)
     '';
   meta = {
-    license = lib.licenses.mit; # nixpkgs license
     maintainers = with lib.maintainers; [
       roberth
     ];
-    description = "Run the Nixpkgs trivial builders tests";
   };
 }
diff --git a/pkgs/build-support/writers/default.nix b/pkgs/build-support/writers/default.nix
index ca0184beeb0c0..2c26f350fbd77 100644
--- a/pkgs/build-support/writers/default.nix
+++ b/pkgs/build-support/writers/default.nix
@@ -71,12 +71,12 @@ let
     let
       name = last (builtins.split "/" nameOrPath);
     in
-    pkgs.runCommand name (if (types.str.check content) then {
+    pkgs.runCommand name ((if (types.str.check content) then {
       inherit content;
       passAsFile = [ "content" ];
     } else {
       contentPath = content;
-    } // lib.optionalAttrs (stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64) {
+    }) // lib.optionalAttrs (stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64) {
       # post-link-hook expects codesign_allocate to be in PATH
       # https://github.com/NixOS/nixpkgs/issues/154203
       # https://github.com/NixOS/nixpkgs/issues/148189