about summary refs log tree commit diff
path: root/nixpkgs/pkgs/build-support
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2023-12-15 19:32:38 +0100
committerAlyssa Ross <hi@alyssa.is>2023-12-15 19:32:38 +0100
commit6b8e2555ef013b579cda57025b17d662e0f1fe1f (patch)
tree5a83c673af26c9976acd5a5dfa20e09e06898047 /nixpkgs/pkgs/build-support
parent66ca7a150b5c051f0728f13134e6265cc46f370c (diff)
parent02357adddd0889782362d999628de9d309d202dc (diff)
downloadnixlib-6b8e2555ef013b579cda57025b17d662e0f1fe1f.tar
nixlib-6b8e2555ef013b579cda57025b17d662e0f1fe1f.tar.gz
nixlib-6b8e2555ef013b579cda57025b17d662e0f1fe1f.tar.bz2
nixlib-6b8e2555ef013b579cda57025b17d662e0f1fe1f.tar.lz
nixlib-6b8e2555ef013b579cda57025b17d662e0f1fe1f.tar.xz
nixlib-6b8e2555ef013b579cda57025b17d662e0f1fe1f.tar.zst
nixlib-6b8e2555ef013b579cda57025b17d662e0f1fe1f.zip
Merge branch 'nixos-unstable-small' of https://github.com/NixOS/nixpkgs
Diffstat (limited to 'nixpkgs/pkgs/build-support')
-rw-r--r--nixpkgs/pkgs/build-support/appimage/default.nix1
-rw-r--r--nixpkgs/pkgs/build-support/bintools-wrapper/default.nix4
-rw-r--r--nixpkgs/pkgs/build-support/build-fhsenv-bubblewrap/default.nix18
-rw-r--r--nixpkgs/pkgs/build-support/build-graalvm-native-image/default.nix7
-rw-r--r--nixpkgs/pkgs/build-support/build-setupcfg/default.nix26
-rw-r--r--nixpkgs/pkgs/build-support/dotnet/build-dotnet-module/default.nix2
-rw-r--r--nixpkgs/pkgs/build-support/dotnet/make-nuget-source/default.nix20
-rw-r--r--nixpkgs/pkgs/build-support/node/build-npm-package/hooks/npm-install-hook.sh6
-rw-r--r--nixpkgs/pkgs/build-support/node/fetch-npm-deps/src/main.rs4
-rw-r--r--nixpkgs/pkgs/build-support/node/fetch-npm-deps/src/parse/lock.rs87
-rw-r--r--nixpkgs/pkgs/build-support/php/hooks/composer-install-hook.sh2
-rw-r--r--nixpkgs/pkgs/build-support/rust/rustc-wrapper/default.nix30
-rw-r--r--nixpkgs/pkgs/build-support/rust/rustc-wrapper/rustc-wrapper.sh16
-rw-r--r--nixpkgs/pkgs/build-support/setup-hooks/auto-patchelf.py7
-rw-r--r--nixpkgs/pkgs/build-support/setup-hooks/separate-debug-info.sh2
-rw-r--r--nixpkgs/pkgs/build-support/templaterpm/default.nix25
-rwxr-xr-xnixpkgs/pkgs/build-support/templaterpm/nix-template-rpm.py518
-rw-r--r--nixpkgs/pkgs/build-support/trivial-builders/test/default.nix11
-rw-r--r--nixpkgs/pkgs/build-support/trivial-builders/test/invoke-writeDirectReferencesToFile.nix4
-rw-r--r--nixpkgs/pkgs/build-support/trivial-builders/test/invoke-writeReferencesToFile.nix4
-rwxr-xr-xnixpkgs/pkgs/build-support/trivial-builders/test/references-test.sh62
-rw-r--r--nixpkgs/pkgs/build-support/trivial-builders/test/references.nix52
-rw-r--r--nixpkgs/pkgs/build-support/trivial-builders/test/references/default.nix124
-rwxr-xr-xnixpkgs/pkgs/build-support/trivial-builders/test/references/references-test.sh61
-rw-r--r--nixpkgs/pkgs/build-support/trivial-builders/test/references/samples.nix30
-rw-r--r--nixpkgs/pkgs/build-support/trivial-builders/test/sample.nix29
-rw-r--r--nixpkgs/pkgs/build-support/trivial-builders/test/writeStringReferencesToFile.nix7
27 files changed, 380 insertions, 779 deletions
diff --git a/nixpkgs/pkgs/build-support/appimage/default.nix b/nixpkgs/pkgs/build-support/appimage/default.nix
index 7b9bb239402b..078570ec7aea 100644
--- a/nixpkgs/pkgs/build-support/appimage/default.nix
+++ b/nixpkgs/pkgs/build-support/appimage/default.nix
@@ -173,6 +173,7 @@ rec {
       libpulseaudio
       libsamplerate
       libmikmod
+      libthai
       libtheora
       libtiff
       pixman
diff --git a/nixpkgs/pkgs/build-support/bintools-wrapper/default.nix b/nixpkgs/pkgs/build-support/bintools-wrapper/default.nix
index dd6032fc52cf..525b44fe0480 100644
--- a/nixpkgs/pkgs/build-support/bintools-wrapper/default.nix
+++ b/nixpkgs/pkgs/build-support/bintools-wrapper/default.nix
@@ -316,10 +316,10 @@ stdenv.mkDerivation {
     ''
 
     ###
-    ### Remove LC_UUID
+    ### Remove certain timestamps from final binaries
     ###
     + optionalString (stdenv.targetPlatform.isDarwin && !(bintools.isGNU or false)) ''
-      echo "-no_uuid" >> $out/nix-support/libc-ldflags-before
+      echo "export ZERO_AR_DATE=1" >> $out/nix-support/setup-hook
     ''
 
     + ''
diff --git a/nixpkgs/pkgs/build-support/build-fhsenv-bubblewrap/default.nix b/nixpkgs/pkgs/build-support/build-fhsenv-bubblewrap/default.nix
index 3500e5e9216f..b6b5f13bba97 100644
--- a/nixpkgs/pkgs/build-support/build-fhsenv-bubblewrap/default.nix
+++ b/nixpkgs/pkgs/build-support/build-fhsenv-bubblewrap/default.nix
@@ -16,6 +16,7 @@
 , extraInstallCommands ? ""
 , meta ? {}
 , passthru ? {}
+, extraPreBwrapCmds ? ""
 , extraBwrapArgs ? []
 , unshareUser ? false
 , unshareIpc ? false
@@ -23,6 +24,7 @@
 , unshareNet ? false
 , unshareUts ? false
 , unshareCgroup ? false
+, privateTmp ? false
 , dieWithParent ? true
 , ...
 } @ args:
@@ -38,8 +40,8 @@ let
   buildFHSEnv = callPackage ./buildFHSEnv.nix { };
 
   fhsenv = buildFHSEnv (removeAttrs (args // { inherit name; }) [
-    "runScript" "extraInstallCommands" "meta" "passthru" "extraBwrapArgs" "dieWithParent"
-    "unshareUser" "unshareCgroup" "unshareUts" "unshareNet" "unsharePid" "unshareIpc"
+    "runScript" "extraInstallCommands" "meta" "passthru" "extraPreBwrapCmds" "extraBwrapArgs" "dieWithParent"
+    "unshareUser" "unshareCgroup" "unshareUts" "unshareNet" "unsharePid" "unshareIpc" "privateTmp"
     "pname" "version"
   ]);
 
@@ -116,7 +118,8 @@ let
 
   indentLines = str: lib.concatLines (map (s: "  " + s) (filter (s: s != "") (lib.splitString "\n" str)));
   bwrapCmd = { initArgs ? "" }: ''
-    ignored=(/nix /dev /proc /etc)
+    ${extraPreBwrapCmds}
+    ignored=(/nix /dev /proc /etc ${lib.optionalString privateTmp "/tmp"})
     ro_mounts=()
     symlinks=()
     etc_ignored=()
@@ -150,10 +153,8 @@ let
       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")
+      if [[ -e $i ]]; then
+        symlinks+=(--symlink "/.host-etc/''${i#/etc/}" "$i")
       fi
     done
 
@@ -192,6 +193,8 @@ let
       ${lib.optionalString unshareCgroup "--unshare-cgroup"}
       ${lib.optionalString dieWithParent "--die-with-parent"}
       --ro-bind /nix /nix
+      --ro-bind /etc /.host-etc
+      ${lib.optionalString privateTmp "--tmpfs /tmp"}
       # Our glibc will look for the cache in its own path in `/nix/store`.
       # As such, we need a cache to exist there, because pressure-vessel
       # depends on the existence of an ld cache. However, adding one
@@ -200,6 +203,7 @@ let
       # Also, the cache needs to go to both 32 and 64 bit glibcs, for games
       # of both architectures to work.
       --tmpfs ${glibc}/etc \
+      --tmpfs /etc \
       --symlink /etc/ld.so.conf ${glibc}/etc/ld.so.conf \
       --symlink /etc/ld.so.cache ${glibc}/etc/ld.so.cache \
       --ro-bind ${glibc}/etc/rpc ${glibc}/etc/rpc \
diff --git a/nixpkgs/pkgs/build-support/build-graalvm-native-image/default.nix b/nixpkgs/pkgs/build-support/build-graalvm-native-image/default.nix
index e5fe1abe1d11..0612db2ad79b 100644
--- a/nixpkgs/pkgs/build-support/build-graalvm-native-image/default.nix
+++ b/nixpkgs/pkgs/build-support/build-graalvm-native-image/default.nix
@@ -49,6 +49,13 @@ stdenv.mkDerivation ({
 
   nativeImageBuildArgs = nativeImageBuildArgs ++ extraNativeImageBuildArgs ++ [ graalvmXmx ];
 
+  # Workaround GraalVM issue where the builder does not have access to the
+  # environment variables since 21.0.0
+  # https://github.com/oracle/graal/pull/6095
+  # https://github.com/oracle/graal/pull/6095
+  # https://github.com/oracle/graal/issues/7502
+  env.NATIVE_IMAGE_DEPRECATED_BUILDER_SANITATION = "true";
+
   buildPhase = args.buildPhase or ''
     runHook preBuild
 
diff --git a/nixpkgs/pkgs/build-support/build-setupcfg/default.nix b/nixpkgs/pkgs/build-support/build-setupcfg/default.nix
deleted file mode 100644
index 5737989249af..000000000000
--- a/nixpkgs/pkgs/build-support/build-setupcfg/default.nix
+++ /dev/null
@@ -1,26 +0,0 @@
-# Build a python package from info made available by setupcfg2nix.
-#
-# * src: The source of the package.
-# * info: The package information generated by setupcfg2nix.
-# * meta: Standard nixpkgs metadata.
-# * application: Whether this package is a python library or an
-#   application which happens to be written in python.
-# * doCheck: Whether to run the test suites.
-lib: pythonPackages:
-{ src, info, meta ? {}, application ? false, doCheck ? true}: let
-  build = if application
-    then pythonPackages.buildPythonApplication
-  else pythonPackages.buildPythonPackage;
-in build {
-  inherit (info) pname version;
-
-  inherit src meta doCheck;
-
-  nativeBuildInputs = map (p: pythonPackages.${p}) (
-    (info.setup_requires or []) ++
-    (lib.optionals doCheck (info.tests_require or []))
-  );
-
-  propagatedBuildInputs = map (p: pythonPackages.${p})
-    (info.install_requires or []);
-}
diff --git a/nixpkgs/pkgs/build-support/dotnet/build-dotnet-module/default.nix b/nixpkgs/pkgs/build-support/dotnet/build-dotnet-module/default.nix
index f8ed3a38890c..573b270ee408 100644
--- a/nixpkgs/pkgs/build-support/dotnet/build-dotnet-module/default.nix
+++ b/nixpkgs/pkgs/build-support/dotnet/build-dotnet-module/default.nix
@@ -165,7 +165,7 @@ stdenvNoCC.mkDerivation (args // {
     components = lib.pipe args.version [
       lib.splitVersion
       (lib.filter (x: (lib.strings.match "[0-9]+" x) != null))
-      (lib.filter (x: (lib.toInt x) < 65535)) # one version component in dotnet has to fit in 16 bits
+      (lib.filter (x: (lib.toIntBase10 x) < 65535)) # one version component in dotnet has to fit in 16 bits
     ];
   in if (lib.length components) == 0
   then null
diff --git a/nixpkgs/pkgs/build-support/dotnet/make-nuget-source/default.nix b/nixpkgs/pkgs/build-support/dotnet/make-nuget-source/default.nix
index a23a143ab246..48de65e8a881 100644
--- a/nixpkgs/pkgs/build-support/dotnet/make-nuget-source/default.nix
+++ b/nixpkgs/pkgs/build-support/dotnet/make-nuget-source/default.nix
@@ -6,10 +6,9 @@
 }:
 
 let
-  nuget-source = stdenvNoCC.mkDerivation rec {
+  nuget-source = stdenvNoCC.mkDerivation {
     inherit name;
 
-    meta.description = description;
     nativeBuildInputs = [ python3 ];
 
     buildCommand = ''
@@ -18,17 +17,22 @@ let
       # use -L to follow symbolic links. When `projectReferences` is used in
       # buildDotnetModule, one of the deps will be a symlink farm.
       find -L ${lib.concatStringsSep " " deps} -type f -name '*.nupkg' -exec \
-        cp --no-clobber '{}' $out/lib ';'
+        ln -s '{}' -t $out/lib ';'
 
       # Generates a list of all licenses' spdx ids, if available.
       # Note that this currently ignores any license provided in plain text (e.g. "LICENSE.txt")
       python ${./extract-licenses-from-nupkgs.py} $out/lib > $out/share/licenses
     '';
+
+    meta.description = description;
   } // { # We need data from `$out` for `meta`, so we have to use overrides as to not hit infinite recursion.
-    meta.licence = let
-      depLicenses = lib.splitString "\n" (builtins.readFile "${nuget-source}/share/licenses");
-    in (lib.flatten (lib.forEach depLicenses (spdx:
-      lib.optionals (spdx != "") (lib.getLicenseFromSpdxId spdx)
-    )));
+    meta = nuget-source.meta // {
+      licenses = let
+        # TODO: avoid IFD
+        depLicenses = lib.splitString "\n" (builtins.readFile "${nuget-source}/share/licenses");
+      in lib.flatten (lib.forEach depLicenses (spdx:
+        lib.optionals (spdx != "") (lib.getLicenseFromSpdxId spdx)
+      ));
+    };
   };
 in nuget-source
diff --git a/nixpkgs/pkgs/build-support/node/build-npm-package/hooks/npm-install-hook.sh b/nixpkgs/pkgs/build-support/node/build-npm-package/hooks/npm-install-hook.sh
index a2f77bdc6d43..1e446bb1b051 100644
--- a/nixpkgs/pkgs/build-support/node/build-npm-package/hooks/npm-install-hook.sh
+++ b/nixpkgs/pkgs/build-support/node/build-npm-package/hooks/npm-install-hook.sh
@@ -5,16 +5,14 @@ npmInstallHook() {
 
     runHook preInstall
 
-    # `npm pack` writes to cache
-    npm config delete cache
-
     local -r packageOut="$out/lib/node_modules/$(@jq@ --raw-output '.name' package.json)"
 
+    # `npm pack` writes to cache so temporarily override it
     while IFS= read -r file; do
         local dest="$packageOut/$(dirname "$file")"
         mkdir -p "$dest"
         cp "${npmWorkspace-.}/$file" "$dest"
-    done < <(@jq@ --raw-output '.[0].files | map(.path) | join("\n")' <<< "$(npm pack --json --dry-run --loglevel=warn --no-foreground-scripts ${npmWorkspace+--workspace=$npmWorkspace} $npmPackFlags "${npmPackFlagsArray[@]}" $npmFlags "${npmFlagsArray[@]}")")
+    done < <(@jq@ --raw-output '.[0].files | map(.path) | join("\n")' <<< "$(npm_config_cache="$HOME/.npm" npm pack --json --dry-run --loglevel=warn --no-foreground-scripts ${npmWorkspace+--workspace=$npmWorkspace} $npmPackFlags "${npmPackFlagsArray[@]}" $npmFlags "${npmFlagsArray[@]}")")
 
     # Based on code from Python's buildPythonPackage wrap.sh script, for
     # supporting both the case when makeWrapperArgs is an array and a
diff --git a/nixpkgs/pkgs/build-support/node/fetch-npm-deps/src/main.rs b/nixpkgs/pkgs/build-support/node/fetch-npm-deps/src/main.rs
index 2b28e290ad51..dc20c7297049 100644
--- a/nixpkgs/pkgs/build-support/node/fetch-npm-deps/src/main.rs
+++ b/nixpkgs/pkgs/build-support/node/fetch-npm-deps/src/main.rs
@@ -246,7 +246,9 @@ fn main() -> anyhow::Result<()> {
     packages.into_par_iter().try_for_each(|package| {
         eprintln!("{}", package.name);
 
-        let tarball = package.tarball()?;
+        let tarball = package
+            .tarball()
+            .map_err(|e| anyhow!("couldn't fetch {} at {}: {e:?}", package.name, package.url))?;
         let integrity = package.integrity().map(ToString::to_string);
 
         cache
diff --git a/nixpkgs/pkgs/build-support/node/fetch-npm-deps/src/parse/lock.rs b/nixpkgs/pkgs/build-support/node/fetch-npm-deps/src/parse/lock.rs
index e3580cfca0d3..c6e77153a0b8 100644
--- a/nixpkgs/pkgs/build-support/node/fetch-npm-deps/src/parse/lock.rs
+++ b/nixpkgs/pkgs/build-support/node/fetch-npm-deps/src/parse/lock.rs
@@ -214,29 +214,35 @@ fn to_new_packages(
         }
 
         if let UrlOrString::Url(v) = &package.version {
-            for (scheme, host) in [
-                ("github", "github.com"),
-                ("bitbucket", "bitbucket.org"),
-                ("gitlab", "gitlab.com"),
-            ] {
-                if v.scheme() == scheme {
-                    package.version = {
-                        let mut new_url = initial_url.clone();
-
-                        new_url.set_host(Some(host))?;
-
-                        if v.path().ends_with(".git") {
-                            new_url.set_path(v.path());
-                        } else {
-                            new_url.set_path(&format!("{}.git", v.path()));
-                        }
-
-                        new_url.set_fragment(v.fragment());
-
-                        UrlOrString::Url(new_url)
-                    };
-
-                    break;
+            if v.scheme() == "npm" {
+                if let Some(UrlOrString::Url(ref url)) = &package.resolved {
+                    package.version = UrlOrString::Url(url.clone());
+                }
+            } else {
+                for (scheme, host) in [
+                    ("github", "github.com"),
+                    ("bitbucket", "bitbucket.org"),
+                    ("gitlab", "gitlab.com"),
+                ] {
+                    if v.scheme() == scheme {
+                        package.version = {
+                            let mut new_url = initial_url.clone();
+
+                            new_url.set_host(Some(host))?;
+
+                            if v.path().ends_with(".git") {
+                                new_url.set_path(v.path());
+                            } else {
+                                new_url.set_path(&format!("{}.git", v.path()));
+                            }
+
+                            new_url.set_fragment(v.fragment());
+
+                            UrlOrString::Url(new_url)
+                        };
+
+                        break;
+                    }
                 }
             }
         }
@@ -266,7 +272,8 @@ fn get_initial_url() -> anyhow::Result<Url> {
 #[cfg(test)]
 mod tests {
     use super::{
-        get_initial_url, to_new_packages, Hash, HashCollection, OldPackage, Package, UrlOrString,
+        get_initial_url, packages, to_new_packages, Hash, HashCollection, OldPackage, Package,
+        UrlOrString,
     };
     use std::{
         cmp::Ordering,
@@ -328,4 +335,36 @@ mod tests {
             Some(Hash(String::from("sha512-foo")))
         );
     }
+
+    #[test]
+    fn parse_lockfile_correctly() {
+        let packages = packages(
+            r#"{
+                "name": "node-ddr",
+                "version": "1.0.0",
+                "lockfileVersion": 1,
+                "requires": true,
+                "dependencies": {
+                    "string-width-cjs": {
+                        "version": "npm:string-width@4.2.3",
+                        "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+                        "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+                        "requires": {
+                            "emoji-regex": "^8.0.0",
+                            "is-fullwidth-code-point": "^3.0.0",
+                            "strip-ansi": "^6.0.1"
+                        }
+                    }
+                }
+            }"#).unwrap();
+
+        assert_eq!(packages.len(), 1);
+        assert_eq!(
+            packages[0].resolved,
+            Some(UrlOrString::Url(
+                Url::parse("https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz")
+                    .unwrap()
+            ))
+        );
+    }
 }
diff --git a/nixpkgs/pkgs/build-support/php/hooks/composer-install-hook.sh b/nixpkgs/pkgs/build-support/php/hooks/composer-install-hook.sh
index 6fe1c4e5f7dd..6e7fb5d7503b 100644
--- a/nixpkgs/pkgs/build-support/php/hooks/composer-install-hook.sh
+++ b/nixpkgs/pkgs/build-support/php/hooks/composer-install-hook.sh
@@ -155,7 +155,7 @@ composerInstallInstallHook() {
     cp -r . "$out"/share/php/"${pname}"/
 
     # Create symlinks for the binaries.
-    jq -r -c 'try .bin[]' composer.json | while read -r bin; do
+    jq -r -c 'try (.bin[] | select(test(".bat$")? | not) )' composer.json | while read -r bin; do
         mkdir -p "$out"/share/php/"${pname}" "$out"/bin
         makeWrapper "$out"/share/php/"${pname}"/"$bin" "$out"/bin/"$(basename "$bin")"
     done
diff --git a/nixpkgs/pkgs/build-support/rust/rustc-wrapper/default.nix b/nixpkgs/pkgs/build-support/rust/rustc-wrapper/default.nix
new file mode 100644
index 000000000000..d6034c08af47
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/rust/rustc-wrapper/default.nix
@@ -0,0 +1,30 @@
+{ lib, runCommand, rustc-unwrapped, sysroot ? null }:
+
+runCommand "${rustc-unwrapped.pname}-wrapper-${rustc-unwrapped.version}" {
+  preferLocalBuild = true;
+  strictDeps = true;
+  inherit (rustc-unwrapped) outputs;
+
+  env = {
+    prog = "${rustc-unwrapped}/bin/rustc";
+    sysroot = lib.optionalString (sysroot != null) "--sysroot ${sysroot}";
+  };
+
+  passthru = {
+    inherit (rustc-unwrapped) pname version src llvm llvmPackages;
+    unwrapped = rustc-unwrapped;
+  };
+
+  meta = rustc-unwrapped.meta // {
+    description = "${rustc-unwrapped.meta.description} (wrapper script)";
+    priority = 10;
+  };
+} ''
+  mkdir -p $out/bin
+  ln -s ${rustc-unwrapped}/bin/* $out/bin
+  rm $out/bin/rustc
+  substituteAll ${./rustc-wrapper.sh} $out/bin/rustc
+  chmod +x $out/bin/rustc
+  ${lib.concatMapStrings (output: "ln -s ${rustc-unwrapped.${output}} \$${output}\n")
+    (lib.remove "out" rustc-unwrapped.outputs)}
+''
diff --git a/nixpkgs/pkgs/build-support/rust/rustc-wrapper/rustc-wrapper.sh b/nixpkgs/pkgs/build-support/rust/rustc-wrapper/rustc-wrapper.sh
new file mode 100644
index 000000000000..a62e35b8736f
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/rust/rustc-wrapper/rustc-wrapper.sh
@@ -0,0 +1,16 @@
+#!@shell@
+
+extraBefore=(@sysroot@)
+extraAfter=($NIX_RUSTFLAGS)
+
+# Optionally print debug info.
+if (( "${NIX_DEBUG:-0}" >= 1 )); then
+    echo "extra flags before to @prog@:" >&2
+    printf "  %q\n" "${extraBefore[@]}" >&2
+    echo "original flags to @prog@:" >&2
+    printf "  %q\n" "$@" >&2
+    echo "extra flags after to @prog@:" >&2
+    printf "  %q\n" "${extraAfter[@]}" >&2
+fi
+
+exec @prog@ "${extraBefore[@]}" "$@" "${extraAfter[@]}"
diff --git a/nixpkgs/pkgs/build-support/setup-hooks/auto-patchelf.py b/nixpkgs/pkgs/build-support/setup-hooks/auto-patchelf.py
index 261f55854808..4769179167b3 100644
--- a/nixpkgs/pkgs/build-support/setup-hooks/auto-patchelf.py
+++ b/nixpkgs/pkgs/build-support/setup-hooks/auto-patchelf.py
@@ -336,9 +336,12 @@ def main() -> None:
     )
     parser.add_argument(
         "--extra-args",
-        nargs="*",
+        # Undocumented Python argparse feature: consume all remaining arguments
+        # as values for this one. This means this argument should always be passed
+        # last.
+        nargs="...",
         type=str,
-        help="Extra arguments to pass to patchelf"
+        help="Extra arguments to pass to patchelf. This argument should always come last."
     )
 
     print("automatically fixing dependencies for ELF files")
diff --git a/nixpkgs/pkgs/build-support/setup-hooks/separate-debug-info.sh b/nixpkgs/pkgs/build-support/setup-hooks/separate-debug-info.sh
index 3a16ac4fee90..197e8a920b70 100644
--- a/nixpkgs/pkgs/build-support/setup-hooks/separate-debug-info.sh
+++ b/nixpkgs/pkgs/build-support/setup-hooks/separate-debug-info.sh
@@ -1,7 +1,7 @@
 export NIX_SET_BUILD_ID=1
 export NIX_LDFLAGS+=" --compress-debug-sections=zlib"
 export NIX_CFLAGS_COMPILE+=" -ggdb -Wa,--compress-debug-sections"
-export RUSTFLAGS+=" -g"
+export NIX_RUSTFLAGS+=" -g"
 
 fixupOutputHooks+=(_separateDebugInfo)
 
diff --git a/nixpkgs/pkgs/build-support/templaterpm/default.nix b/nixpkgs/pkgs/build-support/templaterpm/default.nix
deleted file mode 100644
index 56c543e8a930..000000000000
--- a/nixpkgs/pkgs/build-support/templaterpm/default.nix
+++ /dev/null
@@ -1,25 +0,0 @@
-{lib, stdenv, makeWrapper, python, toposort, rpm}:
-
-stdenv.mkDerivation {
-  pname = "nix-template-rpm";
-  version = "0.1";
-
-  nativeBuildInputs = [ makeWrapper ];
-  buildInputs = [ python toposort rpm ];
-
-  dontUnpack = true;
-
-  installPhase = ''
-    mkdir -p $out/bin
-    cp ${./nix-template-rpm.py} $out/bin/nix-template-rpm
-    wrapProgram $out/bin/nix-template-rpm \
-      --set PYTHONPATH "${rpm}/lib/${python.libPrefix}/site-packages":"${toposort}/lib/${python.libPrefix}/site-packages"
-    '';
-
-  meta = with lib; {
-    description = "Create templates of nix expressions from RPM .spec files";
-    maintainers = with maintainers; [ ];
-    platforms = platforms.unix;
-    hydraPlatforms = [];
-  };
-}
diff --git a/nixpkgs/pkgs/build-support/templaterpm/nix-template-rpm.py b/nixpkgs/pkgs/build-support/templaterpm/nix-template-rpm.py
deleted file mode 100755
index db8c0f2064c2..000000000000
--- a/nixpkgs/pkgs/build-support/templaterpm/nix-template-rpm.py
+++ /dev/null
@@ -1,518 +0,0 @@
-#!/bin/env python
-
-import sys
-import os
-import subprocess
-import argparse
-import re
-import shutil
-import rpm
-import urlparse
-import traceback
-import toposort
-
-
-
-
-
-class SPECTemplate(object):
-  def __init__(self, specFilename, outputDir, inputDir=None, buildRootInclude=None, translateTable=None, repositoryDir=None, allPackagesDir=None, maintainer="MAINTAINER"):
-    rpm.addMacro("buildroot","$out")
-    rpm.addMacro("_libdir","lib")
-    rpm.addMacro("_libexecdir","libexec")
-    rpm.addMacro("_sbindir","sbin")
-    rpm.addMacro("_sysconfdir","etc")
-    rpm.addMacro("_topdir","SPACER_DIR_FOR_REMOVAL")
-    rpm.addMacro("_sourcedir","SOURCE_DIR_SPACER")
-
-    self.packageGroups = [ "ocaml", "python" ]
-
-    ts = rpm.TransactionSet()
-
-    self.specFilename = specFilename
-    self.spec = ts.parseSpec(specFilename)
-
-    self.inputDir = inputDir
-    self.buildRootInclude = buildRootInclude
-    self.repositoryDir = repositoryDir
-    self.allPackagesDir = allPackagesDir
-    self.maintainer = maintainer
-
-    self.translateTable = translateTable
-
-    self.facts = self.getFacts()
-    self.key = self.getSelfKey()
-
-    tmpDir = os.path.join(outputDir, self.rewriteName(self.spec.sourceHeader['name']))
-    if self.translateTable is not None:
-      self.relOutputDir = self.translateTable.path(self.key,tmpDir)
-    else:
-      self.relOutputDir = tmpDir
-
-    self.final_output_dir = os.path.normpath( self.relOutputDir )
-
-    if self.repositoryDir is not None:
-      self.potential_repository_dir = os.path.normpath( os.path.join(self.repositoryDir,self.relOutputDir) )
-
-
-
-  def rewriteCommands(self, string):
-    string = string.replace('SPACER_DIR_FOR_REMOVAL/','')
-    string = string.replace('SPACER_DIR_FOR_REMOVAL','')
-    string = '\n'.join(map(lambda line: ' '.join(map(lambda x: x.replace('SOURCE_DIR_SPACER/',('${./' if (self.buildRootInclude is None) else '${buildRoot}/usr/share/buildroot/SOURCES/'))+('}' if (self.buildRootInclude is None) else '') if x.startswith('SOURCE_DIR_SPACER/') else x, line.split(' '))), string.split('\n')))
-    string = string.replace('\n','\n    ')
-    string = string.rstrip()
-    return string
-
-
-  def rewriteName(self, string):
-    parts = string.split('-')
-    parts = filter(lambda x: not x == "devel", parts)
-    parts = filter(lambda x: not x == "doc", parts)
-    if len(parts) > 1 and parts[0] in self.packageGroups:
-      return parts[0] + '-' + ''.join(parts[1:2] + map(lambda x: x.capitalize(), parts[2:]))
-    else:
-      return ''.join(parts[:1] + map(lambda x: x.capitalize(), parts[1:]))
-
-
-  def rewriteInputs(self,target,inputs):
-    camelcase = lambda l: l[:1] + map(lambda x: x.capitalize(), l[1:])
-    filterDevel = lambda l: filter(lambda x: not x == "devel", l)
-    filterDoc = lambda l: filter(lambda x: not x == "doc", l)
-    rewrite = lambda l: ''.join(camelcase(filterDoc(filterDevel(l))))
-
-    def filterPackageGroup(target):
-      if target is None:
-        return [ rewrite(x.split('-')) for x in inputs if (not x.split('-')[0] in self.packageGroups) or (len(x.split('-')) == 1) ]
-      elif target in self.packageGroups:
-        return [ target + '_' + rewrite(x.split('-')[1:]) for x in inputs if (x.split('-')[0] == target) and (len(x.split('-')) > 1)]
-      else:
-        raise Exception("Unknown target")
-        return []
-
-    if target is None:
-      packages = filterPackageGroup(None)
-      packages.sort()
-    elif target in self.packageGroups:
-      packages = filterPackageGroup(target)
-      packages.sort()
-    elif target == "ALL":
-      packages = []
-      for t in [None] + self.packageGroups:
-        tmp = filterPackageGroup(t)
-        tmp.sort()
-        packages += tmp
-    else:
-      raise Exception("Unknown target")
-      packages = []
-
-    return packages
-
-
-  def getBuildInputs(self,target=None):
-    inputs = self.rewriteInputs(target,self.spec.sourceHeader['requires'])
-    if self.translateTable is not None:
-      return map(lambda x: self.translateTable.name(x), inputs)
-    else:
-      return inputs
-
-  def getSelfKey(self):
-    name = self.spec.sourceHeader['name']
-    if len(name.split('-')) > 1 and name.split('-')[0] in self.packageGroups:
-      key = self.rewriteInputs(name.split('-')[0], [self.spec.sourceHeader['name']])[0]
-    else:
-      key = self.rewriteInputs(None, [self.spec.sourceHeader['name']])[0]
-    return key
-
-  def getSelf(self):
-    if self.translateTable is not None:
-      return self.translateTable.name(self.key)
-    else:
-      return self.key
-
-
-
-
-  def copyPatches(self, input_dir, output_dir):
-    patches = [source for (source, _, flag) in self.spec.sources if flag==2]
-    for filename in patches:
-      shutil.copyfile(os.path.join(input_dir, filename), os.path.join(output_dir, filename))
-
-
-  def copySources(self, input_dir, output_dir):
-    filenames = [source for (source, _, flag) in self.spec.sources if flag==1 if not urlparse.urlparse(source).scheme in ["http", "https"] ]
-    for filename in filenames:
-      shutil.copyfile(os.path.join(input_dir, filename), os.path.join(output_dir, filename))
-
-
-  def getFacts(self):
-    facts = {}
-    facts["name"] = self.rewriteName(self.spec.sourceHeader['name'])
-    facts["version"] = self.spec.sourceHeader['version']
-
-    facts["url"] = []
-    facts["sha256"] = []
-    sources = [source for (source, _, flag) in self.spec.sources if flag==1 if urlparse.urlparse(source).scheme in ["http", "https"] ]
-    for url in sources:
-      p = subprocess.Popen(['nix-prefetch-url', url], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-      output, err = p.communicate()
-      sha256 = output[:-1] #remove new line
-      facts["url"].append(url)
-      facts["sha256"].append(sha256)
-
-    patches = [source for (source, _, flag) in self.spec.sources if flag==2]
-    if self.buildRootInclude is None:
-      facts["patches"] = map(lambda x: './'+x, patches)
-    else:
-      facts["patches"] = map(lambda x: '"${buildRoot}/usr/share/buildroot/SOURCES/'+x+'"', reversed(patches))
-
-    return facts
-
-
-  @property
-  def name(self):
-    out = '  name = "' + self.facts["name"] + '-' + self.facts["version"] + '";\n'
-    out += '  version = "' + self.facts['version'] + '";\n'
-    return out
-
-
-  @property
-  def src(self):
-    sources = [source for (source, _, flag) in self.spec.sources if flag==1 if urlparse.urlparse(source).scheme in ["http", "https"] ]
-    out = ''
-    for (url,sha256) in zip(self.facts['url'],self.facts['sha256']):
-      out += '  src = fetchurl {\n'
-      out += '    url = "' + url + '";\n'
-      out += '    sha256 = "' + sha256 + '";\n'
-      out += '  };\n'
-    return out
-
-
-  @property
-  def patch(self):
-    out = '  patches = [ ' + ' '.join(self.facts['patches']) + ' ];\n'
-    return out
-
-
-  @property
-  def buildInputs(self):
-    out = '  buildInputs = [ '
-    out += ' '.join(self.getBuildInputs("ALL"))
-    out += ' ];\n'
-    return out
-
-
-  @property
-  def configure(self):
-    out = '  configurePhase = \'\'\n    ' + self.rewriteCommands(self.spec.prep) + '\n    \'\';\n';
-    return out
-
-
-  @property
-  def build(self):
-    out = '  buildPhase = \'\'\n    ' + self.rewriteCommands(self.spec.build) + '\n    \'\';\n';
-    return out
-
-
-  @property
-  def install(self):
-    out = '  installPhase = \'\'\n    ' + self.rewriteCommands(self.spec.install) + '\n    \'\';\n';
-    return out
-
-  @property
-  def ocamlExtra(self):
-    if "ocaml" in self.getBuildInputs("ALL"):
-      return '  createFindlibDestdir = true;\n'
-    else:
-      return ''
-
-
-  @property
-  def meta(self):
-    out = '  meta = with lib; {\n'
-    out += '    homepage = ' + self.spec.sourceHeader['url'] + ';\n'
-    out += '    description = "' + self.spec.sourceHeader['summary'] + '";\n'
-    out += '    license = lib.licenses.' + self.spec.sourceHeader['license'] + ';\n'
-    out += '    platforms = [ "i686-linux" "x86_64-linux" ];\n'
-    out += '    maintainers = with lib.maintainers; [ ' + self.maintainer + ' ];\n'
-    out += '  };\n'
-    out += '}\n'
-    return out
-
-
-  def __str__(self):
-    head = '{lib, stdenv, fetchurl, ' + ', '.join(self.getBuildInputs("ALL")) + '}:\n\n'
-    head += 'stdenv.mkDerivation {\n'
-    body = [ self.name, self.src, self.patch, self.buildInputs, self.configure, self.build, self.ocamlExtra, self.install, self.meta ]
-    return head + '\n'.join(body)
-
-
-  def getTemplate(self):
-    head = '{lib, stdenv, buildRoot, fetchurl, ' + ', '.join(self.getBuildInputs("ALL")) + '}:\n\n'
-    head += 'let\n'
-    head += '  buildRootInput = (import "${buildRoot}/usr/share/buildroot/buildRootInput.nix") { fetchurl=fetchurl; buildRoot=buildRoot; };\n'
-    head += 'in\n\n'
-    head += 'stdenv.mkDerivation {\n'
-    head += '  inherit (buildRootInput.'+self.rewriteName(self.spec.sourceHeader['name'])+') name version src;\n'
-    head += '  patches = buildRootInput.'+self.rewriteName(self.spec.sourceHeader['name'])+'.patches ++ [];\n\n'
-    body = [ self.buildInputs, self.configure, self.build, self.ocamlExtra, self.install, self.meta ]
-    return head + '\n'.join(body)
-
-
-  def getInclude(self):
-    head = self.rewriteName(self.spec.sourceHeader['name']) + ' = {\n'
-    body = [ self.name, self.src, self.patch ]
-    return head + '\n'.join(body) + '};\n'
-
-
-  def __cmp__(self,other):
-    if self.getSelf() in other.getBuildInputs("ALL"):
-      return 1
-    else:
-      return -1
-
-
-  def callPackage(self):
-    callPackage = '  ' + self.getSelf() + ' = callPackage ' + os.path.relpath(self.final_output_dir, self.allPackagesDir) + ' {'
-    newline = False;
-    for target in self.packageGroups:
-      tmp = self.getBuildInputs(target)
-      if len(tmp) > 0:
-        newline = True;
-        callPackage += '\n    ' + 'inherit (' + target + 'Packages) ' + ' '.join(tmp) + ';'
-    if newline:
-      callPackage += '\n  };'
-    else:
-      callPackage += ' };'
-    return callPackage
-
-
-
-  def generateCombined(self):
-    if not os.path.exists(self.final_output_dir):
-      os.makedirs(self.final_output_dir)
-
-    if self.inputDir is not None:
-      self.copySources(self.inputDir, self.final_output_dir)
-      self.copyPatches(self.inputDir, self.final_output_dir)
-
-    nixfile = open(os.path.join(self.final_output_dir,'default.nix'), 'w')
-    nixfile.write(str(self))
-    nixfile.close()
-
-    shutil.copyfile(self.specFilename, os.path.join(self.final_output_dir, os.path.basename(self.specFilename)))
-
-
-
-  def generateSplit(self):
-    if not os.path.exists(self.final_output_dir):
-      os.makedirs(self.final_output_dir)
-
-    nixfile = open(os.path.join(self.final_output_dir,'default.nix'), 'w')
-    nixfile.write(self.getTemplate())
-    nixfile.close()
-
-    return self.getInclude()
-
-
-
-
-
-
-class NixTemplate(object):
-  def __init__(self, nixfile):
-    self.nixfile = nixfile
-    self.original = { "name":None, "version":None, "url":None, "sha256":None, "patches":None }
-    self.update = { "name":None, "version":None, "url":None, "sha256":None, "patches":None }
-    self.matchedLines = {}
-
-    if os.path.isfile(nixfile):
-      with file(nixfile, 'r') as infile:
-        for (n,line) in enumerate(infile):
-          name = re.match(r'^\s*name\s*=\s*"(.*?)"\s*;\s*$', line)
-          version = re.match(r'^\s*version\s*=\s*"(.*?)"\s*;\s*$', line)
-          url = re.match(r'^\s*url\s*=\s*"?(.*?)"?\s*;\s*$', line)
-          sha256 = re.match(r'^\s*sha256\s*=\s*"(.*?)"\s*;\s*$', line)
-          patches = re.match(r'^\s*patches\s*=\s*(\[.*?\])\s*;\s*$', line)
-          if name is not None and self.original["name"] is None:
-              self.original["name"] = name.group(1)
-              self.matchedLines[n] = "name"
-          if version is not None and self.original["version"] is None:
-              self.original["version"] = version.group(1)
-              self.matchedLines[n] = "version"
-          if url is not None and self.original["url"] is None:
-              self.original["url"] = url.group(1)
-              self.matchedLines[n] = "url"
-          if sha256 is not None and self.original["sha256"] is None:
-              self.original["sha256"] = sha256.group(1)
-              self.matchedLines[n] = "sha256"
-          if patches is not None and self.original["patches"] is None:
-              self.original["patches"] = patches.group(1)
-              self.matchedLines[n] = "patches"
-
-
-  def generateUpdated(self, nixOut):
-    nixTemplateFile = open(os.path.normpath(self.nixfile),'r')
-    nixOutFile = open(os.path.normpath(nixOut),'w')
-    for (n,line) in enumerate(nixTemplateFile):
-      if self.matchedLines.has_key(n) and self.update[self.matchedLines[n]] is not None:
-        nixOutFile.write(line.replace(self.original[self.matchedLines[n]], self.update[self.matchedLines[n]], 1))
-      else:
-        nixOutFile.write(line)
-    nixTemplateFile.close()
-    nixOutFile.close()
-
-
-  def loadUpdate(self,orig):
-    if orig.has_key("name") and orig.has_key("version"):
-      self.update["name"] = orig["name"] + '-' + orig["version"]
-      self.update["version"] = orig["version"]
-    if orig.has_key("url") and orig.has_key("sha256") and len(orig["url"])>0:
-      self.update["url"] = orig["url"][0]
-      self.update["sha256"] = orig["sha256"][0]
-      for url in orig["url"][1:-1]:
-        sys.stderr.write("WARNING: URL has been dropped: %s\n" % url)
-    if orig.has_key("patches"):
-      self.update["patches"] = '[ ' + ' '.join(orig['patches']) + ' ]'
-
-
-class TranslationTable(object):
-  def __init__(self):
-    self.tablePath = {}
-    self.tableName = {}
-
-  def update(self, key, path, name=None):
-    self.tablePath[key] = path
-    if name is not None:
-      self.tableName[key] = name
-
-  def readTable(self, tableFile):
-    with file(tableFile, 'r') as infile:
-      for line in infile:
-        match = re.match(r'^(.+?)\s+(.+?)\s+(.+?)\s*$', line)
-        if match is not None:
-          if not self.tablePath.has_key(match.group(1)):
-            self.tablePath[match.group(1)] = match.group(2)
-          if not self.tableName.has_key(match.group(1)):
-            self.tableName[match.group(1)] = match.group(3)
-        else:
-          match = re.match(r'^(.+?)\s+(.+?)\s*$', line)
-          if not self.tablePath.has_key(match.group(1)):
-            self.tablePath[match.group(1)] = match.group(2)
-
-  def writeTable(self, tableFile):
-    outFile = open(os.path.normpath(tableFile),'w')
-    keys = self.tablePath.keys()
-    keys.sort()
-    for k in keys:
-      if self.tableName.has_key(k):
-        outFile.write( k + " " + self.tablePath[k] + " " + self.tableName[k] + "\n" )
-      else:
-        outFile.write( k + " " + self.tablePath[k] + "\n" )
-    outFile.close()
-
-  def name(self, key):
-   if self.tableName.has_key(key):
-     return self.tableName[key]
-   else:
-     return key
-
-  def path(self, key, orig):
-   if self.tablePath.has_key(key):
-     return self.tablePath[key]
-   else:
-     return orig
-
-
-
-
-
-if __name__ == "__main__":
-    #Parse command line options
-    parser = argparse.ArgumentParser(description="Generate .nix templates from RPM spec files")
-    parser.add_argument("specs", metavar="SPEC", nargs="+", help="spec file")
-    parser.add_argument("-o", "--output", metavar="OUT_DIR", required=True, help="output directory")
-    parser.add_argument("-b", "--buildRoot", metavar="BUILDROOT_DIR", default=None, help="buildroot output directory")
-    parser.add_argument("-i", "--inputSources", metavar="IN_DIR", default=None, help="sources input directory")
-    parser.add_argument("-m", "--maintainer", metavar="MAINTAINER", default="__NIX_MAINTAINER__", help="package maintainer")
-    parser.add_argument("-r", "--repository", metavar="REP_DIR", default=None, help="nix repository to compare output against")
-    parser.add_argument("-t", "--translate", metavar="TRANSLATE_TABLE", default=None, help="path of translation table for name and path")
-    parser.add_argument("-u", "--translateOut", metavar="TRANSLATE_OUT", default=None, help="output path for updated translation table")
-    parser.add_argument("-a", "--allPackages", metavar="ALL_PACKAGES", default=None, help="top level dir to call packages from")
-    args = parser.parse_args()
-
-    allPackagesDir = os.path.normpath( os.path.dirname(args.allPackages) )
-    if not os.path.exists(allPackagesDir):
-      os.makedirs(allPackagesDir)
-
-    buildRootContent = {}
-    nameMap = {}
-
-    newTable = TranslationTable()
-    if args.translate is not None:
-      table = TranslationTable()
-      table.readTable(args.translate)
-      newTable.readTable(args.translate)
-    else:
-      table = None
-
-    for specPath in args.specs:
-      try:
-        sys.stderr.write("INFO: generate nix file from: %s\n" % specPath)
-
-        spec = SPECTemplate(specPath, args.output, args.inputSources, args.buildRoot, table, args.repository, allPackagesDir, args.maintainer)
-        if args.repository is not None:
-          if os.path.exists(os.path.join(spec.potential_repository_dir,'default.nix')):
-            nixTemplate = NixTemplate(os.path.join(spec.potential_repository_dir,'default.nix'))
-            nixTemplate.loadUpdate(spec.facts)
-            if not os.path.exists(spec.final_output_dir):
-              os.makedirs(spec.final_output_dir)
-            nixTemplate.generateUpdated(os.path.join(spec.final_output_dir,'default.nix'))
-          else:
-            sys.stderr.write("WARNING: Repository does not contain template: %s\n" % os.path.join(spec.potential_repository_dir,'default.nix'))
-            if args.buildRoot is None:
-              spec.generateCombined()
-            else:
-              buildRootContent[spec.key] = spec.generateSplit()
-        else:
-          if args.buildRoot is None:
-            spec.generateCombined()
-          else:
-            buildRootContent[spec.key] = spec.generateSplit()
-
-        newTable.update(spec.key,spec.relOutputDir,spec.getSelf())
-        nameMap[spec.getSelf()] = spec
-
-      except Exception, e:
-        sys.stderr.write("ERROR: %s failed with:\n%s\n%s\n" % (specPath,e.message,traceback.format_exc()))
-
-    if args.translateOut is not None:
-      if not os.path.exists(os.path.dirname(os.path.normpath(args.translateOut))):
-        os.makedirs(os.path.dirname(os.path.normpath(args.translateOut)))
-      newTable.writeTable(args.translateOut)
-
-    graph = {}
-    for k, v in nameMap.items():
-      graph[k] = set(v.getBuildInputs("ALL"))
-
-    sortedSpecs = toposort.toposort_flatten(graph)
-    sortedSpecs = filter( lambda x: x in nameMap.keys(), sortedSpecs)
-
-    allPackagesFile = open(os.path.normpath( args.allPackages ), 'w')
-    allPackagesFile.write( '\n\n'.join(map(lambda x: x.callPackage(), map(lambda x: nameMap[x], sortedSpecs))) )
-    allPackagesFile.close()
-
-    if args.buildRoot is not None:
-      buildRootFilename = os.path.normpath( args.buildRoot )
-      if not os.path.exists(os.path.dirname(buildRootFilename)):
-        os.makedirs(os.path.dirname(buildRootFilename))
-      buildRootFile = open(buildRootFilename, 'w')
-      buildRootFile.write( "{ fetchurl, buildRoot }: {\n\n" )
-      keys = buildRootContent.keys()
-      keys.sort()
-      for k in keys:
-        buildRootFile.write( buildRootContent[k] + '\n' )
-      buildRootFile.write( "}\n" )
-      buildRootFile.close()
-
-
diff --git a/nixpkgs/pkgs/build-support/trivial-builders/test/default.nix b/nixpkgs/pkgs/build-support/trivial-builders/test/default.nix
index cbd1b388ef66..59dbba3f1841 100644
--- a/nixpkgs/pkgs/build-support/trivial-builders/test/default.nix
+++ b/nixpkgs/pkgs/build-support/trivial-builders/test/default.nix
@@ -14,21 +14,24 @@
 { callPackage, lib, stdenv }:
 let
   inherit (lib) recurseIntoAttrs;
+  references = callPackage ./references {};
 in
 recurseIntoAttrs {
   concat = callPackage ./concat-test.nix {};
   linkFarm = callPackage ./link-farm.nix {};
   overriding = callPackage ../test-overriding.nix {};
+  # VM test not supported beyond linux yet
   references =
-    # VM test not supported beyond linux yet
     if stdenv.hostPlatform.isLinux
-    then callPackage ./references.nix {}
-    else null;
+    then references
+    else {};
   writeCBin = callPackage ./writeCBin.nix {};
   writeShellApplication = callPackage ./writeShellApplication.nix {};
   writeScriptBin = callPackage ./writeScriptBin.nix {};
   writeShellScript = callPackage ./write-shell-script.nix {};
   writeShellScriptBin = callPackage ./writeShellScriptBin.nix {};
-  writeStringReferencesToFile = callPackage ./writeStringReferencesToFile.nix {};
+  writeStringReferencesToFile = callPackage ./writeStringReferencesToFile.nix {
+    inherit (references) samples;
+  };
   writeTextFile = callPackage ./write-text-file.nix {};
 }
diff --git a/nixpkgs/pkgs/build-support/trivial-builders/test/invoke-writeDirectReferencesToFile.nix b/nixpkgs/pkgs/build-support/trivial-builders/test/invoke-writeDirectReferencesToFile.nix
deleted file mode 100644
index ead3f7a2f571..000000000000
--- a/nixpkgs/pkgs/build-support/trivial-builders/test/invoke-writeDirectReferencesToFile.nix
+++ /dev/null
@@ -1,4 +0,0 @@
-{ pkgs ? import ../../../.. { config = {}; overlays = []; } }:
-pkgs.lib.mapAttrs
-  (k: v: pkgs.writeDirectReferencesToFile v)
-  (import ./sample.nix { inherit pkgs; })
diff --git a/nixpkgs/pkgs/build-support/trivial-builders/test/invoke-writeReferencesToFile.nix b/nixpkgs/pkgs/build-support/trivial-builders/test/invoke-writeReferencesToFile.nix
deleted file mode 100644
index 99c6c2f7dcc4..000000000000
--- a/nixpkgs/pkgs/build-support/trivial-builders/test/invoke-writeReferencesToFile.nix
+++ /dev/null
@@ -1,4 +0,0 @@
-{ pkgs ? import ../../../.. { config = {}; overlays = []; } }:
-pkgs.lib.mapAttrs
-  (k: v: pkgs.writeReferencesToFile v)
-  (import ./sample.nix { inherit pkgs; })
diff --git a/nixpkgs/pkgs/build-support/trivial-builders/test/references-test.sh b/nixpkgs/pkgs/build-support/trivial-builders/test/references-test.sh
deleted file mode 100755
index 473ca6e10769..000000000000
--- a/nixpkgs/pkgs/build-support/trivial-builders/test/references-test.sh
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/usr/bin/env bash
-
-# -------------------------------------------------------------------------- #
-#
-#                         trivial-builders test
-#
-# -------------------------------------------------------------------------- #
-#
-#  This file can be run independently (quick):
-#
-#      $ pkgs/build-support/trivial-builders/references-test.sh
-#
-#  or in the build sandbox with a ~20s VM overhead
-#
-#      $ nix-build -A tests.trivial-builders.references
-#
-# -------------------------------------------------------------------------- #
-
-# strict bash
-set -euo pipefail
-
-# debug
-# set -x
-# PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
-
-cd "$(dirname ${BASH_SOURCE[0]})"  # nixpkgs root
-
-if [[ -z ${SAMPLE:-} ]]; then
-  echo "Running the script directly is currently not supported."
-  echo "If you need to iterate, remove the raw path, which is not returned by nix-build."
-  exit 1
-#   sample=( `nix-build --no-out-link sample.nix` )
-#   directRefs=( `nix-build --no-out-link invoke-writeDirectReferencesToFile.nix` )
-#   references=( `nix-build --no-out-link invoke-writeReferencesToFile.nix` )
-#   echo "sample: ${#sample[@]}"
-#   echo "direct: ${#directRefs[@]}"
-#   echo "indirect: ${#references[@]}"
-else
-  # Injected by Nix (to avoid evaluating in a derivation)
-  # turn them into arrays
-  sample=($SAMPLE)
-  directRefs=($DIRECT_REFS)
-  references=($REFERENCES)
-fi
-
-echo >&2 Testing direct references...
-for i in "${!sample[@]}"; do
-  echo >&2 Checking '#'$i ${sample[$i]} ${directRefs[$i]}
-  diff -U3 \
-    <(sort <${directRefs[$i]}) \
-    <(nix-store -q --references ${sample[$i]} | sort)
-done
-
-echo >&2 Testing closure...
-for i in "${!sample[@]}"; do
-  echo >&2 Checking '#'$i ${sample[$i]} ${references[$i]}
-  diff -U3 \
-    <(sort <${references[$i]}) \
-    <(nix-store -q --requisites ${sample[$i]} | sort)
-done
-
-echo 'OK!'
diff --git a/nixpkgs/pkgs/build-support/trivial-builders/test/references.nix b/nixpkgs/pkgs/build-support/trivial-builders/test/references.nix
deleted file mode 100644
index 7c8ea83f3c8b..000000000000
--- a/nixpkgs/pkgs/build-support/trivial-builders/test/references.nix
+++ /dev/null
@@ -1,52 +0,0 @@
-{ lib, testers, pkgs, writeText, hello, figlet, stdenvNoCC }:
-
-# -------------------------------------------------------------------------- #
-#
-#                         trivial-builders test
-#
-# -------------------------------------------------------------------------- #
-#
-#  This file can be run independently (quick):
-#
-#      $ pkgs/build-support/trivial-builders/references-test.sh
-#
-#  or in the build sandbox with a ~20s VM overhead
-#
-#      $ nix-build -A tests.trivial-builders.references
-#
-# -------------------------------------------------------------------------- #
-
-let
-  invokeSamples = file:
-    lib.concatStringsSep " " (
-      lib.attrValues (import file { inherit pkgs; })
-    );
-in
-testers.nixosTest {
-  name = "nixpkgs-trivial-builders";
-  nodes.machine = { ... }: {
-    virtualisation.writableStore = true;
-
-    # Test runs without network, so we don't substitute and prepare our deps
-    nix.settings.substituters = lib.mkForce [];
-    environment.etc."pre-built-paths".source = writeText "pre-built-paths" (
-      builtins.toJSON [hello figlet stdenvNoCC]
-    );
-    environment.variables = {
-      SAMPLE = invokeSamples ./sample.nix;
-      REFERENCES = invokeSamples ./invoke-writeReferencesToFile.nix;
-      DIRECT_REFS = invokeSamples ./invoke-writeDirectReferencesToFile.nix;
-    };
-  };
-  testScript =
-    ''
-      machine.succeed("""
-        ${./references-test.sh} 2>/dev/console
-      """)
-    '';
-  meta = {
-    maintainers = with lib.maintainers; [
-      roberth
-    ];
-  };
-}
diff --git a/nixpkgs/pkgs/build-support/trivial-builders/test/references/default.nix b/nixpkgs/pkgs/build-support/trivial-builders/test/references/default.nix
new file mode 100644
index 000000000000..3e21c905321e
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/trivial-builders/test/references/default.nix
@@ -0,0 +1,124 @@
+{ lib
+, stdenvNoCC
+, testers
+, callPackage
+, writeText
+  # nativeBuildInputs
+, shellcheck-minimal
+  # Samples
+, samples ? cleanSamples (callPackage ./samples.nix { })
+  # Filter out the non-string-like attributes such as <pkg>.override added by
+  # callPackage.
+, cleanSamples ? lib.filterAttrs (n: lib.isStringLike)
+  # Test targets
+, writeDirectReferencesToFile
+, writeReferencesToFile
+}:
+
+# -------------------------------------------------------------------------- #
+#
+#                         trivial-builders test
+#
+# -------------------------------------------------------------------------- #
+#
+# Execute this build script directly (quick):
+#
+# * Classic
+#   $ NIX_PATH="nixpkgs=$PWD" nix-shell -p tests.trivial-builders.references.testScriptBin --run references-test
+#
+# * Flake-based
+#   $ nix run .#tests.trivial-builders.references.testScriptBin
+#
+# or in the build sandbox with a ~20s VM overhead:
+#
+# * Classic
+#   $ nix-build --no-out-link -A tests.trivial-builders.references
+#
+# * Flake-based
+#   $ nix build -L --no-link .#tests.trivial-builders.references
+#
+# -------------------------------------------------------------------------- #
+
+let
+  # Map each attribute to an element specification of Bash associative arrary
+  # and concatenate them with white spaces, to be used to define a
+  # one-line Bash associative array.
+  samplesToString = attrs:
+    lib.concatMapStringsSep " " (name: "[${name}]=${lib.escapeShellArg "${attrs.${name}}"}") (builtins.attrNames attrs);
+
+  references = lib.mapAttrs (n: v: writeReferencesToFile v) samples;
+  directReferences = lib.mapAttrs (n: v: writeDirectReferencesToFile v) samples;
+
+  testScriptBin = stdenvNoCC.mkDerivation (finalAttrs: {
+    name = "references-test";
+
+    src = ./references-test.sh;
+    dontUnpack = true;
+    dontBuild = true;
+
+    installPhase = ''
+      runHook preInstall
+      mkdir -p "$out/bin"
+      substitute "$src" "$out/bin/${finalAttrs.meta.mainProgram}" \
+        --replace "@SAMPLES@" ${lib.escapeShellArg (samplesToString samples)} \
+        --replace "@REFERENCES@" ${lib.escapeShellArg (samplesToString references)} \
+        --replace "@DIRECT_REFS@" ${lib.escapeShellArg (samplesToString directReferences)}
+      runHook postInstall
+      chmod +x "$out/bin/${finalAttrs.meta.mainProgram}"
+    '';
+
+    doInstallCheck = true;
+    nativeInstallCheckInputs = [
+      shellcheck-minimal
+    ];
+    installCheckPhase = ''
+      runHook preInstallCheck
+      shellcheck "$out/bin/${finalAttrs.meta.mainProgram}"
+      runHook postInstallCheck
+    '';
+
+    passthru = {
+      inherit
+        directReferences
+        references
+        samples
+        ;
+    };
+
+    meta = with lib; {
+      mainProgram = "references-test";
+    };
+  });
+in
+testers.nixosTest {
+  name = "nixpkgs-trivial-builders";
+  nodes.machine = { ... }: {
+    virtualisation.writableStore = true;
+
+    # Test runs without network, so we don't substitute and prepare our deps
+    nix.settings.substituters = lib.mkForce [ ];
+    environment.etc."pre-built-paths".source = writeText "pre-built-paths" (
+      builtins.toJSON [ testScriptBin ]
+    );
+  };
+  testScript =
+    ''
+      machine.succeed("""
+        ${lib.getExe testScriptBin} 2>/dev/console
+      """)
+    '';
+  passthru = {
+    inherit
+      directReferences
+      references
+      samples
+      testScriptBin
+      ;
+  };
+  meta = {
+    maintainers = with lib.maintainers; [
+      roberth
+      ShamrockLee
+    ];
+  };
+}
diff --git a/nixpkgs/pkgs/build-support/trivial-builders/test/references/references-test.sh b/nixpkgs/pkgs/build-support/trivial-builders/test/references/references-test.sh
new file mode 100755
index 000000000000..1b8f8e1504ec
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/trivial-builders/test/references/references-test.sh
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+
+# -------------------------------------------------------------------------- #
+#
+#                         trivial-builders test
+#
+# -------------------------------------------------------------------------- #
+#
+# Execute this build script directly (quick):
+#
+# * Classic
+#   $ NIX_PATH="nixpkgs=$PWD" nix-shell -p tests.trivial-builders.references.testScriptBin --run references-test
+#
+# * Flake-based
+#   $ nix run .#tests.trivial-builders.references.testScriptBin
+#
+# or in the build sandbox with a ~20s VM overhead:
+#
+# * Classic
+#   $ nix-build --no-out-link -A tests.trivial-builders.references
+#
+# * Flake-based
+#   $ nix build -L --no-link .#tests.trivial-builders.references
+#
+# -------------------------------------------------------------------------- #
+
+# strict bash
+set -euo pipefail
+
+# debug
+# set -x
+# PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
+
+cd "$(dirname "${BASH_SOURCE[0]}")"  # nixpkgs root
+
+  # Injected by Nix (to avoid evaluating in a derivation)
+  # turn them into arrays
+  # shellcheck disable=SC2206 # deliberately unquoted
+  declare -A samples=( @SAMPLES@ )
+  # shellcheck disable=SC2206 # deliberately unquoted
+  declare -A directRefs=( @DIRECT_REFS@ )
+  # shellcheck disable=SC2206 # deliberately unquoted
+  declare -A references=( @REFERENCES@ )
+
+echo >&2 Testing direct references...
+for i in "${!samples[@]}"; do
+  echo >&2 Checking "$i" "${samples[$i]}" "${directRefs[$i]}"
+  diff -U3 \
+    <(sort <"${directRefs[$i]}") \
+    <(nix-store -q --references "${samples[$i]}" | sort)
+done
+
+echo >&2 Testing closure...
+for i in "${!samples[@]}"; do
+  echo >&2 Checking "$i" "${samples[$i]}" "${references[$i]}"
+  diff -U3 \
+    <(sort <"${references[$i]}") \
+    <(nix-store -q --requisites "${samples[$i]}" | sort)
+done
+
+echo 'OK!'
diff --git a/nixpkgs/pkgs/build-support/trivial-builders/test/references/samples.nix b/nixpkgs/pkgs/build-support/trivial-builders/test/references/samples.nix
new file mode 100644
index 000000000000..3afb970c08ae
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/trivial-builders/test/references/samples.nix
@@ -0,0 +1,30 @@
+{ lib
+, runCommand
+, writeText
+, emptyFile
+, emptyDirectory
+, figlet
+, hello
+, zlib
+}:
+{
+  inherit
+    figlet
+    hello
+    zlib
+    ;
+  zlib-dev = zlib.dev;
+  norefs = writeText "hi" "hello";
+  norefsDup = writeText "hi" "hello";
+  helloRef = writeText "hi" "hello ${hello}";
+  helloRefDup = writeText "hi" "hello ${hello}";
+  path = ./samples.nix;
+  pathLike.outPath = ./samples.nix;
+  helloFigletRef = writeText "hi" "hello ${hello} ${figlet}";
+  selfRef = runCommand "self-ref-1" { } "echo $out >$out";
+  selfRef2 = runCommand "self-ref-2" { } ''echo "${figlet}, $out" >$out'';
+  inherit
+    emptyFile
+    emptyDirectory
+    ;
+}
diff --git a/nixpkgs/pkgs/build-support/trivial-builders/test/sample.nix b/nixpkgs/pkgs/build-support/trivial-builders/test/sample.nix
deleted file mode 100644
index a4eedce8417e..000000000000
--- a/nixpkgs/pkgs/build-support/trivial-builders/test/sample.nix
+++ /dev/null
@@ -1,29 +0,0 @@
-{ pkgs ? import ../../../.. { config = { }; overlays = [ ]; } }:
-let
-  inherit (pkgs)
-    figlet
-    zlib
-    hello
-    writeText
-    runCommand
-    ;
-in
-{
-  hello = hello;
-  figlet = figlet;
-  zlib = zlib;
-  zlib-dev = zlib.dev;
-  norefs = writeText "hi" "hello";
-  norefsDup = writeText "hi" "hello";
-  helloRef = writeText "hi" "hello ${hello}";
-  helloRefDup = writeText "hi" "hello ${hello}";
-  path = ./invoke-writeReferencesToFile.nix;
-  pathLike.outPath = ./invoke-writeReferencesToFile.nix;
-  helloFigletRef = writeText "hi" "hello ${hello} ${figlet}";
-  selfRef = runCommand "self-ref-1" {} "echo $out >$out";
-  selfRef2 = runCommand "self-ref-2" {} ''echo "${figlet}, $out" >$out'';
-  inherit (pkgs)
-    emptyFile
-    emptyDirectory
-  ;
-}
diff --git a/nixpkgs/pkgs/build-support/trivial-builders/test/writeStringReferencesToFile.nix b/nixpkgs/pkgs/build-support/trivial-builders/test/writeStringReferencesToFile.nix
index b93b43b74aa4..dedd7e183a17 100644
--- a/nixpkgs/pkgs/build-support/trivial-builders/test/writeStringReferencesToFile.nix
+++ b/nixpkgs/pkgs/build-support/trivial-builders/test/writeStringReferencesToFile.nix
@@ -1,14 +1,13 @@
-{ callPackage, lib, pkgs, runCommand, writeText, writeStringReferencesToFile }:
+{ callPackage, lib, pkgs, runCommand, samples, writeText, writeStringReferencesToFile }:
 let
-  sample = import ./sample.nix { inherit pkgs; };
-  samplePaths = lib.unique (lib.attrValues sample);
+  samplePaths = lib.unique (lib.attrValues samples);
   stri = x: "${x}";
   sampleText = writeText "sample-text" (lib.concatStringsSep "\n" (lib.unique (map stri samplePaths)));
   stringReferencesText =
     writeStringReferencesToFile
       ((lib.concatMapStringsSep "fillertext"
         stri
-        (lib.attrValues sample)) + ''
+        (lib.attrValues samples)) + ''
         STORE=${builtins.storeDir};\nsystemctl start bar-foo.service
       '');
 in