about summary refs log tree commit diff
path: root/nixpkgs/pkgs/build-support
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2024-02-13 12:25:07 +0100
committerAlyssa Ross <hi@alyssa.is>2024-02-13 12:25:07 +0100
commita5e1520e4538e29ecfbd4b168306f890566d7bfd (patch)
tree28099c268b5d4b1e33c2b29f0714c45f0b961382 /nixpkgs/pkgs/build-support
parent822f7c15c04567fbdc27020e862ea2b70cfbf8eb (diff)
parent3560d1c8269d0091b9aae10731b5e85274b7bbc1 (diff)
downloadnixlib-a5e1520e4538e29ecfbd4b168306f890566d7bfd.tar
nixlib-a5e1520e4538e29ecfbd4b168306f890566d7bfd.tar.gz
nixlib-a5e1520e4538e29ecfbd4b168306f890566d7bfd.tar.bz2
nixlib-a5e1520e4538e29ecfbd4b168306f890566d7bfd.tar.lz
nixlib-a5e1520e4538e29ecfbd4b168306f890566d7bfd.tar.xz
nixlib-a5e1520e4538e29ecfbd4b168306f890566d7bfd.tar.zst
nixlib-a5e1520e4538e29ecfbd4b168306f890566d7bfd.zip
Merge branch 'nixos-unstable-small' of https://github.com/NixOS/nixpkgs
Conflicts:
	nixpkgs/nixos/modules/services/mail/rss2email.nix
	nixpkgs/pkgs/build-support/go/module.nix
Diffstat (limited to 'nixpkgs/pkgs/build-support')
-rw-r--r--nixpkgs/pkgs/build-support/bintools-wrapper/default.nix2
-rw-r--r--nixpkgs/pkgs/build-support/build-fhsenv-chroot/env.nix1
-rw-r--r--nixpkgs/pkgs/build-support/build-graalvm-native-image/default.nix14
-rw-r--r--nixpkgs/pkgs/build-support/cc-wrapper/add-hardening.sh6
-rw-r--r--nixpkgs/pkgs/build-support/cc-wrapper/default.nix41
-rw-r--r--nixpkgs/pkgs/build-support/dart/build-dart-application/default.nix2
-rw-r--r--nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-install-hook.sh16
-rw-r--r--nixpkgs/pkgs/build-support/docker/default.nix3
-rw-r--r--nixpkgs/pkgs/build-support/fetchgithub/default.nix6
-rw-r--r--nixpkgs/pkgs/build-support/flutter/default.nix281
-rw-r--r--nixpkgs/pkgs/build-support/go/module.nix6
-rw-r--r--nixpkgs/pkgs/build-support/go/package.nix6
-rw-r--r--nixpkgs/pkgs/build-support/kernel/compress-firmware-xz.nix13
-rw-r--r--nixpkgs/pkgs/build-support/kernel/make-initrd-ng/Cargo.lock4
-rw-r--r--nixpkgs/pkgs/build-support/rust/build-rust-crate/configure-crate.nix16
-rw-r--r--nixpkgs/pkgs/build-support/rust/build-rust-crate/default.nix10
-rw-r--r--nixpkgs/pkgs/build-support/rust/lib/default.nix33
-rw-r--r--nixpkgs/pkgs/build-support/rust/rustc-wrapper/rustc-wrapper.sh2
-rw-r--r--nixpkgs/pkgs/build-support/setup-hooks/postgresql-test-hook/postgresql-test-hook.sh2
-rw-r--r--nixpkgs/pkgs/build-support/testers/hasPkgConfigModules/tester.nix5
-rw-r--r--nixpkgs/pkgs/build-support/trivial-builders/default.nix127
-rw-r--r--nixpkgs/pkgs/build-support/trivial-builders/test/writeShellApplication.nix152
-rw-r--r--nixpkgs/pkgs/build-support/writers/default.nix1
-rw-r--r--nixpkgs/pkgs/build-support/writers/scripts.nix107
-rw-r--r--nixpkgs/pkgs/build-support/writers/test.nix119
25 files changed, 663 insertions, 312 deletions
diff --git a/nixpkgs/pkgs/build-support/bintools-wrapper/default.nix b/nixpkgs/pkgs/build-support/bintools-wrapper/default.nix
index 5b185b09a4c5..66027485ee71 100644
--- a/nixpkgs/pkgs/build-support/bintools-wrapper/default.nix
+++ b/nixpkgs/pkgs/build-support/bintools-wrapper/default.nix
@@ -321,7 +321,7 @@ stdenv.mkDerivation {
       hardening_unsupported_flags+=" pic"
     ''
 
-    + optionalString targetPlatform.isAvr ''
+    + optionalString (targetPlatform.isAvr || targetPlatform.isWindows) ''
       hardening_unsupported_flags+=" relro bindnow"
     ''
 
diff --git a/nixpkgs/pkgs/build-support/build-fhsenv-chroot/env.nix b/nixpkgs/pkgs/build-support/build-fhsenv-chroot/env.nix
index a1a26472373f..6a82435d7067 100644
--- a/nixpkgs/pkgs/build-support/build-fhsenv-chroot/env.nix
+++ b/nixpkgs/pkgs/build-support/build-fhsenv-chroot/env.nix
@@ -135,6 +135,7 @@ let
 
       # symlink ALSA stuff
       ln -s /host/etc/asound.conf asound.conf
+      ln -s /host/etc/alsa alsa
 
       # symlink SSL certs
       mkdir -p ssl
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 0612db2ad79b..f0e73901c8db 100644
--- a/nixpkgs/pkgs/build-support/build-graalvm-native-image/default.nix
+++ b/nixpkgs/pkgs/build-support/build-graalvm-native-image/default.nix
@@ -16,14 +16,13 @@
     "-H:Name=${executable}"
     "-march=compatibility"
     "--verbose"
-    "-J-Dsun.stdout.encoding=UTF-8"
-    "-J-Dsun.stderr.encoding=UTF-8"
   ]
   # Extra arguments to be passed to the native-image
 , extraNativeImageBuildArgs ? [ ]
   # XMX size of GraalVM during build
 , graalvmXmx ? "-J-Xmx6g"
 , meta ? { }
+, LC_ALL ? "en_US.UTF-8"
 , ...
 } @ args:
 
@@ -45,21 +44,16 @@ in
 stdenv.mkDerivation ({
   inherit dontUnpack jar;
 
+  env = { inherit LC_ALL; };
+
   nativeBuildInputs = (args.nativeBuildInputs or [ ]) ++ [ graalvmDrv glibcLocales removeReferencesTo ];
 
   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
 
-    native-image -jar "$jar" ''${nativeImageBuildArgs[@]}
+    native-image -jar "$jar" $(export -p | sed -n 's/^declare -x \([^=]\+\)=.*$/ -E\1/p' | tr -d \\n) ''${nativeImageBuildArgs[@]}
 
     runHook postBuild
   '';
diff --git a/nixpkgs/pkgs/build-support/cc-wrapper/add-hardening.sh b/nixpkgs/pkgs/build-support/cc-wrapper/add-hardening.sh
index 2eae278da160..e884f8388b58 100644
--- a/nixpkgs/pkgs/build-support/cc-wrapper/add-hardening.sh
+++ b/nixpkgs/pkgs/build-support/cc-wrapper/add-hardening.sh
@@ -32,7 +32,7 @@ if [[ -n "${hardeningEnableMap[fortify3]-}" ]]; then
 fi
 
 if (( "${NIX_DEBUG:-0}" >= 1 )); then
-  declare -a allHardeningFlags=(fortify fortify3 stackprotector pie pic strictoverflow format)
+  declare -a allHardeningFlags=(fortify fortify3 stackprotector pie pic strictoverflow format zerocallusedregs)
   declare -A hardeningDisableMap=()
 
   # Determine which flags were effectively disabled so we can report below.
@@ -110,6 +110,10 @@ for flag in "${!hardeningEnableMap[@]}"; do
       if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling format >&2; fi
       hardeningCFlagsBefore+=('-Wformat' '-Wformat-security' '-Werror=format-security')
       ;;
+    zerocallusedregs)
+      if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling zerocallusedregs >&2; fi
+      hardeningCFlagsBefore+=('-fzero-call-used-regs=used-gpr')
+      ;;
     *)
       # Ignore unsupported. Checked in Nix that at least *some*
       # tool supports each flag.
diff --git a/nixpkgs/pkgs/build-support/cc-wrapper/default.nix b/nixpkgs/pkgs/build-support/cc-wrapper/default.nix
index 0b25d70b14a2..693c6e6fcfd4 100644
--- a/nixpkgs/pkgs/build-support/cc-wrapper/default.nix
+++ b/nixpkgs/pkgs/build-support/cc-wrapper/default.nix
@@ -223,6 +223,15 @@ let
 
   defaultHardeningFlags = bintools.defaultHardeningFlags or [];
 
+  # if cc.hardeningUnsupportedFlagsByTargetPlatform exists, this is
+  # called with the targetPlatform as an argument and
+  # cc.hardeningUnsupportedFlags is completely ignored - the function
+  # is responsible for including the constant hardeningUnsupportedFlags
+  # list however it sees fit.
+  ccHardeningUnsupportedFlags = if cc ? hardeningUnsupportedFlagsByTargetPlatform
+    then cc.hardeningUnsupportedFlagsByTargetPlatform targetPlatform
+    else (cc.hardeningUnsupportedFlags or []);
+
   darwinPlatformForCC = optionalString stdenv.targetPlatform.isDarwin (
     if (targetPlatform.darwinPlatform == "macos" && isGNU) then "macosx"
     else targetPlatform.darwinPlatform
@@ -264,25 +273,6 @@ stdenv.mkDerivation {
     inherit bintools;
     inherit cc libc libcxx nativeTools nativeLibc nativePrefix isGNU isClang;
 
-    # Expose the C++ standard library we're using. See the comments on "General
-    # libc++ support". This is also relevant when using older gcc than the
-    # stdenv's, as may be required e.g. by CUDAToolkit's nvcc.
-    cxxStdlib =
-      let
-        givenLibcxx = libcxx.isLLVM or false;
-        givenGccForLibs = useGccForLibs && gccForLibs.langCC or false;
-      in
-      if (!givenLibcxx) && givenGccForLibs then
-        { kind = "libstdc++"; package = gccForLibs; solib = gccForLibs_solib; }
-      else if givenLibcxx then
-        { kind = "libc++"; package = libcxx;  solib = libcxx_solib;}
-      else
-      # We're probably using the `libstdc++` that came with our `gcc`.
-      # TODO: this is maybe not always correct?
-      # TODO: what happens when `nativeTools = true`?
-        { kind = "libstdc++"; package = cc; solib = cc_solib; }
-    ;
-
     emacsBufferSetup = pkgs: ''
       ; We should handle propagation here too
       (mapc
@@ -462,13 +452,6 @@ stdenv.mkDerivation {
       echo "-L${gccForLibs}/lib/gcc/${targetPlatform.config}/${gccForLibs.version}" >> $out/nix-support/cc-ldflags
       echo "-L${gccForLibs_solib}/lib" >> $out/nix-support/cc-ldflags
     ''
-    # The above "fix" may be incorrect; gcc.cc.lib doesn't contain a
-    # `target-triple` dir but the correct fix may be to just remove the above?
-    #
-    # For clang it's not necessary (see `--gcc-toolchain` below) and for other
-    # situations adding in the above will bring in lots of other gcc libraries
-    # (i.e. sanitizer libraries, `libatomic`, `libquadmath`) besides just
-    # `libstdc++`; this may actually break clang.
 
     # TODO We would like to connect this to `useGccForLibs`, but we cannot yet
     # because `libcxxStdenv` on linux still needs this. Maybe someday we'll
@@ -551,10 +534,10 @@ stdenv.mkDerivation {
     # additional -isystem flags will confuse gfortran (see
     # https://github.com/NixOS/nixpkgs/pull/209870#issuecomment-1500550903)
     + optionalString (libcxx == null && isClang && (useGccForLibs && gccForLibs.langCC or false)) ''
-      for dir in ${gccForLibs}${lib.optionalString (hostPlatform != targetPlatform) "/${targetPlatform.config}"}/include/c++/*; do
+      for dir in ${gccForLibs}/include/c++/*; do
         echo "-isystem $dir" >> $out/nix-support/libcxx-cxxflags
       done
-      for dir in ${gccForLibs}${lib.optionalString (hostPlatform != targetPlatform) "/${targetPlatform.config}"}/include/c++/*/${targetPlatform.config}; do
+      for dir in ${gccForLibs}/include/c++/*/${targetPlatform.config}; do
         echo "-isystem $dir" >> $out/nix-support/libcxx-cxxflags
       done
     ''
@@ -610,7 +593,7 @@ stdenv.mkDerivation {
     ## Hardening support
     ##
     + ''
-      export hardening_unsupported_flags="${builtins.concatStringsSep " " (cc.hardeningUnsupportedFlags or [])}"
+      export hardening_unsupported_flags="${builtins.concatStringsSep " " ccHardeningUnsupportedFlags}"
     ''
 
     # Machine flags. These are necessary to support
diff --git a/nixpkgs/pkgs/build-support/dart/build-dart-application/default.nix b/nixpkgs/pkgs/build-support/dart/build-dart-application/default.nix
index f9a49fec3a2d..c99b8bbf325e 100644
--- a/nixpkgs/pkgs/build-support/dart/build-dart-application/default.nix
+++ b/nixpkgs/pkgs/build-support/dart/build-dart-application/default.nix
@@ -87,7 +87,7 @@ let
       dartCompileCommand dartOutputType dartRuntimeCommand dartCompileFlags
       dartJitFlags;
 
-    outputs = args.outputs or [ ] ++ [ "out" "pubcache" ];
+    outputs = [ "out" "pubcache" ] ++ args.outputs or [ ];
 
     dartEntryPoints =
       if (dartEntryPoints != null)
diff --git a/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-install-hook.sh b/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-install-hook.sh
index 888e12a07d83..349a0dfdef0e 100644
--- a/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-install-hook.sh
+++ b/nixpkgs/pkgs/build-support/dart/build-dart-application/hooks/dart-install-hook.sh
@@ -19,15 +19,25 @@ dartInstallHook() {
         fi
     done < <(_getDartEntryPoints)
 
+    runHook postInstall
+
+    echo "Finished dartInstallHook"
+}
+
+dartInstallCacheHook() {
+    echo "Executing dartInstallCacheHook"
+
     # Install the package_config.json file.
     mkdir -p "$pubcache"
     cp .dart_tool/package_config.json "$pubcache/package_config.json"
 
-    runHook postInstall
-
-    echo "Finished dartInstallHook"
+    echo "Finished dartInstallCacheHook"
 }
 
 if [ -z "${dontDartInstall-}" ] && [ -z "${installPhase-}" ]; then
     installPhase=dartInstallHook
 fi
+
+if [ -z "${dontDartInstallCache-}" ]; then
+    postInstallHooks+=(dartInstallCacheHook)
+fi
diff --git a/nixpkgs/pkgs/build-support/docker/default.nix b/nixpkgs/pkgs/build-support/docker/default.nix
index 7218d67062e7..05a1a6fbbdaf 100644
--- a/nixpkgs/pkgs/build-support/docker/default.nix
+++ b/nixpkgs/pkgs/build-support/docker/default.nix
@@ -805,6 +805,7 @@ rec {
   '';
 
   # This provides /bin/sh, pointing to bashInteractive.
+  # The use of bashInteractive here is intentional to support cases like `docker run -it <image_name>`, so keep these use cases in mind if making any changes to how this works.
   binSh = runCommand "bin-sh" { } ''
     mkdir -p $out/bin
     ln -s ${bashInteractive}/bin/bash $out/bin/sh
@@ -915,7 +916,7 @@ rec {
 
             mkdir $out
             ${if enableFakechroot then ''
-              proot -r $PWD/old_out ${bind-paths} --pwd=/ --root-id bash -c '
+              proot -r $PWD/old_out ${bind-paths} --pwd=/ fakeroot bash -c '
                 source $stdenv/setup
                 eval "$fakeRootCommands"
                 tar \
diff --git a/nixpkgs/pkgs/build-support/fetchgithub/default.nix b/nixpkgs/pkgs/build-support/fetchgithub/default.nix
index 37f7dcfa3006..4ce3c6e84d76 100644
--- a/nixpkgs/pkgs/build-support/fetchgithub/default.nix
+++ b/nixpkgs/pkgs/build-support/fetchgithub/default.nix
@@ -28,7 +28,11 @@ let
   useFetchGit = fetchSubmodules || (leaveDotGit == true) || deepClone || forceFetchGit || (sparseCheckout != []);
   # We prefer fetchzip in cases we don't need submodules as the hash
   # is more stable in that case.
-  fetcher = if useFetchGit then fetchgit else fetchzip.override { withUnzip = false; };
+  fetcher =
+    if useFetchGit then fetchgit
+    # fetchzip may not be overridable when using external tools, for example nix-prefetch
+    else if fetchzip ? override then fetchzip.override { withUnzip = false; }
+    else fetchzip;
   privateAttrs = lib.optionalAttrs private {
     netrcPhase = ''
       if [ -z "''$${varBase}USERNAME" -o -z "''$${varBase}PASSWORD" ]; then
diff --git a/nixpkgs/pkgs/build-support/flutter/default.nix b/nixpkgs/pkgs/build-support/flutter/default.nix
index 4d00e177370e..5d7cd7d984c1 100644
--- a/nixpkgs/pkgs/build-support/flutter/default.nix
+++ b/nixpkgs/pkgs/build-support/flutter/default.nix
@@ -17,134 +17,163 @@
 
 { pubGetScript ? "flutter pub get"
 , flutterBuildFlags ? [ ]
+, targetFlutterPlatform ? "linux"
 , extraWrapProgramArgs ? ""
 , ...
 }@args:
 
-(buildDartApplication.override {
-  dart = flutter;
-}) (args // {
-  sdkSetupScript = ''
-    # Pub needs SSL certificates. Dart normally looks in a hardcoded path.
-    # https://github.com/dart-lang/sdk/blob/3.1.0/runtime/bin/security_context_linux.cc#L48
-    #
-    # Dart does not respect SSL_CERT_FILE...
-    # https://github.com/dart-lang/sdk/issues/48506
-    # ...and Flutter does not support --root-certs-file, so the path cannot be manually set.
-    # https://github.com/flutter/flutter/issues/56607
-    # https://github.com/flutter/flutter/issues/113594
-    #
-    # libredirect is of no use either, as Flutter does not pass any
-    # environment variables (including LD_PRELOAD) to the Pub process.
-    #
-    # Instead, Flutter is patched to allow the path to the Dart binary used for
-    # Pub commands to be overriden.
-    export NIX_FLUTTER_PUB_DART="${runCommand "dart-with-certs" { nativeBuildInputs = [ makeWrapper ]; } ''
-      mkdir -p "$out/bin"
-      makeWrapper ${flutter.dart}/bin/dart "$out/bin/dart" \
-        --add-flags "--root-certs-file=${cacert}/etc/ssl/certs/ca-bundle.crt"
-    ''}/bin/dart"
-
-    export HOME="$NIX_BUILD_TOP"
-    flutter config --no-analytics &>/dev/null # mute first-run
-    flutter config --enable-linux-desktop >/dev/null
-  '';
-
-  inherit pubGetScript;
-
-  sdkSourceBuilders = {
-    # https://github.com/dart-lang/pub/blob/68dc2f547d0a264955c1fa551fa0a0e158046494/lib/src/sdk/flutter.dart#L81
-    "flutter" = name: runCommand "flutter-sdk-${name}" { passthru.packageRoot = "."; } ''
-      for path in '${flutter}/packages/${name}' '${flutter}/bin/cache/pkg/${name}'; do
-        if [ -d "$path" ]; then
-          ln -s "$path" "$out"
-          break
+let
+  builderArgs = rec {
+    universal = args // {
+      sdkSetupScript = ''
+        # Pub needs SSL certificates. Dart normally looks in a hardcoded path.
+        # https://github.com/dart-lang/sdk/blob/3.1.0/runtime/bin/security_context_linux.cc#L48
+        #
+        # Dart does not respect SSL_CERT_FILE...
+        # https://github.com/dart-lang/sdk/issues/48506
+        # ...and Flutter does not support --root-certs-file, so the path cannot be manually set.
+        # https://github.com/flutter/flutter/issues/56607
+        # https://github.com/flutter/flutter/issues/113594
+        #
+        # libredirect is of no use either, as Flutter does not pass any
+        # environment variables (including LD_PRELOAD) to the Pub process.
+        #
+        # Instead, Flutter is patched to allow the path to the Dart binary used for
+        # Pub commands to be overriden.
+        export NIX_FLUTTER_PUB_DART="${runCommand "dart-with-certs" { nativeBuildInputs = [ makeWrapper ]; } ''
+          mkdir -p "$out/bin"
+          makeWrapper ${flutter.dart}/bin/dart "$out/bin/dart" \
+            --add-flags "--root-certs-file=${cacert}/etc/ssl/certs/ca-bundle.crt"
+        ''}/bin/dart"
+
+        export HOME="$NIX_BUILD_TOP"
+        flutter config --no-analytics &>/dev/null # mute first-run
+        flutter config --enable-linux-desktop >/dev/null
+      '';
+
+      inherit pubGetScript;
+
+      sdkSourceBuilders = {
+        # https://github.com/dart-lang/pub/blob/68dc2f547d0a264955c1fa551fa0a0e158046494/lib/src/sdk/flutter.dart#L81
+        "flutter" = name: runCommand "flutter-sdk-${name}" { passthru.packageRoot = "."; } ''
+          for path in '${flutter}/packages/${name}' '${flutter}/bin/cache/pkg/${name}'; do
+            if [ -d "$path" ]; then
+              ln -s "$path" "$out"
+              break
+            fi
+          done
+
+          if [ ! -e "$out" ]; then
+            echo 1>&2 'The Flutter SDK does not contain the requested package: ${name}!'
+            exit 1
+          fi
+        '';
+      };
+
+      extraPackageConfigSetup = ''
+        # https://github.com/flutter/flutter/blob/3.13.8/packages/flutter_tools/lib/src/dart/pub.dart#L755
+        if [ "$('${yq}/bin/yq' '.flutter.generate // false' pubspec.yaml)" = "true" ]; then
+          '${jq}/bin/jq' '.packages |= . + [{
+            name: "flutter_gen",
+            rootUri: "flutter_gen",
+            languageVersion: "2.12",
+          }]' "$out" | '${moreutils}/bin/sponge' "$out"
         fi
-      done
-
-      if [ ! -e "$out" ]; then
-        echo 1>&2 'The Flutter SDK does not contain the requested package: ${name}!'
-        exit 1
-      fi
-    '';
-  };
-
-  extraPackageConfigSetup = ''
-    # https://github.com/flutter/flutter/blob/3.13.8/packages/flutter_tools/lib/src/dart/pub.dart#L755
-    if [ "$('${yq}/bin/yq' '.flutter.generate // false' pubspec.yaml)" = "true" ]; then
-      '${jq}/bin/jq' '.packages |= . + [{
-        name: "flutter_gen",
-        rootUri: "flutter_gen",
-        languageVersion: "2.12",
-      }]' "$out" | '${moreutils}/bin/sponge' "$out"
-    fi
-  '';
-
-  nativeBuildInputs = (args.nativeBuildInputs or [ ]) ++ [
-    wrapGAppsHook
-
-    # Flutter requires pkg-config for Linux desktop support, and many plugins
-    # attempt to use it.
-    #
-    # It is available to the `flutter` tool through its wrapper, but it must be
-    # added here as well so the setup hook adds plugin dependencies to the
-    # pkg-config search paths.
-    pkg-config
-  ];
-
-  buildInputs = (args.buildInputs or [ ]) ++ [ glib ];
-
-  dontDartBuild = true;
-  buildPhase = args.buildPhase or ''
-    runHook preBuild
-
-    mkdir -p build/flutter_assets/fonts
-
-    flutter build linux -v --release --split-debug-info="$debug" ${builtins.concatStringsSep " " (map (flag: "\"${flag}\"") flutterBuildFlags)}
-
-    runHook postBuild
-  '';
-
-  dontDartInstall = true;
-  installPhase = args.installPhase or ''
-    runHook preInstall
-
-    built=build/linux/*/release/bundle
-
-    mkdir -p $out/bin
-    mv $built $out/app
-
-    for f in $(find $out/app -iname "*.desktop" -type f); do
-      install -D $f $out/share/applications/$(basename $f)
-    done
-
-    for f in $(find $out/app -maxdepth 1 -type f); do
-      ln -s $f $out/bin/$(basename $f)
-    done
-
-    # make *.so executable
-    find $out/app -iname "*.so" -type f -exec chmod +x {} +
-
-    # remove stuff like /build/source/packages/ubuntu_desktop_installer/linux/flutter/ephemeral
-    for f in $(find $out/app -executable -type f); do
-      if patchelf --print-rpath "$f" | grep /build; then # this ignores static libs (e,g. libapp.so) also
-        echo "strip RPath of $f"
-        newrp=$(patchelf --print-rpath $f | sed -r "s|/build.*ephemeral:||g" | sed -r "s|/build.*profile:||g")
-        patchelf --set-rpath "$newrp" "$f"
-      fi
-    done
-
-    # Install the package_config.json file.
-    # This is normally done by dartInstallHook, but we disable it.
-    mkdir -p "$pubcache"
-    cp .dart_tool/package_config.json "$pubcache/package_config.json"
-
-    runHook postInstall
-  '';
-
-  dontWrapGApps = true;
-  extraWrapProgramArgs = ''
-    ''${gappsWrapperArgs[@]} \
-    ${extraWrapProgramArgs}
-  '';
-})
+      '';
+    };
+
+    linux = universal // {
+      outputs = universal.outputs or [ ] ++ [ "debug" ];
+
+      nativeBuildInputs = (universal.nativeBuildInputs or [ ]) ++ [
+        wrapGAppsHook
+
+        # Flutter requires pkg-config for Linux desktop support, and many plugins
+        # attempt to use it.
+        #
+        # It is available to the `flutter` tool through its wrapper, but it must be
+        # added here as well so the setup hook adds plugin dependencies to the
+        # pkg-config search paths.
+        pkg-config
+      ];
+
+      buildInputs = (universal.buildInputs or [ ]) ++ [ glib ];
+
+      dontDartBuild = true;
+      buildPhase = universal.buildPhase or ''
+        runHook preBuild
+
+        mkdir -p build/flutter_assets/fonts
+
+        flutter build linux -v --release --split-debug-info="$debug" ${builtins.concatStringsSep " " (map (flag: "\"${flag}\"") flutterBuildFlags)}
+
+        runHook postBuild
+      '';
+
+      dontDartInstall = true;
+      installPhase = universal.installPhase or ''
+        runHook preInstall
+
+        built=build/linux/*/release/bundle
+
+        mkdir -p $out/bin
+        mv $built $out/app
+
+        for f in $(find $out/app -iname "*.desktop" -type f); do
+          install -D $f $out/share/applications/$(basename $f)
+        done
+
+        for f in $(find $out/app -maxdepth 1 -type f); do
+          ln -s $f $out/bin/$(basename $f)
+        done
+
+        # make *.so executable
+        find $out/app -iname "*.so" -type f -exec chmod +x {} +
+
+        # remove stuff like /build/source/packages/ubuntu_desktop_installer/linux/flutter/ephemeral
+        for f in $(find $out/app -executable -type f); do
+          if patchelf --print-rpath "$f" | grep /build; then # this ignores static libs (e,g. libapp.so) also
+            echo "strip RPath of $f"
+            newrp=$(patchelf --print-rpath $f | sed -r "s|/build.*ephemeral:||g" | sed -r "s|/build.*profile:||g")
+            patchelf --set-rpath "$newrp" "$f"
+          fi
+        done
+
+        runHook postInstall
+      '';
+
+      dontWrapGApps = true;
+      extraWrapProgramArgs = ''
+        ''${gappsWrapperArgs[@]} \
+        ${extraWrapProgramArgs}
+      '';
+    };
+
+    web = universal // {
+      dontDartBuild = true;
+      buildPhase = universal.buildPhase or ''
+        runHook preBuild
+
+        mkdir -p build/flutter_assets/fonts
+
+        flutter build web -v --release ${builtins.concatStringsSep " " (map (flag: "\"${flag}\"") flutterBuildFlags)}
+
+        runHook postBuild
+      '';
+
+      dontDartInstall = true;
+      installPhase = universal.installPhase or ''
+        runHook preInstall
+
+        cp -r build/web "$out"
+
+        runHook postInstall
+      '';
+    };
+  }.${targetFlutterPlatform} or (throw "Unsupported Flutter host platform: ${targetFlutterPlatform}");
+
+  minimalFlutter = flutter.override { supportedTargetFlutterPlatforms = [ "universal" targetFlutterPlatform ]; };
+
+  buildAppWith = flutter: buildDartApplication.override { dart = flutter; };
+in
+buildAppWith minimalFlutter (builderArgs // { passthru = builderArgs.passthru or { } // { multiShell = buildAppWith flutter builderArgs; }; })
diff --git a/nixpkgs/pkgs/build-support/go/module.nix b/nixpkgs/pkgs/build-support/go/module.nix
index b79d4a008466..53287c7182ba 100644
--- a/nixpkgs/pkgs/build-support/go/module.nix
+++ b/nixpkgs/pkgs/build-support/go/module.nix
@@ -41,6 +41,8 @@ let
       # Not needed with buildGoModule
     , goPackagePath ? ""
 
+    , ldflags ? [ ]
+
       # needed for buildFlags{,Array} warning
     , buildFlags ? ""
     , buildFlagsArray ? ""
@@ -156,6 +158,9 @@ let
         GOFLAGS = lib.optionals (!proxyVendor) [ "-mod=vendor" ] ++ lib.optionals (!allowGoReference) [ "-trimpath" ];
         inherit CGO_ENABLED enableParallelBuilding GO111MODULE GOTOOLCHAIN;
 
+        # If not set to an explicit value, set the buildid empty for reproducibility.
+        ldflags = ldflags ++ lib.optionals (!lib.any (lib.hasPrefix "-buildid=") ldflags) [ "-buildid=" ];
+
         configurePhase = args.configurePhase or (''
           runHook preConfigure
 
@@ -305,6 +310,7 @@ let
     lib.warnIf (args' ? vendorSha256) "`vendorSha256` is deprecated. Use `vendorHash` instead"
     lib.warnIf (buildFlags != "" || buildFlagsArray != "")
       "Use the `ldflags` and/or `tags` attributes instead of `buildFlags`/`buildFlagsArray`"
+    lib.warnIf (builtins.elem "-buildid=" ldflags) "`-buildid=` is set by default as ldflag by buildGoModule"
       package;
 in
   buildGoPackage
diff --git a/nixpkgs/pkgs/build-support/go/package.nix b/nixpkgs/pkgs/build-support/go/package.nix
index 7e099b76f0b7..8ca5ca0dca01 100644
--- a/nixpkgs/pkgs/build-support/go/package.nix
+++ b/nixpkgs/pkgs/build-support/go/package.nix
@@ -37,6 +37,8 @@
 
 , CGO_ENABLED ? go.CGO_ENABLED
 
+, ldflags ? [ ]
+
 # needed for buildFlags{,Array} warning
 , buildFlags ? ""
 , buildFlagsArray ? ""
@@ -91,6 +93,9 @@ let
 
     GOARM = toString (lib.intersectLists [(stdenv.hostPlatform.parsed.cpu.version or "")] ["5" "6" "7"]);
 
+    # If not set to an explicit value, set the buildid empty for reproducibility.
+    ldflags = ldflags ++ lib.optionals (!lib.any (lib.hasPrefix "-buildid=") ldflags) [ "-buildid=" ];
+
     configurePhase = args.configurePhase or (''
       runHook preConfigure
 
@@ -280,4 +285,5 @@ let
 in
 lib.warnIf (buildFlags != "" || buildFlagsArray != "")
   "Use the `ldflags` and/or `tags` attributes instead of `buildFlags`/`buildFlagsArray`"
+lib.warnIf (builtins.elem "-buildid=" ldflags) "`-buildid=` is set by default as ldflag by buildGoModule"
   package
diff --git a/nixpkgs/pkgs/build-support/kernel/compress-firmware-xz.nix b/nixpkgs/pkgs/build-support/kernel/compress-firmware-xz.nix
index cfb06a5c0f15..cb9ce7a71338 100644
--- a/nixpkgs/pkgs/build-support/kernel/compress-firmware-xz.nix
+++ b/nixpkgs/pkgs/build-support/kernel/compress-firmware-xz.nix
@@ -3,7 +3,9 @@
 firmware:
 
 let
-  args = lib.optionalAttrs (firmware ? meta) { inherit (firmware) meta; };
+  args = {
+    allowedRequisites = [];
+  } // lib.optionalAttrs (firmware ? meta) { inherit (firmware) meta; };
 in
 
 runCommand "${firmware.name}-xz" args ''
@@ -15,6 +17,13 @@ runCommand "${firmware.name}-xz" args ''
           sh -c 'xz -9c -T1 -C crc32 --lzma2=dict=2MiB "${firmware}/$1" > "$1.xz"' --)
   (cd ${firmware} && find lib/firmware -type l) | while read link; do
       target="$(readlink "${firmware}/$link")"
-      ln -vs -- "''${target/^${firmware}/$out}.xz" "$out/$link.xz"
+      if [ -f "${firmware}/$link" ]; then
+        ln -vs -- "''${target/^${firmware}/$out}.xz" "$out/$link.xz"
+      else
+        ln -vs -- "''${target/^${firmware}/$out}" "$out/$link"
+      fi
   done
+
+  echo "Checking for broken symlinks:"
+  find -L $out -type l -print -execdir false -- '{}' '+'
 ''
diff --git a/nixpkgs/pkgs/build-support/kernel/make-initrd-ng/Cargo.lock b/nixpkgs/pkgs/build-support/kernel/make-initrd-ng/Cargo.lock
index 961c5a3c1ab6..83e0fd3a2c5e 100644
--- a/nixpkgs/pkgs/build-support/kernel/make-initrd-ng/Cargo.lock
+++ b/nixpkgs/pkgs/build-support/kernel/make-initrd-ng/Cargo.lock
@@ -57,9 +57,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.76"
+version = "1.0.78"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
+checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
 dependencies = [
  "unicode-ident",
 ]
diff --git a/nixpkgs/pkgs/build-support/rust/build-rust-crate/configure-crate.nix b/nixpkgs/pkgs/build-support/rust/build-rust-crate/configure-crate.nix
index d837d0012590..6b8827160262 100644
--- a/nixpkgs/pkgs/build-support/rust/build-rust-crate/configure-crate.nix
+++ b/nixpkgs/pkgs/build-support/rust/build-rust-crate/configure-crate.nix
@@ -7,12 +7,17 @@
 , completeBuildDeps
 , completeDeps
 , crateAuthors
-, crateLinks
 , crateDescription
-, crateHomepage
 , crateFeatures
+, crateHomepage
+, crateLicense
+, crateLicenseFile
+, crateLinks
 , crateName
+, crateReadme
 , crateRenames
+, crateRepository
+, crateRustVersion
 , crateVersion
 , extraLinkFlags
 , extraRustcOptsForBuildRs
@@ -120,6 +125,8 @@ in ''
 
   EXTRA_BUILD=""
   BUILD_OUT_DIR=""
+
+  # Set up Cargo Environment variables: https://doc.rust-lang.org/cargo/reference/environment-variables.html
   export CARGO_PKG_NAME=${crateName}
   export CARGO_PKG_VERSION=${crateVersion}
   export CARGO_PKG_AUTHORS="${authors}"
@@ -147,6 +154,11 @@ in ''
   export CARGO_PKG_VERSION_PATCH=${lib.elemAt version 2}
   export CARGO_PKG_VERSION_PRE="${versionPre}"
   export CARGO_PKG_HOMEPAGE="${crateHomepage}"
+  export CARGO_PKG_LICENSE="${crateLicense}"
+  export CARGO_PKG_LICENSE_FILE="${crateLicenseFile}"
+  export CARGO_PKG_README="${crateReadme}"
+  export CARGO_PKG_REPOSITORY="${crateRepository}"
+  export CARGO_PKG_RUST_VERSION="${crateRustVersion}"
   export NUM_JOBS=$NIX_BUILD_CORES
   export RUSTC="rustc"
   export RUSTDOC="rustdoc"
diff --git a/nixpkgs/pkgs/build-support/rust/build-rust-crate/default.nix b/nixpkgs/pkgs/build-support/rust/build-rust-crate/default.nix
index 1760ab6e99a6..4a7fd114829a 100644
--- a/nixpkgs/pkgs/build-support/rust/build-rust-crate/default.nix
+++ b/nixpkgs/pkgs/build-support/rust/build-rust-crate/default.nix
@@ -314,11 +314,16 @@ crate_: lib.makeOverridable
       # Either set to a concrete sub path to the crate root
       # or use `null` for auto-detect.
       workspace_member = crate.workspace_member or ".";
-      crateVersion = crate.version;
-      crateDescription = crate.description or "";
       crateAuthors = if crate ? authors && lib.isList crate.authors then crate.authors else [ ];
+      crateDescription = crate.description or "";
       crateHomepage = crate.homepage or "";
+      crateLicense = crate.license or "";
+      crateLicenseFile = crate.license-file or "";
       crateLinks = crate.links or "";
+      crateReadme = crate.readme or "";
+      crateRepository = crate.repository or "";
+      crateRustVersion = crate.rust-version or "";
+      crateVersion = crate.version;
       crateType =
         if lib.attrByPath [ "procMacro" ] false crate then [ "proc-macro" ] else
         if lib.attrByPath [ "plugin" ] false crate then [ "dylib" ] else
@@ -341,6 +346,7 @@ crate_: lib.makeOverridable
         inherit crateName buildDependencies completeDeps completeBuildDeps crateDescription
           crateFeatures crateRenames libName build workspace_member release libPath crateVersion crateLinks
           extraLinkFlags extraRustcOptsForBuildRs
+          crateLicense crateLicenseFile crateReadme crateRepository crateRustVersion
           crateAuthors crateHomepage verbose colors codegenUnits;
       };
       buildPhase = buildCrate {
diff --git a/nixpkgs/pkgs/build-support/rust/lib/default.nix b/nixpkgs/pkgs/build-support/rust/lib/default.nix
index e70b8229d356..e09f913bfbd3 100644
--- a/nixpkgs/pkgs/build-support/rust/lib/default.nix
+++ b/nixpkgs/pkgs/build-support/rust/lib/default.nix
@@ -1,7 +1,8 @@
 { lib
 , stdenv
-, buildPackages
-, targetPackages
+, pkgsBuildHost
+, pkgsBuildTarget
+, pkgsTargetTarget
 }:
 
 rec {
@@ -16,26 +17,26 @@ rec {
     # As a workaround for https://github.com/rust-lang/rust/issues/89626 use lld on pkgsStatic aarch64
     shouldUseLLD = platform: platform.isAarch64 && platform.isStatic && !stdenv.isDarwin;
 
-    ccForBuild = "${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}cc";
-    cxxForBuild = "${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}c++";
+    ccForBuild = "${pkgsBuildHost.stdenv.cc}/bin/${pkgsBuildHost.stdenv.cc.targetPrefix}cc";
+    cxxForBuild = "${pkgsBuildHost.stdenv.cc}/bin/${pkgsBuildHost.stdenv.cc.targetPrefix}c++";
     linkerForBuild = ccForBuild;
 
     ccForHost = "${stdenv.cc}/bin/${stdenv.cc.targetPrefix}cc";
     cxxForHost = "${stdenv.cc}/bin/${stdenv.cc.targetPrefix}c++";
     linkerForHost = if shouldUseLLD stdenv.targetPlatform
       && !stdenv.cc.bintools.isLLVM
-      then "${buildPackages.lld}/bin/ld.lld"
+      then "${pkgsBuildHost.llvmPackages.bintools}/bin/${stdenv.cc.targetPrefix}ld.lld"
       else ccForHost;
 
-    # Unfortunately we must use the dangerous `targetPackages` here
+    # Unfortunately we must use the dangerous `pkgsTargetTarget` here
     # because hooks are artificially phase-shifted one slot earlier
     # (they go in nativeBuildInputs, so the hostPlatform looks like
     # a targetPlatform to them).
-    ccForTarget = "${targetPackages.stdenv.cc}/bin/${targetPackages.stdenv.cc.targetPrefix}cc";
-    cxxForTarget = "${targetPackages.stdenv.cc}/bin/${targetPackages.stdenv.cc.targetPrefix}c++";
-    linkerForTarget = if shouldUseLLD targetPackages.stdenv.targetPlatform
-      && !targetPackages.stdenv.cc.bintools.isLLVM # whether stdenv's linker is lld already
-      then "${buildPackages.lld}/bin/ld.lld"
+    ccForTarget = "${pkgsTargetTarget.stdenv.cc}/bin/${pkgsTargetTarget.stdenv.cc.targetPrefix}cc";
+    cxxForTarget = "${pkgsTargetTarget.stdenv.cc}/bin/${pkgsTargetTarget.stdenv.cc.targetPrefix}c++";
+    linkerForTarget = if shouldUseLLD pkgsTargetTarget.stdenv.targetPlatform
+      && !pkgsTargetTarget.stdenv.cc.bintools.isLLVM # whether stdenv's linker is lld already
+      then "${pkgsBuildTarget.llvmPackages.bintools}/bin/${pkgsTargetTarget.stdenv.cc.targetPrefix}ld.lld"
       else ccForTarget;
 
     rustBuildPlatform = stdenv.buildPlatform.rust.rustcTarget;
@@ -56,9 +57,9 @@ rec {
     setEnv = ''
     env \
     ''
-    # Due to a bug in how splicing and targetPackages works, in
-    # situations where targetPackages is irrelevant
-    # targetPackages.stdenv.cc is often simply wrong.  We must omit
+    # Due to a bug in how splicing and pkgsTargetTarget works, in
+    # situations where pkgsTargetTarget is irrelevant
+    # pkgsTargetTarget.stdenv.cc is often simply wrong.  We must omit
     # the following lines when rustTargetPlatform collides with
     # rustHostPlatform.
     + lib.optionalString (rustTargetPlatform != rustHostPlatform) ''
@@ -74,8 +75,8 @@ rec {
       "CXX_${stdenv.buildPlatform.rust.cargoEnvVarTarget}=${cxxForBuild}" \
       "CARGO_TARGET_${stdenv.buildPlatform.rust.cargoEnvVarTarget}_LINKER=${linkerForBuild}" \
       "CARGO_BUILD_TARGET=${rustBuildPlatform}" \
-      "HOST_CC=${buildPackages.stdenv.cc}/bin/cc" \
-      "HOST_CXX=${buildPackages.stdenv.cc}/bin/c++" \
+      "HOST_CC=${pkgsBuildHost.stdenv.cc}/bin/cc" \
+      "HOST_CXX=${pkgsBuildHost.stdenv.cc}/bin/c++" \
     '';
   };
 } // lib.mapAttrs (old: new: platform:
diff --git a/nixpkgs/pkgs/build-support/rust/rustc-wrapper/rustc-wrapper.sh b/nixpkgs/pkgs/build-support/rust/rustc-wrapper/rustc-wrapper.sh
index 2082f3126a53..4a90e30652fe 100644
--- a/nixpkgs/pkgs/build-support/rust/rustc-wrapper/rustc-wrapper.sh
+++ b/nixpkgs/pkgs/build-support/rust/rustc-wrapper/rustc-wrapper.sh
@@ -4,7 +4,7 @@ defaultSysroot=(@sysroot@)
 
 for arg; do
     case "$arg" in
-        --sysroot)
+        --sysroot|--sysroot=*)
             defaultSysroot=()
             ;;
         --)
diff --git a/nixpkgs/pkgs/build-support/setup-hooks/postgresql-test-hook/postgresql-test-hook.sh b/nixpkgs/pkgs/build-support/setup-hooks/postgresql-test-hook/postgresql-test-hook.sh
index 3eec67d60feb..d09153b2d644 100644
--- a/nixpkgs/pkgs/build-support/setup-hooks/postgresql-test-hook/postgresql-test-hook.sh
+++ b/nixpkgs/pkgs/build-support/setup-hooks/postgresql-test-hook/postgresql-test-hook.sh
@@ -56,6 +56,8 @@ EOF
   echo 'initializing postgresql'
   initdb -U postgres
 
+  echo "$postgresqlExtraSettings" >>"$PGDATA/postgresql.conf"
+
   # Move the socket
   echo "unix_socket_directories = '$NIX_BUILD_TOP/run/postgresql'" >>"$PGDATA/postgresql.conf"
 
diff --git a/nixpkgs/pkgs/build-support/testers/hasPkgConfigModules/tester.nix b/nixpkgs/pkgs/build-support/testers/hasPkgConfigModules/tester.nix
index 755559038271..bbcc4f0c0f71 100644
--- a/nixpkgs/pkgs/build-support/testers/hasPkgConfigModules/tester.nix
+++ b/nixpkgs/pkgs/build-support/testers/hasPkgConfigModules/tester.nix
@@ -30,10 +30,11 @@ runCommand testName {
         }
         package.meta;
   } ''
+    touch "$out"
     for moduleName in $moduleNames; do
       echo "checking pkg-config module $moduleName in $buildInputs"
       set +e
-      version="$(pkg-config --modversion $moduleName)"
+      version="$($PKG_CONFIG --modversion $moduleName)"
       r=$?
       set -e
       if [[ $r = 0 ]]; then
@@ -41,7 +42,7 @@ runCommand testName {
         printf '%s\t%s\n' "$moduleName" "$version" >> "$out"
       else
         echo "These modules were available in the input propagation closure:"
-        pkg-config --list-all
+        $PKG_CONFIG --list-all
         echo "❌ pkg-config module $moduleName was not found"
         false
       fi
diff --git a/nixpkgs/pkgs/build-support/trivial-builders/default.nix b/nixpkgs/pkgs/build-support/trivial-builders/default.nix
index 9643c9ba048e..a38231bdcaa3 100644
--- a/nixpkgs/pkgs/build-support/trivial-builders/default.nix
+++ b/nixpkgs/pkgs/build-support/trivial-builders/default.nix
@@ -152,19 +152,21 @@ rec {
     , meta ? { }
     , allowSubstitutes ? false
     , preferLocalBuild ? true
+    , derivationArgs ? { } # Extra arguments to pass to `stdenv.mkDerivation`
     }:
     let
       matches = builtins.match "/bin/([^/]+)" destination;
     in
     runCommand name
-      {
+      ({
         inherit text executable checkPhase allowSubstitutes preferLocalBuild;
-        passAsFile = [ "text" ];
+        passAsFile = [ "text" ]
+          ++ derivationArgs.passAsFile or [ ];
         meta = lib.optionalAttrs (executable && matches != null)
           {
             mainProgram = lib.head matches;
-          } // meta;
-      }
+          } // meta // derivationArgs.meta or {};
+      } // removeAttrs derivationArgs [ "passAsFile" "meta" ])
       ''
         target=$out${lib.escapeShellArg destination}
         mkdir -p "$(dirname "$target")"
@@ -238,53 +240,94 @@ rec {
       meta.mainProgram = name;
     };
 
-  /*
-    Similar to writeShellScriptBin and writeScriptBin.
-    Writes an executable Shell script to /nix/store/<store path>/bin/<name> and
-    checks its syntax with shellcheck and the shell's -n option.
-    Individual checks can be foregone by putting them in the excludeShellChecks
-    list, e.g. [ "SC2016" ].
-    Automatically includes sane set of shellopts (errexit, nounset, pipefail)
-    and handles creation of PATH based on runtimeInputs
-
-    Note that the checkPhase uses stdenv.shell for the test run of the script,
-    while the generated shebang uses runtimeShell. If, for whatever reason,
-    those were to mismatch you might lose fidelity in the default checks.
-
-    Example:
-
-    Writes my-file to /nix/store/<store path>/bin/my-file and makes executable.
-
-
-    writeShellApplication {
-      name = "my-file";
-      runtimeInputs = [ curl w3m ];
-      text = ''
-        curl -s 'https://nixos.org' | w3m -dump -T text/html
-       '';
-    }
-
-  */
+  # See doc/build-helpers/trivial-build-helpers.chapter.md
+  # or https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-text-writing
   writeShellApplication =
-    { name
-    , text
-    , runtimeInputs ? [ ]
-    , meta ? { }
-    , checkPhase ? null
-    , excludeShellChecks ? [ ]
+    {
+      /*
+         The name of the script to write.
+
+         Type: String
+       */
+      name,
+      /*
+         The shell script's text, not including a shebang.
+
+         Type: String
+       */
+      text,
+      /*
+         Inputs to add to the shell script's `$PATH` at runtime.
+
+         Type: [String|Derivation]
+       */
+      runtimeInputs ? [ ],
+      /*
+         Extra environment variables to set at runtime.
+
+         Type: AttrSet
+       */
+      runtimeEnv ? null,
+      /*
+         `stdenv.mkDerivation`'s `meta` argument.
+
+         Type: AttrSet
+       */
+      meta ? { },
+      /*
+         The `checkPhase` to run. Defaults to `shellcheck` on supported
+         platforms and `bash -n`.
+
+         The script path will be given as `$target` in the `checkPhase`.
+
+         Type: String
+       */
+      checkPhase ? null,
+      /*
+         Checks to exclude when running `shellcheck`, e.g. `[ "SC2016" ]`.
+
+         See <https://www.shellcheck.net/wiki/> for a list of checks.
+
+         Type: [String]
+       */
+      excludeShellChecks ? [ ],
+      /*
+         Bash options to activate with `set -o` at the start of the script.
+
+         Defaults to `[ "errexit" "nounset" "pipefail" ]`.
+
+         Type: [String]
+       */
+      bashOptions ? [ "errexit" "nounset" "pipefail" ],
+      /* Extra arguments to pass to `stdenv.mkDerivation`.
+
+         :::{.caution}
+         Certain derivation attributes are used internally,
+         overriding those could cause problems.
+         :::
+
+         Type: AttrSet
+       */
+      derivationArgs ? { },
     }:
     writeTextFile {
-      inherit name meta;
+      inherit name meta derivationArgs;
       executable = true;
       destination = "/bin/${name}";
       allowSubstitutes = true;
       preferLocalBuild = false;
       text = ''
         #!${runtimeShell}
-        set -o errexit
-        set -o nounset
-        set -o pipefail
-      '' + lib.optionalString (runtimeInputs != [ ]) ''
+        ${lib.concatMapStringsSep "\n" (option: "set -o ${option}") bashOptions}
+      '' + lib.optionalString (runtimeEnv != null)
+        (lib.concatStrings
+          (lib.mapAttrsToList
+            (name: value: ''
+              ${lib.toShellVar name value}
+              export ${name}
+            '')
+            runtimeEnv))
+      + lib.optionalString (runtimeInputs != [ ]) ''
 
         export PATH="${lib.makeBinPath runtimeInputs}:$PATH"
       '' + ''
diff --git a/nixpkgs/pkgs/build-support/trivial-builders/test/writeShellApplication.nix b/nixpkgs/pkgs/build-support/trivial-builders/test/writeShellApplication.nix
index 6ce6f0720fcf..c50f5a4d283f 100644
--- a/nixpkgs/pkgs/build-support/trivial-builders/test/writeShellApplication.nix
+++ b/nixpkgs/pkgs/build-support/trivial-builders/test/writeShellApplication.nix
@@ -1,29 +1,141 @@
-/*
-  Run with:
+# Run with:
+# nix-build -A tests.trivial-builders.writeShellApplication
+{ writeShellApplication
+, writeTextFile
+, runCommand
+, lib
+, linkFarm
+, diffutils
+, hello
+}:
+let
+  checkShellApplication = args@{name, expected, ...}:
+    let
+      writeShellApplicationArgs = builtins.removeAttrs args ["expected"];
+      script = writeShellApplication writeShellApplicationArgs;
+      executable = lib.getExe script;
+      expected' = writeTextFile {
+        name = "${name}-expected";
+        text = expected;
+      };
+      actual = "${name}-actual";
+    in
+    runCommand name { } ''
+      echo "Running test executable ${name}"
+      ${executable} > ${actual}
+      echo "Got output from test executable:"
+      cat ${actual}
+      echo "Checking test output against expected output:"
+      ${diffutils}/bin/diff --color --unified ${expected'} ${actual}
+      touch $out
+    '';
+in
+linkFarm "writeShellApplication-tests" {
+  test-meta =
+    let
+      script = writeShellApplication {
+        name = "test-meta";
+        text = "";
+        meta.description = "A test for the `writeShellApplication` `meta` argument.";
+      };
+    in
+    assert script.meta.mainProgram == "test-meta";
+    assert script.meta.description == "A test for the `writeShellApplication` `meta` argument.";
+    script;
 
-      cd nixpkgs
-      nix-build -A tests.trivial-builders.writeShellApplication
-*/
+  test-runtime-inputs =
+    checkShellApplication {
+      name = "test-runtime-inputs";
+      text = ''
+        hello
+      '';
+      runtimeInputs = [ hello ];
+      expected = "Hello, world!\n";
+    };
 
-{ lib, writeShellApplication, runCommand }:
-let
-  pkg = writeShellApplication {
-    name = "test-script";
+  test-runtime-env =
+    checkShellApplication {
+      name = "test-runtime-env";
+      runtimeEnv = {
+        MY_COOL_ENV_VAR = "my-cool-env-value";
+        MY_OTHER_COOL_ENV_VAR = "my-other-cool-env-value";
+        # Check that we can serialize a bunch of different types:
+        BOOL = true;
+        INT = 1;
+        LIST = [1 2 3];
+        MAP = {
+          a = "a";
+          b = "b";
+        };
+      };
+      text = ''
+        echo "$MY_COOL_ENV_VAR"
+        echo "$MY_OTHER_COOL_ENV_VAR"
+      '';
+      expected = ''
+        my-cool-env-value
+        my-other-cool-env-value
+      '';
+    };
+
+  test-check-phase =
+    checkShellApplication {
+      name = "test-check-phase";
+      text = "";
+      checkPhase = ''
+        echo "echo -n hello" > $target
+      '';
+      expected = "hello";
+    };
+
+  test-argument-forwarding =
+    checkShellApplication {
+      name = "test-argument-forwarding";
+      text = "";
+      derivationArgs.MY_BUILD_TIME_VARIABLE = "puppy";
+      derivationArgs.postCheck = ''
+        if [[ "$MY_BUILD_TIME_VARIABLE" != puppy ]]; then
+          echo "\$MY_BUILD_TIME_VARIABLE is not set to 'puppy'!"
+          exit 1
+        fi
+      '';
+      meta.description = "A test checking that `writeShellApplication` forwards extra arguments to `stdenv.mkDerivation`.";
+      expected = "";
+    };
+
+  test-exclude-shell-checks = writeShellApplication {
+    name = "test-exclude-shell-checks";
     excludeShellChecks = [ "SC2016" ];
     text = ''
-      echo -e '#!/usr/bin/env bash\n' \
-       'echo "$SHELL"' > /tmp/something.sh  # this line would normally
-                                            # ...cause shellcheck error
+      # Triggers SC2016: Expressions don't expand in single quotes, use double
+      # quotes for that.
+      echo '$SHELL'
     '';
   };
-in
-  assert pkg.meta.mainProgram == "test-script";
-  runCommand "test-writeShellApplication" { } ''
 
-    echo Testing if writeShellApplication builds without shellcheck error...
-
-    target=${lib.getExe pkg}
+  test-bash-options-pipefail = checkShellApplication {
+    name = "test-bash-options-pipefail";
+    text = ''
+      touch my-test-file
+      echo puppy | grep doggy | sed 's/doggy/puppy/g'
+      #            ^^^^^^^^^^ This will fail.
+      true
+    '';
+    # Don't use `pipefail`:
+    bashOptions = ["errexit" "nounset"];
+    expected = "";
+  };
 
-    touch $out
-  ''
+  test-bash-options-nounset = checkShellApplication {
+    name = "test-bash-options-nounset";
+    text = ''
+      echo -n "$someUndefinedVariable"
+    '';
+    # Don't use `nounset`:
+    bashOptions = [];
+    # Don't warn about the undefined variable at build time:
+    excludeShellChecks = [ "SC2154" ];
+    expected = "";
+  };
 
+}
diff --git a/nixpkgs/pkgs/build-support/writers/default.nix b/nixpkgs/pkgs/build-support/writers/default.nix
index a161322cd35b..cadb69781481 100644
--- a/nixpkgs/pkgs/build-support/writers/default.nix
+++ b/nixpkgs/pkgs/build-support/writers/default.nix
@@ -1,5 +1,6 @@
 { config, lib, callPackages }:
 
+# If you are reading this, you can test these writers by running: nix-build . -A tests.writers
 let
   aliases = if config.allowAliases then (import ./aliases.nix lib) else prev: {};
 
diff --git a/nixpkgs/pkgs/build-support/writers/scripts.nix b/nixpkgs/pkgs/build-support/writers/scripts.nix
index 184ecee68777..8a23e5dd4a66 100644
--- a/nixpkgs/pkgs/build-support/writers/scripts.nix
+++ b/nixpkgs/pkgs/build-support/writers/scripts.nix
@@ -13,7 +13,7 @@ let
 in
 rec {
   # Base implementation for non-compiled executables.
-  # Takes an interpreter, for example `${pkgs.bash}/bin/bash`
+  # Takes an interpreter, for example `${lib.getExe pkgs.bash}`
   #
   # Examples:
   #   writeBash = makeScriptWriter { interpreter = "${pkgs.bash}/bin/bash"; }
@@ -116,7 +116,7 @@ rec {
   #     echo hello world
   #   ''
   writeBash = makeScriptWriter {
-    interpreter = "${pkgs.bash}/bin/bash";
+    interpreter = "${lib.getExe pkgs.bash}";
   };
 
   # Like writeScriptBin but the first line is a shebang to bash
@@ -130,7 +130,7 @@ rec {
   #     echo hello world
   #   ''
   writeDash = makeScriptWriter {
-    interpreter = "${pkgs.dash}/bin/dash";
+    interpreter = "${lib.getExe pkgs.dash}";
   };
 
   # Like writeScriptBin but the first line is a shebang to dash
@@ -144,8 +144,8 @@ rec {
   #     echo hello world
   #   ''
   writeFish = makeScriptWriter {
-    interpreter = "${pkgs.fish}/bin/fish --no-config";
-    check = "${pkgs.fish}/bin/fish --no-config --no-execute";  # syntax check only
+    interpreter = "${lib.getExe pkgs.fish} --no-config";
+    check = "${lib.getExe pkgs.fish} --no-config --no-execute";  # syntax check only
   };
 
   # Like writeScriptBin but the first line is a shebang to fish
@@ -175,7 +175,7 @@ rec {
     in makeBinWriter {
       compileScript = ''
         cp $contentPath tmp.hs
-        ${ghc.withPackages (_: libraries )}/bin/ghc ${lib.escapeShellArgs ghcArgs'} tmp.hs
+        ${(ghc.withPackages (_: libraries ))}/bin/ghc ${lib.escapeShellArgs ghcArgs'} tmp.hs
         mv tmp $out
       '';
       inherit strip;
@@ -185,6 +185,85 @@ rec {
   writeHaskellBin = name:
     writeHaskell "/bin/${name}";
 
+  # Like writeScript but the first line is a shebang to nu
+  #
+  # Example:
+  #   writeNu "example" ''
+  #     echo hello world
+  #   ''
+  writeNu = makeScriptWriter {
+    interpreter = "${lib.getExe pkgs.nushell} --no-config-file";
+  };
+
+  # Like writeScriptBin but the first line is a shebang to nu
+  writeNuBin = name:
+    writeNu "/bin/${name}";
+
+  # makeRubyWriter takes ruby and compatible rubyPackages and produces ruby script writer,
+  # If any libraries are specified, ruby.withPackages is used as interpreter, otherwise the "bare" ruby is used.
+  makeRubyWriter = ruby: rubyPackages: buildRubyPackages: name: { libraries ? [], }:
+  makeScriptWriter {
+    interpreter =
+      if libraries == []
+      then "${ruby}/bin/ruby"
+      else "${(ruby.withPackages (ps: libraries))}/bin/ruby";
+    # Rubocop doesnt seem to like running in this fashion.
+    #check = (writeDash "rubocop.sh" ''
+    #  exec ${lib.getExe buildRubyPackages.rubocop} "$1"
+    #'');
+  } name;
+
+  # Like writeScript but the first line is a shebang to ruby
+  #
+  # Example:
+  #   writeRuby "example" ''
+  #    puts "hello world"
+  #   ''
+  writeRuby = makeRubyWriter pkgs.ruby pkgs.rubyPackages buildPackages.rubyPackages;
+
+  writeRubyBin = name:
+    writeRuby "/bin/${name}";
+
+  # makeLuaWriter takes lua and compatible luaPackages and produces lua script writer,
+  # which validates the script with luacheck at build time. If any libraries are specified,
+  # lua.withPackages is used as interpreter, otherwise the "bare" lua is used.
+  makeLuaWriter = lua: luaPackages: buildLuaPackages: name: { libraries ? [], }:
+  makeScriptWriter {
+    interpreter = lua.interpreter;
+      # if libraries == []
+      # then lua.interpreter
+      # else (lua.withPackages (ps: libraries)).interpreter
+      # This should support packages! I just cant figure out why some dependency collision happens whenever I try to run this.
+    check = (writeDash "luacheck.sh" ''
+      exec ${buildLuaPackages.luacheck}/bin/luacheck "$1"
+    '');
+  } name;
+
+  # writeLua takes a name an attributeset with libraries and some lua source code and
+  # returns an executable (should also work with luajit)
+  #
+  # Example:
+  # writeLua "test_lua" { libraries = [ pkgs.luaPackages.say ]; } ''
+  #   s = require("say")
+  #   s:set_namespace("en")
+  #
+  #   s:set('money', 'I have %s dollars')
+  #   s:set('wow', 'So much money!')
+  #
+  #   print(s('money', {1000})) -- I have 1000 dollars
+  #
+  #   s:set_namespace("fr") -- switch to french!
+  #   s:set('wow', "Tant d'argent!")
+  #
+  #   print(s('wow')) -- Tant d'argent!
+  #   s:set_namespace("en")  -- switch back to english!
+  #   print(s('wow')) -- So much money!
+  # ''
+  writeLua = makeLuaWriter pkgs.lua pkgs.luaPackages buildPackages.luaPackages;
+
+  writeLuaBin = name:
+    writeLua "/bin/${name}";
+
   writeRust = name: {
       rustc ? pkgs.rustc,
       rustcArgs ? [],
@@ -196,7 +275,7 @@ rec {
     makeBinWriter {
       compileScript = ''
         cp "$contentPath" tmp.rs
-        PATH=${lib.makeBinPath [pkgs.gcc]} ${lib.getBin rustc}/bin/rustc ${lib.escapeShellArgs rustcArgs} ${lib.escapeShellArgs darwinArgs} -o "$out" tmp.rs
+        PATH=${lib.makeBinPath [pkgs.gcc]} ${rustc}/bin/rustc ${lib.escapeShellArgs rustcArgs} ${lib.escapeShellArgs darwinArgs} -o "$out" tmp.rs
       '';
       inherit strip;
     } name;
@@ -225,7 +304,7 @@ rec {
     };
   in writeDash name ''
     export NODE_PATH=${node-env}/lib/node_modules
-    exec ${pkgs.nodejs}/bin/node ${pkgs.writeText "js" content} "$@"
+    exec ${lib.getExe pkgs.nodejs} ${pkgs.writeText "js" content} "$@"
   '';
 
   # writeJSBin takes the same arguments as writeJS but outputs a directory (like writeScriptBin)
@@ -260,7 +339,7 @@ rec {
   #   ''
   writePerl = name: { libraries ? [] }:
     makeScriptWriter {
-      interpreter = "${pkgs.perl.withPackages (p: libraries)}/bin/perl";
+      interpreter = "${lib.getExe (pkgs.perl.withPackages (p: libraries))}";
     } name;
 
   # writePerlBin takes the same arguments as writePerl but outputs a directory (like writeScriptBin)
@@ -276,9 +355,11 @@ rec {
   in
   makeScriptWriter {
     interpreter =
-      if libraries == []
-      then python.interpreter
-      else (python.withPackages (ps: libraries)).interpreter
+      if pythonPackages != pkgs.pypy2Packages || pythonPackages != pkgs.pypy3Packages then
+        if libraries == []
+        then python.interpreter
+        else (python.withPackages (ps: libraries)).interpreter
+      else python.interpreter
     ;
     check = optionalString python.isPy3k (writeDash "pythoncheck.sh" ''
       exec ${buildPythonPackages.flake8}/bin/flake8 --show-source ${ignoreAttribute} "$1"
@@ -358,7 +439,7 @@ rec {
       export DOTNET_CLI_TELEMETRY_OPTOUT=1
       export DOTNET_NOLOGO=1
       script="$1"; shift
-      ${dotnet-sdk}/bin/dotnet fsi --quiet --nologo --readline- ${fsi-flags} "$@" < "$script"
+      ${lib.getExe dotnet-sdk} fsi --quiet --nologo --readline- ${fsi-flags} "$@" < "$script"
     '';
 
   in content: makeScriptWriter {
diff --git a/nixpkgs/pkgs/build-support/writers/test.nix b/nixpkgs/pkgs/build-support/writers/test.nix
index 005daf0be5b4..982c550d28e0 100644
--- a/nixpkgs/pkgs/build-support/writers/test.nix
+++ b/nixpkgs/pkgs/build-support/writers/test.nix
@@ -6,11 +6,16 @@
 , pypy2Packages
 , python3Packages
 , pypy3Packages
+, luaPackages
+, rubyPackages
 , runCommand
 , testers
 , writers
 , writeText
 }:
+
+# If you are reading this, you can test these writers by running: nix-build . -A tests.writers
+
 with writers;
 let
   expectSuccess = test:
@@ -88,15 +93,6 @@ lib.recurseIntoAttrs {
       print "success\n" if true;
     '');
 
-    pypy2 = expectSuccessBin (writePyPy2Bin "test-writers-pypy2-bin" { libraries = [ pypy2Packages.enum ]; } ''
-      from enum import Enum
-
-      class Test(Enum):
-          a = "success"
-
-      print Test.a
-    '');
-
     python3 = expectSuccessBin (writePython3Bin "test-writers-python3-bin" { libraries = [ python3Packages.pyyaml ]; } ''
       import yaml
 
@@ -106,14 +102,47 @@ lib.recurseIntoAttrs {
       print(y[0]['test'])
     '');
 
-    pypy3 = expectSuccessBin (writePyPy3Bin "test-writers-pypy3-bin" { libraries = [ pypy3Packages.pyyaml ]; } ''
-      import yaml
-
-      y = yaml.safe_load("""
-        - test: success
-      """)
-      print(y[0]['test'])
-    '');
+    # Commented out because of this issue: https://github.com/NixOS/nixpkgs/issues/39356
+
+    #pypy2 = expectSuccessBin (writePyPy2Bin "test-writers-pypy2-bin" { libraries = [ pypy2Packages.enum ]; } ''
+    #  from enum import Enum
+    #
+    #  class Test(Enum):
+    #      a = "success"
+    #
+    #  print Test.a
+    #'');
+
+    #pypy3 = expectSuccessBin (writePyPy3Bin "test-writers-pypy3-bin" { libraries = [ pypy3Packages.pyyaml ]; } ''
+    #  import yaml
+    #
+    #  y = yaml.safe_load("""
+    #    - test: success
+    #  """)
+    #  print(y[0]['test'])
+    #'');
+
+    # Could not test this because of external package issues :(
+    #lua = writeLuaBin "test-writers-lua-bin" { libraries = [ pkgs.luaPackages.say ]; } ''
+    #  s = require("say")
+    #  s:set_namespace("en")
+
+    #  s:set('money', 'I have %s dollars')
+    #  s:set('wow', 'So much money!')
+
+    #  print(s('money', {1000})) -- I have 1000 dollars
+
+    #  s:set_namespace("fr") -- switch to french!
+    #  s:set('wow', "Tant d'argent!")
+
+    #  print(s('wow')) -- Tant d'argent!
+    #  s:set_namespace("en")  -- switch back to english!
+    #  print(s('wow')) -- So much money!
+    #'';
+
+    #ruby = expectSuccessBin (writeRubyBin "test-writers-ruby-bin" { libraries = [ rubyPackages.rubocop ]; } ''
+    #puts "This should work!"
+    #'');
   };
 
   simple = lib.recurseIntoAttrs {
@@ -131,6 +160,10 @@ lib.recurseIntoAttrs {
       end
     '');
 
+    nu = expectSuccess (writeNu "test-writers-nushell" ''
+      echo "success"
+    '');
+
     haskell = expectSuccess (writeHaskell "test-writers-haskell" { libraries = [ haskellPackages.acme-default ]; } ''
       import Data.Default
 
@@ -158,15 +191,6 @@ lib.recurseIntoAttrs {
       print "success\n" if true;
     '');
 
-    pypy2 = expectSuccess (writePyPy2 "test-writers-pypy2" { libraries = [ pypy2Packages.enum ]; } ''
-      from enum import Enum
-
-      class Test(Enum):
-          a = "success"
-
-      print Test.a
-    '');
-
     python3 = expectSuccess (writePython3 "test-writers-python3" { libraries = [ python3Packages.pyyaml ]; } ''
       import yaml
 
@@ -176,20 +200,33 @@ lib.recurseIntoAttrs {
       print(y[0]['test'])
     '');
 
-    pypy3 = expectSuccess (writePyPy3 "test-writers-pypy3" { libraries = [ pypy3Packages.pyyaml ]; } ''
-      import yaml
-
-      y = yaml.safe_load("""
-        - test: success
-      """)
-      print(y[0]['test'])
-    '');
+    # Commented out because of this issue: https://github.com/NixOS/nixpkgs/issues/39356
+
+    #pypy2 = expectSuccessBin (writePyPy2Bin "test-writers-pypy2-bin" { libraries = [ pypy2Packages.enum ]; } ''
+    #  from enum import Enum
+    #
+    #  class Test(Enum):
+    #      a = "success"
+    #
+    #  print Test.a
+    #'');
+
+    #pypy3 = expectSuccessBin (writePyPy3Bin "test-writers-pypy3-bin" { libraries = [ pypy3Packages.pyyaml ]; } ''
+    #  import yaml
+    #
+    #  y = yaml.safe_load("""
+    #    - test: success
+    #  """)
+    #  print(y[0]['test'])
+    #'');
 
     fsharp = expectSuccess (makeFSharpWriter {
       libraries = { fetchNuGet }: [
         (fetchNuGet { pname = "FSharp.SystemTextJson"; version = "0.17.4"; sha256 = "1bplzc9ybdqspii4q28l8gmfvzpkmgq5l1hlsiyg2h46w881lwg2"; })
+        (fetchNuGet { pname = "System.Text.Json"; version = "4.6.0"; sha256 = "0ism236hwi0k6axssfq58s1d8lihplwiz058pdvl8al71hagri39"; })
       ];
     } "test-writers-fsharp" ''
+
       #r "nuget: FSharp.SystemTextJson, 0.17.4"
 
       module Json =
@@ -208,9 +245,9 @@ lib.recurseIntoAttrs {
       |> printfn "%s"
     '');
 
-    pypy2NoLibs = expectSuccess (writePyPy2 "test-writers-pypy2-no-libs" {} ''
-      print("success")
-    '');
+    #pypy2NoLibs = expectSuccess (writePyPy2 "test-writers-pypy2-no-libs" {} ''
+    #  print("success")
+    #'');
 
     python3NoLibs = expectSuccess (writePython3 "test-writers-python3-no-libs" {} ''
       print("success")
@@ -222,6 +259,14 @@ lib.recurseIntoAttrs {
 
     fsharpNoNugetDeps = expectSuccess (writeFSharp "test-writers-fsharp-no-nuget-deps" ''
       printfn "success"
+      '');
+
+    luaNoLibs = expectSuccess (writeLua "test-writers-lua-no-libs" {} ''
+      print("success")
+      '');
+
+    rubyNoLibs = expectSuccess (writeRuby "test-writers-ruby-no-libs" {} ''
+      puts "success"
     '');
   };