about summary refs log tree commit diff
path: root/pkgs/build-support
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/build-support')
-rw-r--r--pkgs/build-support/alternatives/blas/default.nix2
-rw-r--r--pkgs/build-support/alternatives/lapack/default.nix2
-rwxr-xr-xpkgs/build-support/appimage/appimage-exec.sh14
-rw-r--r--pkgs/build-support/appimage/default.nix5
-rw-r--r--pkgs/build-support/bintools-wrapper/add-flags.sh5
-rw-r--r--pkgs/build-support/bintools-wrapper/default.nix41
-rw-r--r--pkgs/build-support/bintools-wrapper/ld-wrapper.sh13
-rw-r--r--pkgs/build-support/build-bazel-package/default.nix4
-rw-r--r--pkgs/build-support/build-dotnet-package/default.nix4
-rw-r--r--pkgs/build-support/build-fhs-userenv-bubblewrap/default.nix33
-rw-r--r--pkgs/build-support/build-fhs-userenv/chrootenv/chrootenv.c16
-rw-r--r--pkgs/build-support/build-fhs-userenv/chrootenv/default.nix6
-rw-r--r--pkgs/build-support/cc-wrapper/cc-wrapper.sh6
-rw-r--r--pkgs/build-support/cc-wrapper/default.nix63
-rw-r--r--pkgs/build-support/coq/default.nix92
-rw-r--r--pkgs/build-support/coq/extra-lib.nix145
-rw-r--r--pkgs/build-support/coq/meta-fetch/default.nix66
-rw-r--r--pkgs/build-support/docker/default.nix63
-rw-r--r--pkgs/build-support/docker/examples.nix28
-rwxr-xr-xpkgs/build-support/docker/nix-prefetch-docker14
-rw-r--r--pkgs/build-support/docker/nix-prefetch-docker.nix8
-rw-r--r--pkgs/build-support/docker/stream_layered_image.py6
-rw-r--r--pkgs/build-support/dotnetbuildhelpers/default.nix4
-rw-r--r--pkgs/build-support/dotnetenv/build-solution.nix4
-rw-r--r--pkgs/build-support/dotnetenv/default.nix4
-rw-r--r--pkgs/build-support/emacs/elpa.nix11
-rw-r--r--pkgs/build-support/emacs/generic.nix7
-rw-r--r--pkgs/build-support/emacs/melpa.nix2
-rw-r--r--pkgs/build-support/emacs/setup-hook.sh11
-rw-r--r--pkgs/build-support/emacs/trivial.nix2
-rw-r--r--pkgs/build-support/emacs/wrapper.nix57
-rw-r--r--pkgs/build-support/emacs/wrapper.sh47
-rw-r--r--pkgs/build-support/fetchbzr/default.nix2
-rw-r--r--pkgs/build-support/fetchdocker/fetchDockerConfig.nix2
-rw-r--r--pkgs/build-support/fetchdocker/fetchDockerLayer.nix2
-rw-r--r--pkgs/build-support/fetchfirefoxaddon/default.nix41
-rw-r--r--pkgs/build-support/fetchfossil/default.nix4
-rw-r--r--pkgs/build-support/fetchgit/builder.sh1
-rw-r--r--pkgs/build-support/fetchgit/default.nix9
-rwxr-xr-xpkgs/build-support/fetchgit/nix-prefetch-git7
-rw-r--r--pkgs/build-support/fetchmavenartifact/default.nix29
-rw-r--r--pkgs/build-support/fetchmtn/default.nix2
-rw-r--r--pkgs/build-support/fetchurl/mirrors.nix6
-rw-r--r--pkgs/build-support/fetchzip/default.nix16
-rw-r--r--pkgs/build-support/icon-conv-tools/default.nix8
-rw-r--r--pkgs/build-support/kernel/initrd-compressor-meta.nix53
-rw-r--r--pkgs/build-support/kernel/make-initrd.nix93
-rw-r--r--pkgs/build-support/kernel/make-initrd.sh11
-rw-r--r--pkgs/build-support/kernel/modules-closure.sh3
-rw-r--r--pkgs/build-support/libredirect/default.nix4
-rw-r--r--pkgs/build-support/make-desktopitem/default.nix21
-rw-r--r--pkgs/build-support/nix-gitignore/default.nix4
-rw-r--r--pkgs/build-support/ocaml/default.nix4
-rw-r--r--pkgs/build-support/ocaml/dune.nix6
-rw-r--r--pkgs/build-support/ocaml/oasis.nix4
-rw-r--r--pkgs/build-support/pkg-config-wrapper/default.nix7
-rw-r--r--pkgs/build-support/plugins.nix4
-rw-r--r--pkgs/build-support/release/ant-build.nix16
-rw-r--r--pkgs/build-support/release/debian-build.nix9
-rw-r--r--pkgs/build-support/release/default.nix10
-rw-r--r--pkgs/build-support/release/nix-build.nix12
-rw-r--r--pkgs/build-support/rust/build-rust-crate/build-crate.nix2
-rw-r--r--pkgs/build-support/rust/build-rust-crate/configure-crate.nix6
-rw-r--r--pkgs/build-support/rust/build-rust-crate/default.nix6
-rw-r--r--pkgs/build-support/rust/build-rust-crate/test/default.nix18
-rw-r--r--pkgs/build-support/rust/default-crate-overrides.nix69
-rw-r--r--pkgs/build-support/rust/default.nix72
-rw-r--r--pkgs/build-support/rust/fetchCargoTarball.nix19
-rw-r--r--pkgs/build-support/rust/sysroot/Cargo.lock29
-rw-r--r--pkgs/build-support/rust/sysroot/cargo.py45
-rw-r--r--pkgs/build-support/rust/sysroot/default.nix41
-rwxr-xr-xpkgs/build-support/rust/sysroot/update-lockfile.sh21
-rw-r--r--pkgs/build-support/setup-hooks/auto-patchelf.sh92
-rw-r--r--pkgs/build-support/setup-hooks/compress-man-pages.sh1
-rw-r--r--pkgs/build-support/setup-hooks/copy-desktop-items.sh42
-rw-r--r--pkgs/build-support/setup-hooks/reproducible-builds.sh9
-rw-r--r--pkgs/build-support/setup-hooks/strip.sh2
-rw-r--r--pkgs/build-support/setup-hooks/wrap-gapps-hook/default.nix4
-rw-r--r--pkgs/build-support/singularity-tools/default.nix7
-rw-r--r--pkgs/build-support/skaware/build-skaware-package.nix7
-rw-r--r--pkgs/build-support/skaware/clean-packaging.nix6
-rw-r--r--pkgs/build-support/substitute-files/substitute-all-files.nix6
-rw-r--r--pkgs/build-support/templaterpm/default.nix6
-rw-r--r--pkgs/build-support/vm/deb/deb-closure.pl2
-rw-r--r--pkgs/build-support/vm/default.nix41
-rw-r--r--pkgs/build-support/vm/windows/bootstrap.nix83
-rw-r--r--pkgs/build-support/vm/windows/controller/default.nix263
-rw-r--r--pkgs/build-support/vm/windows/cygwin-iso/default.nix56
-rw-r--r--pkgs/build-support/vm/windows/cygwin-iso/mkclosure.py78
-rw-r--r--pkgs/build-support/vm/windows/default.nix44
-rw-r--r--pkgs/build-support/vm/windows/install/default.nix74
-rw-r--r--pkgs/build-support/vm/windows/install/unattended-image.nix123
-rw-r--r--pkgs/build-support/writers/default.nix34
-rw-r--r--pkgs/build-support/writers/test.nix8
94 files changed, 1399 insertions, 1092 deletions
diff --git a/pkgs/build-support/alternatives/blas/default.nix b/pkgs/build-support/alternatives/blas/default.nix
index 5ebbc737e11a..cf880677fddc 100644
--- a/pkgs/build-support/alternatives/blas/default.nix
+++ b/pkgs/build-support/alternatives/blas/default.nix
@@ -132,7 +132,7 @@ Description: BLAS C implementation
 Cflags: -I$dev/include
 Libs: -L$out/lib -lcblas
 EOF
-'' + stdenv.lib.optionalString (blasImplementation == "mkl") ''
+'' + lib.optionalString (blasImplementation == "mkl") ''
   mkdir -p $out/nix-support
   echo 'export MKL_INTERFACE_LAYER=${lib.optionalString isILP64 "I"}LP64,GNU' > $out/nix-support/setup-hook
   ln -s $out/lib/libblas${canonicalExtension} $out/lib/libmkl_rt${stdenv.hostPlatform.extensions.sharedLibrary}
diff --git a/pkgs/build-support/alternatives/lapack/default.nix b/pkgs/build-support/alternatives/lapack/default.nix
index 98b458b778a7..7e74eb96b747 100644
--- a/pkgs/build-support/alternatives/lapack/default.nix
+++ b/pkgs/build-support/alternatives/lapack/default.nix
@@ -98,7 +98,7 @@ Description: LAPACK C implementation
 Cflags: -I$dev/include
 Libs: -L$out/lib -llapacke
 EOF
-'' + stdenv.lib.optionalString (lapackImplementation == "mkl") ''
+'' + lib.optionalString (lapackImplementation == "mkl") ''
   mkdir -p $out/nix-support
   echo 'export MKL_INTERFACE_LAYER=${lib.optionalString isILP64 "I"}LP64,GNU' > $out/nix-support/setup-hook
   ln -s $out/lib/liblapack${canonicalExtension} $out/lib/libmkl_rt${stdenv.hostPlatform.extensions.sharedLibrary}
diff --git a/pkgs/build-support/appimage/appimage-exec.sh b/pkgs/build-support/appimage/appimage-exec.sh
index 82ebdd0bbe4a..4ff6802e6453 100755
--- a/pkgs/build-support/appimage/appimage-exec.sh
+++ b/pkgs/build-support/appimage/appimage-exec.sh
@@ -1,4 +1,6 @@
 #!@shell@
+# shellcheck shell=bash
+
 if [ -n "$DEBUG" ] ; then
   set -x
 fi
@@ -13,8 +15,10 @@ unpack() {
   local out="$2"
 
   # https://github.com/AppImage/libappimage/blob/ca8d4b53bed5cbc0f3d0398e30806e0d3adeaaab/src/libappimage/utils/MagicBytesChecker.cpp#L45-L63
-  local appimageSignature=$(readelf -h "$src" | awk 'NR==2{print $10$11;}')
-  local appimageType=$(readelf -h "$src" | awk 'NR==2{print $12;}')
+  local appimageSignature;
+  appimageSignature="$(LC_ALL=C readelf -h "$src" | awk 'NR==2{print $10$11;}')"
+  local appimageType;
+  appimageType="$(LC_ALL=C readelf -h "$src" | awk 'NR==2{print $12;}')"
 
   # check AppImage signature
   if [ "$appimageSignature" != "4149" ]; then
@@ -35,7 +39,7 @@ unpack() {
 
       # multiarch offset one-liner using same method as AppImage
       # see https://gist.github.com/probonopd/a490ba3401b5ef7b881d5e603fa20c93
-      offset=$(readelf -h "$src" | awk 'NR==13{e_shoff=$5} NR==18{e_shentsize=$5} NR==19{e_shnum=$5} END{print e_shoff+e_shentsize*e_shnum}')
+      offset=$(LC_ALL=C readelf -h "$src" | awk 'NR==13{e_shoff=$5} NR==18{e_shentsize=$5} NR==19{e_shnum=$5} END{print e_shoff+e_shentsize*e_shnum}')
       echo "Uncompress $(basename "$src") of type $appimageType @ offset $offset"
       unsquashfs -q -d "$out" -o "$offset" "$src"
       chmod go-w "$out"
@@ -71,15 +75,15 @@ apprun() {
 
 wrap() {
 
-  cd "$APPDIR" || exit
   # quite same in appimageTools
   export APPIMAGE_SILENT_INSTALL=1
 
   if [ -n "$APPIMAGE_DEBUG_EXEC" ]; then
+    cd "$APPDIR" || true
     exec "$APPIMAGE_DEBUG_EXEC"
   fi
 
-  exec ./AppRun "$@"
+  exec "$APPDIR/AppRun" "$@"
 }
 
 usage() {
diff --git a/pkgs/build-support/appimage/default.nix b/pkgs/build-support/appimage/default.nix
index e6014e35aef9..1613e9dea24b 100644
--- a/pkgs/build-support/appimage/default.nix
+++ b/pkgs/build-support/appimage/default.nix
@@ -1,4 +1,5 @@
-{ stdenv
+{ lib
+
 , bash
 , binutils-unwrapped
 , coreutils
@@ -15,7 +16,7 @@ rec {
     src = ./appimage-exec.sh;
     isExecutable = true;
     dir = "bin";
-    path = with pkgs; stdenv.lib.makeBinPath [
+    path = lib.makeBinPath [
       bash
       binutils-unwrapped
       coreutils
diff --git a/pkgs/build-support/bintools-wrapper/add-flags.sh b/pkgs/build-support/bintools-wrapper/add-flags.sh
index e99beb381586..3b94daba65d7 100644
--- a/pkgs/build-support/bintools-wrapper/add-flags.sh
+++ b/pkgs/build-support/bintools-wrapper/add-flags.sh
@@ -3,6 +3,7 @@ var_templates_list=(
     NIX_IGNORE_LD_THROUGH_GCC
     NIX_LDFLAGS
     NIX_LDFLAGS_BEFORE
+    NIX_DYNAMIC_LINKER
     NIX_LDFLAGS_AFTER
     NIX_LDFLAGS_HARDEN
     NIX_HARDENING_ENABLE
@@ -25,6 +26,10 @@ if [ -e @out@/nix-support/libc-ldflags ]; then
     NIX_LDFLAGS_@suffixSalt@+=" $(< @out@/nix-support/libc-ldflags)"
 fi
 
+if [ -z "$NIX_DYNAMIC_LINKER_@suffixSalt@" ] && [ -e @out@/nix-support/ld-set-dynamic-linker ]; then
+    NIX_DYNAMIC_LINKER_@suffixSalt@="$(< @out@/nix-support/dynamic-linker)"
+fi
+
 if [ -e @out@/nix-support/libc-ldflags-before ]; then
     NIX_LDFLAGS_BEFORE_@suffixSalt@="$(< @out@/nix-support/libc-ldflags-before) $NIX_LDFLAGS_BEFORE_@suffixSalt@"
 fi
diff --git a/pkgs/build-support/bintools-wrapper/default.nix b/pkgs/build-support/bintools-wrapper/default.nix
index 15fcc3742932..48a3ebb32dfe 100644
--- a/pkgs/build-support/bintools-wrapper/default.nix
+++ b/pkgs/build-support/bintools-wrapper/default.nix
@@ -6,6 +6,7 @@
 # compiler and the linker just "work".
 
 { name ? ""
+, lib
 , stdenvNoCC
 , bintools ? null, libc ? null, coreutils ? null, shell ? stdenvNoCC.shell, gnugrep ? null
 , nativeTools, noLibc ? false, nativeLibc, nativePrefix ? ""
@@ -15,7 +16,7 @@
 , useMacosReexportHack ? false
 }:
 
-with stdenvNoCC.lib;
+with lib;
 
 assert nativeTools -> !propagateDoc && nativePrefix != "";
 assert !nativeTools ->
@@ -31,11 +32,11 @@ let
   #
   # TODO(@Ericson2314) Make unconditional, or optional but always true by
   # default.
-  targetPrefix = stdenv.lib.optionalString (targetPlatform != hostPlatform)
+  targetPrefix = lib.optionalString (targetPlatform != hostPlatform)
                                         (targetPlatform.config + "-");
 
-  bintoolsVersion = stdenv.lib.getVersion bintools;
-  bintoolsName = stdenv.lib.removePrefix targetPrefix (stdenv.lib.getName bintools);
+  bintoolsVersion = lib.getVersion bintools;
+  bintoolsName = lib.removePrefix targetPrefix (lib.getName bintools);
 
   libc_bin = if libc == null then null else getBin libc;
   libc_dev = if libc == null then null else getDev libc;
@@ -63,7 +64,7 @@ let
     else if targetPlatform.system == "powerpc-linux"  then "${libc_lib}/lib/ld.so.1"
     else if targetPlatform.isMips                     then "${libc_lib}/lib/ld.so.1"
     else if targetPlatform.isDarwin                   then "/usr/lib/dyld"
-    else if stdenv.lib.hasSuffix "pc-gnu" targetPlatform.config then "ld.so.1"
+    else if lib.hasSuffix "pc-gnu" targetPlatform.config then "ld.so.1"
     else null;
 
   expand-response-params =
@@ -168,7 +169,7 @@ stdenv.mkDerivation {
       else if targetPlatform.isWindows then "pe"
       else "elf" + toString targetPlatform.parsed.cpu.bits;
     endianPrefix = if targetPlatform.isBigEndian then "big" else "little";
-    sep = optionalString (!targetPlatform.isMips && !targetPlatform.isPower) "-";
+    sep = optionalString (!targetPlatform.isMips && !targetPlatform.isPower && !targetPlatform.isRiscV) "-";
     arch =
       /**/ if targetPlatform.isAarch64 then endianPrefix + "aarch64"
       else if targetPlatform.isAarch32     then endianPrefix + "arm"
@@ -188,9 +189,10 @@ stdenv.mkDerivation {
       else if targetPlatform.isAlpha then "alpha"
       else if targetPlatform.isVc4 then "vc4"
       else if targetPlatform.isOr1k then "or1k"
+      else if targetPlatform.isRiscV then "lriscv"
       else throw "unknown emulation for platform: ${targetPlatform.config}";
     in if targetPlatform.useLLVM or false then ""
-       else targetPlatform.platform.bfdEmulation or (fmt + sep + arch);
+       else targetPlatform.bfdEmulation or (fmt + sep + arch);
 
   strictDeps = true;
   depsTargetTargetPropagated = extraPackages;
@@ -237,19 +239,14 @@ stdenv.mkDerivation {
       if [ -n "''${dynamicLinker-}" ]; then
         echo $dynamicLinker > $out/nix-support/dynamic-linker
 
-    '' + (if targetPlatform.isDarwin then ''
-        printf "export LD_DYLD_PATH=%q\n" "$dynamicLinker" >> $out/nix-support/setup-hook
-      '' else ''
-        if [ -e ${libc_lib}/lib/32/ld-linux.so.2 ]; then
-          echo ${libc_lib}/lib/32/ld-linux.so.2 > $out/nix-support/dynamic-linker-m32
-        fi
-      ''
-      # The dynamic linker is passed in `ldflagsBefore' to allow
-      # explicit overrides of the dynamic linker by callers to ld
-      # (the *last* value counts, so ours should come first).
-      + ''
-        echo -dynamic-linker "$dynamicLinker" >> $out/nix-support/libc-ldflags-before
-    '') + ''
+        ${if targetPlatform.isDarwin then ''
+          printf "export LD_DYLD_PATH=%q\n" "$dynamicLinker" >> $out/nix-support/setup-hook
+        '' else ''
+          if [ -e ${libc_lib}/lib/32/ld-linux.so.2 ]; then
+            echo ${libc_lib}/lib/32/ld-linux.so.2 > $out/nix-support/dynamic-linker-m32
+          fi
+          touch $out/nix-support/ld-set-dynamic-linker
+        ''}
       fi
     '')
 
@@ -331,10 +328,10 @@ stdenv.mkDerivation {
     let bintools_ = if bintools != null then bintools else {}; in
     (if bintools_ ? meta then removeAttrs bintools.meta ["priority"] else {}) //
     { description =
-        stdenv.lib.attrByPath ["meta" "description"] "System binary utilities" bintools_
+        lib.attrByPath ["meta" "description"] "System binary utilities" bintools_
         + " (wrapper script)";
       priority = 10;
   } // optionalAttrs useMacosReexportHack {
-    platforms = stdenv.lib.platforms.darwin;
+    platforms = lib.platforms.darwin;
   };
 }
diff --git a/pkgs/build-support/bintools-wrapper/ld-wrapper.sh b/pkgs/build-support/bintools-wrapper/ld-wrapper.sh
index 81b5a90edd5c..9d02f99851a5 100644
--- a/pkgs/build-support/bintools-wrapper/ld-wrapper.sh
+++ b/pkgs/build-support/bintools-wrapper/ld-wrapper.sh
@@ -20,6 +20,7 @@ if [ -z "${NIX_BINTOOLS_WRAPPER_FLAGS_SET_@suffixSalt@:-}" ]; then
     source @out@/nix-support/add-flags.sh
 fi
 
+setDynamicLinker=1
 
 # Optionally filter out paths not refering to the store.
 expandResponseParams "$@"
@@ -47,6 +48,11 @@ if [[ "${NIX_ENFORCE_PURITY:-}" = 1 && -n "${NIX_STORE:-}"
             # Our ld is not built with sysroot support (Can we fix that?)
             :
         else
+            if [[ "$p" = -static || "$p" = -static-pie ]]; then
+                # Using a dynamic linker for static binaries can lead to crashes.
+                # This was observed for rust binaries.
+                setDynamicLinker=0
+            fi
             rest+=("$p")
         fi
         n+=1
@@ -63,6 +69,11 @@ extraBefore=(${hardeningLDFlags[@]+"${hardeningLDFlags[@]}"})
 if [ -z "${NIX_LDFLAGS_SET_@suffixSalt@:-}" ]; then
     extraAfter+=($NIX_LDFLAGS_@suffixSalt@)
     extraBefore+=($NIX_LDFLAGS_BEFORE_@suffixSalt@)
+    # By adding dynamic linker to extraBefore we allow the users set their
+    # own dynamic linker as NIX_LD_FLAGS will override earlier set flags
+    if [[ "$setDynamicLinker" = 1 && -n "$NIX_DYNAMIC_LINKER_@suffixSalt@" ]]; then
+        extraBefore+=("-dynamic-linker" "$NIX_DYNAMIC_LINKER_@suffixSalt@")
+    fi
 fi
 
 extraAfter+=($NIX_LDFLAGS_AFTER_@suffixSalt@)
@@ -134,7 +145,7 @@ then
     done
 fi
 
-if [ -e "@out@/nix-support/dynamic-linker-m32" ] && (( "$link32" )); then
+if [[ "$link32" = "1" && "$setDynamicLinker" = 1 && -e "@out@/nix-support/dynamic-linker-m32" ]]; then
     # We have an alternate 32-bit linker and we're producing a 32-bit ELF, let's
     # use it.
     extraAfter+=(
diff --git a/pkgs/build-support/build-bazel-package/default.nix b/pkgs/build-support/build-bazel-package/default.nix
index 10a331bcc9e7..3be72bd22c3f 100644
--- a/pkgs/build-support/build-bazel-package/default.nix
+++ b/pkgs/build-support/build-bazel-package/default.nix
@@ -172,7 +172,9 @@ in stdenv.mkDerivation (fBuildAttrs // {
 
     chmod -R +w $bazelOut
     find $bazelOut -type l | while read symlink; do
-      ln -sf $(readlink "$symlink" | sed "s,NIX_BUILD_TOP,$NIX_BUILD_TOP,") "$symlink"
+      if [[ $(readlink "$symlink") == *NIX_BUILD_TOP* ]]; then
+        ln -sf $(readlink "$symlink" | sed "s,NIX_BUILD_TOP,$NIX_BUILD_TOP,") "$symlink"
+      fi
     done
   '' + fBuildAttrs.preConfigure or "";
 
diff --git a/pkgs/build-support/build-dotnet-package/default.nix b/pkgs/build-support/build-dotnet-package/default.nix
index dae9ed888c75..440b10044f0f 100644
--- a/pkgs/build-support/build-dotnet-package/default.nix
+++ b/pkgs/build-support/build-dotnet-package/default.nix
@@ -1,4 +1,4 @@
-{ stdenv, lib, makeWrapper, pkgconfig, mono, dotnetbuildhelpers }:
+{ stdenv, lib, makeWrapper, pkg-config, mono, dotnetbuildhelpers }:
 
 attrsOrig @
 { baseName
@@ -19,7 +19,7 @@ attrsOrig @
     attrs = {
       name = "${baseName}-${version}";
 
-      nativeBuildInputs = [ pkgconfig ];
+      nativeBuildInputs = [ pkg-config ];
       buildInputs = [
         mono
         dotnetbuildhelpers
diff --git a/pkgs/build-support/build-fhs-userenv-bubblewrap/default.nix b/pkgs/build-support/build-fhs-userenv-bubblewrap/default.nix
index 3a3c9e932fdb..9a9e5a9ce10a 100644
--- a/pkgs/build-support/build-fhs-userenv-bubblewrap/default.nix
+++ b/pkgs/build-support/build-fhs-userenv-bubblewrap/default.nix
@@ -1,20 +1,27 @@
-{ callPackage, runCommandLocal, writeShellScriptBin, stdenv, coreutils, bubblewrap }:
-
-let buildFHSEnv = callPackage ./env.nix { }; in
+{ lib, callPackage, runCommandLocal, writeShellScriptBin, coreutils, bubblewrap }:
 
 args @ {
-  name,
-  runScript ? "bash",
-  extraInstallCommands ? "",
-  meta ? {},
-  passthru ? {},
-  ...
+  name
+, runScript ? "bash"
+, extraInstallCommands ? ""
+, meta ? {}
+, passthru ? {}
+, unshareUser ? true
+, unshareIpc ? true
+, unsharePid ? true
+, unshareNet ? false
+, unshareUts ? true
+, unshareCgroup ? true
+, ...
 }:
 
 with builtins;
 let
+  buildFHSEnv = callPackage ./env.nix { };
+
   env = buildFHSEnv (removeAttrs args [
     "runScript" "extraInstallCommands" "meta" "passthru"
+    "unshareUser" "unshareCgroup" "unshareUts" "unshareNet" "unsharePid" "unshareIpc"
   ]);
 
   chrootenv = callPackage ./chrootenv {};
@@ -92,8 +99,12 @@ let
       --dev-bind /dev /dev
       --proc /proc
       --chdir "$(pwd)"
-      --unshare-all
-      --share-net
+      ${lib.optionalString unshareUser "--unshare-user"}
+      ${lib.optionalString unshareIpc "--unshare-ipc"}
+      ${lib.optionalString unsharePid "--unshare-pid"}
+      ${lib.optionalString unshareNet "--unshare-net"}
+      ${lib.optionalString unshareUts "--unshare-uts"}
+      ${lib.optionalString unshareCgroup "--unshare-cgroup"}
       --die-with-parent
       --ro-bind /nix /nix
       ${etcBindFlags}
diff --git a/pkgs/build-support/build-fhs-userenv/chrootenv/chrootenv.c b/pkgs/build-support/build-fhs-userenv/chrootenv/chrootenv.c
index dcb2e97aa932..a438b80e1829 100644
--- a/pkgs/build-support/build-fhs-userenv/chrootenv/chrootenv.c
+++ b/pkgs/build-support/build-fhs-userenv/chrootenv/chrootenv.c
@@ -43,6 +43,7 @@ const gchar *create_tmpdir() {
 void pivot_host(const gchar *guest) {
   g_autofree gchar *point = g_build_filename(guest, "host", NULL);
   fail_if(g_mkdir(point, 0755));
+  fail_if(mount(0, "/", 0, MS_PRIVATE | MS_REC, 0));
   fail_if(pivot_root(guest, point));
 }
 
@@ -56,6 +57,7 @@ void bind_mount_item(const gchar *host, const gchar *guest, const gchar *name) {
 
 void bind(const gchar *host, const gchar *guest) {
   mount_tmpfs(guest);
+
   pivot_host(guest);
 
   g_autofree gchar *host_dir = g_build_filename("/host", host, NULL);
@@ -105,7 +107,11 @@ int main(gint argc, gchar **argv) {
     uid_t uid = getuid();
     gid_t gid = getgid();
 
-    if (unshare(CLONE_NEWNS | CLONE_NEWUSER) < 0) {
+    int namespaces = CLONE_NEWNS;
+    if (uid != 0) {
+      namespaces |= CLONE_NEWUSER;
+    }
+    if (unshare(namespaces) < 0) {
       int unshare_errno = errno;
 
       g_message("Requires Linux version >= 3.19 built with CONFIG_USER_NS");
@@ -116,9 +122,11 @@ int main(gint argc, gchar **argv) {
       fail("unshare", unshare_errno);
     }
 
-    spit("/proc/self/setgroups", "deny");
-    spit("/proc/self/uid_map", "%d %d 1", uid, uid);
-    spit("/proc/self/gid_map", "%d %d 1", gid, gid);
+    if (uid != 0) {
+      spit("/proc/self/setgroups", "deny");
+      spit("/proc/self/uid_map", "%d %d 1", uid, uid);
+      spit("/proc/self/gid_map", "%d %d 1", gid, gid);
+    }
 
     // If there is a /host directory, assume this is nested chrootenv and use it as host instead.
     gboolean nested_host = g_file_test("/host", G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR);
diff --git a/pkgs/build-support/build-fhs-userenv/chrootenv/default.nix b/pkgs/build-support/build-fhs-userenv/chrootenv/default.nix
index 70a7a43bd398..15d7b3153580 100644
--- a/pkgs/build-support/build-fhs-userenv/chrootenv/default.nix
+++ b/pkgs/build-support/build-fhs-userenv/chrootenv/default.nix
@@ -1,13 +1,13 @@
-{ stdenv, meson, ninja, pkgconfig, glib }:
+{ lib, stdenv, meson, ninja, pkg-config, glib }:
 
 stdenv.mkDerivation {
   name = "chrootenv";
   src = ./.;
 
-  nativeBuildInputs = [ meson ninja pkgconfig ];
+  nativeBuildInputs = [ meson ninja pkg-config ];
   buildInputs = [ glib ];
 
-  meta = with stdenv.lib; {
+  meta = with lib; {
     description = "Setup mount/user namespace for FHS emulation";
     license = licenses.mit;
     maintainers = with maintainers; [ yegortimoshenko ];
diff --git a/pkgs/build-support/cc-wrapper/cc-wrapper.sh b/pkgs/build-support/cc-wrapper/cc-wrapper.sh
index 7e734f57773e..1450218aff27 100644
--- a/pkgs/build-support/cc-wrapper/cc-wrapper.sh
+++ b/pkgs/build-support/cc-wrapper/cc-wrapper.sh
@@ -28,6 +28,7 @@ cc1=0
 [[ "@prog@" = *++ ]] && isCpp=1 || isCpp=0
 cppInclude=1
 cInclude=1
+setDynamicLinker=1
 
 expandResponseParams "$@"
 declare -i n=0
@@ -58,6 +59,8 @@ while (( "$n" < "$nParams" )); do
         cppInclude=0
     elif [ "$p" = -nostdinc++ ]; then
         cppInclude=0
+    elif [[ "$p" = -static || "$p" = -static-pie ]]; then
+        setDynamicLinker=0
     elif [[ "$p" != -?* ]]; then
         # A dash alone signifies standard input; it is not a flag
         nonFlagArgs=1
@@ -152,6 +155,9 @@ if [ "$dontLink" != 1 ]; then
     for i in $NIX_LDFLAGS_BEFORE_@suffixSalt@; do
         extraBefore+=("-Wl,$i")
     done
+    if [[ "$setDynamicLinker" = 1 && -n "$NIX_DYNAMIC_LINKER_@suffixSalt@" ]]; then
+        extraBefore+=("-Wl,-dynamic-linker=$NIX_DYNAMIC_LINKER_@suffixSalt@")
+    fi
     for i in $NIX_LDFLAGS_@suffixSalt@; do
         if [ "${i:0:3}" = -L/ ]; then
             extraAfter+=("$i")
diff --git a/pkgs/build-support/cc-wrapper/default.nix b/pkgs/build-support/cc-wrapper/default.nix
index 09cef8b8678d..341e2850437c 100644
--- a/pkgs/build-support/cc-wrapper/default.nix
+++ b/pkgs/build-support/cc-wrapper/default.nix
@@ -6,6 +6,7 @@
 # compiler and the linker just "work".
 
 { name ? ""
+, lib
 , stdenvNoCC
 , cc ? null, libc ? null, bintools, coreutils ? null, shell ? stdenvNoCC.shell
 , gccForLibs ? null
@@ -18,7 +19,7 @@
 , libcxx ? null
 }:
 
-with stdenvNoCC.lib;
+with lib;
 
 assert nativeTools -> !propagateDoc && nativePrefix != "";
 assert !nativeTools ->
@@ -34,11 +35,11 @@ let
   #
   # TODO(@Ericson2314) Make unconditional, or optional but always true by
   # default.
-  targetPrefix = stdenv.lib.optionalString (targetPlatform != hostPlatform)
+  targetPrefix = lib.optionalString (targetPlatform != hostPlatform)
                                            (targetPlatform.config + "-");
 
-  ccVersion = stdenv.lib.getVersion cc;
-  ccName = stdenv.lib.removePrefix targetPrefix (stdenv.lib.getName cc);
+  ccVersion = lib.getVersion cc;
+  ccName = lib.removePrefix targetPrefix (lib.getName cc);
 
   libc_bin = if libc == null then null else getBin libc;
   libc_dev = if libc == null then null else getDev libc;
@@ -65,6 +66,7 @@ let
     && libcxx == null
     && !(stdenv.targetPlatform.useLLVM or false)
     && !(stdenv.targetPlatform.useAndroidPrebuilt or false)
+    && !(stdenv.targetPlatform.isiOS or false)
     && gccForLibs != null;
 
   # older compilers (for example bootstrap's GCC 5) fail with -march=too-modern-cpu
@@ -76,10 +78,14 @@ let
         cannonlake     = versionAtLeast ccVersion "8.0";
         icelake-client = versionAtLeast ccVersion "8.0";
         icelake-server = versionAtLeast ccVersion "8.0";
+        cascadelake    = versionAtLeast ccVersion "9.0";
+        cooperlake     = versionAtLeast ccVersion "10.0";
+        tigerlake      = versionAtLeast ccVersion "10.0";
         knm            = versionAtLeast ccVersion "8.0";
         # AMD
         znver1         = versionAtLeast ccVersion "6.0";
         znver2         = versionAtLeast ccVersion "9.0";
+        znver3         = versionAtLeast ccVersion "11.0";
       }.${arch} or true
     else if isClang then
       { # Intel
@@ -242,8 +248,8 @@ stdenv.mkDerivation {
 
   setupHooks = [
     ../setup-hooks/role.bash
-  ] ++ stdenv.lib.optional (cc.langC or true) ./setup-hook.sh
-    ++ stdenv.lib.optional (cc.langFortran or false) ./fortran-hook.sh;
+  ] ++ lib.optional (cc.langC or true) ./setup-hook.sh
+    ++ lib.optional (cc.langFortran or false) ./fortran-hook.sh;
 
   postFixup =
     # Ensure flags files exists, as some other programs cat them. (That these
@@ -285,6 +291,17 @@ stdenv.mkDerivation {
       echo "-L${gccForLibs.lib}/${targetPlatform.config}/lib" >> $out/nix-support/cc-ldflags
     ''
 
+    # TODO We would like to connect this to `useGccForLibs`, but we cannot yet
+    # because `libcxxStdenv` on linux still needs this. Maybe someday we'll
+    # always set `useLLVM` on Darwin, and maybe also break down `useLLVM` into
+    # fine-grained use flags (libgcc vs compiler-rt, ld.lld vs legacy, libc++
+    # vs libstdc++, etc.) since Darwin isn't `useLLVM` on all counts. (See
+    # https://clang.llvm.org/docs/Toolchain.html for all the axes one might
+    # break `useLLVM` into.)
+    + optionalString (isClang && gccForLibs != null && targetPlatform.isLinux && !(stdenv.targetPlatform.useLLVM or false)) ''
+      echo "--gcc-toolchain=${gccForLibs}" >> $out/nix-support/cc-cflags
+    ''
+
     ##
     ## General libc support
     ##
@@ -337,7 +354,7 @@ stdenv.mkDerivation {
     + optionalString (libcxx.isLLVM or false) (''
       echo "-isystem ${libcxx}/include/c++/v1" >> $out/nix-support/libcxx-cxxflags
       echo "-stdlib=libc++" >> $out/nix-support/libcxx-ldflags
-    '' + stdenv.lib.optionalString stdenv.targetPlatform.isLinux ''
+    '' + lib.optionalString stdenv.targetPlatform.isLinux ''
       echo "-lc++abi" >> $out/nix-support/libcxx-ldflags
     '')
 
@@ -397,32 +414,32 @@ stdenv.mkDerivation {
     # Always add -march based on cpu in triple. Sometimes there is a
     # discrepency (x86_64 vs. x86-64), so we provide an "arch" arg in
     # that case.
-    + optionalString ((targetPlatform ? platform.gcc.arch) &&
-                      isGccArchSupported targetPlatform.platform.gcc.arch) ''
-      echo "-march=${targetPlatform.platform.gcc.arch}" >> $out/nix-support/cc-cflags-before
+    + optionalString ((targetPlatform ? gcc.arch) &&
+                      isGccArchSupported targetPlatform.gcc.arch) ''
+      echo "-march=${targetPlatform.gcc.arch}" >> $out/nix-support/cc-cflags-before
     ''
 
     # -mcpu is not very useful. You should use mtune and march
     # instead. It’s provided here for backwards compatibility.
-    + optionalString (targetPlatform ? platform.gcc.cpu) ''
-      echo "-mcpu=${targetPlatform.platform.gcc.cpu}" >> $out/nix-support/cc-cflags-before
+    + optionalString (targetPlatform ? gcc.cpu) ''
+      echo "-mcpu=${targetPlatform.gcc.cpu}" >> $out/nix-support/cc-cflags-before
     ''
 
     # -mfloat-abi only matters on arm32 but we set it here
     # unconditionally just in case. If the abi specifically sets hard
     # vs. soft floats we use it here.
-    + optionalString (targetPlatform ? platform.gcc.float-abi) ''
-      echo "-mfloat-abi=${targetPlatform.platform.gcc.float-abi}" >> $out/nix-support/cc-cflags-before
+    + optionalString (targetPlatform ? gcc.float-abi) ''
+      echo "-mfloat-abi=${targetPlatform.gcc.float-abi}" >> $out/nix-support/cc-cflags-before
     ''
-    + optionalString (targetPlatform ? platform.gcc.fpu) ''
-      echo "-mfpu=${targetPlatform.platform.gcc.fpu}" >> $out/nix-support/cc-cflags-before
+    + optionalString (targetPlatform ? gcc.fpu) ''
+      echo "-mfpu=${targetPlatform.gcc.fpu}" >> $out/nix-support/cc-cflags-before
     ''
-    + optionalString (targetPlatform ? platform.gcc.mode) ''
-      echo "-mmode=${targetPlatform.platform.gcc.mode}" >> $out/nix-support/cc-cflags-before
+    + optionalString (targetPlatform ? gcc.mode) ''
+      echo "-mmode=${targetPlatform.gcc.mode}" >> $out/nix-support/cc-cflags-before
     ''
-    + optionalString (targetPlatform ? platform.gcc.tune &&
-                      isGccArchSupported targetPlatform.platform.gcc.tune) ''
-      echo "-mtune=${targetPlatform.platform.gcc.tune}" >> $out/nix-support/cc-cflags-before
+    + optionalString (targetPlatform ? gcc.tune &&
+                      isGccArchSupported targetPlatform.gcc.tune) ''
+      echo "-mtune=${targetPlatform.gcc.tune}" >> $out/nix-support/cc-cflags-before
     ''
 
     # TODO: categorize these and figure out a better place for them
@@ -437,7 +454,7 @@ stdenv.mkDerivation {
     '' + optionalString targetPlatform.isNetBSD ''
       hardening_unsupported_flags+=" stackprotector fortify"
     '' + optionalString cc.langAda or false ''
-      hardening_unsupported_flags+=" stackprotector strictoverflow"
+      hardening_unsupported_flags+=" format stackprotector strictoverflow"
     '' + optionalString cc.langD or false ''
       hardening_unsupported_flags+=" format"
     '' + optionalString targetPlatform.isWasm ''
@@ -476,7 +493,7 @@ stdenv.mkDerivation {
     let cc_ = if cc != null then cc else {}; in
     (if cc_ ? meta then removeAttrs cc.meta ["priority"] else {}) //
     { description =
-        stdenv.lib.attrByPath ["meta" "description"] "System C compiler" cc_
+        lib.attrByPath ["meta" "description"] "System C compiler" cc_
         + " (wrapper script)";
       priority = 10;
   };
diff --git a/pkgs/build-support/coq/default.nix b/pkgs/build-support/coq/default.nix
new file mode 100644
index 000000000000..7e925e2473e1
--- /dev/null
+++ b/pkgs/build-support/coq/default.nix
@@ -0,0 +1,92 @@
+{ lib, stdenv, coqPackages, coq, fetchzip }@args:
+let lib = import ./extra-lib.nix {inherit (args) lib;}; in
+with builtins; with lib;
+let
+  isGitHubDomain = d: match "^github.*" d != null;
+  isGitLabDomain = d: match "^gitlab.*" d != null;
+in
+{ pname,
+  version ? null,
+  fetcher ? null,
+  owner ? "coq-community",
+  domain ? "github.com",
+  repo ? pname,
+  defaultVersion ? null,
+  releaseRev ? (v: v),
+  displayVersion ? {},
+  release ? {},
+  extraBuildInputs ? [],
+  namePrefix ? [],
+  enableParallelBuilding ? true,
+  extraInstallFlags ? [],
+  setCOQBIN ? true,
+  mlPlugin ? false,
+  useMelquiondRemake ? null,
+  dropAttrs ? [],
+  keepAttrs ? [],
+  dropDerivationAttrs ? [],
+  ...
+}@args:
+let
+  args-to-remove = foldl (flip remove) ([
+    "version" "fetcher" "repo" "owner" "domain" "releaseRev"
+    "displayVersion" "defaultVersion" "useMelquiondRemake"
+    "release" "extraBuildInputs" "extraPropagatedBuildInputs" "namePrefix" "meta"
+    "extraInstallFlags" "setCOQBIN" "mlPlugin"
+    "dropAttrs" "dropDerivationAttrs" "keepAttrs" ] ++ dropAttrs) keepAttrs;
+  fetch = import ../coq/meta-fetch/default.nix
+    { inherit stdenv fetchzip; } ({
+      inherit release releaseRev;
+      location = { inherit domain owner repo; };
+    } // optionalAttrs (args?fetcher) {inherit fetcher;});
+  fetched = fetch (if !isNull version then version else defaultVersion);
+  namePrefix = args.namePrefix or [ "coq" ];
+  display-pkg = n: sep: v:
+    let d = displayVersion.${n} or (if sep == "" then ".." else true); in
+    n + optionalString (v != "" && v != null) (switch d [
+      { case = true;       out = sep + v; }
+      { case = ".";        out = sep + versions.major v; }
+      { case = "..";       out = sep + versions.majorMinor v; }
+      { case = "...";      out = sep + versions.majorMinorPatch v; }
+      { case = isFunction; out = optionalString (d v != "") (sep + d v); }
+      { case = isString;   out = optionalString (d != "") (sep + d); }
+    ] "") + optionalString (v == null) "-broken";
+  append-version = p: n: p + display-pkg n "" coqPackages.${n}.version + "-";
+  prefix-name = foldl append-version "" namePrefix;
+  var-coqlib-install = (optionalString (versions.isGe "8.7" coq.coq-version) "COQMF_") + "COQLIB";
+in
+
+stdenv.mkDerivation (removeAttrs ({
+
+  name = prefix-name + (display-pkg pname "-" fetched.version);
+
+  inherit (fetched) version src;
+
+  buildInputs = [ coq ] ++ optionals mlPlugin coq.ocamlBuildInputs ++ extraBuildInputs;
+  inherit enableParallelBuilding;
+
+  meta = ({ platforms = coq.meta.platforms; } //
+    (switch domain [{
+        case = pred.union isGitHubDomain isGitLabDomain;
+        out = { homepage = "https://${domain}/${owner}/${repo}"; };
+      }] {}) //
+    optionalAttrs (fetched.broken or false) { coqFilter = true; broken = true; }) //
+    (args.meta or {}) ;
+
+} //
+(optionalAttrs setCOQBIN { COQBIN = "${coq}/bin/"; }) //
+(optionalAttrs (!args?installPhase && !args?useMelquiondRemake) {
+  installFlags =
+    [ "${var-coqlib-install}=$(out)/lib/coq/${coq.coq-version}/" ] ++
+    optional (match ".*doc$" (args.installTargets or "") != null)
+      "DOCDIR=$(out)/share/coq/${coq.coq-version}/" ++
+    extraInstallFlags;
+}) //
+(optionalAttrs (args?useMelquiondRemake) rec {
+  COQUSERCONTRIB = "$out/lib/coq/${coq.coq-version}/user-contrib";
+  preConfigurePhases = "autoconf";
+  configureFlags = [ "--libdir=${COQUSERCONTRIB}/${useMelquiondRemake.logpath or ""}" ];
+  buildPhase = "./remake -j$NIX_BUILD_CORES";
+  installPhase = "./remake install";
+}) //
+(removeAttrs args args-to-remove)) dropDerivationAttrs)
diff --git a/pkgs/build-support/coq/extra-lib.nix b/pkgs/build-support/coq/extra-lib.nix
new file mode 100644
index 000000000000..65b48f511267
--- /dev/null
+++ b/pkgs/build-support/coq/extra-lib.nix
@@ -0,0 +1,145 @@
+{ lib }:
+with builtins; with lib; recursiveUpdate lib (rec {
+
+  versions =
+    let
+      truncate = n: v: concatStringsSep "." (take n (splitVersion v));
+      opTruncate = op: v0: v: let n = length (splitVersion v0); in
+         op (truncate n v) (truncate n v0);
+    in rec {
+
+    /* Get string of the first n parts of a version string.
+
+       Example:
+       - truncate 2 "1.2.3-stuff"
+         => "1.2"
+
+       - truncate 4 "1.2.3-stuff"
+         => "1.2.3.stuff"
+    */
+
+    inherit truncate;
+
+    /* Get string of the first three parts (major, minor and patch)
+       of a version string.
+
+       Example:
+         majorMinorPatch "1.2.3-stuff"
+         => "1.2.3"
+    */
+    majorMinorPatch = truncate 3;
+
+    /* Version comparison predicates,
+      - isGe v0 v <-> v is greater or equal than v0   [*]
+      - isLe v0 v <-> v is lesser  or equal than v0   [*]
+      - isGt v0 v <-> v is strictly greater than v0   [*]
+      - isLt v0 v <-> v is strictly lesser  than v0   [*]
+      - isEq v0 v <-> v is equal to v0                [*]
+      - range low high v <-> v is between low and high [**]
+
+    [*]  truncating v to the same number of digits as v0
+    [**] truncating v to low for the lower bound and high for the upper bound
+
+      Examples:
+      - isGe "8.10" "8.10.1"
+        => true
+      - isLe "8.10" "8.10.1"
+        => true
+      - isGt "8.10" "8.10.1"
+        => false
+      - isGt "8.10.0" "8.10.1"
+        => true
+      - isEq "8.10" "8.10.1"
+        => true
+      - range "8.10" "8.11" "8.11.1"
+        => true
+      - range "8.10" "8.11+" "8.11.0"
+        => false
+      - range "8.10" "8.11+" "8.11+beta1"
+        => false
+
+    */
+    isGe = opTruncate versionAtLeast;
+    isGt = opTruncate (flip versionOlder);
+    isLe = opTruncate (flip versionAtLeast);
+    isLt = opTruncate versionOlder;
+    isEq = opTruncate pred.equal;
+    range = low: high: pred.inter (versions.isGe low) (versions.isLe high);
+  };
+
+  /* Returns a list of list, splitting it using a predicate.
+     This is analoguous to builtins.split sep list,
+     with a predicate as a separator and a list instead of a string.
+
+    Type: splitList :: (a -> bool) -> [a] -> [[a]]
+
+    Example:
+      splitList (x: x == "x") [ "y" "x" "z" "t" ]
+      => [ [ "y" ] "x" [ "z" "t" ] ]
+  */
+  splitList = pred: l: # put in file lists
+    let loop = (vv: v: l: if l == [] then vv ++ [v]
+      else let hd = head l; tl = tail l; in
+      if pred hd then loop (vv ++ [ v hd ]) [] tl else loop vv (v ++ [hd]) tl);
+    in loop [] [] l;
+
+  pred = {
+    /* Predicate intersection, union, and complement */
+    inter = p: q: x: p x && q x;
+    union = p: q: x: p x || q x;
+    compl = p:    x: ! p x;
+    true  = p: true;
+    false = p: false;
+
+    /* predicate "being equal to y" */
+    equal = y:    x: x == y;
+  };
+
+  /* Emulate a "switch - case" construct,
+   instead of relying on `if then else if ...` */
+  /* Usage:
+  ```nix
+  switch-if [
+    if-clause-1
+    ..
+    if-clause-k
+  ] default-out
+  ```
+  where a if-clause has the form `{ cond = b; out = r; }`
+  the first branch such as `b` is true */
+
+  switch-if = c: d: (findFirst (getAttr "cond") {} c).out or d;
+
+  /* Usage:
+  ```nix
+  switch x [
+    simple-clause-1
+    ..
+    simple-clause-k
+  ] default-out
+  ```
+  where a simple-clause has the form `{ case = p; out = r; }`
+  the first branch such as `p x` is true
+  or
+  ```nix
+  switch [ x1 .. xn ] [
+    complex-clause-1
+    ..
+    complex-clause-k
+  ] default-out
+  ```
+  where a complex-clause is either a simple-clause
+  or has the form { cases = [ p1 .. pn ]; out = r; }
+  in which case the first branch such as all `pi x` are true
+
+  if the variables p are not functions,
+  they are converted to a equal p
+  if out is missing the default-out is taken */
+
+  switch = var: clauses: default: with pred; let
+      compare = f:  if isFunction f then f else equal f;
+      combine = cl: var:
+        if cl?case then compare cl.case var
+        else all (equal true) (zipListsWith compare cl.cases var); in
+    switch-if (map (cl: { cond = combine cl var; inherit (cl) out; }) clauses) default;
+})
diff --git a/pkgs/build-support/coq/meta-fetch/default.nix b/pkgs/build-support/coq/meta-fetch/default.nix
new file mode 100644
index 000000000000..580d58395ef4
--- /dev/null
+++ b/pkgs/build-support/coq/meta-fetch/default.nix
@@ -0,0 +1,66 @@
+{ stdenv, fetchzip }@args:
+let lib = import ../extra-lib.nix {inherit (args.stdenv) lib;}; in
+with builtins; with lib;
+let
+  default-fetcher = {domain ? "github.com", owner ? "", repo, rev, name ? "source", sha256 ? null, ...}@args:
+    let ext = if args?sha256 then "zip" else "tar.gz";
+        fmt = if args?sha256 then "zip" else "tarball";
+        pr  = match "^#(.*)$" rev;
+        url = switch-if [
+          { cond = isNull pr && !isNull (match "^github.*" domain);
+            out = "https://${domain}/${owner}/${repo}/archive/${rev}.${ext}"; }
+          { cond = !isNull pr && !isNull (match "^github.*" domain);
+            out = "https://api.${domain}/repos/${owner}/${repo}/${fmt}/pull/${head pr}/head"; }
+          { cond = isNull pr && !isNull (match "^gitlab.*" domain);
+            out = "https://${domain}/${owner}/${repo}/-/archive/${rev}/${repo}-${rev}.${ext}"; }
+          { cond = !isNull (match "(www.)?mpi-sws.org" domain);
+            out = "https://www.mpi-sws.org/~${owner}/${repo}/download/${repo}-${rev}.${ext}";}
+        ] (throw "meta-fetch: no fetcher found for domain ${domain} on ${rev}");
+        fetch = x: if args?sha256 then fetchzip (x // { inherit sha256; }) else fetchTarball x;
+    in fetch { inherit url ; };
+in
+{
+  fetcher ? default-fetcher,
+  location,
+  release ? {},
+  releaseRev ? (v: v),
+}:
+let isVersion      = x: isString x && match "^/.*" x == null && release?${x};
+    shortVersion   = x: if (isString x && match "^/.*" x == null)
+      then findFirst (v: versions.majorMinor v == x) null
+        (sort versionAtLeast (attrNames release))
+      else null;
+    isShortVersion = x: shortVersion x != null;
+    isPathString   = x: isString x && match "^/.*" x != null && pathExists x; in
+arg:
+switch arg [
+  { case = isNull;       out = { version = "broken"; src = ""; broken = true; }; }
+  { case = isPathString; out = { version = "dev"; src = arg; }; }
+  { case = pred.union isVersion isShortVersion;
+    out = let v = if isVersion arg then arg else shortVersion arg; in
+      if !release.${v}?sha256 then throw "meta-fetch: a sha256 must be provided for each release"
+      else {
+        version = release.${v}.version or v;
+        src = release.${v}.src or fetcher (location // { rev = releaseRev v; } // release.${v});
+      };
+    }
+  { case = isString;
+    out = let
+        splitted  = filter isString (split ":" arg);
+        rev       = last splitted;
+        has-owner = length splitted > 1;
+        version   = "dev"; in {
+      inherit version;
+      src = fetcher (location // { inherit rev; } //
+        (optionalAttrs has-owner { owner = head splitted; }));
+    }; }
+  { case = isAttrs;
+    out = let
+    { version = arg.version or "dev";
+      src = (arg.fetcher or fetcher) (location // (arg.location or {}));
+    }; }
+  { case = isPath;
+    out = {
+      version = "dev" ;
+      src = builtins.path {path = arg; name = location.name or "source";}; }; }
+] (throw "not a valid source description")
diff --git a/pkgs/build-support/docker/default.nix b/pkgs/build-support/docker/default.nix
index 4da26ba7cfda..0c9d4f110ada 100644
--- a/pkgs/build-support/docker/default.nix
+++ b/pkgs/build-support/docker/default.nix
@@ -1,4 +1,5 @@
 {
+  bashInteractive,
   buildPackages,
   cacert,
   callPackage,
@@ -24,16 +25,16 @@
   storeDir ? builtins.storeDir,
   substituteAll,
   symlinkJoin,
-  utillinux,
+  util-linux,
   vmTools,
   writeReferencesToFile,
   writeScript,
   writeText,
+  writeTextDir,
   writePython3,
   system,  # Note: This is the cross system we're compiling for
 }:
 
-# WARNING: this API is unstable and may be subject to backwards-incompatible changes in the future.
 let
 
   mkDbExtraCommand = contents: let
@@ -56,21 +57,18 @@ let
     done;
   '';
 
-  # Map nixpkgs architecture to Docker notation
-  # Reference: https://github.com/docker-library/official-images#architectures-other-than-amd64
-  getArch = nixSystem: {
-    aarch64-linux = "arm64v8";
-    armv7l-linux = "arm32v7";
-    x86_64-linux = "amd64";
-    powerpc64le-linux = "ppc64le";
-    i686-linux = "i386";
-  }.${nixSystem} or "Can't map Nix system ${nixSystem} to Docker architecture notation. Please check that your input and your requested build are correct or update the mapping in Nixpkgs.";
+  # The OCI Image specification recommends that configurations use values listed
+  # in the Go Language document for GOARCH.
+  # Reference: https://github.com/opencontainers/image-spec/blob/master/config.md#properties
+  # For the mapping from Nixpkgs system parameters to GOARCH, we can reuse the
+  # mapping from the go package.
+  defaultArch = go.GOARCH;
 
 in
 rec {
 
   examples = callPackage ./examples.nix {
-    inherit buildImage pullImage shadowSetup buildImageWithNixDb;
+    inherit buildImage buildLayeredImage fakeNss pullImage shadowSetup buildImageWithNixDb;
   };
 
   pullImage = let
@@ -82,7 +80,7 @@ rec {
     , imageDigest
     , sha256
     , os ? "linux"
-    , arch ? getArch system
+    , arch ? defaultArch
 
       # This is used to set name to the pulled image
     , finalImageName ? imageName
@@ -96,7 +94,7 @@ rec {
       inherit imageDigest;
       imageName = finalImageName;
       imageTag = finalImageTag;
-      impureEnvVars = stdenv.lib.fetchers.proxyImpureEnvVars;
+      impureEnvVars = lib.fetchers.proxyImpureEnvVars;
       outputHashMode = "flat";
       outputHashAlgo = "sha256";
       outputHash = sha256;
@@ -111,7 +109,7 @@ rec {
     '';
 
   # We need to sum layer.tar, not a directory, hence tarsum instead of nix-hash.
-  # And we cannot untar it, because then we cannot preserve permissions ecc.
+  # And we cannot untar it, because then we cannot preserve permissions etc.
   tarsum = runCommand "tarsum" {
     nativeBuildInputs = [ go ];
   } ''
@@ -122,7 +120,7 @@ rec {
     export GOPATH=$(pwd)
     export GOCACHE="$TMPDIR/go-cache"
     mkdir -p src/github.com/docker/docker/pkg
-    ln -sT ${docker.src}/components/engine/pkg/tarsum src/github.com/docker/docker/pkg/tarsum
+    ln -sT ${docker.moby.src}/pkg/tarsum src/github.com/docker/docker/pkg/tarsum
     go build
 
     mkdir -p $out/bin
@@ -204,7 +202,7 @@ rec {
         };
         inherit fromImage fromImageName fromImageTag;
 
-        nativeBuildInputs = [ utillinux e2fsprogs jshon rsync jq ];
+        nativeBuildInputs = [ util-linux e2fsprogs jshon rsync jq ];
       } ''
       mkdir disk
       mkfs /dev/${vmTools.hd}
@@ -498,7 +496,7 @@ rec {
       baseJson = let
           pure = writeText "${baseName}-config.json" (builtins.toJSON {
             inherit created config;
-            architecture = getArch system;
+            architecture = defaultArch;
             os = "linux";
           });
           impure = runCommand "${baseName}-config.json"
@@ -684,6 +682,33 @@ rec {
     in
     result;
 
+  # Provide a /etc/passwd and /etc/group that contain root and nobody.
+  # Useful when packaging binaries that insist on using nss to look up
+  # username/groups (like nginx).
+  # /bin/sh is fine to not exist, and provided by another shim.
+  fakeNss = symlinkJoin {
+    name = "fake-nss";
+    paths = [
+      (writeTextDir "etc/passwd" ''
+        root:x:0:0:root user:/var/empty:/bin/sh
+        nobody:x:65534:65534:nobody:/var/empty:/bin/sh
+      '')
+      (writeTextDir "etc/group" ''
+        root:x:0:
+        nobody:x:65534:
+      '')
+      (runCommand "var-empty" {} ''
+        mkdir -p $out/var/empty
+      '')
+    ];
+  };
+
+  # This provides /bin/sh, pointing to bashInteractive.
+  binSh = runCommand "bin-sh" {} ''
+    mkdir -p $out/bin
+    ln -s ${bashInteractive}/bin/bash $out/bin/sh
+  '';
+
   # Build an image and populate its nix database with the provided
   # contents. The main purpose is to be able to use nix commands in
   # the container.
@@ -725,7 +750,7 @@ rec {
       streamScript = writePython3 "stream" {} ./stream_layered_image.py;
       baseJson = writeText "${name}-base.json" (builtins.toJSON {
          inherit config;
-         architecture = getArch system;
+         architecture = defaultArch;
          os = "linux";
       });
 
diff --git a/pkgs/build-support/docker/examples.nix b/pkgs/build-support/docker/examples.nix
index 3f30f1a2adb4..86375a40baa0 100644
--- a/pkgs/build-support/docker/examples.nix
+++ b/pkgs/build-support/docker/examples.nix
@@ -7,7 +7,7 @@
 #  $ nix-build '<nixpkgs>' -A dockerTools.examples.redis
 #  $ docker load < result
 
-{ pkgs, buildImage, pullImage, shadowSetup, buildImageWithNixDb, pkgsCross }:
+{ pkgs, buildImage, buildLayeredImage, fakeNss, pullImage, shadowSetup, buildImageWithNixDb, pkgsCross }:
 
 rec {
   # 1. basic example
@@ -44,7 +44,7 @@ rec {
   nginx = let
     nginxPort = "80";
     nginxConf = pkgs.writeText "nginx.conf" ''
-      user nginx nginx;
+      user nobody nobody;
       daemon off;
       error_log /dev/stdout info;
       pid /dev/null;
@@ -64,10 +64,13 @@ rec {
       <html><body><h1>Hello from NGINX</h1></body></html>
     '';
   in
-  buildImage {
+  buildLayeredImage {
     name = "nginx-container";
     tag = "latest";
-    contents = pkgs.nginx;
+    contents = [
+      fakeNss
+      pkgs.nginx
+    ];
 
     extraCommands = ''
       # nginx still tries to read this directory even if error_log
@@ -75,12 +78,6 @@ rec {
       mkdir -p var/log/nginx
       mkdir -p var/cache/nginx
     '';
-    runAsRoot = ''
-      #!${pkgs.stdenv.shell}
-      ${shadowSetup}
-      groupadd --system nginx
-      useradd --system --gid nginx nginx
-    '';
 
     config = {
       Cmd = [ "nginx" "-c" nginxConf ];
@@ -419,4 +416,15 @@ rec {
     contents = crossPkgs.hello;
   };
 
+  # layered image where a store path is itself a symlink
+  layeredStoreSymlink =
+  let
+    target = pkgs.writeTextDir "dir/target" "Content doesn't matter.";
+    symlink = pkgs.runCommandNoCC "symlink" {} "ln -s ${target} $out";
+  in
+    pkgs.dockerTools.buildLayeredImage {
+      name = "layeredstoresymlink";
+      tag = "latest";
+      contents = [ pkgs.bash symlink ];
+    } // { passthru = { inherit symlink; }; };
 }
diff --git a/pkgs/build-support/docker/nix-prefetch-docker b/pkgs/build-support/docker/nix-prefetch-docker
index 1b6785189c28..5798ab5984f1 100755
--- a/pkgs/build-support/docker/nix-prefetch-docker
+++ b/pkgs/build-support/docker/nix-prefetch-docker
@@ -127,7 +127,7 @@ trap "rm -rf \"$tmpPath\"" EXIT
 tmpFile="$tmpPath/$(get_name $finalImageName $finalImageTag)"
 
 if test -z "$QUIET"; then
-    skopeo --insecure-policy --tmpdir=$TMPDIR --override-os ${os} --override-arch ${arch} copy "$sourceUrl" "docker-archive://$tmpFile:$finalImageName:$finalImageTag"
+    skopeo --insecure-policy --tmpdir=$TMPDIR --override-os ${os} --override-arch ${arch} copy "$sourceUrl" "docker-archive://$tmpFile:$finalImageName:$finalImageTag" >&2
 else
     skopeo --insecure-policy --tmpdir=$TMPDIR --override-os ${os} --override-arch ${arch} copy "$sourceUrl" "docker-archive://$tmpFile:$finalImageName:$finalImageTag" > /dev/null
 fi
@@ -139,12 +139,12 @@ imageHash=$(nix-hash --flat --type $hashType --base32 "$tmpFile")
 finalPath=$(nix-store --add-fixed "$hashType" "$tmpFile")
 
 if test -z "$QUIET"; then
-    echo "-> ImageName: $imageName"
-    echo "-> ImageDigest: $imageDigest"
-    echo "-> FinalImageName: $finalImageName"
-    echo "-> FinalImageTag: $finalImageTag"
-    echo "-> ImagePath: $finalPath"
-    echo "-> ImageHash: $imageHash"
+    echo "-> ImageName: $imageName" >&2
+    echo "-> ImageDigest: $imageDigest" >&2
+    echo "-> FinalImageName: $finalImageName" >&2
+    echo "-> FinalImageTag: $finalImageTag" >&2
+    echo "-> ImagePath: $finalPath" >&2
+    echo "-> ImageHash: $imageHash" >&2
 fi
 
 if [ "$format" == "nix" ]; then
diff --git a/pkgs/build-support/docker/nix-prefetch-docker.nix b/pkgs/build-support/docker/nix-prefetch-docker.nix
index 6341eb0154b0..61e917461ed9 100644
--- a/pkgs/build-support/docker/nix-prefetch-docker.nix
+++ b/pkgs/build-support/docker/nix-prefetch-docker.nix
@@ -1,6 +1,4 @@
-{ stdenv, makeWrapper, nix, skopeo, jq }:
-
-with stdenv.lib;
+{ lib, stdenv, makeWrapper, nix, skopeo, jq }:
 
 stdenv.mkDerivation {
   name = "nix-prefetch-docker";
@@ -12,13 +10,13 @@ stdenv.mkDerivation {
   installPhase = ''
     install -vD ${./nix-prefetch-docker} $out/bin/$name;
     wrapProgram $out/bin/$name \
-      --prefix PATH : ${makeBinPath [ nix skopeo jq ]} \
+      --prefix PATH : ${lib.makeBinPath [ nix skopeo jq ]} \
       --set HOME /homeless-shelter
   '';
 
   preferLocalBuild = true;
 
-  meta = {
+  meta = with lib; {
     description = "Script used to obtain source hashes for dockerTools.pullImage";
     maintainers = with maintainers; [ offline ];
     platforms = platforms.unix;
diff --git a/pkgs/build-support/docker/stream_layered_image.py b/pkgs/build-support/docker/stream_layered_image.py
index cbae0f723f92..e35bd0b0e8c0 100644
--- a/pkgs/build-support/docker/stream_layered_image.py
+++ b/pkgs/build-support/docker/stream_layered_image.py
@@ -83,7 +83,11 @@ def archive_paths_to(obj, paths, mtime):
 
         for path in paths:
             path = pathlib.Path(path)
-            files = itertools.chain([path], path.rglob("*"))
+            if path.is_symlink():
+                files = [path]
+            else:
+                files = itertools.chain([path], path.rglob("*"))
+
             for filename in sorted(files):
                 ti = append_root(tar.gettarinfo(filename))
 
diff --git a/pkgs/build-support/dotnetbuildhelpers/default.nix b/pkgs/build-support/dotnetbuildhelpers/default.nix
index 809619ed55d9..4348832ac04c 100644
--- a/pkgs/build-support/dotnetbuildhelpers/default.nix
+++ b/pkgs/build-support/dotnetbuildhelpers/default.nix
@@ -1,4 +1,4 @@
-{ runCommand, mono, pkgconfig }:
+{ runCommand, mono, pkg-config }:
   runCommand
     "dotnetbuildhelpers"
     { preferLocalBuild = true; }
@@ -12,7 +12,7 @@
         cp -v "$script" "$target"/"$scriptName"
         chmod 755 "$target"/"$scriptName"
         patchShebangs "$target"/"$scriptName"
-        substituteInPlace "$target"/"$scriptName" --replace pkg-config ${pkgconfig}/bin/${pkgconfig.targetPrefix}pkg-config
+        substituteInPlace "$target"/"$scriptName" --replace pkg-config ${pkg-config}/bin/${pkg-config.targetPrefix}pkg-config
         substituteInPlace "$target"/"$scriptName" --replace monodis ${mono}/bin/monodis
       done
     ''
diff --git a/pkgs/build-support/dotnetenv/build-solution.nix b/pkgs/build-support/dotnetenv/build-solution.nix
index 57af1fe9bd49..b3372b942177 100644
--- a/pkgs/build-support/dotnetenv/build-solution.nix
+++ b/pkgs/build-support/dotnetenv/build-solution.nix
@@ -1,4 +1,4 @@
-{stdenv, dotnetfx}:
+{ lib, stdenv, dotnetfx }:
 { name
 , src
 , baseDir ? "."
@@ -24,7 +24,7 @@ stdenv.mkDerivation {
   '';
 
   preBuild = ''
-    ${stdenv.lib.optionalString modifyPublicMain ''
+    ${lib.optionalString modifyPublicMain ''
       sed -i -e "s|static void Main|public static void Main|" ${mainClassFile}
     ''}
     ${preBuild}
diff --git a/pkgs/build-support/dotnetenv/default.nix b/pkgs/build-support/dotnetenv/default.nix
index c7145504eb7b..3015db42b07b 100644
--- a/pkgs/build-support/dotnetenv/default.nix
+++ b/pkgs/build-support/dotnetenv/default.nix
@@ -1,9 +1,9 @@
-{stdenv, dotnetfx}:
+{ lib, stdenv, dotnetfx }:
 
 let dotnetenv =
 {
   buildSolution = import ./build-solution.nix {
-    inherit stdenv;
+    inherit lib stdenv;
     dotnetfx = dotnetfx.pkg;
   };
 
diff --git a/pkgs/build-support/emacs/elpa.nix b/pkgs/build-support/emacs/elpa.nix
index e6f6c23e449f..214aed9c3f9c 100644
--- a/pkgs/build-support/emacs/elpa.nix
+++ b/pkgs/build-support/emacs/elpa.nix
@@ -7,9 +7,18 @@ with lib;
 { pname
 , version
 , src
+, meta ? {}
 , ...
 }@args:
 
+let
+
+  defaultMeta = {
+    homepage = args.src.meta.homepage or "https://elpa.gnu.org/packages/${pname}.html";
+  };
+
+in
+
 import ./generic.nix { inherit lib stdenv emacs texinfo; } ({
 
   phases = "installPhase fixupPhase distPhase";
@@ -23,6 +32,8 @@ import ./generic.nix { inherit lib stdenv emacs texinfo; } ({
 
     runHook postInstall
   '';
+
+  meta = defaultMeta // meta;
 }
 
 // removeAttrs args [ "files" "fileSpecs"
diff --git a/pkgs/build-support/emacs/generic.nix b/pkgs/build-support/emacs/generic.nix
index 956787ad59e4..588699517baf 100644
--- a/pkgs/build-support/emacs/generic.nix
+++ b/pkgs/build-support/emacs/generic.nix
@@ -60,10 +60,13 @@ stdenv.mkDerivation ({
 
   LIBRARY_PATH = "${lib.getLib stdenv.cc.libc}/lib";
 
+  addEmacsNativeLoadPath = true;
+
   postInstall = ''
-    find $out/share/emacs -type f -name '*.el' -print0 | xargs -0 -n 1 -I {} -P $NIX_BUILD_CORES sh -c "emacs --batch -f batch-native-compile {} || true"
+    find $out/share/emacs -type f -name '*.el' -print0 \
+      | xargs -0 -n 1 -I {} -P $NIX_BUILD_CORES sh -c \
+          "emacs --batch --eval=\"(add-to-list 'comp-eln-load-path \\\"$out/share/emacs/native-lisp/\\\")\" -f batch-native-compile {} || true"
   '';
-
 }
 
 // removeAttrs args [ "buildInputs" "packageRequires"
diff --git a/pkgs/build-support/emacs/melpa.nix b/pkgs/build-support/emacs/melpa.nix
index e2ec84c75e66..d6fe3085837e 100644
--- a/pkgs/build-support/emacs/melpa.nix
+++ b/pkgs/build-support/emacs/melpa.nix
@@ -23,7 +23,7 @@ with lib;
 let
 
   defaultMeta = {
-    homepage = args.src.meta.homepage or "http://melpa.org/#/${pname}";
+    homepage = args.src.meta.homepage or "https://melpa.org/#/${pname}";
   };
 
 in
diff --git a/pkgs/build-support/emacs/setup-hook.sh b/pkgs/build-support/emacs/setup-hook.sh
index 83e995631b3e..f6f2331b8e02 100644
--- a/pkgs/build-support/emacs/setup-hook.sh
+++ b/pkgs/build-support/emacs/setup-hook.sh
@@ -7,9 +7,20 @@ addToEmacsLoadPath() {
   fi
 }
 
+addToEmacsNativeLoadPath() {
+  local nativeDir="$1"
+  if [[ -d $nativeDir && ${EMACSNATIVELOADPATH-} != *"$nativeDir":* ]]; then
+    export EMACSNATIVELOADPATH="$nativeDir:${EMACSNATIVELOADPATH-}"
+  fi
+}
+
 addEmacsVars () {
   addToEmacsLoadPath "$1/share/emacs/site-lisp"
 
+  if [ -n "${addEmacsNativeLoadPath:-}" ]; then
+    addToEmacsNativeLoadPath "$1/share/emacs/native-lisp"
+  fi
+
   # Add sub paths to the Emacs load path if it is a directory
   # containing .el files. This is necessary to build some packages,
   # e.g., using trivialBuild.
diff --git a/pkgs/build-support/emacs/trivial.nix b/pkgs/build-support/emacs/trivial.nix
index 396c971b2f01..9a36b44a270d 100644
--- a/pkgs/build-support/emacs/trivial.nix
+++ b/pkgs/build-support/emacs/trivial.nix
@@ -1,6 +1,6 @@
 # trivial builder for Emacs packages
 
-{ lib, stdenv, texinfo, ... }@envargs:
+{ lib, texinfo, ... }@envargs:
 
 with lib;
 
diff --git a/pkgs/build-support/emacs/wrapper.nix b/pkgs/build-support/emacs/wrapper.nix
index 1f2fbd8068e7..f34835eaf096 100644
--- a/pkgs/build-support/emacs/wrapper.nix
+++ b/pkgs/build-support/emacs/wrapper.nix
@@ -2,11 +2,11 @@
 
 # Usage
 
-`emacsWithPackages` takes a single argument: a function from a package
+`emacs.pkgs.withPackages` takes a single argument: a function from a package
 set to a list of packages (the packages that will be available in
 Emacs). For example,
 ```
-emacsWithPackages (epkgs: [ epkgs.evil epkgs.magit ])
+emacs.pkgs.withPackages (epkgs: [ epkgs.evil epkgs.magit ])
 ```
 All the packages in the list should come from the provided package
 set. It is possible to add any package to the list, but the provided
@@ -15,26 +15,34 @@ the correct version of Emacs.
 
 # Overriding
 
-`emacsWithPackages` inherits the package set which contains it, so the
+`emacs.pkgs.withPackages` inherits the package set which contains it, so the
 correct way to override the provided package set is to override the
-set which contains `emacsWithPackages`. For example, to override
-`emacsPackages.emacsWithPackages`,
+set which contains `emacs.pkgs.withPackages`. For example, to override
+`emacs.pkgs.emacs.pkgs.withPackages`,
 ```
 let customEmacsPackages =
-      emacsPackages.overrideScope' (self: super: {
+      emacs.pkgs.overrideScope' (self: super: {
         # use a custom version of emacs
         emacs = ...;
         # use the unstable MELPA version of magit
         magit = self.melpaPackages.magit;
       });
-in customEmacsPackages.emacsWithPackages (epkgs: [ epkgs.evil epkgs.magit ])
+in customEmacsPackages.emacs.pkgs.withPackages (epkgs: [ epkgs.evil epkgs.magit ])
 ```
 
 */
 
 { lib, lndir, makeWrapper, runCommand }: self:
 
-with lib; let inherit (self) emacs; in
+with lib;
+
+let
+
+  inherit (self) emacs;
+
+  nativeComp = emacs.nativeComp or false;
+
+in
 
 packagesFun: # packages explicitly requested by the user
 
@@ -95,6 +103,9 @@ runCommand
         }
         mkdir -p $out/bin
         mkdir -p $out/share/emacs/site-lisp
+        ${optionalString nativeComp ''
+          mkdir -p $out/share/emacs/native-lisp
+        ''}
 
         local requires
         for pkg in $explicitRequires; do
@@ -116,6 +127,9 @@ runCommand
         linkEmacsPackage() {
           linkPath "$1" "bin" "bin"
           linkPath "$1" "share/emacs/site-lisp" "share/emacs/site-lisp"
+          ${optionalString nativeComp ''
+            linkPath "$1" "share/emacs/native-lisp" "share/emacs/native-lisp"
+          ''}
         }
 
         # Iterate over the array of inputs (avoiding nix's own interpolation)
@@ -138,12 +152,21 @@ runCommand
         (load-file "$emacs/share/emacs/site-lisp/site-start.el")
         (add-to-list 'load-path "$out/share/emacs/site-lisp")
         (add-to-list 'exec-path "$out/bin")
+        ${optionalString nativeComp ''
+          (add-to-list 'comp-eln-load-path "$out/share/emacs/native-lisp/")
+        ''}
         EOF
         # Link subdirs.el from the emacs distribution
         ln -s $emacs/share/emacs/site-lisp/subdirs.el -T $subdirs
 
         # Byte-compiling improves start-up time only slightly, but costs nothing.
         $emacs/bin/emacs --batch -f batch-byte-compile "$siteStart" "$subdirs"
+
+        ${optionalString nativeComp ''
+          $emacs/bin/emacs --batch \
+            --eval "(add-to-list 'comp-eln-load-path \"$out/share/emacs/native-lisp/\")" \
+            -f batch-native-compile "$siteStart" "$subdirs"
+        ''}
       '';
 
     inherit (emacs) meta;
@@ -155,8 +178,13 @@ runCommand
     for prog in $emacs/bin/*; do # */
       local progname=$(basename "$prog")
       rm -f "$out/bin/$progname"
-      makeWrapper "$prog" "$out/bin/$progname" \
-        --suffix EMACSLOADPATH ":" "$deps/share/emacs/site-lisp:"
+
+      substitute ${./wrapper.sh} $out/bin/$progname \
+        --subst-var-by bash ${emacs.stdenv.shell} \
+        --subst-var-by wrapperSiteLisp "$deps/share/emacs/site-lisp" \
+        --subst-var-by wrapperSiteLispNative "$deps/share/emacs/native-lisp:" \
+        --subst-var prog
+      chmod +x $out/bin/$progname
     done
 
     # Wrap MacOS app
@@ -168,8 +196,13 @@ runCommand
             $emacs/Applications/Emacs.app/Contents/PkgInfo \
             $emacs/Applications/Emacs.app/Contents/Resources \
             $out/Applications/Emacs.app/Contents
-      makeWrapper $emacs/Applications/Emacs.app/Contents/MacOS/Emacs $out/Applications/Emacs.app/Contents/MacOS/Emacs \
-        --suffix EMACSLOADPATH ":" "$deps/share/emacs/site-lisp:"
+
+
+      substitute ${./wrapper.sh} $out/Applications/Emacs.app/Contents/MacOS/Emacs \
+        --subst-var-by bash ${emacs.stdenv.shell} \
+        --subst-var-by wrapperSiteLisp "$deps/share/emacs/site-lisp" \
+        --subst-var-by prog "$emacs/Applications/Emacs.app/Contents/MacOS/Emacs"
+      chmod +x $out/Applications/Emacs.app/Contents/MacOS/Emacs
     fi
 
     mkdir -p $out/share
diff --git a/pkgs/build-support/emacs/wrapper.sh b/pkgs/build-support/emacs/wrapper.sh
new file mode 100644
index 000000000000..e8eecb8c8696
--- /dev/null
+++ b/pkgs/build-support/emacs/wrapper.sh
@@ -0,0 +1,47 @@
+#!@bash@
+
+IFS=:
+
+newLoadPath=()
+newNativeLoadPath=()
+added=
+
+if [[ -n $EMACSLOADPATH ]]
+then
+    while read -rd: entry
+    do
+        if [[ -z $entry && -z $added ]]
+        then
+            newLoadPath+=(@wrapperSiteLisp@)
+            added=1
+        fi
+        newLoadPath+=("$entry")
+    done <<< "$EMACSLOADPATH:"
+else
+    newLoadPath+=(@wrapperSiteLisp@)
+    newLoadPath+=("")
+fi
+
+if [[ -n $EMACSNATIVELOADPATH ]]
+then
+    while read -rd: entry
+    do
+        if [[ -z $entry && -z $added ]]
+        then
+            newNativeLoadPath+=(@wrapperSiteLispNative@)
+            added=1
+        fi
+        newNativeLoadPath+=("$entry")
+    done <<< "$EMACSNATIVELOADPATH:"
+else
+    newNativeLoadPath+=(@wrapperSiteLispNative@)
+    newNativeLoadPath+=("")
+fi
+
+export EMACSLOADPATH="${newLoadPath[*]}"
+export emacsWithPackages_siteLisp=@wrapperSiteLisp@
+
+export EMACSNATIVELOADPATH="${newNativeLoadPath[*]}"
+export emacsWithPackages_siteLispNative=@wrapperSiteLispNative@
+
+exec @prog@ "$@"
diff --git a/pkgs/build-support/fetchbzr/default.nix b/pkgs/build-support/fetchbzr/default.nix
index 2cf169de7a52..b7db9e9274da 100644
--- a/pkgs/build-support/fetchbzr/default.nix
+++ b/pkgs/build-support/fetchbzr/default.nix
@@ -10,6 +10,6 @@ stdenvNoCC.mkDerivation {
   outputHashAlgo = "sha256";
   outputHashMode = "recursive";
   outputHash = sha256;
-  
+
   inherit url rev;
 }
diff --git a/pkgs/build-support/fetchdocker/fetchDockerConfig.nix b/pkgs/build-support/fetchdocker/fetchDockerConfig.nix
index 9fd813bfa575..e8b2403d8f33 100644
--- a/pkgs/build-support/fetchdocker/fetchDockerConfig.nix
+++ b/pkgs/build-support/fetchdocker/fetchDockerConfig.nix
@@ -1,4 +1,4 @@
-pkgargs@{ stdenv, lib, haskellPackages, writeText, gawk }:
+pkgargs@{ lib, haskellPackages, writeText, gawk }:
 let
   generic-fetcher =
     import ./generic-fetcher.nix pkgargs;
diff --git a/pkgs/build-support/fetchdocker/fetchDockerLayer.nix b/pkgs/build-support/fetchdocker/fetchDockerLayer.nix
index 869ba637429c..0fbbc078efc3 100644
--- a/pkgs/build-support/fetchdocker/fetchDockerLayer.nix
+++ b/pkgs/build-support/fetchdocker/fetchDockerLayer.nix
@@ -1,4 +1,4 @@
-pkgargs@{ stdenv, lib, haskellPackages, writeText, gawk }:
+pkgargs@{ lib, haskellPackages, writeText, gawk }:
 let
   generic-fetcher =
     import ./generic-fetcher.nix pkgargs;
diff --git a/pkgs/build-support/fetchfirefoxaddon/default.nix b/pkgs/build-support/fetchfirefoxaddon/default.nix
new file mode 100644
index 000000000000..9efe9197d687
--- /dev/null
+++ b/pkgs/build-support/fetchfirefoxaddon/default.nix
@@ -0,0 +1,41 @@
+{stdenv, lib, coreutils, unzip, jq, zip, fetchurl,writeScript,  ...}:
+
+{
+  name
+, url
+, md5 ? ""
+, sha1 ? ""
+, sha256 ? ""
+, sha512 ? ""
+, fixedExtid ? null
+, hash ? ""
+}:
+
+stdenv.mkDerivation rec {
+
+  inherit name;
+  extid = if fixedExtid == null then "nixos@${name}" else fixedExtid;
+  passthru = {
+    exitd=extid;
+  };
+
+  builder = writeScript "xpibuilder" ''
+    source $stdenv/setup
+
+    header "firefox addon $name into $out"
+
+    UUID="${extid}"
+    mkdir -p "$out/$UUID"
+    unzip -q ${src} -d "$out/$UUID"
+    NEW_MANIFEST=$(jq '. + {"applications": { "gecko": { "id": "${extid}" }}, "browser_specific_settings":{"gecko":{"id": "${extid}"}}}' "$out/$UUID/manifest.json")
+    echo "$NEW_MANIFEST" > "$out/$UUID/manifest.json"
+    cd "$out/$UUID"
+    zip -r -q -FS "$out/$UUID.xpi" *
+    rm -r "$out/$UUID"
+  '';
+  src = fetchurl {
+    url = url;
+    inherit md5 sha1 sha256 sha512 hash;
+  };
+  nativeBuildInputs = [ coreutils unzip zip jq  ];
+}
diff --git a/pkgs/build-support/fetchfossil/default.nix b/pkgs/build-support/fetchfossil/default.nix
index 27933b47178a..3a4876bc5de3 100644
--- a/pkgs/build-support/fetchfossil/default.nix
+++ b/pkgs/build-support/fetchfossil/default.nix
@@ -1,11 +1,11 @@
-{stdenv, fossil}:
+{stdenv, fossil, cacert}:
 
 {name ? null, url, rev, sha256}:
 
 stdenv.mkDerivation {
   name = "fossil-archive" + (if name != null then "-${name}" else "");
   builder = ./builder.sh;
-  nativeBuildInputs = [fossil];
+  nativeBuildInputs = [fossil cacert];
 
   # Envvar docs are hard to find. A link for the future:
   # https://www.fossil-scm.org/index.html/doc/trunk/www/env-opts.md
diff --git a/pkgs/build-support/fetchgit/builder.sh b/pkgs/build-support/fetchgit/builder.sh
index 6ae46469738a..0047a335c76c 100644
--- a/pkgs/build-support/fetchgit/builder.sh
+++ b/pkgs/build-support/fetchgit/builder.sh
@@ -8,6 +8,7 @@ header "exporting $url (rev $rev) into $out"
 
 $SHELL $fetcher --builder --url "$url" --out "$out" --rev "$rev" \
   ${leaveDotGit:+--leave-dotGit} \
+  ${fetchLFS:+--fetch-lfs} \
   ${deepClone:+--deepClone} \
   ${fetchSubmodules:+--fetch-submodules} \
   ${branchName:+--branch-name "$branchName"}
diff --git a/pkgs/build-support/fetchgit/default.nix b/pkgs/build-support/fetchgit/default.nix
index 0405951a9e40..5f5ded128de5 100644
--- a/pkgs/build-support/fetchgit/default.nix
+++ b/pkgs/build-support/fetchgit/default.nix
@@ -1,4 +1,4 @@
-{stdenvNoCC, git, cacert}: let
+{stdenvNoCC, git, git-lfs, cacert}: let
   urlToName = url: rev: let
     inherit (stdenvNoCC.lib) removeSuffix splitString last;
     base = last (splitString ":" (baseNameOf (removeSuffix "/" url)));
@@ -20,6 +20,7 @@ in
   # successfully. This can do things like check or transform the file.
   postFetch ? ""
 , preferLocalBuild ? true
+, fetchLFS ? false
 }:
 
 /* NOTE:
@@ -53,13 +54,15 @@ stdenvNoCC.mkDerivation {
   inherit name;
   builder = ./builder.sh;
   fetcher = ./nix-prefetch-git;  # This must be a string to ensure it's called with bash.
-  nativeBuildInputs = [git];
+
+  nativeBuildInputs = [ git ]
+    ++ stdenvNoCC.lib.optionals fetchLFS [ git-lfs ];
 
   outputHashAlgo = "sha256";
   outputHashMode = "recursive";
   outputHash = sha256;
 
-  inherit url rev leaveDotGit fetchSubmodules deepClone branchName postFetch;
+  inherit url rev leaveDotGit fetchLFS fetchSubmodules deepClone branchName postFetch;
 
   GIT_SSL_CAINFO = "${cacert}/etc/ssl/certs/ca-bundle.crt";
 
diff --git a/pkgs/build-support/fetchgit/nix-prefetch-git b/pkgs/build-support/fetchgit/nix-prefetch-git
index 43f7c5acd5ad..3cb115c5e6e6 100755
--- a/pkgs/build-support/fetchgit/nix-prefetch-git
+++ b/pkgs/build-support/fetchgit/nix-prefetch-git
@@ -9,6 +9,7 @@ hashType=$NIX_HASH_ALGO
 deepClone=$NIX_PREFETCH_GIT_DEEP_CLONE
 leaveDotGit=$NIX_PREFETCH_GIT_LEAVE_DOT_GIT
 fetchSubmodules=
+fetchLFS=
 builder=
 branchName=$NIX_PREFETCH_GIT_BRANCH_NAME
 
@@ -72,6 +73,7 @@ for arg; do
             --quiet) QUIET=true;;
             --no-deepClone) deepClone=;;
             --leave-dotGit) leaveDotGit=true;;
+            --fetch-lfs) fetchLFS=true;;
             --fetch-submodules) fetchSubmodules=true;;
             --builder) builder=true;;
             -h|--help) usage; exit;;
@@ -283,6 +285,11 @@ clone_user_rev() {
     local url="$2"
     local rev="${3:-HEAD}"
 
+    if [ -n "$fetchLFS" ]; then
+        HOME=$TMPDIR
+        git lfs install
+    fi
+
     # Perform the checkout.
     case "$rev" in
         HEAD|refs/*)
diff --git a/pkgs/build-support/fetchmavenartifact/default.nix b/pkgs/build-support/fetchmavenartifact/default.nix
index 583a9ea396cf..4274b4b52bfa 100644
--- a/pkgs/build-support/fetchmavenartifact/default.nix
+++ b/pkgs/build-support/fetchmavenartifact/default.nix
@@ -1,12 +1,12 @@
 # Adaptation of the MIT-licensed work on `sbt2nix` done by Charles O'Farrell
 
-{ fetchurl, stdenv }:
+{ lib, fetchurl, stdenv }:
 let
   defaultRepos = [
-    "http://repo1.maven.org/maven2"
-    "http://oss.sonatype.org/content/repositories/releases"
-    "http://oss.sonatype.org/content/repositories/public"
-    "http://repo.typesafe.com/typesafe/releases"
+    "https://repo1.maven.org/maven2"
+    "https://oss.sonatype.org/content/repositories/releases"
+    "https://oss.sonatype.org/content/repositories/public"
+    "https://repo.typesafe.com/typesafe/releases"
   ];
 in
 
@@ -17,6 +17,8 @@ args@
   artifactId
 , # Example: "4.3.6"
   version
+, # Example: "jdk11"
+  classifier ? null
 , # List of maven repositories from where to fetch the artifact.
   # Example: [ http://oss.sonatype.org/content/repositories/public ].
   repos ? defaultRepos
@@ -34,21 +36,20 @@ assert (url == "") || (urls == []);
 # if repos is empty, then url or urls must be specified.
 assert (repos != []) || (url != "") || (urls != []);
 
-
 let
   name_ =
-    with stdenv.lib; concatStrings [
-      (replaceChars ["."] ["_"] groupId) "_"
-      (replaceChars ["."] ["_"] artifactId) "-"
+    lib.concatStrings [
+      (lib.replaceChars ["."] ["_"] groupId) "_"
+      (lib.replaceChars ["."] ["_"] artifactId) "-"
       version
     ];
   mkJarUrl = repoUrl:
-    with stdenv.lib; concatStringsSep "/" [
-      (removeSuffix "/" repoUrl)
-      (replaceChars ["."] ["/"] groupId)
+    lib.concatStringsSep "/" [
+      (lib.removeSuffix "/" repoUrl)
+      (lib.replaceChars ["."] ["/"] groupId)
       artifactId
       version
-      "${artifactId}-${version}.jar"
+      "${artifactId}-${version}${lib.optionalString (!isNull classifier) "-${classifier}"}.jar"
     ];
   urls_ =
     if url != "" then [url]
@@ -56,7 +57,7 @@ let
     else map mkJarUrl repos;
   jar =
     fetchurl (
-      builtins.removeAttrs args ["groupId" "artifactId" "version" "repos" "url" ]
+      builtins.removeAttrs args ["groupId" "artifactId" "version" "classifier" "repos" "url" ]
         // { urls = urls_; name = "${name_}.jar"; }
     );
 in
diff --git a/pkgs/build-support/fetchmtn/default.nix b/pkgs/build-support/fetchmtn/default.nix
index 7ce67453d698..b5da0f80a31f 100644
--- a/pkgs/build-support/fetchmtn/default.nix
+++ b/pkgs/build-support/fetchmtn/default.nix
@@ -4,7 +4,7 @@
 # each is an url for sync
 
 # selector is mtn selector, like h:org.example.branch
-# 
+#
 {name ? "mtn-checkout", dbs ? [], sha256
 , selector ? "h:" + branch, branch}:
 
diff --git a/pkgs/build-support/fetchurl/mirrors.nix b/pkgs/build-support/fetchurl/mirrors.nix
index 0eba8816b638..b61cd9a0d902 100644
--- a/pkgs/build-support/fetchurl/mirrors.nix
+++ b/pkgs/build-support/fetchurl/mirrors.nix
@@ -9,10 +9,10 @@
   # "sourceforge", "gnu", etc.
 
   luarocks = [
-    "https://luarocks.org"
+    "https://luarocks.org/"
     "https://raw.githubusercontent.com/rocks-moonscript-org/moonrocks-mirror/master/"
-    "http://luafr.org/moonrocks"
-    "http://luarocks.logiceditor.com/rocks"
+    "http://luafr.org/moonrocks/"
+    "http://luarocks.logiceditor.com/rocks/"
   ];
 
   # SourceForge.
diff --git a/pkgs/build-support/fetchzip/default.nix b/pkgs/build-support/fetchzip/default.nix
index c61df8ceb001..a1744b48deb9 100644
--- a/pkgs/build-support/fetchzip/default.nix
+++ b/pkgs/build-support/fetchzip/default.nix
@@ -44,8 +44,20 @@
       mv "$unpackDir/$fn" "$out"
     '' else ''
       mv "$unpackDir" "$out"
-    '') #*/
-    + extraPostFetch;
+    '')
+    + extraPostFetch
+    # Remove write permissions for files unpacked with write bits set
+    # Fixes https://github.com/NixOS/nixpkgs/issues/38649
+    #
+    # However, we should (for the moment) retain write permission on the directory
+    # itself, to avoid tickling https://github.com/NixOS/nix/issues/4295 in
+    # single-user Nix installations. This is because in sandbox mode we'll try to
+    # move the path, and if we don't have write permissions on the directory,
+    # then we can't update the ".." entry.
+    + ''
+      chmod -R a-w "$out"
+      chmod u+w "$out"
+    '';
 } // removeAttrs args [ "stripRoot" "extraPostFetch" ])).overrideAttrs (x: {
   # Hackety-hack: we actually need unzip hooks, too
   nativeBuildInputs = x.nativeBuildInputs ++ [ unzip ];
diff --git a/pkgs/build-support/icon-conv-tools/default.nix b/pkgs/build-support/icon-conv-tools/default.nix
index 0ea18d8768ac..79d3838e6884 100644
--- a/pkgs/build-support/icon-conv-tools/default.nix
+++ b/pkgs/build-support/icon-conv-tools/default.nix
@@ -1,4 +1,4 @@
-{ stdenv, icoutils }:
+{ lib, stdenv, icoutils }:
 
 stdenv.mkDerivation {
   name = "icon-conv-tools-0.0.0";
@@ -23,9 +23,9 @@ stdenv.mkDerivation {
   dontPatchELF = true;
   dontStrip = true;
 
-  meta = {
+  meta = with lib; {
     description = "Tools for icon conversion specific to nix package manager";
-    maintainers = with stdenv.lib.maintainers; [ jraygauthier ];
-    platforms = with stdenv.lib.platforms; linux;
+    maintainers = with maintainers; [ jraygauthier ];
+    platforms = platforms.linux;
   };
 }
diff --git a/pkgs/build-support/kernel/initrd-compressor-meta.nix b/pkgs/build-support/kernel/initrd-compressor-meta.nix
new file mode 100644
index 000000000000..443e599a239e
--- /dev/null
+++ b/pkgs/build-support/kernel/initrd-compressor-meta.nix
@@ -0,0 +1,53 @@
+rec {
+  cat = {
+    executable = pkgs: "cat";
+    ubootName = "none";
+    extension = ".cpio";
+  };
+  gzip = {
+    executable = pkgs: "${pkgs.gzip}/bin/gzip";
+    defaultArgs = ["-9n"];
+    ubootName = "gzip";
+    extension = ".gz";
+  };
+  bzip2 = {
+    executable = pkgs: "${pkgs.bzip2}/bin/bzip2";
+    ubootName = "bzip2";
+    extension = ".bz2";
+  };
+  xz = {
+    executable = pkgs: "${pkgs.xz}/bin/xz";
+    defaultArgs = ["--check=crc32" "--lzma2=dict=512KiB"];
+    extension = ".xz";
+  };
+  lzma = {
+    executable = pkgs: "${pkgs.xz}/bin/lzma";
+    defaultArgs = ["--check=crc32" "--lzma1=dict=512KiB"];
+    ubootName = "lzma";
+    extension = ".lzma";
+  };
+  lz4 = {
+    executable = pkgs: "${pkgs.lz4}/bin/lz4";
+    defaultArgs = ["-l"];
+    ubootName = "lz4";
+    extension = ".lz4";
+  };
+  lzop = {
+    executable = pkgs: "${pkgs.lzop}/bin/lzop";
+    ubootName = "lzo";
+    extension = ".lzo";
+  };
+  zstd = {
+    executable = pkgs: "${pkgs.zstd}/bin/zstd";
+    defaultArgs = ["-10"];
+    ubootName = "zstd";
+    extension = ".zst";
+  };
+  pigz = gzip // {
+    executable = pkgs: "${pkgs.pigz}/bin/pigz";
+  };
+  pixz = xz // {
+    executable = pkgs: "${pkgs.pixz}/bin/pixz";
+    defaultArgs = [];
+  };
+}
diff --git a/pkgs/build-support/kernel/make-initrd.nix b/pkgs/build-support/kernel/make-initrd.nix
index ed5dbdaee171..9af40d33242d 100644
--- a/pkgs/build-support/kernel/make-initrd.nix
+++ b/pkgs/build-support/kernel/make-initrd.nix
@@ -1,22 +1,74 @@
-# Create an initial ramdisk containing the closure of the specified
-# file system objects.  An initial ramdisk is used during the initial
+# Create an initramfs containing the closure of the specified
+# file system objects.  An initramfs is used during the initial
 # stages of booting a Linux system.  It is loaded by the boot loader
 # along with the kernel image.  It's supposed to contain everything
 # (such as kernel modules) necessary to allow us to mount the root
 # file system.  Once the root file system is mounted, the `real' boot
 # script can be called.
 #
-# An initrd is really just a gzipped cpio archive.
-#
-# Symlinks are created for each top-level file system object.  E.g.,
-# `contents = {object = ...; symlink = /init;}' is a typical
-# argument.
-
-{ stdenvNoCC, perl, cpio, contents, ubootTools
+# An initramfs is a cpio archive, and may be compressed with a number
+# of algorithms.
+let
+  # Some metadata on various compression programs, relevant to naming
+  # the initramfs file and, if applicable, generating a u-boot image
+  # from it.
+  compressors = import ./initrd-compressor-meta.nix;
+  # Get the basename of the actual compression program from the whole
+  # compression command, for the purpose of guessing the u-boot
+  # compression type and filename extension.
+  compressorName = fullCommand: builtins.elemAt (builtins.match "([^ ]*/)?([^ ]+).*" fullCommand) 1;
+in
+{ stdenvNoCC, perl, cpio, ubootTools, lib, pkgsBuildHost
+# Name of the derivation (not of the resulting file!)
 , name ? "initrd"
-, compressor ? "gzip -9n"
+
+# Program used to compress the cpio archive; use "cat" for no compression.
+# This can also be a function which takes a package set and returns the path to the compressor,
+# such as `pkgs: "${pkgs.lzop}/bin/lzop"`.
+, compressor ? "gzip"
+, _compressorFunction ?
+  if lib.isFunction compressor then compressor
+  else if ! builtins.hasContext compressor && builtins.hasAttr compressor compressors then compressors.${compressor}.executable
+  else _: compressor
+, _compressorExecutable ? _compressorFunction pkgsBuildHost
+, _compressorName ? compressorName _compressorExecutable
+, _compressorMeta ? compressors.${_compressorName} or {}
+
+# List of arguments to pass to the compressor program, or null to use its defaults
+, compressorArgs ? null
+, _compressorArgsReal ? if compressorArgs == null then _compressorMeta.defaultArgs or [] else compressorArgs
+
+# Filename extension to use for the compressed initramfs. This is
+# included for clarity, but $out/initrd will always be a symlink to
+# the final image.
+# If this isn't guessed, you may want to complete the metadata above and send a PR :)
+, extension ? _compressorMeta.extension or
+    (throw "Unrecognised compressor ${_compressorName}, please specify filename extension")
+
+# List of { object = path_or_derivation; symlink = "/path"; }
+# The paths are copied into the initramfs in their nix store path
+# form, then linked at the root according to `symlink`.
+, contents
+
+# List of uncompressed cpio files to prepend to the initramfs. This
+# can be used to add files in specified paths without them becoming
+# symlinks to store paths.
 , prepend ? []
-, lib
+
+# Whether to wrap the initramfs in a u-boot image.
+, makeUInitrd ? stdenvNoCC.hostPlatform.linux-kernel.target == "uImage"
+
+# If generating a u-boot image, the architecture to use. The default
+# guess may not align with u-boot's nomenclature correctly, so it can
+# be overridden.
+# See https://gitlab.denx.de/u-boot/u-boot/-/blob/9bfb567e5f1bfe7de8eb41f8c6d00f49d2b9a426/common/image.c#L81-106 for a list.
+, uInitrdArch ? stdenvNoCC.hostPlatform.linuxArch
+
+# The name of the compression, as recognised by u-boot.
+# See https://gitlab.denx.de/u-boot/u-boot/-/blob/9bfb567e5f1bfe7de8eb41f8c6d00f49d2b9a426/common/image.c#L195-204 for a list.
+# If this isn't guessed, you may want to complete the metadata above and send a PR :)
+, uInitrdCompression ? _compressorMeta.ubootName or
+    (throw "Unrecognised compressor ${_compressorName}, please specify uInitrdCompression")
 }:
 let
   # !!! Move this into a public lib function, it is probably useful for others
@@ -24,15 +76,26 @@ let
     lib.concatStringsSep "-" (filter (x: !(isList x)) (split "[^a-zA-Z0-9_=.?-]+" x));
 
 in stdenvNoCC.mkDerivation rec {
-  inherit name;
+  inherit name makeUInitrd extension uInitrdArch prepend;
 
-  builder = ./make-initrd.sh;
+  ${if makeUInitrd then "uinitrdCompression" else null} = uInitrdCompression;
 
-  makeUInitrd = stdenvNoCC.hostPlatform.platform.kernelTarget == "uImage";
+  builder = ./make-initrd.sh;
 
   nativeBuildInputs = [ perl cpio ]
     ++ stdenvNoCC.lib.optional makeUInitrd ubootTools;
 
+  compress = "${_compressorExecutable} ${lib.escapeShellArgs _compressorArgsReal}";
+
+  # Pass the function through, for reuse in append-initrd-secrets. The
+  # function is used instead of the string, in order to support
+  # cross-compilation (append-initrd-secrets running on a different
+  # architecture than what the main initramfs is built on).
+  passthru = {
+    compressorExecutableFunction = _compressorFunction;
+    compressorArgs = _compressorArgsReal;
+  };
+
   # !!! should use XML.
   objects = map (x: x.object) contents;
   symlinks = map (x: x.symlink) contents;
@@ -47,6 +110,4 @@ in stdenvNoCC.mkDerivation rec {
       contents
       (lib.range 0 (lib.length contents - 1));
   pathsFromGraph = ./paths-from-graph.pl;
-
-  inherit compressor prepend;
 }
diff --git a/pkgs/build-support/kernel/make-initrd.sh b/pkgs/build-support/kernel/make-initrd.sh
index 0aeaedeb3724..c0619ef14ae0 100644
--- a/pkgs/build-support/kernel/make-initrd.sh
+++ b/pkgs/build-support/kernel/make-initrd.sh
@@ -39,10 +39,13 @@ mkdir -p $out
 for PREP in $prepend; do
   cat $PREP >> $out/initrd
 done
-(cd root && find * -print0 | xargs -0r touch -h -d '@1')
-(cd root && find * -print0 | sort -z | cpio -o -H newc -R +0:+0 --reproducible --null | $compressor >> $out/initrd)
+(cd root && find * .[^.*] -exec touch -h -d '@1' '{}' +)
+(cd root && find * .[^.*] -print0 | sort -z | cpio -o -H newc -R +0:+0 --reproducible --null | eval -- $compress >> "$out/initrd")
 
 if [ -n "$makeUInitrd" ]; then
-    mv $out/initrd $out/initrd.gz
-    mkimage -A arm -O linux -T ramdisk -C gzip -d $out/initrd.gz $out/initrd
+    mkimage -A $uInitrdArch -O linux -T ramdisk -C "$uInitrdCompression" -d $out/initrd"$extension" $out/initrd.img
+    # Compatibility symlink
+    ln -s "initrd.img" "$out/initrd"
+else
+    ln -s "initrd" "$out/initrd$extension"
 fi
diff --git a/pkgs/build-support/kernel/modules-closure.sh b/pkgs/build-support/kernel/modules-closure.sh
index 3f895d9cfed9..3b3a38ea1d33 100644
--- a/pkgs/build-support/kernel/modules-closure.sh
+++ b/pkgs/build-support/kernel/modules-closure.sh
@@ -81,7 +81,8 @@ for module in $(cat closure); do
     for i in $(modinfo -b $kernel --set-version "$version" -F firmware $module | grep -v '^name:'); do
         mkdir -p "$out/lib/firmware/$(dirname "$i")"
         echo "firmware for $module: $i"
-        cp "$firmware/lib/firmware/$i" "$out/lib/firmware/$i" 2>/dev/null || if test -z "$allowMissing"; then exit 1; fi
+        cp "$firmware/lib/firmware/$i" "$out/lib/firmware/$i" 2>/dev/null \
+            || echo "WARNING: missing firmware $i for module $module"
     done
 done
 
diff --git a/pkgs/build-support/libredirect/default.nix b/pkgs/build-support/libredirect/default.nix
index 6e54e2a696c5..70da5bf5b5fb 100644
--- a/pkgs/build-support/libredirect/default.nix
+++ b/pkgs/build-support/libredirect/default.nix
@@ -46,8 +46,8 @@ stdenv.mkDerivation {
     )
   '';
 
-  meta = {
-    platforms = stdenv.lib.platforms.unix;
+  meta = with lib; {
+    platforms = platforms.unix;
     description = "An LD_PRELOAD library to intercept and rewrite the paths in glibc calls";
     longDescription = ''
       libredirect is an LD_PRELOAD library to intercept and rewrite the paths in
diff --git a/pkgs/build-support/make-desktopitem/default.nix b/pkgs/build-support/make-desktopitem/default.nix
index 8e51dc1b8480..329286bd3628 100644
--- a/pkgs/build-support/make-desktopitem/default.nix
+++ b/pkgs/build-support/make-desktopitem/default.nix
@@ -12,16 +12,16 @@
 , mimeType ? null
 , categories ? null
 , startupNotify ? null
-, extraDesktopEntries ? {} # Extra key-value pairs to add to the [Desktop Entry] section. This may override other values
+, extraDesktopEntries ? { } # Extra key-value pairs to add to the [Desktop Entry] section. This may override other values
 , extraEntries ? "" # Extra configuration. Will be appended to the end of the file and may thus contain extra sections
 , fileValidation ? true # whether to validate resulting desktop file.
 }:
-
 let
   # like builtins.toString, but null -> null instead of null -> ""
-  nullableToString = value: if value == null then null
-        else if builtins.isBool value then lib.boolToString value
-        else builtins.toString value;
+  nullableToString = value:
+    if value == null then null
+    else if builtins.isBool value then lib.boolToString value
+    else builtins.toString value;
 
   # The [Desktop entry] section of the desktop file, as attribute set.
   mainSection = {
@@ -39,16 +39,19 @@ let
 
   # Map all entries to a list of lines
   desktopFileStrings =
-    ["[Desktop Entry]"]
+    [ "[Desktop Entry]" ]
     ++ builtins.filter
       (v: v != null)
       (lib.mapAttrsToList
         (name: value: if value != null then "${name}=${value}" else null)
         mainSection
       )
-    ++ (if extraEntries == "" then [] else ["${extraEntries}"]);
+    ++ (if extraEntries == "" then [ ] else [ "${extraEntries}" ]);
 in
-runCommandLocal "${name}.desktop" {}
+runCommandLocal "${name}.desktop"
+{
+  nativeBuildInputs = [ desktop-file-utils ];
+}
   (''
     mkdir -p "$out/share/applications"
     cat > "$out/share/applications/${name}.desktop" <<EOF
@@ -56,5 +59,5 @@ runCommandLocal "${name}.desktop" {}
     EOF
   '' + lib.optionalString fileValidation ''
     echo "Running desktop-file validation"
-    ${desktop-file-utils}/bin/desktop-file-validate "$out/share/applications/${name}.desktop"
+    desktop-file-validate "$out/share/applications/${name}.desktop"
   '')
diff --git a/pkgs/build-support/nix-gitignore/default.nix b/pkgs/build-support/nix-gitignore/default.nix
index 28ee6bad5540..5d7b945bf1b1 100644
--- a/pkgs/build-support/nix-gitignore/default.nix
+++ b/pkgs/build-support/nix-gitignore/default.nix
@@ -148,10 +148,10 @@ in rec {
       '');
 
   withGitignoreFile = patterns: root:
-    lib.toList patterns ++ [(root + "/.gitignore")];
+    lib.toList patterns ++ [ ".git" ] ++ [(root + "/.gitignore")];
 
   withRecursiveGitignoreFile = patterns: root:
-    lib.toList patterns ++ [(compileRecursiveGitignore root)];
+    lib.toList patterns ++ [ ".git" ] ++ [(compileRecursiveGitignore root)];
 
   # filterSource derivatives
 
diff --git a/pkgs/build-support/ocaml/default.nix b/pkgs/build-support/ocaml/default.nix
index 3957b955a2c6..88ed3dfc2c2f 100644
--- a/pkgs/build-support/ocaml/default.nix
+++ b/pkgs/build-support/ocaml/default.nix
@@ -1,4 +1,4 @@
-{ stdenv, writeText, ocaml, findlib, ocamlbuild, camlp4 }:
+{ lib, stdenv, writeText, ocaml, findlib, ocamlbuild, camlp4 }:
 
 { name, version, buildInputs ? [],
   createFindlibDestdir ?  true,
@@ -14,7 +14,7 @@ let
   };
 in
   assert minimumSupportedOcamlVersion != null ->
-          stdenv.lib.versionOlder minimumSupportedOcamlVersion ocaml.version;
+          lib.versionOlder minimumSupportedOcamlVersion ocaml.version;
 
 stdenv.mkDerivation (args // {
   name = "ocaml-${name}-${version}";
diff --git a/pkgs/build-support/ocaml/dune.nix b/pkgs/build-support/ocaml/dune.nix
index b134effab8ac..f9f59b21510f 100644
--- a/pkgs/build-support/ocaml/dune.nix
+++ b/pkgs/build-support/ocaml/dune.nix
@@ -1,11 +1,11 @@
-{ stdenv, ocaml, findlib, dune, dune_2, opaline }:
+{ lib, stdenv, ocaml, findlib, dune, dune_2 }:
 
 { pname, version, buildInputs ? [], enableParallelBuilding ? true, ... }@args:
 
 let Dune = if args.useDune2 or false then dune_2 else dune; in
 
 if args ? minimumOCamlVersion &&
-   ! stdenv.lib.versionAtLeast ocaml.version args.minimumOCamlVersion
+   ! lib.versionAtLeast ocaml.version args.minimumOCamlVersion
 then throw "${pname}-${version} is not available for OCaml ${ocaml.version}"
 else
 
@@ -25,7 +25,7 @@ stdenv.mkDerivation ({
   '';
   installPhase = ''
     runHook preInstall
-    ${opaline}/bin/opaline -prefix $out -libdir $OCAMLFIND_DESTDIR
+    dune install --prefix $out --libdir $OCAMLFIND_DESTDIR ${pname}
     runHook postInstall
   '';
 
diff --git a/pkgs/build-support/ocaml/oasis.nix b/pkgs/build-support/ocaml/oasis.nix
index c1d1d699765b..ee231a6e258c 100644
--- a/pkgs/build-support/ocaml/oasis.nix
+++ b/pkgs/build-support/ocaml/oasis.nix
@@ -1,4 +1,4 @@
-{ stdenv, ocaml_oasis, ocaml, findlib, ocamlbuild }:
+{ lib, stdenv, ocaml_oasis, ocaml, findlib, ocamlbuild }:
 
 { pname, version, buildInputs ? [], meta ? { platforms = ocaml.meta.platforms or []; },
   minimumOCamlVersion ? null,
@@ -8,7 +8,7 @@
 }@args:
 
 if args ? minimumOCamlVersion &&
-   ! stdenv.lib.versionAtLeast ocaml.version args.minimumOCamlVersion
+   ! lib.versionAtLeast ocaml.version args.minimumOCamlVersion
 then throw "${pname}-${version} is not available for OCaml ${ocaml.version}"
 else
 
diff --git a/pkgs/build-support/pkg-config-wrapper/default.nix b/pkgs/build-support/pkg-config-wrapper/default.nix
index e01df107dd17..bbc49d6728c9 100644
--- a/pkgs/build-support/pkg-config-wrapper/default.nix
+++ b/pkgs/build-support/pkg-config-wrapper/default.nix
@@ -2,6 +2,7 @@
 # PKG_CONFIG_PATH_FOR_BUILD work properly.
 
 { stdenvNoCC
+, lib
 , buildPackages
 , pkg-config
 , baseBinName ? "pkg-config"
@@ -9,7 +10,7 @@
 , extraPackages ? [], extraBuildCommands ? ""
 }:
 
-with stdenvNoCC.lib;
+with lib;
 
 let
   stdenv = stdenvNoCC;
@@ -19,7 +20,7 @@ let
   #
   # TODO(@Ericson2314) Make unconditional, or optional but always true by
   # default.
-  targetPrefix = stdenv.lib.optionalString (targetPlatform != hostPlatform)
+  targetPrefix = lib.optionalString (targetPlatform != hostPlatform)
                                         (targetPlatform.config + "-");
 
   # See description in cc-wrapper.
@@ -119,7 +120,7 @@ stdenv.mkDerivation {
     let pkg-config_ = if pkg-config != null then pkg-config else {}; in
     (if pkg-config_ ? meta then removeAttrs pkg-config.meta ["priority"] else {}) //
     { description =
-        stdenv.lib.attrByPath ["meta" "description"] "pkg-config" pkg-config_
+        lib.attrByPath ["meta" "description"] "pkg-config" pkg-config_
         + " (wrapper script)";
       priority = 10;
   };
diff --git a/pkgs/build-support/plugins.nix b/pkgs/build-support/plugins.nix
index bf8a982a88f9..31b478c6c0de 100644
--- a/pkgs/build-support/plugins.nix
+++ b/pkgs/build-support/plugins.nix
@@ -1,4 +1,4 @@
-{ stdenv }:
+{ lib }:
 # helper functions for packaging programs with plugin systems
 {
 
@@ -13,7 +13,7 @@
   diffPlugins = expectedPlugins: foundPluginsFilePath: ''
      # sort both lists first
      plugins_expected=$(mktemp)
-     (${stdenv.lib.concatMapStrings (s: "echo \"${s}\";") expectedPlugins}) \
+     (${lib.concatMapStrings (s: "echo \"${s}\";") expectedPlugins}) \
        | sort -u > "$plugins_expected"
      plugins_found=$(mktemp)
      sort -u "${foundPluginsFilePath}" > "$plugins_found"
diff --git a/pkgs/build-support/release/ant-build.nix b/pkgs/build-support/release/ant-build.nix
index 2d24d5bd7041..996f4f45d07b 100644
--- a/pkgs/build-support/release/ant-build.nix
+++ b/pkgs/build-support/release/ant-build.nix
@@ -1,5 +1,6 @@
 { src
 , pkgs
+, lib
 , stdenv ? pkgs.stdenv
 , name
 , antTargets ? []
@@ -16,8 +17,7 @@
 , ... } @ args:
 
 let
-  antFlags = "-f ${buildfile} " + stdenv.lib.concatMapStrings ({name, value}: "-D${name}=${value} " ) antProperties ;
-  lib = stdenv.lib;
+  antFlags = "-f ${buildfile} " + lib.concatMapStrings ({name, value}: "-D${name}=${value} " ) antProperties ;
 in
 stdenv.mkDerivation (
 
@@ -31,7 +31,7 @@ stdenv.mkDerivation (
     prePhases =
       ["antSetupPhase"];
 
-    antSetupPhase = with stdenv.lib; ''
+    antSetupPhase = with lib; ''
       if test "$hydraAntLogger" != "" ; then
         export ANT_ARGS="-logger org.hydra.ant.HydraLogger -lib `ls $hydraAntLogger/share/java/*.jar | head -1`"
       fi
@@ -46,7 +46,7 @@ stdenv.mkDerivation (
       mkdir -p $out/share/java
       ${ if jars == [] then ''
            find . -name "*.jar" | xargs -I{} cp -v {} $out/share/java
-         '' else stdenv.lib.concatMapStrings (j: ''
+         '' else lib.concatMapStrings (j: ''
            cp -v ${j} $out/share/java
          '') jars }
 
@@ -65,7 +65,7 @@ stdenv.mkDerivation (
       in
       ''
       header "Generating jar wrappers"
-    '' + (stdenv.lib.concatMapStrings (w: ''
+    '' + (lib.concatMapStrings (w: ''
 
       mkdir -p $out/bin
       cat >> $out/bin/${w.name} <<EOF
@@ -85,7 +85,7 @@ stdenv.mkDerivation (
       header "Building default ant target"
       ant ${antFlags}
       closeNest
-    '' else stdenv.lib.concatMapStrings (t: ''
+    '' else lib.concatMapStrings (t: ''
       header "Building '${t}' target"
       ant ${antFlags} ${t}
       closeNest
@@ -103,12 +103,12 @@ stdenv.mkDerivation (
       '';
   }
 
-  // removeAttrs args ["antProperties" "buildInputs" "pkgs" "jarWrappers"] //
+  // removeAttrs args ["antProperties" "buildInputs" "pkgs" "lib" "jarWrappers"] //
 
   {
     name = name + (if src ? version then "-" + src.version else "");
 
-    buildInputs = [ant jre zip unzip] ++ stdenv.lib.optional (args ? buildInputs) args.buildInputs ;
+    buildInputs = [ant jre zip unzip] ++ lib.optional (args ? buildInputs) args.buildInputs ;
 
     postHook = ''
       mkdir -p $out/nix-support
diff --git a/pkgs/build-support/release/debian-build.nix b/pkgs/build-support/release/debian-build.nix
index dfa896a86a60..2544d5c740c2 100644
--- a/pkgs/build-support/release/debian-build.nix
+++ b/pkgs/build-support/release/debian-build.nix
@@ -2,8 +2,9 @@
 # that contains a Debian-like (i.e. dpkg-based) OS.
 
 { name ? "debian-build"
+, lib
 , diskImage
-, src, stdenv, vmTools, checkinstall
+, src, lib, stdenv, vmTools, checkinstall
 , fsTranslation ? false
 , # Features provided by this package.
   debProvides ? []
@@ -11,8 +12,6 @@
   debRequires ? []
 , ... } @ args:
 
-with stdenv.lib;
-
 vmTools.runInLinuxImage (stdenv.mkDerivation (
 
   {
@@ -59,8 +58,8 @@ vmTools.runInLinuxImage (stdenv.mkDerivation (
       export PAGER=cat
       ${checkinstall}/sbin/checkinstall --nodoc -y -D \
         --fstrans=${if fsTranslation then "yes" else "no"} \
-        --requires="${concatStringsSep "," debRequires}" \
-        --provides="${concatStringsSep "," debProvides}" \
+        --requires="${lib.concatStringsSep "," debRequires}" \
+        --provides="${lib.concatStringsSep "," debProvides}" \
         ${if (src ? version) then "--pkgversion=$(echo ${src.version} | tr _ -)"
                              else "--pkgversion=0.0.0"} \
         ''${debMaintainer:+--maintainer="'$debMaintainer'"} \
diff --git a/pkgs/build-support/release/default.nix b/pkgs/build-support/release/default.nix
index 6aaa0338f0cc..83f755b2bece 100644
--- a/pkgs/build-support/release/default.nix
+++ b/pkgs/build-support/release/default.nix
@@ -1,4 +1,4 @@
-{ pkgs }:
+{ lib, pkgs }:
 
 with pkgs;
 
@@ -15,7 +15,7 @@ rec {
     } // args);
 
   antBuild = args: import ./ant-build.nix (
-    { inherit pkgs;
+    { inherit lib pkgs;
     } // args);
 
   mvnBuild = args: import ./maven-build.nix (
@@ -23,7 +23,7 @@ rec {
     } // args);
 
   nixBuild = args: import ./nix-build.nix (
-    { inherit stdenv;
+    { inherit lib stdenv;
     } // args);
 
   coverageAnalysis = args: nixBuild (
@@ -46,7 +46,7 @@ rec {
     } // args);
 
   debBuild = args: import ./debian-build.nix (
-    { inherit stdenv vmTools checkinstall;
+    { inherit lib stdenv vmTools checkinstall;
     } // args);
 
   aggregate =
@@ -94,7 +94,7 @@ rec {
 
       phases = [ "unpackPhase" "patchPhase" "installPhase" ];
 
-      patchPhase = stdenv.lib.optionalString isNixOS ''
+      patchPhase = lib.optionalString isNixOS ''
         touch .update-on-nixos-rebuild
       '';
 
diff --git a/pkgs/build-support/release/nix-build.nix b/pkgs/build-support/release/nix-build.nix
index feda54de46fe..97df52eaced2 100644
--- a/pkgs/build-support/release/nix-build.nix
+++ b/pkgs/build-support/release/nix-build.nix
@@ -12,7 +12,7 @@
 , doCoverityAnalysis ? false
 , lcovFilter ? []
 , lcovExtraTraceFiles ? []
-, src, stdenv
+, src, lib, stdenv
 , name ? if doCoverageAnalysis then "nix-coverage" else "nix-build"
 , failureHook ? null
 , prePhases ? []
@@ -69,7 +69,7 @@ stdenv.mkDerivation (
         fi
       '';
 
-    failureHook = (stdenv.lib.optionalString (failureHook != null) failureHook) +
+    failureHook = (lib.optionalString (failureHook != null) failureHook) +
     ''
       if test -n "$succeedOnFailure"; then
           if test -n "$keepBuildDirectory"; then
@@ -136,10 +136,10 @@ stdenv.mkDerivation (
 
     buildInputs =
       buildInputs ++
-      (stdenv.lib.optional doCoverageAnalysis args.makeGCOVReport) ++
-      (stdenv.lib.optional doClangAnalysis args.clang-analyzer) ++
-      (stdenv.lib.optional doCoverityAnalysis args.cov-build) ++
-      (stdenv.lib.optional doCoverityAnalysis args.xz);
+      (lib.optional doCoverageAnalysis args.makeGCOVReport) ++
+      (lib.optional doClangAnalysis args.clang-analyzer) ++
+      (lib.optional doCoverityAnalysis args.cov-build) ++
+      (lib.optional doCoverityAnalysis args.xz);
 
     lcovFilter = ["/nix/store/*"] ++ lcovFilter;
 
diff --git a/pkgs/build-support/rust/build-rust-crate/build-crate.nix b/pkgs/build-support/rust/build-rust-crate/build-crate.nix
index 142109cef49f..84d1b2300f14 100644
--- a/pkgs/build-support/rust/build-rust-crate/build-crate.nix
+++ b/pkgs/build-support/rust/build-rust-crate/build-crate.nix
@@ -15,7 +15,7 @@
       ++ [(mkRustcDepArgs dependencies crateRenames)]
       ++ [(mkRustcFeatureArgs crateFeatures)]
       ++ extraRustcOpts
-      ++ lib.optional (stdenv.hostPlatform != stdenv.buildPlatform) "--target ${rust.toRustTarget stdenv.hostPlatform} -C linker=${stdenv.hostPlatform.config}-gcc"
+      ++ lib.optional (stdenv.hostPlatform != stdenv.buildPlatform) "--target ${rust.toRustTargetSpec stdenv.hostPlatform} -C linker=${stdenv.hostPlatform.config}-gcc"
       # since rustc 1.42 the "proc_macro" crate is part of the default crate prelude
       # https://github.com/rust-lang/cargo/commit/4d64eb99a4#diff-7f98585dbf9d30aa100c8318e2c77e79R1021-R1022
       ++ lib.optional (lib.elem "proc-macro" crateType) "--extern proc_macro"
diff --git a/pkgs/build-support/rust/build-rust-crate/configure-crate.nix b/pkgs/build-support/rust/build-rust-crate/configure-crate.nix
index 18587f7047c4..d1010ac1adb3 100644
--- a/pkgs/build-support/rust/build-rust-crate/configure-crate.nix
+++ b/pkgs/build-support/rust/build-rust-crate/configure-crate.nix
@@ -135,8 +135,8 @@ in ''
   export CARGO_MANIFEST_DIR=$(pwd)
   export DEBUG="${toString (!release)}"
   export OPT_LEVEL="${toString optLevel}"
-  export TARGET="${rust.toRustTarget stdenv.hostPlatform}"
-  export HOST="${rust.toRustTarget stdenv.buildPlatform}"
+  export TARGET="${rust.toRustTargetSpec stdenv.hostPlatform}"
+  export HOST="${rust.toRustTargetSpec stdenv.buildPlatform}"
   export PROFILE=${if release then "release" else "debug"}
   export OUT_DIR=$(pwd)/target/build/${crateName}.out
   export CARGO_PKG_VERSION_MAJOR=${lib.elemAt version 0}
@@ -144,7 +144,7 @@ in ''
   export CARGO_PKG_VERSION_PATCH=${lib.elemAt version 2}
   export CARGO_PKG_VERSION_PRE="${versionPre}"
   export CARGO_PKG_HOMEPAGE="${crateHomepage}"
-  export NUM_JOBS=1
+  export NUM_JOBS=$NIX_BUILD_CORES
   export RUSTC="rustc"
   export RUSTDOC="rustdoc"
 
diff --git a/pkgs/build-support/rust/build-rust-crate/default.nix b/pkgs/build-support/rust/build-rust-crate/default.nix
index 9d98e0851780..e605c9550e53 100644
--- a/pkgs/build-support/rust/build-rust-crate/default.nix
+++ b/pkgs/build-support/rust/build-rust-crate/default.nix
@@ -54,6 +54,10 @@ let
    };
 
    installCrate = import ./install-crate.nix { inherit stdenv; };
+
+   # Allow access to the rust attribute set from inside buildRustCrate, which
+   # has a parameter that shadows the name.
+   rustAttrs = rust;
 in
 
 /* The overridable pkgs.buildRustCrate function.
@@ -250,7 +254,7 @@ stdenv.mkDerivation (rec {
       depsMetadata = lib.foldl' (str: dep: str + dep.metadata) "" (dependencies ++ buildDependencies);
       hashedMetadata = builtins.hashString "sha256"
         (crateName + "-" + crateVersion + "___" + toString (mkRustcFeatureArgs crateFeatures) +
-          "___" + depsMetadata);
+          "___" + depsMetadata + "___" + rustAttrs.toRustTarget stdenv.hostPlatform);
       in lib.substring 0 10 hashedMetadata;
 
     build = crate.build or "";
diff --git a/pkgs/build-support/rust/build-rust-crate/test/default.nix b/pkgs/build-support/rust/build-rust-crate/test/default.nix
index f6cd54c4ee3e..65c8880b134d 100644
--- a/pkgs/build-support/rust/build-rust-crate/test/default.nix
+++ b/pkgs/build-support/rust/build-rust-crate/test/default.nix
@@ -146,12 +146,18 @@ let
         };
       in
       runCommand "assert-outputs-${name}" {
-      } ''
+      } (''
       local actualFiles=$(mktemp)
 
       cd "${crateOutput}"
-      find . -type f | sort >$actualFiles
-      diff -q ${expectedFilesFile} $actualFiles >/dev/null || {
+      find . -type f \
+        | sort \
+      ''
+      # sed out the hash because it differs per platform
+      + ''
+        | sed -E -e 's/-[0-9a-fA-F]{10}\.rlib/-HASH.rlib/g' \
+        > "$actualFiles"
+      diff -q ${expectedFilesFile} "$actualFiles" > /dev/null || {
         echo -e "\033[0;1;31mERROR: Difference in expected output files in ${crateOutput} \033[0m" >&2
         echo === Got:
         sed -e 's/^/  /' $actualFiles
@@ -164,7 +170,7 @@ let
         exit 1
       }
       touch $out
-      ''
+      '')
       ;
 
   in rec {
@@ -594,7 +600,7 @@ let
       };
       expectedFiles = [
         "./nix-support/propagated-build-inputs"
-        "./lib/libtest_lib-042a1fdbef.rlib"
+        "./lib/libtest_lib-HASH.rlib"
         "./lib/link"
       ];
     };
@@ -611,7 +617,7 @@ let
       };
       expectedFiles = [
         "./nix-support/propagated-build-inputs"
-        "./lib/libtest_lib-042a1fdbef.rlib"
+        "./lib/libtest_lib-HASH.rlib"
         "./lib/link"
       ];
     };
diff --git a/pkgs/build-support/rust/default-crate-overrides.nix b/pkgs/build-support/rust/default-crate-overrides.nix
index d0e69ad698a8..3d2dc3733c22 100644
--- a/pkgs/build-support/rust/default-crate-overrides.nix
+++ b/pkgs/build-support/rust/default-crate-overrides.nix
@@ -1,6 +1,7 @@
-{ stdenv, pkgconfig, curl, darwin, libiconv, libgit2, libssh2,
+{ lib, stdenv, pkg-config, curl, darwin, libiconv, libgit2, libssh2,
   openssl, sqlite, zlib, dbus, dbus-glib, gdk-pixbuf, cairo, python3,
-  libsodium, postgresql, gmp, foundationdb, ... }:
+  libsodium, postgresql, gmp, foundationdb, capnproto, nettle, clang,
+  llvmPackages, ... }:
 
 let
   inherit (darwin.apple_sdk.frameworks) CoreFoundation Security;
@@ -10,26 +11,30 @@ in
     buildInputs = [ cairo ];
   };
 
+  capnp-rpc = attrs: {
+    nativeBuildInputs = [ capnproto ];
+  };
+
   cargo = attrs: {
     buildInputs = [ openssl zlib curl ]
-      ++ stdenv.lib.optionals stdenv.isDarwin [ CoreFoundation Security libiconv ];
+      ++ lib.optionals stdenv.isDarwin [ CoreFoundation Security libiconv ];
   };
 
   libz-sys = attrs: {
-    nativeBuildInputs = [ pkgconfig ];
+    nativeBuildInputs = [ pkg-config ];
     buildInputs = [ zlib ];
     extraLinkFlags = ["-L${zlib.out}/lib"];
   };
 
   curl-sys = attrs: {
-    nativeBuildInputs = [ pkgconfig ];
+    nativeBuildInputs = [ pkg-config ];
     buildInputs = [ zlib curl ];
     propagatedBuildInputs = [ curl zlib ];
     extraLinkFlags = ["-L${zlib.out}/lib"];
   };
 
   dbus = attrs: {
-    nativeBuildInputs = [ pkgconfig ];
+    nativeBuildInputs = [ pkg-config ];
     buildInputs = [ dbus ];
   };
 
@@ -65,36 +70,42 @@ in
 
   libgit2-sys = attrs: {
     LIBGIT2_SYS_USE_PKG_CONFIG = true;
-    nativeBuildInputs = [ pkgconfig ];
+    nativeBuildInputs = [ pkg-config ];
     buildInputs = [ openssl zlib libgit2 ];
   };
 
   libsqlite3-sys = attrs: {
-    nativeBuildInputs = [ pkgconfig ];
+    nativeBuildInputs = [ pkg-config ];
     buildInputs = [ sqlite ];
   };
 
   libssh2-sys = attrs: {
-    nativeBuildInputs = [ pkgconfig ];
+    nativeBuildInputs = [ pkg-config ];
     buildInputs = [ openssl zlib libssh2 ];
   };
 
   libdbus-sys = attrs: {
-    nativeBuildInputs = [ pkgconfig ];
+    nativeBuildInputs = [ pkg-config ];
     buildInputs = [ dbus ];
   };
 
+  nettle-sys = attrs: {
+    nativeBuildInputs = [ pkg-config ];
+    buildInputs = [ nettle clang ];
+    LIBCLANG_PATH = "${llvmPackages.libclang}/lib";
+  };
+
   openssl = attrs: {
     buildInputs = [ openssl ];
   };
 
   openssl-sys = attrs: {
-    nativeBuildInputs = [ pkgconfig ];
+    nativeBuildInputs = [ pkg-config ];
     buildInputs = [ openssl ];
   };
 
   pq-sys = attr: {
-    nativeBuildInputs = [ pkgconfig ];
+    nativeBuildInputs = [ pkg-config ];
     buildInputs = [ postgresql ];
   };
 
@@ -107,12 +118,42 @@ in
     propagatedBuildInputs = [ Security ];
   };
 
+  sequoia-openpgp = attrs: {
+    buildInputs = [ gmp ];
+  };
+
+  sequoia-openpgp-ffi = attrs: {
+    buildInputs = [ gmp ];
+  };
+
+  sequoia-ipc = attrs: {
+    buildInputs = [ gmp ];
+  };
+
+  sequoia-guide = attrs: {
+    buildInputs = [ gmp ];
+  };
+
+  sequoia-store = attrs: {
+    nativeBuildInputs = [ capnproto ];
+    buildInputs = [ sqlite gmp ];
+  };
+
+  sequoia-sq = attrs: {
+    buildInputs = [ sqlite gmp ];
+  };
+
+  sequoia-tool = attrs: {
+    nativeBuildInputs = [ capnproto ];
+    buildInputs = [ sqlite gmp ];
+  };
+
   serde_derive = attrs: {
-    buildInputs = stdenv.lib.optional stdenv.isDarwin Security;
+    buildInputs = lib.optional stdenv.isDarwin Security;
   };
 
   thrussh-libsodium = attrs: {
-    nativeBuildInputs = [ pkgconfig ];
+    nativeBuildInputs = [ pkg-config ];
     buildInputs = [ libsodium ];
   };
 
diff --git a/pkgs/build-support/rust/default.nix b/pkgs/build-support/rust/default.nix
index f6177ce198da..dc86a7dc581f 100644
--- a/pkgs/build-support/rust/default.nix
+++ b/pkgs/build-support/rust/default.nix
@@ -1,9 +1,14 @@
 { stdenv
+, lib
 , buildPackages
 , cacert
 , cargo
 , diffutils
 , fetchCargoTarball
+, runCommandNoCC
+, rustPlatform
+, callPackage
+, remarshal
 , git
 , rust
 , rustc
@@ -11,7 +16,13 @@
 }:
 
 { name ? "${args.pname}-${args.version}"
-, cargoSha256 ? "unset"
+
+  # SRI hash
+, cargoHash ? ""
+
+  # Legacy hash
+, cargoSha256 ? ""
+
 , src ? null
 , srcs ? null
 , unpackPhase ? null
@@ -26,12 +37,15 @@
 , cargoBuildFlags ? []
 , buildType ? "release"
 , meta ? {}
-, target ? null
+, target ? rust.toRustTargetSpec stdenv.hostPlatform
 , cargoVendorDir ? null
 , checkType ? buildType
 , depsExtraArgs ? {}
 , cargoParallelTestThreads ? true
 
+# Toggles whether a custom sysroot is created when the target is a .json file.
+, __internal_dontAddSysroot ? false
+
 # Needed to `pushd`/`popd` into a subdir of a tarball if this subdir
 # contains a Cargo.toml, but isn't part of a workspace (which is e.g. the
 # case for `rustfmt`/etc from the `rust-sources).
@@ -39,7 +53,7 @@
 , buildAndTestSubdir ? null
 , ... } @ args:
 
-assert cargoVendorDir == null -> cargoSha256 != "unset";
+assert cargoVendorDir == null -> !(cargoSha256 == "" && cargoHash == "");
 assert buildType == "release" || buildType == "debug";
 
 let
@@ -47,6 +61,7 @@ let
   cargoDeps = if cargoVendorDir == null
     then fetchCargoTarball ({
         inherit name src srcs sourceRoot unpackPhase cargoUpdateHook;
+        hash = cargoHash;
         patches = cargoPatches;
         sha256 = cargoSha256;
       } // depsExtraArgs)
@@ -54,7 +69,7 @@ let
 
   # If we have a cargoSha256 fixed-output derivation, validate it at build time
   # against the src fixed-output derivation to check consistency.
-  validateCargoDeps = cargoSha256 != "unset";
+  validateCargoDeps = !(cargoHash == "" && cargoSha256 == "");
 
   # Some cargo builds include build hooks that modify their own vendor
   # dependencies. This copies the vendor directory into the build tree and makes
@@ -69,13 +84,26 @@ let
       cargoDepsCopy="$sourceRoot/${cargoVendorDir}"
     '';
 
-  rustTarget = if target == null then rust.toRustTarget stdenv.hostPlatform else target;
+  targetIsJSON = lib.hasSuffix ".json" target;
+  useSysroot = targetIsJSON && !__internal_dontAddSysroot;
+
+  # see https://github.com/rust-lang/cargo/blob/964a16a28e234a3d397b2a7031d4ab4a428b1391/src/cargo/core/compiler/compile_kind.rs#L151-L168
+  # the "${}" is needed to transform the path into a /nix/store path before baseNameOf
+  shortTarget = if targetIsJSON then
+      (lib.removeSuffix ".json" (builtins.baseNameOf "${target}"))
+    else target;
+
+  sysroot = (callPackage ./sysroot {}) {
+    inherit target shortTarget;
+    RUSTFLAGS = args.RUSTFLAGS or "";
+    originalCargoToml = src + /Cargo.toml; # profile info is later extracted
+  };
 
   ccForBuild="${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}cc";
   cxxForBuild="${buildPackages.stdenv.cc}/bin/${buildPackages.stdenv.cc.targetPrefix}c++";
   ccForHost="${stdenv.cc}/bin/${stdenv.cc.targetPrefix}cc";
   cxxForHost="${stdenv.cc}/bin/${stdenv.cc.targetPrefix}c++";
-  releaseDir = "target/${rustTarget}/${buildType}";
+  releaseDir = "target/${shortTarget}/${buildType}";
   tmpDir = "${releaseDir}-tmp";
 
   # Specify the stdenv's `diff` by abspath to ensure that the user's build
@@ -85,13 +113,19 @@ let
 
 in
 
-stdenv.mkDerivation ((removeAttrs args ["depsExtraArgs"]) // {
+# Tests don't currently work for `no_std`, and all custom sysroots are currently built without `std`.
+# See https://os.phil-opp.com/testing/ for more information.
+assert useSysroot -> !(args.doCheck or true);
+
+stdenv.mkDerivation ((removeAttrs args ["depsExtraArgs"]) // lib.optionalAttrs useSysroot {
+  RUSTFLAGS = "--sysroot ${sysroot} " + (args.RUSTFLAGS or "");
+} // {
   inherit cargoDeps;
 
   patchRegistryDeps = ./patch-registry-deps;
 
   nativeBuildInputs = nativeBuildInputs ++ [ cacert git cargo rustc ];
-  buildInputs = buildInputs ++ stdenv.lib.optional stdenv.hostPlatform.isMinGW windows.pthreads;
+  buildInputs = buildInputs ++ lib.optional stdenv.hostPlatform.isMinGW windows.pthreads;
 
   patches = cargoPatches ++ patches;
 
@@ -114,11 +148,11 @@ stdenv.mkDerivation ((removeAttrs args ["depsExtraArgs"]) // {
     cat >> .cargo/config <<'EOF'
     [target."${rust.toRustTarget stdenv.buildPlatform}"]
     "linker" = "${ccForBuild}"
-    ${stdenv.lib.optionalString (stdenv.buildPlatform.config != stdenv.hostPlatform.config) ''
-    [target."${rustTarget}"]
+    ${lib.optionalString (stdenv.buildPlatform.config != stdenv.hostPlatform.config) ''
+    [target."${shortTarget}"]
     "linker" = "${ccForHost}"
     ${# https://github.com/rust-lang/rust/issues/46651#issuecomment-433611633
-      stdenv.lib.optionalString (stdenv.hostPlatform.isMusl && stdenv.hostPlatform.isAarch64) ''
+      lib.optionalString (stdenv.hostPlatform.isMusl && stdenv.hostPlatform.isAarch64) ''
     "rustflags" = [ "-C", "target-feature=+crt-static", "-C", "link-arg=-lgcc" ]
     ''}
     ''}
@@ -130,7 +164,7 @@ stdenv.mkDerivation ((removeAttrs args ["depsExtraArgs"]) // {
   # After unpacking and applying patches, check that the Cargo.lock matches our
   # src package. Note that we do this after the patchPhase, because the
   # patchPhase may create the Cargo.lock if upstream has not shipped one.
-  postPatch = (args.postPatch or "") + stdenv.lib.optionalString validateCargoDeps ''
+  postPatch = (args.postPatch or "") + lib.optionalString validateCargoDeps ''
     cargoDepsLockfile=$NIX_BUILD_TOP/$cargoDepsCopy/Cargo.lock
     srcLockfile=$NIX_BUILD_TOP/$sourceRoot/Cargo.lock
 
@@ -173,7 +207,7 @@ stdenv.mkDerivation ((removeAttrs args ["depsExtraArgs"]) // {
   '';
 
   buildPhase = with builtins; args.buildPhase or ''
-    ${stdenv.lib.optionalString (buildAndTestSubdir != null) "pushd ${buildAndTestSubdir}"}
+    ${lib.optionalString (buildAndTestSubdir != null) "pushd ${buildAndTestSubdir}"}
     runHook preBuild
 
     (
@@ -184,14 +218,14 @@ stdenv.mkDerivation ((removeAttrs args ["depsExtraArgs"]) // {
       "CC_${rust.toRustTarget stdenv.hostPlatform}"="${ccForHost}" \
       "CXX_${rust.toRustTarget stdenv.hostPlatform}"="${cxxForHost}" \
       cargo build -j $NIX_BUILD_CORES \
-        ${stdenv.lib.optionalString (buildType == "release") "--release"} \
-        --target ${rustTarget} \
+        ${lib.optionalString (buildType == "release") "--release"} \
+        --target ${target} \
         --frozen ${concatStringsSep " " cargoBuildFlags}
     )
 
     runHook postBuild
 
-    ${stdenv.lib.optionalString (buildAndTestSubdir != null) "popd"}
+    ${lib.optionalString (buildAndTestSubdir != null) "popd"}
 
     # This needs to be done after postBuild: packages like `cargo` do a pushd/popd in
     # the pre/postBuild-hooks that need to be taken into account before gathering
@@ -205,15 +239,15 @@ stdenv.mkDerivation ((removeAttrs args ["depsExtraArgs"]) // {
   '';
 
   checkPhase = args.checkPhase or (let
-    argstr = "${stdenv.lib.optionalString (checkType == "release") "--release"} --target ${rustTarget} --frozen";
+    argstr = "${lib.optionalString (checkType == "release") "--release"} --target ${target} --frozen";
     threads = if cargoParallelTestThreads then "$NIX_BUILD_CORES" else "1";
   in ''
-    ${stdenv.lib.optionalString (buildAndTestSubdir != null) "pushd ${buildAndTestSubdir}"}
+    ${lib.optionalString (buildAndTestSubdir != null) "pushd ${buildAndTestSubdir}"}
     runHook preCheck
     echo "Running cargo test ${argstr} -- ''${checkFlags} ''${checkFlagsArray+''${checkFlagsArray[@]}}"
     cargo test -j $NIX_BUILD_CORES ${argstr} -- --test-threads=${threads} ''${checkFlags} ''${checkFlagsArray+"''${checkFlagsArray[@]}"}
     runHook postCheck
-    ${stdenv.lib.optionalString (buildAndTestSubdir != null) "popd"}
+    ${lib.optionalString (buildAndTestSubdir != null) "popd"}
   '');
 
   doCheck = args.doCheck or true;
diff --git a/pkgs/build-support/rust/fetchCargoTarball.nix b/pkgs/build-support/rust/fetchCargoTarball.nix
index dff5d99da9eb..c30e88d99b83 100644
--- a/pkgs/build-support/rust/fetchCargoTarball.nix
+++ b/pkgs/build-support/rust/fetchCargoTarball.nix
@@ -1,4 +1,4 @@
-{ stdenv, cacert, git, cargo, python3 }:
+{ lib, stdenv, cacert, git, cargo, python3 }:
 let cargo-vendor-normalise = stdenv.mkDerivation {
   name = "cargo-vendor-normalise";
   src = ./cargo-vendor-normalise.py;
@@ -22,11 +22,17 @@ in
 , srcs ? []
 , patches ? []
 , sourceRoot
-, sha256
+, hash ? ""
+, sha256 ? ""
 , cargoUpdateHook ? ""
 , ...
 } @ args:
-stdenv.mkDerivation ({
+
+let hash_ =
+  if hash != "" then { outputHashAlgo = null; outputHash = hash; }
+  else if sha256 != "" then { outputHashAlgo = "sha256"; outputHash = sha256; }
+  else throw "fetchCargoTarball requires a hash for ${name}";
+in stdenv.mkDerivation ({
   name = "${name}-vendor.tar.gz";
   nativeBuildInputs = [ cacert git cargo-vendor-normalise cargo ];
 
@@ -40,7 +46,7 @@ stdenv.mkDerivation ({
         echo
         echo "ERROR: The Cargo.lock file doesn't exist"
         echo
-        echo "Cargo.lock is needed to make sure that cargoSha256 doesn't change"
+        echo "Cargo.lock is needed to make sure that cargoHash/cargoSha256 doesn't change"
         echo "when the registry is updated."
         echo
 
@@ -72,10 +78,9 @@ stdenv.mkDerivation ({
         -czf $out $name
   '';
 
-  outputHashAlgo = "sha256";
-  outputHash = sha256;
+  inherit (hash_) outputHashAlgo outputHash;
 
-  impureEnvVars = stdenv.lib.fetchers.proxyImpureEnvVars;
+  impureEnvVars = lib.fetchers.proxyImpureEnvVars;
 } // (builtins.removeAttrs args [
   "name" "sha256" "cargoUpdateHook"
 ]))
diff --git a/pkgs/build-support/rust/sysroot/Cargo.lock b/pkgs/build-support/rust/sysroot/Cargo.lock
new file mode 100644
index 000000000000..61fcef61744e
--- /dev/null
+++ b/pkgs/build-support/rust/sysroot/Cargo.lock
@@ -0,0 +1,29 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "alloc"
+version = "0.0.0"
+dependencies = [
+ "compiler_builtins",
+ "core",
+]
+
+[[package]]
+name = "compiler_builtins"
+version = "0.1.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cd0782e0a7da7598164153173e5a5d4d9b1da094473c98dce0ff91406112369"
+dependencies = [
+ "rustc-std-workspace-core",
+]
+
+[[package]]
+name = "core"
+version = "0.0.0"
+
+[[package]]
+name = "rustc-std-workspace-core"
+version = "1.99.0"
+dependencies = [
+ "core",
+]
diff --git a/pkgs/build-support/rust/sysroot/cargo.py b/pkgs/build-support/rust/sysroot/cargo.py
new file mode 100644
index 000000000000..09f6fba6d1c8
--- /dev/null
+++ b/pkgs/build-support/rust/sysroot/cargo.py
@@ -0,0 +1,45 @@
+import os
+import toml
+
+rust_src = os.environ['RUSTC_SRC']
+orig_cargo = os.environ['ORIG_CARGO'] if 'ORIG_CARGO' in os.environ else None
+
+base = {
+  'package': {
+    'name': 'alloc',
+    'version': '0.0.0',
+    'authors': ['The Rust Project Developers'],
+    'edition': '2018',
+  },
+  'dependencies': {
+    'compiler_builtins': {
+      'version': '0.1.0',
+      'features': ['rustc-dep-of-std', 'mem'],
+    },
+    'core': {
+      'path': os.path.join(rust_src, 'libcore'),
+    },
+  },
+  'lib': {
+    'name': 'alloc',
+    'path': os.path.join(rust_src, 'liballoc/lib.rs'),
+  },
+  'patch': {
+    'crates-io': {
+      'rustc-std-workspace-core': {
+        'path': os.path.join(rust_src, 'tools/rustc-std-workspace-core'),
+      },
+    },
+  },
+}
+
+if orig_cargo is not None:
+  with open(orig_cargo, 'r') as f:
+    src = toml.loads(f.read())
+    if 'profile' in src:
+      base['profile'] = src['profile']
+
+out = toml.dumps(base)
+
+with open('Cargo.toml', 'x') as f:
+  f.write(out)
diff --git a/pkgs/build-support/rust/sysroot/default.nix b/pkgs/build-support/rust/sysroot/default.nix
new file mode 100644
index 000000000000..4db7cf0dc392
--- /dev/null
+++ b/pkgs/build-support/rust/sysroot/default.nix
@@ -0,0 +1,41 @@
+{ stdenv, rust, rustPlatform, buildPackages }:
+
+{ shortTarget, originalCargoToml, target, RUSTFLAGS }:
+
+let
+  cargoSrc = stdenv.mkDerivation {
+    name = "cargo-src";
+    preferLocalBuild = true;
+    phases = [ "installPhase" ];
+    installPhase = ''
+      RUSTC_SRC=${rustPlatform.rustcSrc.override { minimalContent = false; }} ORIG_CARGO=${originalCargoToml} \
+        ${buildPackages.python3.withPackages (ps: with ps; [ toml ])}/bin/python3 ${./cargo.py}
+      mkdir -p $out
+      cp Cargo.toml $out/Cargo.toml
+      cp ${./Cargo.lock} $out/Cargo.lock
+    '';
+  };
+in rustPlatform.buildRustPackage {
+  inherit target RUSTFLAGS;
+
+  name = "custom-sysroot";
+  src =  cargoSrc;
+
+  RUSTC_BOOTSTRAP = 1;
+  __internal_dontAddSysroot = true;
+  cargoSha256 = "0y6dqfhsgk00y3fv5bnjzk0s7i30nwqc1rp0xlrk83hkh80x81mw";
+
+  doCheck = false;
+
+  installPhase = ''
+    export LIBS_DIR=$out/lib/rustlib/${shortTarget}/lib
+    mkdir -p $LIBS_DIR
+    for f in target/${shortTarget}/release/deps/*.{rlib,rmeta}; do
+      cp $f $LIBS_DIR
+    done
+
+    export RUST_SYSROOT=$(rustc --print=sysroot)
+    host=${rust.toRustTarget stdenv.buildPlatform}
+    cp -r $RUST_SYSROOT/lib/rustlib/$host $out
+  '';
+}
diff --git a/pkgs/build-support/rust/sysroot/update-lockfile.sh b/pkgs/build-support/rust/sysroot/update-lockfile.sh
new file mode 100755
index 000000000000..83d29832384f
--- /dev/null
+++ b/pkgs/build-support/rust/sysroot/update-lockfile.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env nix-shell
+#!nix-shell -i bash -p python3 python3.pkgs.toml cargo
+
+set -e
+
+HERE=$(dirname "${BASH_SOURCE[0]}")
+NIXPKGS_ROOT="$HERE/../../../.."
+
+# https://unix.stackexchange.com/a/84980/390173
+tempdir=$(mktemp -d 2>/dev/null || mktemp -d -t 'update-lockfile')
+
+cd "$tempdir"
+nix-build -E "with import (/. + \"${NIXPKGS_ROOT}\") {}; pkgs.rustPlatform.rustcSrc.override { minimalContent = false; }"
+RUSTC_SRC="$(pwd)/result" python3 "$HERE/cargo.py"
+RUSTC_BOOTSTRAP=1 cargo build || echo "Build failure is expected. All that's needed is the lockfile."
+
+cp Cargo.lock "$HERE"
+
+rm -rf "$tempdir"
+
+
diff --git a/pkgs/build-support/setup-hooks/auto-patchelf.sh b/pkgs/build-support/setup-hooks/auto-patchelf.sh
index 4f7c0c14304c..511371931de8 100644
--- a/pkgs/build-support/setup-hooks/auto-patchelf.sh
+++ b/pkgs/build-support/setup-hooks/auto-patchelf.sh
@@ -1,9 +1,20 @@
+#!/usr/bin/env bash
+
 declare -a autoPatchelfLibs
+declare -Ag autoPatchelfFailedDeps
 
 gatherLibraries() {
     autoPatchelfLibs+=("$1/lib")
 }
 
+# wrapper around patchelf to raise proper error messages
+# containing the tried file name and command
+runPatchelf() {
+  patchelf "$@" || (echo "Command failed: patchelf $*" && exit 1)
+}
+
+# shellcheck disable=SC2154
+# (targetOffset is referenced but not assigned.)
 addEnvHooks "$targetOffset" gatherLibraries
 
 isExecutable() {
@@ -23,14 +34,19 @@ isExecutable() {
 
 # We cache dependencies so that we don't need to search through all of them on
 # every consecutive call to findDependency.
-declare -a cachedDependencies
+declare -Ag autoPatchelfCachedDepsAssoc
+declare -ag autoPatchelfCachedDeps
+
 
 addToDepCache() {
-    local existing
-    for existing in "${cachedDependencies[@]}"; do
-        if [ "$existing" = "$1" ]; then return; fi
-    done
-    cachedDependencies+=("$1")
+    if [[ ${autoPatchelfCachedDepsAssoc[$1]+f} ]]; then return; fi
+
+    # store deps in an assoc. array for efficient lookups
+    # otherwise findDependency would have quadratic complexity
+    autoPatchelfCachedDepsAssoc["$1"]=""
+
+    # also store deps in normal array to maintain their order
+    autoPatchelfCachedDeps+=("$1")
 }
 
 declare -gi depCacheInitialised=0
@@ -43,9 +59,8 @@ getDepsFromSo() {
 
 populateCacheWithRecursiveDeps() {
     local so found foundso
-    for so in "${cachedDependencies[@]}"; do
+    for so in "${autoPatchelfCachedDeps[@]}"; do
         for found in $(getDepsFromSo "$so"); do
-            local libdir="${found%/*}"
             local base="${found##*/}"
             local soname="${base%.so*}"
             for foundso in "${found%/*}/$soname".so*; do
@@ -76,7 +91,7 @@ findDependency() {
         depCacheInitialised=1
     fi
 
-    for dep in "${cachedDependencies[@]}"; do
+    for dep in "${autoPatchelfCachedDeps[@]}"; do
         if [ "$filename" = "${dep##*/}" ]; then
             if [ "$(getSoArch "$dep")" = "$arch" ]; then
                 foundDependency="$dep"
@@ -101,9 +116,12 @@ findDependency() {
 autoPatchelfFile() {
     local dep rpath="" toPatch="$1"
 
-    local interpreter="$(< "$NIX_CC/nix-support/dynamic-linker")"
+    local interpreter
+    interpreter="$(< "$NIX_CC/nix-support/dynamic-linker")"
     if isExecutable "$toPatch"; then
-        patchelf --set-interpreter "$interpreter" "$toPatch"
+        runPatchelf --set-interpreter "$interpreter" "$toPatch"
+        # shellcheck disable=SC2154
+        # (runtimeDependencies is referenced but not assigned.)
         if [ -n "$runtimeDependencies" ]; then
             for dep in $runtimeDependencies; do
                 rpath="$rpath${rpath:+:}$dep/lib"
@@ -115,17 +133,19 @@ autoPatchelfFile() {
 
     # We're going to find all dependencies based on ldd output, so we need to
     # clear the RPATH first.
-    patchelf --remove-rpath "$toPatch"
+    runPatchelf --remove-rpath "$toPatch"
 
-    local missing="$(
+    # If the file is not a dynamic executable, ldd/sed will fail,
+    # in which case we return, since there is nothing left to do.
+    local missing
+    missing="$(
         ldd "$toPatch" 2> /dev/null | \
             sed -n -e 's/^[\t ]*\([^ ]\+\) => not found.*/\1/p'
-    )"
+    )" || return 0
 
     # This ensures that we get the output of all missing dependencies instead
     # of failing at the first one, because it's more useful when working on a
     # new package where you don't yet know its dependencies.
-    local -i depNotFound=0
 
     for dep in $missing; do
         echo -n "  $dep -> " >&2
@@ -134,18 +154,13 @@ autoPatchelfFile() {
             echo "found: $foundDependency" >&2
         else
             echo "not found!" >&2
-            depNotFound=1
+            autoPatchelfFailedDeps["$dep"]="$toPatch"
         fi
     done
 
-    # This makes sure the builder fails if we didn't find a dependency, because
-    # the stdenv setup script is run with set -e. The actual error is emitted
-    # earlier in the previous loop.
-    [ $depNotFound -eq 0 -o -n "$autoPatchelfIgnoreMissingDeps" ]
-
     if [ -n "$rpath" ]; then
         echo "setting RPATH to: $rpath" >&2
-        patchelf --set-rpath "$rpath" "$toPatch"
+        runPatchelf --set-rpath "$rpath" "$toPatch"
     fi
 }
 
@@ -168,10 +183,10 @@ addAutoPatchelfSearchPath() {
         esac
     done
 
-    cachedDependencies+=(
-        $(find "$@" "${findOpts[@]}" \! -type d \
-               \( -name '*.so' -o -name '*.so.*' \))
-    )
+    while IFS= read -r -d '' file; do
+    addToDepCache "$file"
+    done <  <(find "$@" "${findOpts[@]}" \! -type d \
+            \( -name '*.so' -o -name '*.so.*' \) -print0)
 }
 
 autoPatchelf() {
@@ -197,14 +212,9 @@ autoPatchelf() {
     echo "automatically fixing dependencies for ELF files" >&2
 
     # Add all shared objects of the current output path to the start of
-    # cachedDependencies so that it's choosen first in findDependency.
+    # autoPatchelfCachedDeps so that it's chosen first in findDependency.
     addAutoPatchelfSearchPath ${norecurse:+--no-recurse} -- "$@"
 
-    # Here we actually have a subshell, which also means that
-    # $cachedDependencies is final at this point, so whenever we want to run
-    # findDependency outside of this, the dependency cache needs to be rebuilt
-    # from scratch, so keep this in mind if you want to run findDependency
-    # outside of this function.
     while IFS= read -r -d $'\0' file; do
       isELF "$file" || continue
       segmentHeaders="$(LANG=C $READELF -l "$file")"
@@ -215,8 +225,26 @@ autoPatchelf() {
           # Skip if the executable is statically linked.
           [ -n "$(echo "$segmentHeaders" | grep "^ *INTERP\\>")" ] || continue
       fi
+      # Jump file if patchelf is unable to parse it
+      # Some programs contain binary blobs for testing,
+      # which are identified as ELF but fail to be parsed by patchelf
+      patchelf "$file" || continue
       autoPatchelfFile "$file"
     done < <(find "$@" ${norecurse:+-maxdepth 1} -type f -print0)
+
+    # fail if any dependencies were not found and
+    # autoPatchelfIgnoreMissingDeps is not set
+    local depsMissing=0
+    for failedDep in "${!autoPatchelfFailedDeps[@]}"; do
+      echo "autoPatchelfHook could not satisfy dependency $failedDep wanted by ${autoPatchelfFailedDeps[$failedDep]}"
+      depsMissing=1
+    done
+    # shellcheck disable=SC2154
+    # (autoPatchelfIgnoreMissingDeps is referenced but not assigned.)
+    if [[ $depsMissing == 1 && -z "$autoPatchelfIgnoreMissingDeps" ]]; then
+      echo "Add the missing dependencies to the build inputs or set autoPatchelfIgnoreMissingDeps=true"
+      exit 1
+    fi
 }
 
 # XXX: This should ultimately use fixupOutputHooks but we currently don't have
diff --git a/pkgs/build-support/setup-hooks/compress-man-pages.sh b/pkgs/build-support/setup-hooks/compress-man-pages.sh
index 82e48cd8aa77..f5af76e8168f 100644
--- a/pkgs/build-support/setup-hooks/compress-man-pages.sh
+++ b/pkgs/build-support/setup-hooks/compress-man-pages.sh
@@ -21,6 +21,7 @@ compressManPages() {
 
     # Point symlinks to compressed manpages.
     find "$dir"/share/man/ -type l -a '!' -regex '.*\.\(bz2\|gz\)$' -print0 \
+        | sort -z \
         | while IFS= read -r -d $'\0' f
     do
         local target
diff --git a/pkgs/build-support/setup-hooks/copy-desktop-items.sh b/pkgs/build-support/setup-hooks/copy-desktop-items.sh
new file mode 100644
index 000000000000..f96a10f33d5c
--- /dev/null
+++ b/pkgs/build-support/setup-hooks/copy-desktop-items.sh
@@ -0,0 +1,42 @@
+# shellcheck shell=bash
+
+# Setup hook that installs specified desktop items.
+#
+# Example usage in a derivation:
+#
+#   { …, makeDesktopItem, copyDesktopItems, … }:
+#
+#   let desktopItem = makeDesktopItem { … }; in
+#   stdenv.mkDerivation {
+#     …
+#     nativeBuildInputs = [ copyDesktopItems ];
+#
+#     desktopItems =  [ desktopItem ];
+#     …
+#   }
+#
+# This hook will copy files which are either given by full path
+# or all '*.desktop' files placed inside the 'share/applications'
+# folder of each `desktopItems` argument.
+
+postInstallHooks+=(copyDesktopItems)
+
+copyDesktopItems() {
+    if [ "${dontCopyDesktopItems-}" = 1 ]; then return; fi
+
+    if [ -z "$desktopItems" ]; then
+        return
+    fi
+
+    for desktopItem in $desktopItems; do
+        if [[ -f "$desktopItem" ]]; then
+            echo "Copying '$f' into '$out/share/applications'"
+            install -D -m 444 -t "$out"/share/applications "$f"
+        else
+            for f in "$desktopItem"/share/applications/*.desktop; do
+                echo "Copying '$f' into '$out/share/applications'"
+                install -D -m 444 -t "$out"/share/applications "$f"
+            done
+        fi
+    done
+}
diff --git a/pkgs/build-support/setup-hooks/reproducible-builds.sh b/pkgs/build-support/setup-hooks/reproducible-builds.sh
new file mode 100644
index 000000000000..5b01c213fe4a
--- /dev/null
+++ b/pkgs/build-support/setup-hooks/reproducible-builds.sh
@@ -0,0 +1,9 @@
+# Use the last part of the out path as hash input for the build.
+# This should ensure that it is deterministic across rebuilds of the same
+# derivation and not easily collide with other builds.
+# We also truncate the hash so that it cannot cause reference cycles.
+export NIX_CFLAGS_COMPILE+=" -frandom-seed=$(
+    outbase="${out##*/}"
+    randomseed="${outbase:0:10}"
+    echo $randomseed
+)"
diff --git a/pkgs/build-support/setup-hooks/strip.sh b/pkgs/build-support/setup-hooks/strip.sh
index f5fa9378fd7e..c31a50eba57b 100644
--- a/pkgs/build-support/setup-hooks/strip.sh
+++ b/pkgs/build-support/setup-hooks/strip.sh
@@ -51,7 +51,7 @@ stripDirs() {
 
     if [ -n "${dirs}" ]; then
         header "stripping (with command $cmd and flags $stripFlags) in$dirs"
-        find $dirs -type f -print0 | xargs -0 ${xargsFlags:--r} $cmd $commonStripFlags $stripFlags 2>/dev/null || true
+        find $dirs -type f -exec $cmd $commonStripFlags $stripFlags '{}' \; 2>/dev/null
         stopNest
     fi
 }
diff --git a/pkgs/build-support/setup-hooks/wrap-gapps-hook/default.nix b/pkgs/build-support/setup-hooks/wrap-gapps-hook/default.nix
index 5a87893d9726..d0ea088bf71e 100644
--- a/pkgs/build-support/setup-hooks/wrap-gapps-hook/default.nix
+++ b/pkgs/build-support/setup-hooks/wrap-gapps-hook/default.nix
@@ -3,6 +3,7 @@
 , makeSetupHook
 , makeWrapper
 , gobject-introspection
+, isGraphical ? true
 , gtk3
 , librsvg
 , dconf
@@ -21,7 +22,7 @@ makeSetupHook {
     # Unfortunately, it also requires the user to have dconf
     # D-Bus service enabled globally (e.g. through a NixOS module).
     dconf.lib
-  ] ++ [
+  ] ++ lib.optionals isGraphical [
     # TODO: remove this, packages should depend on GTK explicitly.
     gtk3
 
@@ -30,6 +31,7 @@ makeSetupHook {
     # graphics in GTK (e.g. cross for closing window in window title bar)
     # so it is pretty much required for applications using GTK.
     librsvg
+  ] ++ [
 
     # We use the wrapProgram function.
     makeWrapper
diff --git a/pkgs/build-support/singularity-tools/default.nix b/pkgs/build-support/singularity-tools/default.nix
index d937ec626682..318f5b430fef 100644
--- a/pkgs/build-support/singularity-tools/default.nix
+++ b/pkgs/build-support/singularity-tools/default.nix
@@ -1,4 +1,5 @@
 { runCommand
+, lib
 , stdenv
 , storeDir ? builtins.storeDir
 , writeScript
@@ -7,7 +8,7 @@
 , bash
 , vmTools
 , gawk
-, utillinux
+, util-linux
 , runtimeShell
 , e2fsprogs }:
 
@@ -47,7 +48,7 @@ rec {
         runScriptFile = shellScript "run-script.sh" runScript;
         result = vmTools.runInLinuxVM (
           runCommand "singularity-image-${name}.img" {
-            buildInputs = [ singularity e2fsprogs utillinux gawk ];
+            buildInputs = [ singularity e2fsprogs util-linux gawk ];
             layerClosure = writeReferencesToFile layer;
             preVM = vmTools.createEmptyImage {
               size = diskSize;
@@ -64,7 +65,7 @@ rec {
             mkdir proc sys dev
 
             # Run root script
-            ${stdenv.lib.optionalString (runAsRoot != null) ''
+            ${lib.optionalString (runAsRoot != null) ''
               mkdir -p ./${storeDir}
               mount --rbind ${storeDir} ./${storeDir}
               unshare -imnpuf --mount-proc chroot ./ ${runAsRootFile}
diff --git a/pkgs/build-support/skaware/build-skaware-package.nix b/pkgs/build-support/skaware/build-skaware-package.nix
index e6e2e35789bc..7a5db942b2cb 100644
--- a/pkgs/build-support/skaware/build-skaware-package.nix
+++ b/pkgs/build-support/skaware/build-skaware-package.nix
@@ -1,6 +1,5 @@
-{ stdenv, cleanPackaging, fetchurl }:
-let lib = stdenv.lib;
-in {
+{ lib, stdenv, cleanPackaging, fetchurl }:
+{
   # : string
   pname
   # : string
@@ -98,7 +97,7 @@ in stdenv.mkDerivation {
   meta = {
     homepage = "https://skarnet.org/software/${pname}/";
     inherit description platforms;
-    license = stdenv.lib.licenses.isc;
+    license = lib.licenses.isc;
     maintainers = with lib.maintainers;
       [ pmahoney Profpatsch ] ++ maintainers;
   };
diff --git a/pkgs/build-support/skaware/clean-packaging.nix b/pkgs/build-support/skaware/clean-packaging.nix
index 762fe25c0acf..d51cbec8aeb2 100644
--- a/pkgs/build-support/skaware/clean-packaging.nix
+++ b/pkgs/build-support/skaware/clean-packaging.nix
@@ -3,12 +3,12 @@
 # files were either discarded or moved to outputs.
 # This ensures nothing is forgotten and new files
 # are correctly handled on update.
-{ stdenv, file, writeScript }:
+{ lib, stdenv, file, writeScript }:
 
 let
-  globWith = stdenv.lib.concatMapStringsSep "\n";
+  globWith = lib.concatMapStringsSep "\n";
   rmNoise = noiseGlobs: globWith (f:
-    ''rm -rf ${f}'') noiseGlobs;
+    "rm -rf ${f}") noiseGlobs;
   mvDoc = docGlobs: globWith
     (f: ''mv ${f} "$DOCDIR" 2>/dev/null || true'')
     docGlobs;
diff --git a/pkgs/build-support/substitute-files/substitute-all-files.nix b/pkgs/build-support/substitute-files/substitute-all-files.nix
index 66feb695c418..682e976dcfe5 100644
--- a/pkgs/build-support/substitute-files/substitute-all-files.nix
+++ b/pkgs/build-support/substitute-files/substitute-all-files.nix
@@ -1,10 +1,10 @@
-{ stdenv }:
+{ lib, stdenv }:
 
 args:
 
 stdenv.mkDerivation ({
   name = if args ? name then args.name else baseNameOf (toString args.src);
-  builder = with stdenv.lib; builtins.toFile "builder.sh" ''
+  builder = builtins.toFile "builder.sh" ''
     source $stdenv/setup
     set -o pipefail
 
@@ -13,7 +13,7 @@ stdenv.mkDerivation ({
     args=
 
     pushd "$src"
-    echo -ne "${concatStringsSep "\\0" args.files}" | xargs -0 -n1 -I {} -- find {} -type f -print0 | while read -d "" line; do
+    echo -ne "${lib.concatStringsSep "\\0" args.files}" | xargs -0 -n1 -I {} -- find {} -type f -print0 | while read -d "" line; do
       mkdir -p "$out/$(dirname "$line")"
       substituteAll "$line" "$out/$line"
     done
diff --git a/pkgs/build-support/templaterpm/default.nix b/pkgs/build-support/templaterpm/default.nix
index 30465c740e53..ffe5b0b45816 100644
--- a/pkgs/build-support/templaterpm/default.nix
+++ b/pkgs/build-support/templaterpm/default.nix
@@ -1,4 +1,4 @@
-{stdenv, makeWrapper, python, toposort, rpm}:
+{lib, stdenv, makeWrapper, python, toposort, rpm}:
 
 stdenv.mkDerivation {
   pname = "nix-template-rpm";
@@ -15,10 +15,10 @@ stdenv.mkDerivation {
       --set PYTHONPATH "${rpm}/lib/${python.libPrefix}/site-packages":"${toposort}/lib/${python.libPrefix}/site-packages"
     '';
 
-  meta = with stdenv.lib; {
+  meta = with lib; {
     description = "Create templates of nix expressions from RPM .spec files";
     maintainers = with maintainers; [ tstrobel ];
-    platforms = with stdenv.lib.platforms; unix;
+    platforms = platforms.unix;
     hydraPlatforms = [];
   };
 }
diff --git a/pkgs/build-support/vm/deb/deb-closure.pl b/pkgs/build-support/vm/deb/deb-closure.pl
index bed397d6f07e..fe23025df1d8 100644
--- a/pkgs/build-support/vm/deb/deb-closure.pl
+++ b/pkgs/build-support/vm/deb/deb-closure.pl
@@ -50,7 +50,7 @@ sub getDeps {
 # virtual dependencies.
 my %provides;
 
-foreach my $cdata (values %packages) {
+foreach my $cdata (sort {$a->{Package} cmp $b->{Package}} (values %packages)) {
     if (defined $cdata->{Provides}) {
         my @provides = getDeps(Dpkg::Deps::deps_parse($cdata->{Provides}));
         foreach my $name (@provides) {
diff --git a/pkgs/build-support/vm/default.nix b/pkgs/build-support/vm/default.nix
index 909cdc6da044..759245aed1ae 100644
--- a/pkgs/build-support/vm/default.nix
+++ b/pkgs/build-support/vm/default.nix
@@ -1,6 +1,7 @@
-{ pkgs
+{ lib
+, pkgs
 , kernel ? pkgs.linux
-, img ? pkgs.stdenv.hostPlatform.platform.kernelTarget
+, img ? pkgs.stdenv.hostPlatform.linux-kernel.target
 , storeDir ? builtins.storeDir
 , rootModules ?
     [ "virtio_pci" "virtio_mmio" "virtio_blk" "virtio_balloon" "virtio_rng" "ext4" "unix" "9p" "9pnet_virtio" "crc32c_generic" ]
@@ -151,7 +152,7 @@ rec {
 
     # Set the system time from the hardware clock.  Works around an
     # apparent KVM > 1.5.2 bug.
-    ${pkgs.utillinux}/bin/hwclock -s
+    ${pkgs.util-linux}/bin/hwclock -s
 
     export NIX_STORE=${storeDir}
     export NIX_BUILD_TOP=/tmp
@@ -270,7 +271,7 @@ rec {
   defaultCreateRootFS = ''
     mkdir /mnt
     ${e2fsprogs}/bin/mkfs.ext4 /dev/${hd}
-    ${utillinux}/bin/mount -t ext4 /dev/${hd} /mnt
+    ${util-linux}/bin/mount -t ext4 /dev/${hd} /mnt
 
     if test -e /mnt/.debug; then
       exec ${bash}/bin/sh
@@ -317,7 +318,7 @@ rec {
     with pkgs; runInLinuxVM (
     stdenv.mkDerivation {
       name = "extract-file";
-      buildInputs = [ utillinux ];
+      buildInputs = [ util-linux ];
       buildCommand = ''
         ln -s ${kernel}/lib /lib
         ${kmod}/bin/modprobe loop
@@ -342,7 +343,7 @@ rec {
     with pkgs; runInLinuxVM (
     stdenv.mkDerivation {
       name = "extract-file-mtd";
-      buildInputs = [ utillinux mtdutils ];
+      buildInputs = [ util-linux mtdutils ];
       buildCommand = ''
         ln -s ${kernel}/lib /lib
         ${kmod}/bin/modprobe mtd
@@ -417,7 +418,7 @@ rec {
 
         # Make the Nix store available in /mnt, because that's where the RPMs live.
         mkdir -p /mnt${storeDir}
-        ${utillinux}/bin/mount -o bind ${storeDir} /mnt${storeDir}
+        ${util-linux}/bin/mount -o bind ${storeDir} /mnt${storeDir}
 
         # Newer distributions like Fedora 18 require /lib etc. to be
         # symlinked to /usr.
@@ -427,7 +428,7 @@ rec {
           ln -s /usr/sbin /mnt/sbin
           ln -s /usr/lib /mnt/lib
           ln -s /usr/lib64 /mnt/lib64
-          ${utillinux}/bin/mount -t proc none /mnt/proc
+          ${util-linux}/bin/mount -t proc none /mnt/proc
         ''}
 
         echo "unpacking RPMs..."
@@ -445,7 +446,7 @@ rec {
         PATH=/usr/bin:/bin:/usr/sbin:/sbin $chroot /mnt \
           rpm --initdb
 
-        ${utillinux}/bin/mount -o bind /tmp /mnt/tmp
+        ${util-linux}/bin/mount -o bind /tmp /mnt/tmp
 
         echo "installing RPMs..."
         PATH=/usr/bin:/bin:/usr/sbin:/sbin $chroot /mnt \
@@ -456,8 +457,8 @@ rec {
 
         rm /mnt/.debug
 
-        ${utillinux}/bin/umount /mnt${storeDir} /mnt/tmp ${lib.optionalString unifiedSystemDir "/mnt/proc"}
-        ${utillinux}/bin/umount /mnt
+        ${util-linux}/bin/umount /mnt${storeDir} /mnt/tmp ${lib.optionalString unifiedSystemDir "/mnt/proc"}
+        ${util-linux}/bin/umount /mnt
       '';
 
       passthru = { inherit fullName; };
@@ -572,7 +573,7 @@ rec {
       buildCommand = ''
         ${createRootFS}
 
-        PATH=$PATH:${stdenv.lib.makeBinPath [ dpkg dpkg glibc lzma ]}
+        PATH=$PATH:${lib.makeBinPath [ dpkg dpkg glibc lzma ]}
 
         # Unpack the .debs.  We do this to prevent pre-install scripts
         # (which have lots of circular dependencies) from barfing.
@@ -587,9 +588,9 @@ rec {
 
         # Make the Nix store available in /mnt, because that's where the .debs live.
         mkdir -p /mnt/inst${storeDir}
-        ${utillinux}/bin/mount -o bind ${storeDir} /mnt/inst${storeDir}
-        ${utillinux}/bin/mount -o bind /proc /mnt/proc
-        ${utillinux}/bin/mount -o bind /dev /mnt/dev
+        ${util-linux}/bin/mount -o bind ${storeDir} /mnt/inst${storeDir}
+        ${util-linux}/bin/mount -o bind /proc /mnt/proc
+        ${util-linux}/bin/mount -o bind /dev /mnt/dev
 
         # Misc. files/directories assumed by various packages.
         echo "initialising Dpkg DB..."
@@ -635,10 +636,10 @@ rec {
 
         rm /mnt/.debug
 
-        ${utillinux}/bin/umount /mnt/inst${storeDir}
-        ${utillinux}/bin/umount /mnt/proc
-        ${utillinux}/bin/umount /mnt/dev
-        ${utillinux}/bin/umount /mnt
+        ${util-linux}/bin/umount /mnt/inst${storeDir}
+        ${util-linux}/bin/umount /mnt/proc
+        ${util-linux}/bin/umount /mnt/dev
+        ${util-linux}/bin/umount /mnt
       '';
 
       passthru = { inherit fullName; };
@@ -1196,4 +1197,4 @@ rec {
      `debDistros' sets. */
   diskImages = lib.mapAttrs (name: f: f {}) diskImageFuns;
 
-} // import ./windows pkgs
+}
diff --git a/pkgs/build-support/vm/windows/bootstrap.nix b/pkgs/build-support/vm/windows/bootstrap.nix
deleted file mode 100644
index 3b06d8f47490..000000000000
--- a/pkgs/build-support/vm/windows/bootstrap.nix
+++ /dev/null
@@ -1,83 +0,0 @@
-{ stdenv, fetchurl, vmTools, writeScript, writeText, runCommand, makeInitrd
-, python, perl, coreutils, dosfstools, gzip, mtools, netcat-gnu, openssh, qemu
-, samba, socat, vde2, cdrkit, pathsFromGraph, gnugrep
-}:
-
-{ isoFile, productKey, arch ? null }:
-
-with stdenv.lib;
-
-let
-  controller = import ./controller {
-    inherit stdenv writeScript vmTools makeInitrd;
-    inherit samba vde2 openssh socat netcat-gnu coreutils gzip gnugrep;
-  };
-
-  mkCygwinImage = import ./cygwin-iso {
-    inherit stdenv fetchurl runCommand python perl cdrkit pathsFromGraph;
-    arch = let
-      defaultArch = if stdenv.is64bit then "x86_64" else "i686";
-    in if arch == null then defaultArch else arch;
-  };
-
-  installer = import ./install {
-    inherit controller mkCygwinImage;
-    inherit stdenv runCommand openssh qemu writeText dosfstools mtools;
-  };
-in rec {
-  installedVM = installer {
-    inherit isoFile productKey;
-  };
-
-  runInVM = img: attrs: controller (attrs // {
-    inherit (installedVM) sshKey;
-    qemuArgs = attrs.qemuArgs or [] ++ [
-      "-boot order=c"
-      "-drive file=${img},index=0,media=disk"
-    ];
-  });
-
-  runAndSuspend = let
-    drives = {
-      s = {
-        source = "nixstore";
-        target = "/nix/store";
-      };
-      x = {
-        source = "xchg";
-        target = "/tmp/xchg";
-      };
-    };
-
-    genDriveCmds = letter: { source, target }: [
-      "net use ${letter}: '\\\\192.168.0.2\\${source}' /persistent:yes"
-      "mkdir -p '${target}'"
-      "mount -o bind '/cygdrive/${letter}' '${target}'"
-      "echo '/cygdrive/${letter} ${target} none bind 0 0' >> /etc/fstab"
-    ];
-  in runInVM "winvm.img" {
-    command = concatStringsSep " && " ([
-      "net config server /autodisconnect:-1"
-    ] ++ concatLists (mapAttrsToList genDriveCmds drives));
-    suspendTo = "state.gz";
-  };
-
-  suspendedVM = stdenv.mkDerivation {
-    name = "cygwin-suspended-vm";
-    buildCommand = ''
-      ${qemu}/bin/qemu-img create \
-        -b "${installedVM}/disk.img" \
-        -f qcow2 winvm.img
-      ${runAndSuspend}
-      mkdir -p "$out"
-      cp winvm.img "$out/disk.img"
-      cp state.gz "$out/state.gz"
-    '';
-  };
-
-  resumeAndRun = command: runInVM "${suspendedVM}/disk.img" {
-    resumeFrom = "${suspendedVM}/state.gz";
-    qemuArgs = singleton "-snapshot";
-    inherit command;
-  };
-}
diff --git a/pkgs/build-support/vm/windows/controller/default.nix b/pkgs/build-support/vm/windows/controller/default.nix
deleted file mode 100644
index 9d13983a2833..000000000000
--- a/pkgs/build-support/vm/windows/controller/default.nix
+++ /dev/null
@@ -1,263 +0,0 @@
-{ stdenv, writeScript, vmTools, makeInitrd
-, samba, vde2, openssh, socat, netcat-gnu, coreutils, gnugrep, gzip
-, runtimeShell
-}:
-
-{ sshKey
-, qemuArgs ? []
-, command ? "sync"
-, suspendTo ? null
-, resumeFrom ? null
-, installMode ? false
-}:
-
-with stdenv.lib;
-
-let
-  preInitScript = writeScript "preinit.sh" ''
-    #!${vmTools.initrdUtils}/bin/ash -e
-    export PATH=${vmTools.initrdUtils}/bin
-    mount -t proc none /proc
-    mount -t sysfs none /sys
-    for arg in $(cat /proc/cmdline); do
-      if [ "x''${arg#command=}" != "x$arg" ]; then
-        command="''${arg#command=}"
-      fi
-    done
-
-    for i in $(cat ${modulesClosure}/insmod-list); do
-      insmod $i
-    done
-
-    mkdir -p /dev /fs
-
-    mount -t tmpfs none /dev
-    mknod /dev/null    c 1 3
-    mknod /dev/zero    c 1 5
-    mknod /dev/random  c 1 8
-    mknod /dev/urandom c 1 9
-    mknod /dev/tty     c 5 0
-
-    ifconfig lo up
-    ifconfig eth0 up 192.168.0.2
-
-    mount -t tmpfs none /fs
-    mkdir -p /fs/nix/store /fs/xchg /fs/dev /fs/sys /fs/proc /fs/etc /fs/tmp
-
-    mount -o bind /dev /fs/dev
-    mount -t sysfs none /fs/sys
-    mount -t proc none /fs/proc
-
-    mount -t 9p \
-      -o trans=virtio,version=9p2000.L,cache=loose \
-      store /fs/nix/store
-
-    mount -t 9p \
-      -o trans=virtio,version=9p2000.L \
-      xchg /fs/xchg
-
-    echo root:x:0:0::/root:/bin/false > /fs/etc/passwd
-
-    set +e
-    chroot /fs $command $out
-    echo $? > /fs/xchg/in-vm-exit
-
-    poweroff -f
-  '';
-
-  initrd = makeInitrd {
-    contents = singleton {
-      object = preInitScript;
-      symlink = "/init";
-    };
-  };
-
-  loopForever = "while :; do ${coreutils}/bin/sleep 1; done";
-
-  initScript = writeScript "init.sh" (''
-    #!${runtimeShell}
-    ${coreutils}/bin/cp -L "${sshKey}" /ssh.key
-    ${coreutils}/bin/chmod 600 /ssh.key
-  '' + (if installMode then ''
-    echo -n "Waiting for Windows installation to finish..."
-    while ! ${netcat-gnu}/bin/netcat -z 192.168.0.1 22; do
-      echo -n .
-      # Print a dot every 10 seconds only to shorten line length.
-      ${coreutils}/bin/sleep 10
-    done
-    ${coreutils}/bin/touch /xchg/waiting_done
-    echo " success."
-    # Loop forever, because this VM is going to be killed.
-    ${loopForever}
-  '' else ''
-    ${coreutils}/bin/mkdir -p /etc/samba /etc/samba/private \
-                              /var/lib/samba /var/log /var/run
-    ${coreutils}/bin/cat > /etc/samba/smb.conf <<CONFIG
-    [global]
-    security = user
-    map to guest = Bad User
-    guest account = root
-    workgroup = cygwin
-    netbios name = controller
-    server string = %h
-    log level = 1
-    max log size = 1000
-    log file = /var/log/samba.log
-
-    [nixstore]
-    path = /nix/store
-    writable = yes
-    guest ok = yes
-
-    [xchg]
-    path = /xchg
-    writable = yes
-    guest ok = yes
-    CONFIG
-
-    ${samba}/sbin/nmbd -D
-    ${samba}/sbin/smbd -D
-
-    echo -n "Waiting for Windows VM to become available..."
-    while ! ${netcat-gnu}/bin/netcat -z 192.168.0.1 22; do
-      echo -n .
-      ${coreutils}/bin/sleep 1
-    done
-    ${coreutils}/bin/touch /xchg/waiting_done
-    echo " success."
-
-    ${openssh}/bin/ssh \
-      -o UserKnownHostsFile=/dev/null \
-      -o StrictHostKeyChecking=no \
-      -i /ssh.key \
-      -l Administrator \
-      192.168.0.1 -- ${lib.escapeShellArg command}
-  '') + optionalString (suspendTo != null) ''
-    ${coreutils}/bin/touch /xchg/suspend_now
-    ${loopForever}
-  '');
-
-  kernelAppend = concatStringsSep " " [
-    "panic=1"
-    "loglevel=4"
-    "console=tty1"
-    "console=ttyS0"
-    "command=${initScript}"
-  ];
-
-  controllerQemuArgs = concatStringsSep " " (maybeKvm64 ++ [
-    "-pidfile $CTRLVM_PIDFILE"
-    "-nographic"
-    "-no-reboot"
-    "-virtfs local,path=/nix/store,security_model=none,mount_tag=store"
-    "-virtfs local,path=$XCHG_DIR,security_model=none,mount_tag=xchg"
-    "-kernel ${modulesClosure.kernel}/bzImage"
-    "-initrd ${initrd}/initrd"
-    "-append \"${kernelAppend}\""
-    "-net nic,vlan=0,macaddr=52:54:00:12:01:02,model=virtio"
-    "-net vde,vlan=0,sock=$QEMU_VDE_SOCKET"
-  ]);
-
-  maybeKvm64 = optional (stdenv.hostPlatform.system == "x86_64-linux") "-cpu kvm64";
-
-  cygwinQemuArgs = concatStringsSep " " (maybeKvm64 ++ [
-    "-monitor unix:$MONITOR_SOCKET,server,nowait"
-    "-pidfile $WINVM_PIDFILE"
-    "-nographic"
-    "-net nic,vlan=0,macaddr=52:54:00:12:01:01"
-    "-net vde,vlan=0,sock=$QEMU_VDE_SOCKET"
-    "-rtc base=2010-01-01,clock=vm"
-  ] ++ qemuArgs ++ optionals (resumeFrom != null) [
-    "-incoming 'exec: ${gzip}/bin/gzip -c -d \"${resumeFrom}\"'"
-  ]);
-
-  modulesClosure = overrideDerivation vmTools.modulesClosure (o: {
-    rootModules = o.rootModules ++ singleton "virtio_net";
-  });
-
-  preVM = ''
-    (set; declare -p) > saved-env
-    XCHG_DIR="$(${coreutils}/bin/mktemp -d nix-vm.XXXXXXXXXX --tmpdir)"
-    ${coreutils}/bin/mv saved-env "$XCHG_DIR/"
-
-    eval "$preVM"
-
-    QEMU_VDE_SOCKET="$(pwd)/vde.ctl"
-    MONITOR_SOCKET="$(pwd)/monitor"
-    WINVM_PIDFILE="$(pwd)/winvm.pid"
-    CTRLVM_PIDFILE="$(pwd)/ctrlvm.pid"
-    ${vde2}/bin/vde_switch -s "$QEMU_VDE_SOCKET" --dirmode 0700 &
-    echo 'alive?' | ${socat}/bin/socat - \
-      UNIX-CONNECT:$QEMU_VDE_SOCKET/ctl,retry=20
-  '';
-
-  vmExec = ''
-    ${vmTools.qemuProg} ${controllerQemuArgs} &
-    ${vmTools.qemuProg} ${cygwinQemuArgs} &
-    echo -n "Waiting for VMs to start up..."
-    timeout=60
-    while ! test -e "$WINVM_PIDFILE" -a -e "$CTRLVM_PIDFILE"; do
-      timeout=$(($timeout - 1))
-      echo -n .
-      if test $timeout -le 0; then
-        echo " timed out."
-        exit 1
-      fi
-      ${coreutils}/bin/sleep 1
-    done
-    echo " done."
-  '';
-
-  checkDropOut = ''
-    if ! test -e "$XCHG_DIR/waiting_done" &&
-       ! kill -0 $(< "$WINVM_PIDFILE"); then
-      echo "Windows VM has dropped out early, bailing out!" >&2
-      exit 1
-    fi
-  '';
-
-  toMonitor = "${socat}/bin/socat - UNIX-CONNECT:$MONITOR_SOCKET";
-
-  postVM = if suspendTo != null then ''
-    while ! test -e "$XCHG_DIR/suspend_now"; do
-      ${checkDropOut}
-      ${coreutils}/bin/sleep 1
-    done
-    ${toMonitor} <<CMD
-    stop
-    migrate_set_speed 4095m
-    migrate "exec:${gzip}/bin/gzip -c > '${suspendTo}'"
-    CMD
-    echo -n "Waiting for memory dump to finish..."
-    while ! echo info migrate | ${toMonitor} | \
-          ${gnugrep}/bin/grep -qi '^migration *status: *complete'; do
-      ${coreutils}/bin/sleep 1
-      echo -n .
-    done
-    echo " done."
-    echo quit | ${toMonitor}
-    wait $(< "$WINVM_PIDFILE")
-    eval "$postVM"
-    exit 0
-  '' else if installMode then ''
-    wait $(< "$WINVM_PIDFILE")
-    eval "$postVM"
-    exit 0
-  '' else ''
-    while kill -0 $(< "$CTRLVM_PIDFILE"); do
-      ${checkDropOut}
-    done
-    if ! test -e "$XCHG_DIR/in-vm-exit"; then
-      echo "Virtual machine didn't produce an exit code."
-      exit 1
-    fi
-    eval "$postVM"
-    exit $(< "$XCHG_DIR/in-vm-exit")
-  '';
-
-in writeScript "run-cygwin-vm.sh" ''
-  #!${stdenv.shell} -e
-  ${preVM}
-  ${vmExec}
-  ${postVM}
-''
diff --git a/pkgs/build-support/vm/windows/cygwin-iso/default.nix b/pkgs/build-support/vm/windows/cygwin-iso/default.nix
deleted file mode 100644
index 76cd41a75bc7..000000000000
--- a/pkgs/build-support/vm/windows/cygwin-iso/default.nix
+++ /dev/null
@@ -1,56 +0,0 @@
-{ stdenv, fetchurl, runCommand, python, perl, xorriso, pathsFromGraph
-, arch ? "x86_64"
-}:
-
-{ packages ? []
-, mirror ? "http://ftp.gwdg.de/pub/linux/sources.redhat.com/cygwin"
-, extraContents ? []
-}:
-
-let
-  cygPkgList = if arch == "x86_64" then fetchurl {
-    url = "${mirror}/x86_64/setup.ini";
-    sha256 = "0arrxvxbl85l82iy648snx5cl952w791p45p0dfg1xpiaf96cbkj";
-  } else fetchurl {
-    url = "${mirror}/x86/setup.ini";
-    sha256 = "1fayx34868vd5h2nah7chiw65sl3i9qzrwvs7lrlv2h8k412vb69";
-  };
-
-  cygwinCross = (import ../../../../.. {
-    localSystem = stdenv.hostPlatform;
-    crossSystem = {
-      libc = "msvcrt";
-      platform = {};
-      inherit arch;
-      config = "${arch}-w64-mingw32";
-    };
-  }).windows.cygwinSetup;
-
-  makeCygwinClosure = { packages, packageList }: let
-    expr = import (runCommand "cygwin.nix" { buildInputs = [ python ]; } ''
-      python ${./mkclosure.py} "${packages}" ${toString packageList} > "$out"
-    '');
-    gen = { url, hash }: {
-      source = fetchurl {
-        url = "${mirror}/${url}";
-        sha512 = hash;
-      };
-      target = url;
-    };
-  in map gen expr;
-
-in import ../../../../../nixos/lib/make-iso9660-image.nix {
-  inherit stdenv perl xorriso pathsFromGraph;
-  syslinux = null;
-  contents = [
-    { source = "${cygwinCross}/bin/setup.exe";
-      target = "setup.exe";
-    }
-    { source = cygPkgList;
-      target = "setup.ini";
-    }
-  ] ++ makeCygwinClosure {
-    packages = cygPkgList;
-    packageList = packages;
-  } ++ extraContents;
-}
diff --git a/pkgs/build-support/vm/windows/cygwin-iso/mkclosure.py b/pkgs/build-support/vm/windows/cygwin-iso/mkclosure.py
deleted file mode 100644
index 4c0d67c43bac..000000000000
--- a/pkgs/build-support/vm/windows/cygwin-iso/mkclosure.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# Ugliest Python code I've ever written. -- aszlig
-import sys
-
-def get_plist(path):
-    in_pack = False
-    in_str = False
-    current_key = None
-    buf = ""
-    packages = {}
-    package_name = None
-    package_attrs = {}
-    with open(path, 'r') as setup:
-        for line in setup:
-            if in_str and line.rstrip().endswith('"'):
-                package_attrs[current_key] = buf + line.rstrip()[:-1]
-                in_str = False
-                continue
-            elif in_str:
-                buf += line
-                continue
-
-            if line.startswith('@'):
-                in_pack = True
-                package_name = line[1:].strip()
-                package_attrs = {}
-            elif in_pack and ':' in line:
-                key, value = line.split(':', 1)
-                if value.lstrip().startswith('"'):
-                    if value.lstrip()[1:].rstrip().endswith('"'):
-                        value = value.strip().strip('"')
-                    else:
-                        in_str = True
-                        current_key = key.strip().lower()
-                        buf = value.lstrip()[1:]
-                        continue
-                package_attrs[key.strip().lower()] = value.strip()
-            elif in_pack:
-                in_pack = False
-                packages[package_name] = package_attrs
-    return packages
-
-def main():
-    packages = get_plist(sys.argv[1])
-    to_include = set()
-
-    def traverse(package):
-        to_include.add(package)
-        attrs = packages.get(package, {})
-        deps = attrs.get('requires', '').split()
-        for new_dep in set(deps) - to_include:
-            traverse(new_dep)
-
-    map(traverse, sys.argv[2:])
-
-    sys.stdout.write('[\n')
-    for package, attrs in packages.iteritems():
-        if package not in to_include:
-            cats = [c.lower() for c in attrs.get('category', '').split()]
-            if 'base' not in cats:
-                continue
-
-        install_line = attrs.get('install')
-        if install_line is None:
-            continue
-
-        url, size, hash = install_line.split(' ', 2)
-
-        pack = [
-            '  {',
-            '    url = "{0}";'.format(url),
-            '    hash = "{0}";'.format(hash),
-            '  }',
-        ];
-        sys.stdout.write('\n'.join(pack) + '\n')
-    sys.stdout.write(']\n')
-
-if __name__ == '__main__':
-    main()
diff --git a/pkgs/build-support/vm/windows/default.nix b/pkgs/build-support/vm/windows/default.nix
deleted file mode 100644
index 309241c36dee..000000000000
--- a/pkgs/build-support/vm/windows/default.nix
+++ /dev/null
@@ -1,44 +0,0 @@
-#note: the hardcoded /bin/sh is required for the VM's cygwin shell
-pkgs:
-
-let
-  bootstrapper = import ./bootstrap.nix {
-    inherit (pkgs) stdenv vmTools writeScript writeText runCommand makeInitrd;
-    inherit (pkgs) coreutils dosfstools gzip mtools netcat-gnu openssh qemu samba;
-    inherit (pkgs) socat vde2 fetchurl python perl cdrkit pathsFromGraph;
-    inherit (pkgs) gnugrep;
-  };
-
-  builder = ''
-    source /tmp/xchg/saved-env 2> /dev/null || true
-    export NIX_STORE=/nix/store
-    export NIX_BUILD_TOP=/tmp
-    export TMPDIR=/tmp
-    export PATH=/empty
-    cd "$NIX_BUILD_TOP"
-    exec $origBuilder $origArgs
-  '';
-
-in {
-  runInWindowsVM = drv: pkgs.lib.overrideDerivation drv (attrs: let
-    bootstrap = bootstrapper attrs.windowsImage;
-  in {
-    requiredSystemFeatures = [ "kvm" ];
-    builder = pkgs.stdenv.shell;
-    args = ["-e" (bootstrap.resumeAndRun builder)];
-    windowsImage = bootstrap.suspendedVM;
-    origArgs = attrs.args;
-    origBuilder = if attrs.builder == attrs.stdenv.shell
-                  then "/bin/sh"
-                  else attrs.builder;
-
-    postHook = ''
-      PATH=/usr/bin:/bin:/usr/sbin:/sbin
-      SHELL=/bin/sh
-      eval "$origPostHook"
-    '';
-
-    origPostHook = attrs.postHook or "";
-    fixupPhase = ":";
-  });
-}
diff --git a/pkgs/build-support/vm/windows/install/default.nix b/pkgs/build-support/vm/windows/install/default.nix
deleted file mode 100644
index fe8e8f61de02..000000000000
--- a/pkgs/build-support/vm/windows/install/default.nix
+++ /dev/null
@@ -1,74 +0,0 @@
-{ stdenv, runCommand, openssh, qemu, controller, mkCygwinImage
-, writeText, dosfstools, mtools
-}:
-
-{ isoFile
-, productKey
-}:
-
-let
-  bootstrapAfterLogin = runCommand "bootstrap.sh" {} ''
-    cat > "$out" <<EOF
-    mkdir -p ~/.ssh
-    cat > ~/.ssh/authorized_keys <<PUBKEY
-    $(cat "${cygwinSshKey}/key.pub")
-    PUBKEY
-    ssh-host-config -y -c 'binmode ntsec' -w dummy
-    cygrunsrv -S sshd
-    shutdown -s 5
-    EOF
-  '';
-
-  cygwinSshKey = stdenv.mkDerivation {
-    name = "snakeoil-ssh-cygwin";
-    buildCommand = ''
-      mkdir -p "$out"
-      ${openssh}/bin/ssh-keygen -t ecdsa -f "$out/key" -N ""
-    '';
-  };
-
-  sshKey = "${cygwinSshKey}/key";
-
-  packages = [ "openssh" "shutdown" ];
-
-  floppyCreator = import ./unattended-image.nix {
-    inherit stdenv writeText dosfstools mtools;
-  };
-
-  instfloppy = floppyCreator {
-    cygwinPackages = packages;
-    inherit productKey;
-  };
-
-  cygiso = mkCygwinImage {
-    inherit packages;
-    extraContents = stdenv.lib.singleton {
-      source = bootstrapAfterLogin;
-      target = "bootstrap.sh";
-    };
-  };
-
-  installController = controller {
-    inherit sshKey;
-    installMode = true;
-    qemuArgs = [
-      "-boot order=c,once=d"
-      "-drive file=${instfloppy},readonly,index=0,if=floppy"
-      "-drive file=winvm.img,index=0,media=disk"
-      "-drive file=${isoFile},index=1,media=cdrom"
-      "-drive file=${cygiso}/iso/cd.iso,index=2,media=cdrom"
-    ];
-  };
-
-in stdenv.mkDerivation {
-  name = "cygwin-base-vm";
-  buildCommand = ''
-    ${qemu}/bin/qemu-img create -f qcow2 winvm.img 2G
-    ${installController}
-    mkdir -p "$out"
-    cp winvm.img "$out/disk.img"
-  '';
-  passthru = {
-    inherit sshKey;
-  };
-}
diff --git a/pkgs/build-support/vm/windows/install/unattended-image.nix b/pkgs/build-support/vm/windows/install/unattended-image.nix
deleted file mode 100644
index 5b1ff84cf44d..000000000000
--- a/pkgs/build-support/vm/windows/install/unattended-image.nix
+++ /dev/null
@@ -1,123 +0,0 @@
-{ stdenv, writeText, dosfstools, mtools }:
-
-{ productKey
-, shExecAfterwards ? "E:\\bootstrap.sh"
-, cygwinRoot ? "C:\\cygwin"
-, cygwinSetup ? "E:\\setup.exe"
-, cygwinRepository ? "E:\\"
-, cygwinPackages ? [ "openssh" ]
-}:
-
-let
-  afterSetup = [
-    cygwinSetup
-    "-L -n -q"
-    "-l ${cygwinRepository}"
-    "-R ${cygwinRoot}"
-    "-C base"
-  ] ++ map (p: "-P ${p}") cygwinPackages;
-
-  winXpUnattended = writeText "winnt.sif" ''
-    [Data]
-    AutoPartition = 1
-    AutomaticUpdates = 0
-    MsDosInitiated = 0
-    UnattendedInstall = Yes
-
-    [Unattended]
-    DUDisable = Yes
-    DriverSigningPolicy = Ignore
-    Hibernation = No
-    OemPreinstall = No
-    OemSkipEula = Yes
-    Repartition = Yes
-    TargetPath = \WINDOWS
-    UnattendMode = FullUnattended
-    UnattendSwitch = Yes
-    WaitForReboot = No
-
-    [GuiUnattended]
-    AdminPassword = "nopasswd"
-    AutoLogon = Yes
-    AutoLogonCount = 1
-    OEMSkipRegional = 1
-    OemSkipWelcome = 1
-    ServerWelcome = No
-    TimeZone = 85
-
-    [UserData]
-    ComputerName = "cygwin"
-    FullName = "cygwin"
-    OrgName = ""
-    ProductKey = "${productKey}"
-
-    [Networking]
-    InstallDefaultComponents = Yes
-
-    [Identification]
-    JoinWorkgroup = cygwin
-
-    [NetAdapters]
-    PrimaryAdapter = params.PrimaryAdapter
-
-    [params.PrimaryAdapter]
-    InfID = *
-
-    [params.MS_MSClient]
-
-    [NetProtocols]
-    MS_TCPIP = params.MS_TCPIP
-
-    [params.MS_TCPIP]
-    AdapterSections=params.MS_TCPIP.PrimaryAdapter
-
-    [params.MS_TCPIP.PrimaryAdapter]
-    DHCP = No
-    IPAddress = 192.168.0.1
-    SpecificTo = PrimaryAdapter
-    SubnetMask = 255.255.255.0
-    WINS = No
-
-    ; Turn off all components
-    [Components]
-    ${stdenv.lib.concatMapStrings (comp: "${comp} = Off\n") [
-      "AccessOpt" "Appsrv_console" "Aspnet" "BitsServerExtensionsISAPI"
-      "BitsServerExtensionsManager" "Calc" "Certsrv" "Certsrv_client"
-      "Certsrv_server" "Charmap" "Chat" "Clipbook" "Cluster" "Complusnetwork"
-      "Deskpaper" "Dialer" "Dtcnetwork" "Fax" "Fp_extensions" "Fp_vdir_deploy"
-      "Freecell" "Hearts" "Hypertrm" "IEAccess" "IEHardenAdmin" "IEHardenUser"
-      "Iis_asp" "Iis_common" "Iis_ftp" "Iis_inetmgr" "Iis_internetdataconnector"
-      "Iis_nntp" "Iis_serversideincludes" "Iis_smtp" "Iis_webdav" "Iis_www"
-      "Indexsrv_system" "Inetprint" "Licenseserver" "Media_clips" "Media_utopia"
-      "Minesweeper" "Mousepoint" "Msmq_ADIntegrated" "Msmq_Core"
-      "Msmq_HTTPSupport" "Msmq_LocalStorage" "Msmq_MQDSService"
-      "Msmq_RoutingSupport" "Msmq_TriggersService" "Msnexplr" "Mswordpad"
-      "Netcis" "Netoc" "OEAccess" "Objectpkg" "Paint" "Pinball" "Pop3Admin"
-      "Pop3Service" "Pop3Srv" "Rec" "Reminst" "Rootautoupdate" "Rstorage" "SCW"
-      "Sakit_web" "Solitaire" "Spider" "TSWebClient" "Templates"
-      "TerminalServer" "UDDIAdmin" "UDDIDatabase" "UDDIWeb" "Vol" "WMAccess"
-      "WMPOCM" "WbemMSI" "Wms" "Wms_admin_asp" "Wms_admin_mmc" "Wms_isapi"
-      "Wms_server" "Zonegames"
-    ]}
-
-    [WindowsFirewall]
-    Profiles = WindowsFirewall.TurnOffFirewall
-
-    [WindowsFirewall.TurnOffFirewall]
-    Mode = 0
-
-    [SetupParams]
-    UserExecute = "${stdenv.lib.concatStringsSep " " afterSetup}"
-
-    [GuiRunOnce]
-    Command0 = "${cygwinRoot}\bin\bash -l ${shExecAfterwards}"
-  '';
-
-in stdenv.mkDerivation {
-  name = "unattended-floppy.img";
-  buildCommand = ''
-    dd if=/dev/zero of="$out" count=1440 bs=1024
-    ${dosfstools}/sbin/mkfs.msdos "$out"
-    ${mtools}/bin/mcopy -i "$out" "${winXpUnattended}" ::winnt.sif
-  '';
-}
diff --git a/pkgs/build-support/writers/default.nix b/pkgs/build-support/writers/default.nix
index 9c709921d210..f853f37fec63 100644
--- a/pkgs/build-support/writers/default.nix
+++ b/pkgs/build-support/writers/default.nix
@@ -63,7 +63,7 @@ rec {
   #
   # Examples:
   #   writeSimpleC = makeBinWriter { compileScript = name: "gcc -o $out $contentPath"; }
-  makeBinWriter = { compileScript }: nameOrPath: content:
+  makeBinWriter = { compileScript, strip ? true }: nameOrPath: content:
     assert lib.or (types.path.check nameOrPath) (builtins.match "([0-9A-Za-z._])[0-9A-Za-z._-]*" nameOrPath != null);
     assert lib.or (types.path.check content) (types.str.check content);
     let
@@ -76,6 +76,8 @@ rec {
       contentPath = content;
     }) ''
       ${compileScript}
+      ${lib.optionalString strip
+         "${pkgs.binutils-unwrapped}/bin/strip --strip-unneeded $out"}
       ${optionalString (types.path.check nameOrPath) ''
         mv $out tmp
         mkdir -p $out/$(dirname "${nameOrPath}")
@@ -109,7 +111,10 @@ rec {
   #        return 0;
   #      }
   #    ''
-  writeC = name: { libraries ? [] }:
+  writeC = name: {
+    libraries ? [],
+    strip ? true
+  }:
     makeBinWriter {
       compileScript = ''
         PATH=${makeBinPath [
@@ -117,7 +122,7 @@ rec {
           pkgs.coreutils
           pkgs.findutils
           pkgs.gcc
-          pkgs.pkgconfig
+          pkgs.pkg-config
         ]}
         export PKG_CONFIG_PATH=${concatMapStringsSep ":" (pkg: "${pkg}/lib/pkgconfig") libraries}
         gcc \
@@ -131,8 +136,8 @@ rec {
             -Wall \
             -x c \
             "$contentPath"
-        strip --strip-unneeded "$out"
       '';
+      inherit strip;
     } name;
 
   # writeCBin takes the same arguments as writeC but outputs a directory (like writeScriptBin)
@@ -165,21 +170,38 @@ rec {
   writeHaskell = name: {
     libraries ? [],
     ghc ? pkgs.ghc,
-    ghcArgs ? []
+    ghcArgs ? [],
+    strip ? true
   }:
     makeBinWriter {
       compileScript = ''
         cp $contentPath tmp.hs
         ${ghc.withPackages (_: libraries )}/bin/ghc ${lib.escapeShellArgs ghcArgs} tmp.hs
         mv tmp $out
-        ${pkgs.binutils-unwrapped}/bin/strip --strip-unneeded "$out"
       '';
+      inherit strip;
     } name;
 
   # writeHaskellBin takes the same arguments as writeHaskell but outputs a directory (like writeScriptBin)
   writeHaskellBin = name:
     writeHaskell "/bin/${name}";
 
+  writeRust = name: {
+      rustc ? pkgs.rustc,
+      rustcArgs ? [],
+      strip ? true
+  }:
+    makeBinWriter {
+      compileScript = ''
+        cp "$contentPath" tmp.rs
+        PATH=${makeBinPath [pkgs.gcc]} ${lib.getBin rustc}/bin/rustc ${lib.escapeShellArgs rustcArgs} -o "$out" tmp.rs
+      '';
+      inherit strip;
+    } name;
+
+  writeRustBin = name:
+    writeRust "/bin/${name}";
+
   # writeJS takes a name an attributeset with libraries and some JavaScript sourcecode and
   # returns an executable
   #
diff --git a/pkgs/build-support/writers/test.nix b/pkgs/build-support/writers/test.nix
index d284bda43d05..7b7a698376a1 100644
--- a/pkgs/build-support/writers/test.nix
+++ b/pkgs/build-support/writers/test.nix
@@ -31,6 +31,12 @@ let
      test '~' = '~' && echo 'success'
     '';
 
+    rust = writeRustBin "test_writers" {} ''
+      fn main(){
+        println!("success")
+      }
+    '';
+
     haskell = writeHaskellBin "test_writers" { libraries = [ haskellPackages.acme-default ]; } ''
       import Data.Default
 
@@ -190,7 +196,7 @@ let
 
 in runCommand "test-writers" {
   passthru = { inherit writeTest bin simple; };
-  meta.platforms = stdenv.lib.platforms.all;
+  meta.platforms = lib.platforms.all;
 } ''
   ${lib.concatMapStringsSep "\n" (test: writeTest "success" "${test}/bin/test_writers") (lib.attrValues bin)}
   ${lib.concatMapStringsSep "\n" (test: writeTest "success" test) (lib.attrValues simple)}