summary refs log tree commit diff
path: root/pkgs/stdenv
diff options
context:
space:
mode:
authorWeijia Wang <9713184+wegank@users.noreply.github.com>2023-07-05 13:03:24 +0300
committerGitHub <noreply@github.com>2023-07-05 13:03:24 +0300
commitf0a11a54bece3350dbb03e19855b42c62fe53b46 (patch)
tree24c9ee260c05aa017febd35b10c7d7fb8e782294 /pkgs/stdenv
parent031101f58bfdf75d60766f52e156769de407d1c4 (diff)
parent8bee297d1517f527fbbac310e6096f573e226b9c (diff)
downloadnixpkgs-f0a11a54bece3350dbb03e19855b42c62fe53b46.tar
nixpkgs-f0a11a54bece3350dbb03e19855b42c62fe53b46.tar.gz
nixpkgs-f0a11a54bece3350dbb03e19855b42c62fe53b46.tar.bz2
nixpkgs-f0a11a54bece3350dbb03e19855b42c62fe53b46.tar.lz
nixpkgs-f0a11a54bece3350dbb03e19855b42c62fe53b46.tar.xz
nixpkgs-f0a11a54bece3350dbb03e19855b42c62fe53b46.tar.zst
nixpkgs-f0a11a54bece3350dbb03e19855b42c62fe53b46.zip
Merge pull request #240433 from reckenrode/darwin-stdenv-rework
darwin.stdenv: Darwin stdenv rework
Diffstat (limited to 'pkgs/stdenv')
-rw-r--r--pkgs/stdenv/darwin/README.md26
-rw-r--r--pkgs/stdenv/darwin/default.nix1679
-rw-r--r--pkgs/stdenv/default.nix2
3 files changed, 1149 insertions, 558 deletions
diff --git a/pkgs/stdenv/darwin/README.md b/pkgs/stdenv/darwin/README.md
new file mode 100644
index 00000000000..75d30b96a7f
--- /dev/null
+++ b/pkgs/stdenv/darwin/README.md
@@ -0,0 +1,26 @@
+# Darwin stdenv design goals
+
+There are two more goals worth calling out explicitly:
+
+1. The standard environment should build successfully with sandboxing enabled on Darwin. It is
+   fine if a package requires a `sandboxProfile` to build, but it should not be necessary to
+   disable the sandbox to build the stdenv successfully; and
+2. The output should depend weakly on the bootstrap tools. Historically, Darwin required updating
+   the bootstrap tools prior to updating the version of LLVM used in the standard environment.
+   By not depending on a specific version, the LLVM used on Darwin can be updated simply by
+   bumping the definition of llvmPackages in `all-packages.nix`.
+
+# Updating the stdenv
+
+There are effectively two steps when updating the standard environment:
+
+1. Update the definition of llvmPackages in `all-packages.nix` for Darwin to match the value of
+   llvmPackages.latest in `all-packages.nix`. Timing-wise, this done currently using the spring
+   release of LLVM and once llvmPackages.latest has been updated to match. If the LLVM project
+   has announced a release schedule of patch updates, wait until those are in nixpkgs. Otherwise,
+   the LLVM updates will have to go through staging instead of being merged into master; and
+2. Fix the resulting breakage. Most things break due to additional warnings being turned into
+   errors or additional strictness applied by LLVM. Fixes may come in the form of disabling those
+   new warnings or by fixing the actual source (e.g., with a patch or update upstream). If the
+   fix is trivial (e.g., adding a missing int to an implicit declaration), it is better to fix
+   the problem instead of silencing the warning.
diff --git a/pkgs/stdenv/darwin/default.nix b/pkgs/stdenv/darwin/default.nix
index 1e7945d816a..8595cc72b43 100644
--- a/pkgs/stdenv/darwin/default.nix
+++ b/pkgs/stdenv/darwin/default.nix
@@ -1,10 +1,18 @@
+# This file contains the standard build environment for Darwin. It is based on LLVM and is patterned
+# after the Linux stdenv. It shares similar goals to the Linux standard environment in that the
+# resulting environment should be built purely and not contain any references to it.
+#
+# For more on the design of the stdenv and updating it, see `README.md`.
+#
+# See also the top comments of the Linux stdenv `../linux/default.nix` for a good overview of
+# the bootstrap process and working with it.
+
 { lib
 , localSystem
 , crossSystem
 , config
 , overlays
 , crossOverlays ? [ ]
-, bootstrapLlvmVersion ? "11.1.0"
   # Allow passing in bootstrap files directly so we can test the stdenv bootstrap process when changing the bootstrap tools
 , bootstrapFiles ? if localSystem.isAarch64 then
     let
@@ -42,11 +50,6 @@ let
   inherit (localSystem) system;
 
   useAppleSDKLibs = localSystem.isAarch64;
-  haveKRB5 = localSystem.isx86_64;
-
-  # final toolchain is injected into llvmPackages_${finalLlvmVersion}
-  finalLlvmVersion = lib.versions.major bootstrapLlvmVersion;
-  finalLlvmPackages = "llvmPackages_${finalLlvmVersion}";
 
   commonImpureHostDeps = [
     "/bin/sh"
@@ -54,16 +57,23 @@ let
     "/usr/lib/system/libunc.dylib" # This dependency is "hidden", so our scanning code doesn't pick it up
   ];
 
-in
-rec {
-  commonPreHook = ''
+  isFromNixpkgs = pkg: !(isFromBootstrapFiles pkg);
+  isFromBootstrapFiles =
+    pkg: pkg.passthru.isFromBootstrapFiles or false;
+  isBuiltByNixpkgsCompiler =
+    pkg: isFromNixpkgs pkg && isFromNixpkgs pkg.stdenv.cc.cc;
+  isBuiltByBootstrapFilesCompiler =
+    pkg: isFromNixpkgs pkg && isFromBootstrapFiles pkg.stdenv.cc.cc;
+
+  commonPreHook = pkgs: lib.optionalString (pkgs.darwin.system_cmds != null) ''
+    # Only use a response file on older systems with a small ARG_MAX (less than 1 MiB).
+    export NIX_CC_USE_RESPONSE_FILE=$(( "$("${lib.getBin pkgs.darwin.system_cmds}/bin/getconf" ARG_MAX)" < 1048576 ))
+    export NIX_LD_USE_RESPONSE_FILE=$NIX_CC_USE_RESPONSE_FILE
+  '' + ''
     export NIX_ENFORCE_NO_NATIVE=''${NIX_ENFORCE_NO_NATIVE-1}
     export NIX_ENFORCE_PURITY=''${NIX_ENFORCE_PURITY-1}
     export NIX_IGNORE_LD_THROUGH_GCC=1
     unset SDKROOT
-
-    stripAllFlags=" " # the Darwin "strip" command doesn't know "-s"
-    stripDebugFlags="-S" # the Darwin "strip" command does something odd with "-p"
   '';
 
   bootstrapTools = derivation ({
@@ -80,122 +90,101 @@ rec {
     __contentAddressed = true;
     outputHashAlgo = "sha256";
     outputHashMode = "recursive";
-  });
-
-  stageFun = step: last: { shell ? "${bootstrapTools}/bin/bash"
-                         , overrides ? (self: super: { })
-                         , extraPreHook ? ""
-                         , extraNativeBuildInputs
-                         , extraBuildInputs
-                         , libcxx
-                         , allowedRequisites ? null
-                         }:
-    let
-      name = "bootstrap-stage${toString step}";
+  }) // { passthru.isFromBootstrapFiles = true; };
 
-      buildPackages = lib.optionalAttrs (last ? stdenv) {
-        inherit (last) stdenv;
-      };
-
-      doSign = localSystem.isAarch64 && last != null;
-      doUpdateAutoTools = localSystem.isAarch64 && last != null;
+  stageFun = prevStage:
+    { name, overrides ? (self: super: { }), extraNativeBuildInputs ? [ ], extraPreHook ? "" }:
 
-      mkExtraBuildCommands = cc: ''
-        rsrc="$out/resource-root"
-        mkdir "$rsrc"
-        ln -s "${cc.lib or cc}/lib/clang/${cc.version}/include" "$rsrc"
-        ln -s "${last.pkgs."${finalLlvmPackages}".compiler-rt.out}/lib" "$rsrc/lib"
-        echo "-resource-dir=$rsrc" >> $out/nix-support/cc-cflags
-      '';
+    let
+      cc = if prevStage.llvmPackages.clang-unwrapped == null
+           then null else
+           lib.makeOverridable (import ../../build-support/cc-wrapper) {
+        name = "${name}-clang-wrapper";
 
-      mkCC = overrides: import ../../build-support/cc-wrapper (
-        let args = {
-          inherit lib shell;
-          inherit (last) stdenvNoCC;
+        nativeTools = false;
+        nativeLibc = false;
 
-          nativeTools = false;
-          nativeLibc = false;
-          inherit buildPackages libcxx;
-          inherit (last.pkgs) coreutils gnugrep;
-          bintools = last.pkgs.darwin.binutils;
-          libc = last.pkgs.darwin.Libsystem;
-          isClang = true;
-          cc = last.pkgs."${finalLlvmPackages}".clang-unwrapped;
-        }; in args // (overrides args)
-      );
+        buildPackages = lib.optionalAttrs (prevStage ? stdenv) {
+          inherit (prevStage) stdenv;
+        };
 
-      cc = if last == null then "/dev/null" else
-      mkCC ({ cc, ... }: {
         extraPackages = [
-          last.pkgs."${finalLlvmPackages}".libcxxabi
-          last.pkgs."${finalLlvmPackages}".compiler-rt
+          prevStage.llvmPackages.libcxxabi
+          prevStage.llvmPackages.compiler-rt
         ];
-        extraBuildCommands = mkExtraBuildCommands cc;
-      });
 
-      ccNoLibcxx = if last == null then "/dev/null" else
-      mkCC ({ cc, ... }: {
-        libcxx = null;
-        extraPackages = [
-          last.pkgs."${finalLlvmPackages}".compiler-rt
-        ];
-        extraBuildCommands = ''
-          echo "-rtlib=compiler-rt" >> $out/nix-support/cc-cflags
-          echo "-B${last.pkgs."${finalLlvmPackages}".compiler-rt}/lib" >> $out/nix-support/cc-cflags
-          echo "-nostdlib++" >> $out/nix-support/cc-cflags
-        '' + mkExtraBuildCommands cc;
-      });
+        extraBuildCommands =
+          let
+            inherit (prevStage.llvmPackages) clang-unwrapped compiler-rt release_version;
+          in
+          ''
+            function clangResourceRootIncludePath() {
+              clangLib="$1/lib/clang"
+              if (( $(ls "$clangLib" | wc -l) > 1 )); then
+                echo "Multiple LLVM versions were found at "$clangLib", but there must only be one used when building the stdenv." >&2
+                exit 1
+              fi
+              echo "$clangLib/$(ls -1 "$clangLib")/include"
+            }
+
+            rsrc="$out/resource-root"
+            mkdir "$rsrc"
+            ln -s "$(clangResourceRootIncludePath "${clang-unwrapped.lib}")" "$rsrc"
+            ln -s "${compiler-rt.out}/lib"   "$rsrc/lib"
+            ln -s "${compiler-rt.out}/share" "$rsrc/share"
+            echo "-resource-dir=$rsrc" >> $out/nix-support/cc-cflags
+          '';
 
-      thisStdenv = import ../generic {
-        name = "${name}-stdenv-darwin";
+        cc = prevStage.llvmPackages.clang-unwrapped;
+        bintools = prevStage.darwin.binutils;
 
-        inherit config shell extraBuildInputs;
+        isClang = true;
+        libc = prevStage.darwin.Libsystem;
+        inherit (prevStage.llvmPackages) libcxx;
 
-        extraNativeBuildInputs = extraNativeBuildInputs ++ lib.optionals doUpdateAutoTools [
-          last.pkgs.updateAutotoolsGnuConfigScriptsHook
-          last.pkgs.gnu-config
-        ];
+        inherit lib;
+        inherit (prevStage) coreutils gnugrep;
 
-        allowedRequisites = if allowedRequisites == null then null else allowedRequisites ++ [
-          cc.expand-response-params
-          cc.bintools
-        ] ++ lib.optionals doUpdateAutoTools [
-          last.pkgs.updateAutotoolsGnuConfigScriptsHook
-          last.pkgs.gnu-config
-        ] ++ lib.optionals doSign [
-          last.pkgs.darwin.postLinkSignHook
-          last.pkgs.darwin.sigtool
-          last.pkgs.darwin.signingUtils
-        ];
+        stdenvNoCC = prevStage.ccWrapperStdenv;
+      };
+
+      thisStdenv = import ../generic {
+        name = "${name}-stdenv-darwin";
 
         buildPlatform = localSystem;
         hostPlatform = localSystem;
         targetPlatform = localSystem;
 
-        inherit cc;
+        inherit config extraNativeBuildInputs;
+
+        extraBuildInputs = [ prevStage.darwin.CF ];
 
-        preHook = lib.optionalString (shell == "${bootstrapTools}/bin/bash") ''
+        preHook = ''
           # Don't patch #!/interpreter because it leads to retained
           # dependencies on the bootstrapTools in the final stdenv.
           dontPatchShebangs=1
-        '' + ''
-          ${commonPreHook}
+          ${commonPreHook prevStage}
           ${extraPreHook}
+        '' + lib.optionalString (prevStage.darwin ? locale) ''
+          export PATH_LOCALE=${prevStage.darwin.locale}/share/locale
         '';
+
+        shell = "${bootstrapTools}/bin/bash";
         initialPath = [ bootstrapTools ];
 
         fetchurlBoot = import ../../build-support/fetchurl {
           inherit lib;
-          stdenvNoCC = stage0.stdenv;
+          stdenvNoCC = prevStage.ccWrapperStdenv or thisStdenv;
           curl = bootstrapTools;
         };
 
+        inherit cc;
+
         # The stdenvs themselves don't use mkDerivation, so I need to specify this here
         __stdenvImpureHostDeps = commonImpureHostDeps;
         __extraImpureHostDeps = commonImpureHostDeps;
 
         overrides = self: super: (overrides self super) // {
-          inherit ccNoLibcxx;
           fetchurl = thisStdenv.fetchurlBoot;
         };
       };
@@ -205,94 +194,139 @@ rec {
       inherit config overlays;
       stdenv = thisStdenv;
     };
+in
+  assert bootstrapTools.passthru.isFromBootstrapFiles or false;  # sanity check
+[
+  ({}: {
+    __raw = true;
+
+    coreutils = null;
+    gnugrep = null;
+
+    pbzx = null;
+    cpio = null;
+
+    darwin = {
+      binutils = null;
+      binutils-unwrapped = null;
+      cctools = null;
+      print-reexports = null;
+      rewrite-tbd = null;
+      sigtool = null;
+      system_cmds = null;
+      CF = null;
+      Libsystem = null;
+    };
 
-  stage0 = stageFun 0 null {
-    overrides = self: super: with stage0; {
-      coreutils = stdenv.mkDerivation {
-        name = "bootstrap-stage0-coreutils";
-        buildCommand = ''
-          mkdir -p $out
-          ln -s ${bootstrapTools}/bin $out/bin
-        '';
-      };
-
-      gnugrep = stdenv.mkDerivation {
-        name = "bootstrap-stage0-gnugrep";
+    llvmPackages = {
+      clang-unwrapped = null;
+      libllvm = null;
+      libcxx = null;
+      libcxxabi = null;
+      compiler-rt = null;
+    };
+  })
+
+  # Create a stage with the bootstrap tools. This will be used to build the subsequent stages and
+  # build up the standard environment.
+  #
+  # Note: Each stage depends only on the the packages in `prevStage`. If a package is not to be
+  # rebuilt, it should be passed through by inheriting it.
+  (prevStage: stageFun prevStage {
+    name = "bootstrap-stage0";
+
+    overrides = self: super: {
+      # We thread stage0's stdenv through under this name so downstream stages
+      # can use it for wrapping gcc too. This way, downstream stages don't need
+      # to refer to this stage directly, which violates the principle that each
+      # stage should only access the stage that came before it.
+      ccWrapperStdenv = self.stdenv;
+
+      coreutils = bootstrapTools;
+      gnugrep = bootstrapTools;
+
+      pbzx = bootstrapTools;
+      cpio = self.stdenv.mkDerivation {
+        name = "bootstrap-stage0-cpio";
         buildCommand = ''
-          mkdir -p $out
-          ln -s ${bootstrapTools}/bin $out/bin
+          mkdir -p $out/bin
+          ln -s ${bootstrapFiles.cpio} $out/bin/cpio
         '';
+        passthru.isFromBootstrapFiles = true;
       };
 
-      pbzx = self.runCommandLocal "bootstrap-stage0-pbzx" { } ''
-        mkdir -p $out/bin
-        ln -s ${bootstrapTools}/bin/pbzx $out/bin
-      '';
-
-      cpio = self.runCommandLocal "bootstrap-stage0-cpio" { } ''
-        mkdir -p $out/bin
-        ln -s ${bootstrapFiles.cpio} $out/bin/cpio
-      '';
+      darwin = super.darwin.overrideScope (selfDarwin: _: {
+        binutils-unwrapped = bootstrapTools // {
+          version = "boot";
+        };
 
-      darwin = super.darwin.overrideScope (selfDarwin: superDarwin: {
-        darwin-stubs = superDarwin.darwin-stubs.override { inherit (self) stdenvNoCC fetchurl; };
+        binutils = (import ../../build-support/bintools-wrapper) {
+          name = "bootstrap-stage0-binutils-wrapper";
 
-        dyld = {
-          name = "bootstrap-stage0-dyld";
-          buildCommand = ''
-            mkdir -p $out
-            ln -s ${bootstrapTools}/lib     $out/lib
-            ln -s ${bootstrapTools}/include $out/include
-          '';
-        };
+          nativeTools = false;
+          nativeLibc = false;
 
-        sigtool = self.runCommandLocal "bootstrap-stage0-sigtool" { } ''
-           mkdir -p $out/bin
-           ln -s ${bootstrapTools}/bin/sigtool  $out/bin
-           ln -s ${bootstrapTools}/bin/codesign $out/bin
-        '';
+          buildPackages = { };
+          libc = selfDarwin.Libsystem;
 
-        print-reexports = self.runCommandLocal "bootstrap-stage0-print-reexports" { } ''
-          mkdir -p $out/bin
-          ln -s ${bootstrapTools}/bin/print-reexports $out/bin
-        '';
+          inherit lib;
+          inherit (self) stdenvNoCC coreutils gnugrep;
 
-        rewrite-tbd = self.runCommandLocal "bootstrap-stage0-rewrite-tbd" { } ''
-          mkdir -p $out/bin
-          ln -s ${bootstrapTools}/bin/rewrite-tbd $out/bin
-        '';
+          bintools = selfDarwin.binutils-unwrapped;
 
-        binutils-unwrapped = bootstrapTools // {
-          name = "bootstrap-stage0-binutils";
+          inherit (selfDarwin) postLinkSignHook signingUtils;
         };
 
         cctools = bootstrapTools // {
-          name = "bootstrap-stage0-cctools";
           targetPrefix = "";
+          version = "boot";
+          man = bootstrapTools;
         };
 
-        binutils = lib.makeOverridable (import ../../build-support/bintools-wrapper) {
-          shell = "${bootstrapTools}/bin/bash";
-          inherit lib;
-          inherit (self) stdenvNoCC;
+        locale = self.stdenv.mkDerivation {
+          name = "bootstrap-stage0-locale";
+          buildCommand = ''
+            mkdir -p $out/share/locale
+          '';
+        };
 
-          nativeTools = false;
-          nativeLibc = false;
-          inherit (self) buildPackages coreutils gnugrep;
-          libc = selfDarwin.Libsystem;
-          bintools = selfDarwin.binutils-unwrapped;
-          inherit (selfDarwin) postLinkSignHook signingUtils;
+        print-reexports = bootstrapTools;
+
+        rewrite-tbd = bootstrapTools;
+
+        sigtool = bootstrapTools;
+
+        # The bootstrap only needs `getconf` from system_cmds, and it only needs to be able to
+        # query `ARG_MAX`. Using a small value here should be fine for the initial stage 1 build.
+        system_cmds = self.stdenv.mkDerivation {
+          name = "bootstrap-stage0-system_cmds";
+          buildCommand = ''
+            mkdir -p "$out/bin"
+            cat <<block > "$out/bin/getconf"
+            #!${bootstrapTools}/bin/bash
+            case "\$1" in
+              ARG_MAX)
+                echo "262144"
+                ;;
+              *)
+                exit 1
+            esac
+            block
+            chmod a+x "$out/bin/getconf"
+          '';
+          passthru.isFromBootstrapFiles = true;
         };
       } // lib.optionalAttrs (! useAppleSDKLibs) {
-        CF = stdenv.mkDerivation {
+        CF = self.stdenv.mkDerivation {
           name = "bootstrap-stage0-CF";
           buildCommand = ''
             mkdir -p $out/Library/Frameworks
             ln -s ${bootstrapTools}/Library/Frameworks/CoreFoundation.framework $out/Library/Frameworks
           '';
+          passthru.isFromBootstrapFiles = true;
         };
 
-        Libsystem = stdenv.mkDerivation {
+        Libsystem = self.stdenv.mkDerivation {
           name = "bootstrap-stage0-Libsystem";
           buildCommand = ''
             mkdir -p $out
@@ -314,495 +348,1026 @@ rec {
 
             ln -s ${bootstrapTools}/include-Libsystem $out/include
           '';
+          passthru.isFromBootstrapFiles = true;
         };
       });
 
-      "${finalLlvmPackages}" = {
-        clang-unwrapped = stdenv.mkDerivation {
-          name = "bootstrap-stage0-clang";
-          version = bootstrapLlvmVersion;
-          buildCommand = ''
-            mkdir -p $out/lib
-            ln -s ${bootstrapTools}/bin $out/bin
-            ln -s ${bootstrapTools}/lib/clang $out/lib/clang
-            ln -s ${bootstrapTools}/include $out/include
-          '';
-        };
+      llvmPackages = super.llvmPackages // (
+        let
+          tools = super.llvmPackages.tools.extend (selfTools: _: {
+            libclang = self.stdenv.mkDerivation {
+              name = "bootstrap-stage0-clang";
+              version = "boot";
+              outputs = [ "out" "lib" ];
+              buildCommand = ''
+                mkdir -p $out/lib
+                ln -s $out $lib
+                ln -s ${bootstrapTools}/bin       $out/bin
+                ln -s ${bootstrapTools}/lib/clang $out/lib
+                ln -s ${bootstrapTools}/include   $out
+              '';
+              passthru.isFromBootstrapFiles = true;
+            };
+            clang-unwrapped = selfTools.libclang;
+            libllvm = self.stdenv.mkDerivation {
+              name = "bootstrap-stage0-llvm";
+              outputs = [ "out" "lib" ];
+              buildCommand = ''
+                mkdir -p $out/bin $out/lib
+                ln -s $out $lib
+                ln -s ${bootstrapTools}/bin/strip    $out/bin/llvm-strip
+                ln -s ${bootstrapTools}/lib/libLLVM* $out/lib
+              '';
+              passthru.isFromBootstrapFiles = true;
+            };
+            llvm = selfTools.libllvm;
+          });
+          libraries = super.llvmPackages.libraries.extend (_: _: {
+            libcxx = self.stdenv.mkDerivation {
+              name = "bootstrap-stage0-libcxx";
+              buildCommand = ''
+                mkdir -p $out/lib $out/include
+                ln -s ${bootstrapTools}/lib/libc++.dylib $out/lib
+                ln -s ${bootstrapTools}/include/c++      $out/include
+              '';
+              passthru = {
+                isLLVM = true;
+                cxxabi = self.llvmPackages.libcxxabi;
+                isFromBootstrapFiles = true;
+              };
+            };
+            libcxxabi = self.stdenv.mkDerivation {
+              name = "bootstrap-stage0-libcxxabi";
+              buildCommand = ''
+                mkdir -p $out/lib
+                ln -s ${bootstrapTools}/lib/libc++abi.dylib $out/lib
+              '';
+              passthru = {
+                libName = "c++abi";
+                isFromBootstrapFiles = true;
+              };
+            };
+            compiler-rt = self.stdenv.mkDerivation {
+              name = "bootstrap-stage0-compiler-rt";
+              buildCommand = ''
+                mkdir -p $out/lib $out/share
+                ln -s ${bootstrapTools}/lib/libclang_rt* $out/lib
+                ln -s ${bootstrapTools}/lib/darwin       $out/lib
+              '';
+              passthru.isFromBootstrapFiles = true;
+            };
+          });
+        in
+        { inherit tools libraries; } // tools // libraries
+      );
+    };
 
-        libcxx = stdenv.mkDerivation {
-          name = "bootstrap-stage0-libcxx";
-          dontUnpack = true;
-          installPhase = ''
-            mkdir -p $out/lib $out/include
-            ln -s ${bootstrapTools}/lib/libc++.dylib $out/lib/libc++.dylib
-            ln -s ${bootstrapTools}/include/c++      $out/include/c++
-          '';
-          passthru = {
-            isLLVM = true;
-            cxxabi = self."${finalLlvmPackages}".libcxxabi;
-          };
+    # The bootstrap tools may use `strip` from cctools, so use a compatible set of flags until LLVM
+    # is rebuilt, and darwin.binutils can use its implementation instead.
+    extraPreHook = ''
+      stripAllFlags=" "    # the cctools "strip" command doesn't know "-s"
+      stripDebugFlags="-S" # the cctools "strip" command does something odd with "-p"
+    '';
+  })
+
+  # This stage is primarily responsible for building the linker and setting up versions of
+  # certain dependencies needed by the rest of the build process. It is necessary to rebuild the
+  # linker because the `compiler-rt` build process checks the version and attempts to manually
+  # run `codesign` if it detects a version of `ld64` it considers too old. If that happens, the
+  # build process will fail for a few different reasons:
+  #  - sigtool is too old and does not accept the `--sign` argument;
+  #  - sigtool is new enough to accept the `--sign` argument, but it aborts when it is invoked on a
+  #    binary that is already signed; or
+  #  - compiler-rt attempts to invoke `codesign` on x86_64-darwin, but `sigtool` is not currently
+  #    part of the x86_64-darwin bootstrap tools.
+  #
+  # This stage also builds CF and Libsystem to simplify assertions and assumptions for later by
+  # making sure both packages are present on x86_64-darwin and aarch64-darwin.
+  (prevStage:
+    # previous stage0 stdenv:
+    assert lib.all isFromBootstrapFiles (with prevStage; [ coreutils cpio gnugrep pbzx ]);
+
+    assert lib.all isFromBootstrapFiles (with prevStage.darwin; [
+      binutils-unwrapped cctools print-reexports rewrite-tbd sigtool system_cmds
+    ]);
+
+    assert (! useAppleSDKLibs) -> lib.all isFromBootstrapFiles (with prevStage.darwin; [ CF Libsystem ]);
+    assert    useAppleSDKLibs  -> lib.all        isFromNixpkgs (with prevStage.darwin; [ CF Libsystem ]);
+    assert lib.all isFromNixpkgs (with prevStage.darwin; [ dyld launchd xnu ]);
+
+    assert lib.all isFromBootstrapFiles (with prevStage.llvmPackages; [
+      clang-unwrapped libclang libllvm llvm compiler-rt libcxx libcxxabi
+    ]);
+
+    stageFun prevStage {
+    name = "bootstrap-stage1";
+
+    overrides = self: super: {
+      inherit (prevStage) ccWrapperStdenv
+        coreutils gnugrep;
+
+      cmake = super.cmakeMinimal;
+
+      curl = super.curlMinimal;
+
+      # Disable tests because they use dejagnu, which fails to run.
+      libffi = super.libffi.override { doCheck = false; };
+
+      # Avoid pulling in a full python and its extra dependencies for the llvm/clang builds.
+      libxml2 = super.libxml2.override { pythonSupport = false; };
+
+      ninja = super.ninja.override { buildDocs = false; };
+
+      python3 = super.python3Minimal;
+
+      darwin = super.darwin.overrideScope (selfDarwin: superDarwin: {
+        inherit (prevStage.darwin) system_cmds;
+
+        signingUtils = prevStage.darwin.signingUtils.override {
+          inherit (selfDarwin) sigtool;
         };
 
-        libcxxabi = stdenv.mkDerivation {
-          name = "bootstrap-stage0-libcxxabi";
-          buildCommand = ''
-            mkdir -p $out/lib
-            ln -s ${bootstrapTools}/lib/libc++abi.dylib $out/lib/libc++abi.dylib
-          '';
-          passthru = {
-            libName = "c++abi";
-          };
+        binutils = superDarwin.binutils.override {
+          inherit (self) coreutils;
+          inherit (selfDarwin) postLinkSignHook signingUtils;
+
+          bintools = selfDarwin.binutils-unwrapped;
+          libc = selfDarwin.Libsystem;
         };
 
-        compiler-rt = stdenv.mkDerivation {
-          name = "bootstrap-stage0-compiler-rt";
-          buildCommand = ''
-            mkdir -p $out/lib
-            ln -s ${bootstrapTools}/lib/libclang_rt* $out/lib
-            ln -s ${bootstrapTools}/lib/darwin       $out/lib/darwin
-          '';
+        binutils-unwrapped = superDarwin.binutils-unwrapped.override {
+          inherit (selfDarwin) cctools;
         };
-      };
+
+        cctools = selfDarwin.cctools-port;
+      });
+
+      llvmPackages = super.llvmPackages // (
+        let
+          tools = super.llvmPackages.tools.extend (_: _: {
+            inherit (prevStage.llvmPackages) clang-unwrapped libclang libllvm llvm;
+          });
+          libraries = super.llvmPackages.libraries.extend (_: _: {
+            inherit (prevStage.llvmPackages) compiler-rt libcxx libcxxabi;
+          });
+        in
+        { inherit tools libraries; inherit (prevStage.llvmPackages) release_version; } // tools // libraries
+      );
     };
 
-    extraNativeBuildInputs = [ ];
-    extraBuildInputs = [ ];
-    libcxx = null;
-  };
+    extraNativeBuildInputs = lib.optionals localSystem.isAarch64 [
+      prevStage.updateAutotoolsGnuConfigScriptsHook
+      prevStage.gnu-config
+    ];
+
+    # The bootstrap tools may use `strip` from cctools, so use a compatible set of flags until LLVM
+    # is rebuilt, and darwin.binutils can use its implementation instead.
+    extraPreHook = ''
+      stripAllFlags=" "    # the cctools "strip" command doesn't know "-s"
+      stripDebugFlags="-S" # the cctools "strip" command does something odd with "-p"
+
+      # Don’t assume the ld64 in bootstrap tools supports response files. Only recent versions do.
+      export NIX_LD_USE_RESPONSE_FILE=0
+    '';
+  })
+
+  # Build sysctl, system_cmds and Python for use by LLVM’s check phase. These must be built in their
+  # own stage, or an infinite recursion results on x86_64-darwin when using the source-based SDK.
+  (prevStage:
+    # previous stage1 stdenv:
+    assert lib.all isFromBootstrapFiles (with prevStage; [ coreutils gnugrep ]);
+
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage; [
+      autoconf automake bash binutils-unwrapped bison brotli cmake cpio curl cyrus_sasl db
+      ed expat flex gettext gmp groff icu libedit libffi libiconv libidn2 libkrb5 libssh2
+      libtool libunistring libxml2 m4 ncurses nghttp2 ninja openldap openssh openssl
+      patchutils pbzx perl pkg-config.pkg-config python3 python3Minimal scons serf sqlite
+      subversion texinfo unzip which xz zlib zstd
+    ]);
+
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage.darwin; [
+      binutils-unwrapped cctools locale libtapi print-reexports rewrite-tbd sigtool
+    ]);
+    assert lib.all isFromBootstrapFiles (with prevStage.darwin; [ system_cmds ]);
+
+    assert (! useAppleSDKLibs) -> lib.all isBuiltByBootstrapFilesCompiler (with prevStage.darwin; [ CF Libsystem configd ]);
+    assert    useAppleSDKLibs  -> lib.all                   isFromNixpkgs (with prevStage.darwin; [ CF Libsystem libobjc]);
+    assert lib.all isFromNixpkgs (with prevStage.darwin; [ dyld launchd xnu ]);
+
+    assert lib.all isFromBootstrapFiles (with prevStage.llvmPackages; [
+      clang-unwrapped libclang libllvm llvm compiler-rt libcxx libcxxabi
+    ]);
+
+    assert lib.getVersion prevStage.stdenv.cc.bintools.bintools == "boot";
+
+    stageFun prevStage {
+    name = "bootstrap-stage1-sysctl";
+
+    overrides = self: super: {
+      inherit (prevStage) ccWrapperStdenv
+        autoconf automake bash binutils binutils-unwrapped bison brotli cmake cmakeMinimal
+        coreutils cpio curl cyrus_sasl db ed expat flex gettext gmp gnugrep groff icu
+        libedit libffi libiconv libidn2 libkrb5 libssh2 libtool libunistring libxml2 m4
+        ncurses nghttp2 ninja openldap openssh openssl patchutils pbzx perl pkg-config
+        python3Minimal scons sed serf sharutils sqlite subversion texinfo unzip which xz
+        zlib zstd;
+
+      # Support for the SystemConfiguration framework is required to run the LLVM tests, but trying
+      # to override python3Minimal does not appear to work.
+      python3 = (super.python3.override {
+        inherit (self) libffi;
+        inherit (self.darwin) configd;
+        openssl = null;
+        readline = null;
+        ncurses = null;
+        gdbm = null;
+        sqlite = null;
+        tzdata = null;
+        stripConfig = true;
+        stripIdlelib = true;
+        stripTests = true;
+        stripTkinter = true;
+        rebuildBytecode = false;
+        stripBytecode = true;
+        includeSiteCustomize = false;
+        enableOptimizations = false;
+        enableLTO = false;
+        mimetypesSupport = false;
+      }).overrideAttrs (_: { pname = "python3-minimal-scproxy"; });
+
+      darwin = super.darwin.overrideScope (_: superDarwin: {
+        inherit (prevStage.darwin)
+          CF Libsystem binutils-unwrapped cctools cctools-port configd darwin-stubs dyld
+          launchd libclosure libdispatch libobjc locale objc4 postLinkSignHook
+          print-reexports rewrite-tbd signingUtils sigtool;
+      });
 
-  stage1 = prevStage:
-    let
-      persistent = self: super: with prevStage; {
-        cmake = super.cmakeMinimal;
+      llvmPackages = super.llvmPackages // (
+        let
+          tools = super.llvmPackages.tools.extend (_: _: {
+            inherit (prevStage.llvmPackages) clang-unwrapped libclang libllvm llvm;
+            clang = prevStage.stdenv.cc;
+          });
+          libraries = super.llvmPackages.libraries.extend (_: _: {
+            inherit (prevStage.llvmPackages) compiler-rt libcxx libcxxabi;
+          });
+        in
+        { inherit tools libraries; inherit (prevStage.llvmPackages) release_version; } // tools // libraries
+      );
+    };
 
-        curl = super.curlMinimal;
+    extraNativeBuildInputs = lib.optionals localSystem.isAarch64 [
+      prevStage.updateAutotoolsGnuConfigScriptsHook
+      prevStage.gnu-config
+    ];
+
+    # Until LLVM is rebuilt, assume `strip` is the one from cctools.
+    extraPreHook = ''
+      stripAllFlags=" "    # the cctools "strip" command doesn't know "-s"
+      stripDebugFlags="-S" # the cctools "strip" command does something odd with "-p"
+    '';
+  })
+
+  # First rebuild of LLVM. While this LLVM is linked to a bunch of junk from the bootstrap tools,
+  # the libc++ and libc++abi it produces are not. The compiler will be rebuilt in a later stage,
+  # but those libraries will be used in the final stdenv.
+  #
+  # Rebuild coreutils and gnugrep to avoid unwanted references to the bootstrap tools on `PATH`.
+  (prevStage:
+    # previous stage-sysctl stdenv:
+    assert lib.all isFromBootstrapFiles (with prevStage; [ coreutils gnugrep ]);
+
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage; [
+      autoconf automake bash binutils-unwrapped bison brotli cmake cpio curl cyrus_sasl db
+      ed expat flex gettext gmp groff icu libedit libffi libiconv libidn2 libkrb5 libssh2
+      libtool libunistring libxml2 m4 ncurses nghttp2 ninja openldap openssh openssl
+      patchutils pbzx perl pkg-config.pkg-config python3 python3Minimal scons serf sqlite
+      subversion sysctl.provider texinfo unzip which xz zlib zstd
+    ]);
+
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage.darwin; [
+      binutils-unwrapped cctools locale libtapi print-reexports rewrite-tbd sigtool system_cmds
+    ]);
+
+    assert (! useAppleSDKLibs) -> lib.all isBuiltByBootstrapFilesCompiler (with prevStage.darwin; [ CF Libsystem configd ]);
+    assert    useAppleSDKLibs  -> lib.all                   isFromNixpkgs (with prevStage.darwin; [ CF Libsystem libobjc ]);
+    assert lib.all isFromNixpkgs (with prevStage.darwin; [ dyld launchd xnu ]);
+
+    assert lib.all isFromBootstrapFiles (with prevStage.llvmPackages; [
+      clang-unwrapped libclang libllvm llvm compiler-rt libcxx libcxxabi
+    ]);
+
+    assert lib.getVersion prevStage.stdenv.cc.bintools.bintools == lib.getVersion prevStage.darwin.cctools-port;
+
+    stageFun prevStage {
+    name = "bootstrap-stage-xclang";
+
+    overrides = self: super: {
+      inherit (prevStage) ccWrapperStdenv
+        autoconf automake bash binutils binutils-unwrapped bison brotli cmake cmakeMinimal
+        cpio curl cyrus_sasl db ed expat flex gettext gmp groff icu libedit libffi libiconv
+        libidn2 libkrb5 libssh2 libtool libunistring libxml2 m4 ncurses nghttp2 ninja
+        openldap openssh openssl patchutils pbzx perl pkg-config python3 python3Minimal
+        scons sed serf sharutils sqlite subversion sysctl texinfo unzip which xz zlib zstd;
+
+      # Switch from cctools-port to cctools-llvm now that LLVM has been built.
+      darwin = super.darwin.overrideScope (_: superDarwin: {
+        inherit (prevStage.darwin)
+          CF Libsystem configd darwin-stubs dyld launchd libclosure libdispatch libobjc
+          locale objc4 postLinkSignHook print-reexports rewrite-tbd signingUtils sigtool
+          system_cmds;
+
+        # Avoid building unnecessary Python dependencies due to building LLVM manpages.
+        cctools-llvm = superDarwin.cctools-llvm.override { enableManpages = false; };
+      });
 
-        inherit pbzx cpio;
+      llvmPackages = super.llvmPackages // (
+        let
+          llvmMajor = lib.versions.major super.llvmPackages.release_version;
 
-        python3 = super.python3Minimal;
+          # libc++, and libc++abi do not need CoreFoundation. Avoid propagating the CF from prior
+          # stages to the final stdenv via rpath by dropping it from `extraBuildInputs`.
+          stdenvNoCF = self.stdenv.override {
+            extraBuildInputs = [ ];
+          };
 
-        ninja = super.ninja.override { buildDocs = false; };
+          libcxxBootstrapStdenv = self.overrideCC stdenvNoCF (self.llvmPackages.clangNoCompilerRtWithLibc.override {
+            nixSupport.cc-cflags = [ "-nostdlib" ];
+            nixSupport.cc-ldflags = [ "-lSystem" ];
+          });
 
-        "${finalLlvmPackages}" = super."${finalLlvmPackages}" // (
-          let
-            tools = super."${finalLlvmPackages}".tools.extend (_: _: {
-              inherit (pkgs."${finalLlvmPackages}") clang-unwrapped;
+          libraries = super.llvmPackages.libraries.extend (selfLib: superLib: {
+            compiler-rt = null;
+            libcxx = superLib.libcxx.override ({
+              inherit (selfLib) libcxxabi;
+              stdenv = libcxxBootstrapStdenv;
             });
-            libraries = super."${finalLlvmPackages}".libraries.extend (_: _: {
-              inherit (pkgs."${finalLlvmPackages}") compiler-rt libcxx libcxxabi;
-            });
-          in
-          { inherit tools libraries; } // tools // libraries
-        );
+            libcxxabi = superLib.libcxxabi.override {
+              stdenv = libcxxBootstrapStdenv;
+            }
+            # Setting `standalone = true` is only needed with older verions of LLVM. Newer ones
+            # automatically do what is necessary to bootstrap lib++abi.
+            // lib.optionalAttrs (builtins.any (v: llvmMajor == v) [ "7" "11" "12" "13" ]) {
+              standalone = true;
+            };
+          });
+        in
+        { inherit libraries; } // libraries
+      );
+    };
 
-        darwin = super.darwin.overrideScope (selfDarwin: _: {
-          inherit (darwin) rewrite-tbd binutils-unwrapped;
+    extraNativeBuildInputs = lib.optionals localSystem.isAarch64 [
+      prevStage.updateAutotoolsGnuConfigScriptsHook
+      prevStage.gnu-config
+    ];
+
+    extraPreHook = ''
+      stripAllFlags=" "    # the cctools "strip" command doesn't know "-s"
+      stripDebugFlags="-S" # the cctools "strip" command does something odd with "-p"
+    '';
+  })
+
+  # This stage rebuilds Libsystem.
+  (prevStage:
+    # previous stage-xclang stdenv:
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage; [
+      autoconf automake bash binutils-unwrapped bison cmake cmakeMinimal coreutils cpio
+      cyrus_sasl db ed expat flex gettext gmp gnugrep groff icu libedit libtool m4 ninja
+      openbsm openldap openpam openssh patchutils pbzx perl pkg-config.pkg-config python3
+      python3Minimal scons serf sqlite subversion sysctl.provider texinfo unzip which xz
+    ]);
+
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage; [
+      brotli curl libffi libiconv libidn2 libkrb5 libssh2 libunistring libxml2 ncurses
+      nghttp2 openssl zlib zstd
+    ]);
+
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage.darwin; [
+      binutils-unwrapped cctools locale libtapi print-reexports rewrite-tbd sigtool system_cmds
+    ]);
+
+    assert (! useAppleSDKLibs) -> lib.all isBuiltByBootstrapFilesCompiler (with prevStage.darwin; [ CF Libsystem configd ]);
+    assert    useAppleSDKLibs  -> lib.all                   isFromNixpkgs (with prevStage.darwin; [ CF Libsystem libobjc ]);
+    assert lib.all isFromNixpkgs (with prevStage.darwin; [ dyld launchd libclosure libdispatch xnu ]);
+
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage.llvmPackages; [
+      clang-unwrapped libclang libllvm llvm
+    ]);
+    assert lib.all isBuiltByNixpkgsCompiler (with prevStage.llvmPackages; [ libcxx libcxxabi ]);
+    assert prevStage.llvmPackages.compiler-rt == null;
+
+    assert lib.getVersion prevStage.stdenv.cc.bintools.bintools == lib.getVersion prevStage.darwin.cctools-port;
+
+    stageFun prevStage {
+
+    name = "bootstrap-stage2-Libsystem";
+
+    overrides = self: super: {
+      inherit (prevStage) ccWrapperStdenv
+        autoconf automake bash binutils-unwrapped bison brotli cmake cmakeMinimal coreutils
+        cpio curl cyrus_sasl db ed expat flex gettext gmp gnugrep groff icu libedit libffi
+        libiconv libidn2 libkrb5 libssh2 libtool libunistring libxml2 m4 ncurses nghttp2
+        ninja openbsm openldap openpam openssh openssl patchutils pbzx perl pkg-config
+        python3 python3Minimal scons serf sqlite subversion sysctl texinfo unzip which xz
+        zlib zstd;
 
-          signingUtils = darwin.signingUtils.override {
-            inherit (selfDarwin) sigtool;
-          };
+      darwin = super.darwin.overrideScope (selfDarwin: superDarwin: {
+        inherit (prevStage.darwin)
+          CF binutils-unwrapped cctools configd darwin-stubs launchd libobjc libtapi locale
+          objc4 print-reexports rewrite-tbd signingUtils sigtool system_cmds;
+      });
 
-          binutils = darwin.binutils.override {
-            coreutils = self.coreutils;
-            libc = selfDarwin.Libsystem;
-            inherit (selfDarwin) postLinkSignHook signingUtils;
+      llvmPackages = super.llvmPackages // (
+        let
+          tools = super.llvmPackages.tools.extend (_: _: {
+            inherit (prevStage.llvmPackages) clang-unwrapped clangNoCompilerRtWithLibc libclang libllvm llvm;
+          });
+
+          libraries = super.llvmPackages.libraries.extend (selfLib: superLib: {
+            inherit (prevStage.llvmPackages) compiler-rt libcxx libcxxabi;
+          });
+        in
+        { inherit tools libraries; inherit (prevStage.llvmPackages) release_version; } // tools // libraries
+      );
+
+      # Don’t link anything in this stage against CF to prevent propagating CF from prior stages to
+      # the final stdenv, which happens because of the rpath hook.
+      stdenv =
+        let
+          stdenvNoCF = super.stdenv.override {
+            extraBuildInputs = [ ];
           };
+        in
+        self.overrideCC stdenvNoCF (self.llvmPackages.clangNoCompilerRtWithLibc.override {
+          inherit (self.llvmPackages) libcxx;
+          extraPackages = [ self.llvmPackages.libcxxabi ];
         });
-      };
-    in
-    with prevStage; stageFun 1 prevStage {
-      extraPreHook = "export NIX_CFLAGS_COMPILE+=\" -F${bootstrapTools}/Library/Frameworks\"";
-      extraNativeBuildInputs = [ ];
-      extraBuildInputs = [ pkgs.darwin.CF ];
-      libcxx = pkgs."${finalLlvmPackages}".libcxx;
-
-      allowedRequisites =
-        [ bootstrapTools ] ++
-        (with pkgs; [ coreutils gnugrep ]) ++
-        (with pkgs."${finalLlvmPackages}"; [ libcxx libcxxabi compiler-rt clang-unwrapped ]) ++
-        (with pkgs.darwin; [ Libsystem CF ] ++ lib.optional useAppleSDKLibs objc4);
-
-      overrides = persistent;
     };
 
-  stage2 = prevStage:
-    let
-      persistent = self: super: with prevStage; {
-        inherit
-          zlib patchutils m4 scons flex perl bison unifdef unzip openssl python3
-          libxml2 gettext sharutils gmp libarchive ncurses pkg-config libedit groff
-          openssh sqlite sed serf openldap db cyrus-sasl expat apr-util subversion xz
-          findfreetype libssh curl cmake autoconf automake libtool ed cpio coreutils
-          libssh2 nghttp2 libkrb5 ninja brotli libiconv;
-
-        "${finalLlvmPackages}" = super."${finalLlvmPackages}" // (
-          let
-            tools = super."${finalLlvmPackages}".tools.extend (_: _: {
-              inherit (pkgs."${finalLlvmPackages}") clang-unwrapped;
-            });
-            libraries = super."${finalLlvmPackages}".libraries.extend (_: libSuper: {
-              inherit (pkgs."${finalLlvmPackages}") compiler-rt;
-              libcxx = libSuper.libcxx.override {
-                stdenv = overrideCC self.stdenv self.ccNoLibcxx;
+    extraNativeBuildInputs = lib.optionals localSystem.isAarch64 [
+      prevStage.updateAutotoolsGnuConfigScriptsHook
+      prevStage.gnu-config
+    ];
+
+    extraPreHook = ''
+      stripDebugFlags="-S" # llvm-strip does not support "-p" for Mach-O
+    '';
+  })
+
+  # This stage rebuilds CF and compiler-rt.
+  #
+  # CF requires:
+  # - aarch64-darwin: libobjc (due to being apple_sdk.frameworks.CoreFoundation instead of swift-corefoundation)
+  # - x86_64-darwin: libiconv libxml2 icu zlib
+  (prevStage:
+    # previous stage2-Libsystem stdenv:
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage; [
+      autoconf automake bash binutils-unwrapped bison brotli cmake cmakeMinimal coreutils
+      cpio curl cyrus_sasl db ed expat flex gettext gmp gnugrep groff icu libedit libidn2
+      libkrb5 libssh2 libtool libunistring m4 nghttp2 ninja openbsm openldap openpam openssh
+      openssl patchutils pbzx perl pkg-config.pkg-config python3 python3Minimal scons serf
+      sqlite subversion sysctl.provider texinfo unzip which xz zstd
+    ]);
+
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage; [
+      libffi libiconv libxml2 ncurses zlib zstd
+    ]);
+
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage.darwin; [
+      binutils-unwrapped cctools locale libtapi print-reexports rewrite-tbd sigtool system_cmds
+    ]);
+
+    assert (! useAppleSDKLibs) -> lib.all isBuiltByBootstrapFilesCompiler (with prevStage.darwin; [ CF configd ]);
+    assert (! useAppleSDKLibs) -> lib.all        isBuiltByNixpkgsCompiler (with prevStage.darwin; [ Libsystem ]);
+    assert    useAppleSDKLibs  -> lib.all                   isFromNixpkgs (with prevStage.darwin; [ CF Libsystem libobjc ]);
+    assert lib.all isFromNixpkgs (with prevStage.darwin; [ dyld launchd libclosure libdispatch xnu ]);
+
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage.llvmPackages; [
+      clang-unwrapped libclang libllvm llvm
+    ]);
+    assert lib.all isBuiltByNixpkgsCompiler (with prevStage.llvmPackages; [ libcxx libcxxabi ]);
+    assert prevStage.llvmPackages.compiler-rt == null;
+
+    assert lib.getVersion prevStage.stdenv.cc.bintools.bintools == lib.getVersion prevStage.darwin.cctools-llvm;
+
+    stageFun prevStage {
+
+    name = "bootstrap-stage2-CF";
+
+    overrides = self: super: {
+      inherit (prevStage) ccWrapperStdenv
+        autoconf automake bash bison brotli cmake cmakeMinimal coreutils cpio curl
+        cyrus_sasl db ed expat flex gettext gmp gnugrep groff libedit libidn2 libkrb5
+        libssh2 libtool libunistring m4 ncurses nghttp2 ninja openbsm openldap openpam
+        openssh openssl patchutils pbzx perl pkg-config python3 python3Minimal scons serf
+        sqlite subversion sysctl texinfo unzip which xz zstd;
+
+      # Avoid pulling in a full python and its extra dependencies for the llvm/clang builds.
+      libxml2 = super.libxml2.override { pythonSupport = false; };
+
+      darwin = super.darwin.overrideScope (selfDarwin: superDarwin: {
+        inherit (prevStage.darwin)
+          Libsystem configd darwin-stubs launchd locale print-reexports rewrite-tbd
+          signingUtils sigtool system_cmds;
+
+        # Rewrap binutils so it uses the rebuilt Libsystem.
+        binutils = superDarwin.binutils.override {
+          buildPackages = {
+            inherit (prevStage) stdenv;
+          };
+          libc = selfDarwin.Libsystem;
+        } // {
+          passthru = { inherit (prevStage.bintools.passthru) isFromBootstrapFiles; };
+        };
+
+        # Avoid building unnecessary Python dependencies due to building LLVM manpages.
+        cctools-llvm = superDarwin.cctools-llvm.override { enableManpages = false; };
+      });
+
+      llvmPackages = super.llvmPackages // (
+        let
+          tools = super.llvmPackages.tools.extend (_: _: {
+            inherit (prevStage.llvmPackages) clang-unwrapped clangNoCompilerRtWithLibc libclang libllvm llvm;
+            clang = prevStage.stdenv.cc;
+          });
+
+          libraries = super.llvmPackages.libraries.extend (selfLib: superLib: {
+            inherit (prevStage.llvmPackages) libcxx libcxxabi;
+
+            # Make sure compiler-rt is linked against the CF from this stage, which can be
+            # propagated to the final stdenv. CF is required by ASAN.
+            compiler-rt = superLib.compiler-rt.override ({
+              inherit (selfLib) libcxxabi;
+              inherit (self.llvmPackages) libllvm;
+              stdenv = self.stdenv.override {
+                extraBuildInputs = [ self.darwin.CF ];
               };
-              libcxxabi = libSuper.libcxxabi.override ({
-                stdenv = overrideCC self.stdenv self.ccNoLibcxx;
-              } // lib.optionalAttrs (builtins.any (v: finalLlvmVersion == v) [ 7 11 12 13 ]) {
-                # TODO: the bootstrapping of llvm packages isn't consistent.
-                # `standalone` may be redundant if darwin behaves like useLLVM (or
-                # has useLLVM = true).
-                standalone = true;
-              });
             });
-          in
-          { inherit tools libraries; } // tools // libraries
-        );
+          });
+        in
+        { inherit tools libraries; inherit (prevStage.llvmPackages) release_version; } // tools // libraries
+      );
 
-        darwin = super.darwin.overrideScope (_: _: {
-          inherit (darwin)
-            binutils dyld Libsystem xnu configd ICU libdispatch libclosure
-            launchd CF objc4 darwin-stubs sigtool postLinkSignHook signingUtils;
-        });
-      };
-    in
-    with prevStage; stageFun 2 prevStage {
-      extraPreHook = ''
-        export PATH_LOCALE=${pkgs.darwin.locale}/share/locale
-      '';
+      # Don’t link anything in this stage against CF to prevent propagating CF from prior stages to
+      # the final stdenv, which happens because of the rpath hook. Also don’t use a stdenv with
+      # compiler-rt because it needs to be built in this stage.
+      stdenv =
+        let
+          stdenvNoCF = super.stdenv.override {
+            extraBuildInputs = [ ];
+          };
+        in
+        self.overrideCC stdenvNoCF (self.llvmPackages.clangNoCompilerRtWithLibc.override {
+          inherit (self.llvmPackages) libcxx;
+
+          # Make sure the stdenv is using the Libsystem that will be propagated to the final stdenv.
+          libc = self.darwin.Libsystem;
+          bintools = self.llvmPackages.clangNoCompilerRtWithLibc.bintools.override {
+            libc = self.darwin.Libsystem;
+          };
 
-      extraNativeBuildInputs = [ pkgs.xz ];
-      extraBuildInputs = [ pkgs.darwin.CF ];
-      libcxx = pkgs."${finalLlvmPackages}".libcxx;
-
-      allowedRequisites =
-        [ bootstrapTools ] ++
-        (with pkgs; [
-          xz.bin
-          xz.out
-          zlib
-          libxml2.out
-          curl.out
-          openssl.out
-          libssh2.out
-          nghttp2.lib
-          coreutils
-          gnugrep
-          gnugrep.pcre2.out
-          gmp
-          libiconv
-          brotli.lib
-          file
-        ] ++ lib.optional haveKRB5 libkrb5) ++
-        (with pkgs."${finalLlvmPackages}"; [
-          libcxx
-          libcxxabi
-          compiler-rt
-          clang-unwrapped
-        ]) ++
-        (with pkgs.darwin; [ dyld Libsystem CF ICU locale ] ++ lib.optional useAppleSDKLibs objc4);
-
-      overrides = persistent;
+          extraPackages = [ self.llvmPackages.libcxxabi ];
+        });
     };
 
-  stage3 = prevStage:
-    let
-      persistent = self: super: with prevStage; {
-        inherit
-          patchutils m4 scons flex perl bison unifdef unzip openssl python3
-          gettext sharutils libarchive pkg-config groff bash subversion
-          openssh sqlite sed serf openldap db cyrus-sasl expat apr-util
-          findfreetype libssh curl cmake autoconf automake libtool cpio
-          libssh2 nghttp2 libkrb5 ninja;
-
-        # Avoid pulling in a full python and its extra dependencies for the llvm/clang builds.
-        libxml2 = super.libxml2.override { pythonSupport = false; };
-
-        "${finalLlvmPackages}" = super."${finalLlvmPackages}" // (
-          let
-            libraries = super."${finalLlvmPackages}".libraries.extend (_: _: {
-              inherit (pkgs."${finalLlvmPackages}") libcxx libcxxabi;
-            });
-          in
-          { inherit libraries; } // libraries
-        );
+    extraNativeBuildInputs = lib.optionals localSystem.isAarch64 [
+      prevStage.updateAutotoolsGnuConfigScriptsHook
+      prevStage.gnu-config
+    ];
+
+    extraPreHook = ''
+      stripDebugFlags="-S" # llvm-strip does not support "-p" for Mach-O
+    '';
+  })
+
+  # Rebuild LLVM with LLVM. This stage also rebuilds certain dependencies needed by LLVM.
+  #
+  # LLVM requires: libcxx libcxxabi libffi libiconv libxml2 ncurses zlib
+  (prevStage:
+    # previous stage2-CF stdenv:
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage; [
+      autoconf automake bash bison brotli cmake cmakeMinimal coreutils cpio curl cyrus_sasl
+      db ed expat flex gettext gmp gnugrep groff libedit libidn2 libkrb5 libssh2 libtool
+      libunistring m4 ncurses nghttp2 ninja openbsm openldap openpam openssh openssl
+      patchutils pbzx perl pkg-config.pkg-config python3 python3Minimal scons serf sqlite
+      subversion sysctl.provider texinfo unzip which xz zstd
+    ]);
+    assert lib.all isBuiltByNixpkgsCompiler (with prevStage; [
+      binutils-unwrapped icu libffi libiconv libxml2 zlib
+    ]);
+
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage.darwin; [
+      locale print-reexports rewrite-tbd sigtool system_cmds
+    ]);
+    assert lib.all isBuiltByNixpkgsCompiler (with prevStage.darwin; [
+      binutils-unwrapped cctools libtapi
+    ]);
+
+    assert (! useAppleSDKLibs) -> lib.all isBuiltByBootstrapFilesCompiler (with prevStage.darwin; [ configd ]);
+    assert (! useAppleSDKLibs) -> lib.all        isBuiltByNixpkgsCompiler (with prevStage.darwin; [ CF Libsystem ]);
+    assert    useAppleSDKLibs  -> lib.all                   isFromNixpkgs (with prevStage.darwin; [ CF Libsystem libobjc ]);
+    assert lib.all isFromNixpkgs (with prevStage.darwin; [ dyld launchd libclosure libdispatch xnu ]);
+
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage.llvmPackages; [
+      clang-unwrapped libclang libllvm llvm
+    ]);
+    assert lib.all isBuiltByNixpkgsCompiler (with prevStage.llvmPackages; [ libcxx libcxxabi ]);
+
+    assert lib.getVersion prevStage.stdenv.cc.bintools.bintools == lib.getVersion prevStage.darwin.cctools-llvm;
+
+    stageFun prevStage {
+
+    name = "bootstrap-stage3";
+
+    overrides = self: super: {
+      inherit (prevStage) ccWrapperStdenv
+        autoconf automake bash binutils binutils-unwrapped bison brotli cmake cmakeMinimal
+        coreutils cpio curl cyrus_sasl db ed expat flex gettext gmp gnugrep groff libedit
+        libidn2 libkrb5 libssh2 libtool libunistring m4 nghttp2 ninja openbsm openldap
+        openpam openssh openssl patchutils pbzx perl pkg-config python3 python3Minimal scons
+        sed serf sharutils sqlite subversion sysctl texinfo unzip which xz zstd
+
+        # CF dependencies - don’t rebuild them.
+        icu libiconv libxml2 zlib;
+
+      # Disable tests because they use dejagnu, which fails to run.
+      libffi = super.libffi.override { doCheck = false; };
 
-        darwin = super.darwin.overrideScope (_: _: {
-          inherit (darwin)
-            dyld Libsystem xnu configd libdispatch libclosure launchd libiconv
-            locale darwin-stubs sigtool;
-        });
-      };
-    in
-    with prevStage; stageFun 3 prevStage {
-      shell = "${pkgs.bash}/bin/bash";
-
-      # We have a valid shell here (this one has no bootstrap-tools runtime deps) so stageFun
-      # enables patchShebangs above. Unfortunately, patchShebangs ignores our $SHELL setting
-      # and instead goes by $PATH, which happens to contain bootstrapTools. So it goes and
-      # patches our shebangs back to point at bootstrapTools. This makes sure bash comes first.
-      extraNativeBuildInputs = with pkgs; [ xz ];
-      extraBuildInputs = [ pkgs.darwin.CF pkgs.bash ];
-      libcxx = pkgs."${finalLlvmPackages}".libcxx;
-
-      extraPreHook = ''
-        export PATH=${pkgs.bash}/bin:$PATH
-        export PATH_LOCALE=${pkgs.darwin.locale}/share/locale
-      '';
+      darwin = super.darwin.overrideScope (selfDarwin: superDarwin: {
+        inherit (prevStage.darwin)
+          CF Libsystem binutils binutils-unwrapped cctools cctools-llvm cctools-port configd
+          darwin-stubs dyld launchd libclosure libdispatch libobjc libtapi locale objc4
+          postLinkSignHook print-reexports rewrite-tbd signingUtils sigtool system_cmds;
+      });
 
-      allowedRequisites =
-        [ bootstrapTools ] ++
-        (with pkgs; [
-          xz.bin
-          xz.out
-          bash
-          zlib
-          libxml2.out
-          curl.out
-          openssl.out
-          libssh2.out
-          nghttp2.lib
-          coreutils
-          gnugrep
-          gnugrep.pcre2.out
-          gmp
-          libiconv
-          brotli.lib
-          file
-        ] ++ lib.optional haveKRB5 libkrb5) ++
-        (with pkgs."${finalLlvmPackages}"; [
-          libcxx
-          libcxx.dev
-          libcxxabi
-          libcxxabi.dev
-          compiler-rt
-          clang-unwrapped
-        ]) ++
-        (with pkgs.darwin; [ dyld ICU Libsystem locale ] ++ lib.optional useAppleSDKLibs objc4);
-
-      overrides = persistent;
+      llvmPackages = super.llvmPackages // (
+        let
+          libraries = super.llvmPackages.libraries.extend (_: _: {
+           inherit (prevStage.llvmPackages) compiler-rt libcxx libcxxabi;
+          });
+        in
+        { inherit libraries; } // libraries
+      );
     };
 
-  stage4 = prevStage:
-    let
-      persistent = self: super: with prevStage; {
-        inherit
-          gnumake gzip gnused bzip2 ed xz patch bash python3
-          ncurses libffi zlib gmp gnugrep cmake
-          coreutils findutils diffutils patchutils ninja libxml2;
-        inherit (gnugrep) pcre2;
-
-        # Hack to make sure we don't link ncurses in bootstrap tools. The proper
-        # solution is to avoid passing -L/nix-store/...-bootstrap-tools/lib,
-        # quite a sledgehammer just to get the C runtime.
-        gettext = super.gettext.overrideAttrs (drv: {
-          configureFlags = drv.configureFlags ++ [
-            "--disable-curses"
-          ];
-        });
+    extraNativeBuildInputs = lib.optionals localSystem.isAarch64 [
+      prevStage.updateAutotoolsGnuConfigScriptsHook
+      prevStage.gnu-config
+    ];
+
+    extraPreHook = ''
+      stripDebugFlags="-S" # llvm-strip does not support "-p" for Mach-O
+    '';
+  })
+
+  # Construct a standard environment with the new clang. Also use the new compiler to rebuild
+  # everything that will be part of the final stdenv and isn’t required by it, CF, or Libsystem.
+  (prevStage:
+    # previous stage3 stdenv:
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage; [
+      autoconf automake bash bison brotli cmake cmakeMinimal coreutils cpio curl cyrus_sasl
+      db ed expat flex gettext gmp gnugrep groff libedit libidn2 libkrb5 libssh2 libtool
+      libunistring m4 nghttp2 ninja openbsm openldap openpam openssh openssl patchutils pbzx
+      perl pkg-config.pkg-config python3 python3Minimal scons serf sqlite subversion
+      sysctl.provider texinfo unzip which xz zstd
+    ]);
+
+    assert lib.all isBuiltByNixpkgsCompiler (with prevStage; [
+      binutils-unwrapped icu libffi libiconv libxml2 zlib
+    ]);
+
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage.darwin; [
+      locale print-reexports rewrite-tbd sigtool system_cmds
+    ]);
+    assert lib.all isBuiltByNixpkgsCompiler (with prevStage.darwin; [
+      binutils-unwrapped cctools libtapi
+    ]);
+
+    assert (! useAppleSDKLibs) -> lib.all isBuiltByBootstrapFilesCompiler (with prevStage.darwin; [ configd ]);
+    assert (! useAppleSDKLibs) -> lib.all        isBuiltByNixpkgsCompiler (with prevStage.darwin; [ CF Libsystem ]);
+    assert    useAppleSDKLibs  -> lib.all                   isFromNixpkgs (with prevStage.darwin; [ CF Libsystem libobjc ]);
+    assert lib.all isFromNixpkgs (with prevStage.darwin; [ dyld launchd libclosure libdispatch xnu ]);
+
+    assert lib.all isBuiltByNixpkgsCompiler (with prevStage.llvmPackages; [
+      clang-unwrapped libclang libllvm llvm compiler-rt libcxx libcxxabi
+    ]);
+
+    assert lib.getVersion prevStage.stdenv.cc.bintools.bintools == lib.getVersion prevStage.darwin.cctools-llvm;
+
+    stageFun prevStage {
+
+    name = "bootstrap-stage4";
+
+    overrides = self: super: {
+      inherit (prevStage) ccWrapperStdenv
+        autoconf automake bison cmake cmakeMinimal cpio cyrus_sasl db expat flex groff
+        libedit libtool m4 ninja openldap openssh patchutils pbzx perl pkg-config python3
+        python3Minimal scons serf sqlite subversion sysctl texinfo unzip which
+
+        # CF dependencies - don’t rebuild them.
+        icu
+
+        # LLVM dependencies - don’t rebuild them.
+        libffi libiconv libxml2 ncurses zlib;
 
-        "${finalLlvmPackages}" = super."${finalLlvmPackages}" // (
-          let
-            tools = super."${finalLlvmPackages}".tools.extend (llvmSelf: _: {
-              clang-unwrapped-all-outputs = pkgs."${finalLlvmPackages}".clang-unwrapped-all-outputs.override { llvm = llvmSelf.llvm; };
-              libllvm = pkgs."${finalLlvmPackages}".libllvm.override { inherit libxml2; };
-            });
-            libraries = super."${finalLlvmPackages}".libraries.extend (llvmSelf: _: {
-              inherit (pkgs."${finalLlvmPackages}") libcxx libcxxabi compiler-rt;
-            });
-          in
-          { inherit tools libraries; } // tools // libraries
-        );
+      darwin = super.darwin.overrideScope (selfDarwin: superDarwin: {
+        inherit (prevStage.darwin) dyld CF Libsystem darwin-stubs
+          # CF dependencies - don’t rebuild them.
+          libobjc objc4;
 
-        darwin = super.darwin.overrideScope (_: superDarwin: {
-          inherit (darwin) dyld Libsystem libiconv locale darwin-stubs;
+        signingUtils = superDarwin.signingUtils.override {
+          inherit (selfDarwin) sigtool;
+        };
+
+        binutils = superDarwin.binutils.override {
+          shell = self.bash + "/bin/bash";
 
-          # See useAppleSDKLibs in darwin-packages.nix
-          CF = if useAppleSDKLibs then super.darwin.CF else
-          superDarwin.CF.override {
-            inherit libxml2;
-            python3 = prevStage.python3;
+          buildPackages = {
+            inherit (prevStage) stdenv;
           };
-        });
-      };
-    in
-    with prevStage; stageFun 4 prevStage {
-      shell = "${pkgs.bash}/bin/bash";
-      extraNativeBuildInputs = with pkgs; [ xz ];
-      extraBuildInputs = [ pkgs.darwin.CF pkgs.bash ];
-      libcxx = pkgs."${finalLlvmPackages}".libcxx;
-
-      extraPreHook = ''
-        export PATH_LOCALE=${pkgs.darwin.locale}/share/locale
-      '';
-      overrides = persistent;
+
+          bintools = selfDarwin.binutils-unwrapped;
+          libc = selfDarwin.Libsystem;
+        };
+      });
+
+      llvmPackages = super.llvmPackages // (
+        let
+          tools = super.llvmPackages.tools.extend (_: _: {
+            inherit (prevStage.llvmPackages) clang-unwrapped libclang libllvm llvm;
+            libcxxClang = lib.makeOverridable (import ../../build-support/cc-wrapper) {
+              nativeTools = false;
+              nativeLibc = false;
+
+              buildPackages = {
+                inherit (prevStage) stdenv;
+              };
+
+              extraPackages = [
+                self.llvmPackages.libcxxabi
+                self.llvmPackages.compiler-rt
+              ];
+
+              extraBuildCommands =
+                let
+                  inherit (self.llvmPackages) clang-unwrapped compiler-rt release_version;
+
+                  # Clang 16+ uses only the major version in resource-root, but older versions use the complete one.
+                  clangResourceRootIncludePath = clangLib: clangRelease:
+                    let
+                      clangVersion =
+                        if lib.versionAtLeast clangRelease "16"
+                        then lib.versions.major clangRelease
+                        else clangRelease;
+                    in
+                    "${clangLib}/lib/clang/${clangVersion}/include";
+                in
+                ''
+                  rsrc="$out/resource-root"
+                  mkdir "$rsrc"
+                  ln -s "${clangResourceRootIncludePath clang-unwrapped.lib release_version}" "$rsrc"
+                  ln -s "${compiler-rt.out}/lib"   "$rsrc/lib"
+                  ln -s "${compiler-rt.out}/share" "$rsrc/share"
+                  echo "-resource-dir=$rsrc" >> $out/nix-support/cc-cflags
+                '';
+
+              cc = self.llvmPackages.clang-unwrapped;
+              bintools = self.darwin.binutils;
+
+              isClang = true;
+              libc = self.darwin.Libsystem;
+              inherit (self.llvmPackages) libcxx;
+
+              inherit lib;
+              inherit (self) stdenvNoCC coreutils gnugrep;
+
+              shell = self.bash + "/bin/bash";
+            };
+          });
+          libraries = super.llvmPackages.libraries.extend (_: _:{
+            inherit (prevStage.llvmPackages) compiler-rt libcxx libcxxabi;
+          });
+        in
+        { inherit tools libraries; } // tools // libraries
+      );
     };
 
-  stdenvDarwin = prevStage:
+    extraNativeBuildInputs = lib.optionals localSystem.isAarch64 [
+      prevStage.updateAutotoolsGnuConfigScriptsHook
+      prevStage.gnu-config
+    ];
+
+    extraPreHook = ''
+      stripDebugFlags="-S" # llvm-strip does not support "-p" for Mach-O
+    '';
+  })
+
+  # Construct the final stdenv. The version of LLVM provided should match the one defined in
+  # `all-packages.nix` for Darwin. Nothing should depend on the bootstrap tools or originate from
+  # the bootstrap tools.
+  #
+  # When updating the Darwin stdenv, make sure that the result has no dependency (`nix-store -qR`)
+  # on `bootstrapTools` or the binutils built in stage 1.
+  (prevStage:
+    # previous stage4 stdenv:
+    assert lib.all isBuiltByNixpkgsCompiler (with prevStage; [
+      bash binutils-unwrapped brotli bzip2 curl diffutils ed file findutils gawk gettext gmp
+      gnugrep gnumake gnused gnutar gzip icu libffi libiconv libidn2 libkrb5 libssh2
+      libunistring libxml2 ncurses nghttp2 openbsm openpam openssl patch pcre xz zlib zstd
+    ]);
+
+    assert lib.all isBuiltByNixpkgsCompiler (with prevStage.darwin; [
+      binutils-unwrapped cctools libtapi locale print-reexports rewrite-tbd sigtool system_cmds
+    ]);
+
+    assert (! useAppleSDKLibs) -> lib.all isBuiltByNixpkgsCompiler (with prevStage.darwin; [ CF Libsystem configd ]);
+    assert    useAppleSDKLibs  -> lib.all            isFromNixpkgs (with prevStage.darwin; [ CF Libsystem libobjc ]);
+    assert lib.all isFromNixpkgs (with prevStage.darwin; [ dyld launchd libclosure libdispatch xnu ]);
+
+    assert lib.all isBuiltByNixpkgsCompiler (with prevStage.llvmPackages; [
+      clang-unwrapped libclang libllvm llvm compiler-rt libcxx libcxxabi
+    ]);
+
+    assert lib.all isBuiltByBootstrapFilesCompiler (with prevStage; [
+      autoconf automake bison cmake cmakeMinimal cpio cyrus_sasl db expat flex groff libedit
+      libtool m4 ninja openldap openssh patchutils pbzx perl pkg-config.pkg-config python3
+      python3Minimal scons serf sqlite subversion sysctl.provider texinfo unzip which
+    ]);
+
+    assert prevStage.darwin.cctools == prevStage.darwin.cctools-llvm;
+
     let
       doSign = localSystem.isAarch64;
-      pkgs = prevStage;
-      persistent = self: super: with prevStage; {
-        inherit
-          gnumake gzip gnused bzip2 gawk ed xz patch bash
-          ncurses libffi zlib gmp gnugrep
-          coreutils findutils diffutils patchutils pbzx;
-        inherit (gnugrep) pcre2;
-
-        darwin = super.darwin.overrideScope (_: _: {
-          inherit (darwin) dyld ICU Libsystem Csu libiconv rewrite-tbd;
-        } // lib.optionalAttrs (super.stdenv.targetPlatform == localSystem) {
-          inherit (darwin) binutils binutils-unwrapped cctools-port;
-        });
-      } // lib.optionalAttrs (super.stdenv.targetPlatform == localSystem) {
-        inherit llvm;
-
-        # Need to get rid of these when cross-compiling.
-        "${finalLlvmPackages}" = super."${finalLlvmPackages}" // (
-          let
-            tools = super."${finalLlvmPackages}".tools.extend (_: super: {
-              inherit (pkgs."${finalLlvmPackages}") llvm clang-unwrapped;
-            });
-            libraries = super."${finalLlvmPackages}".libraries.extend (_: _: {
-              inherit (pkgs."${finalLlvmPackages}") compiler-rt libcxx libcxxabi;
-            });
-          in
-          { inherit tools libraries; } // tools // libraries
-        );
 
-        inherit binutils binutils-unwrapped;
-      };
+      cc = prevStage.llvmPackages.clang;
     in
-    import ../generic rec {
+    {
+    inherit config overlays;
+    stdenv = import ../generic {
       name = "stdenv-darwin";
 
-      inherit config;
-      inherit (pkgs.stdenv) fetchurlBoot;
-
       buildPlatform = localSystem;
       hostPlatform = localSystem;
       targetPlatform = localSystem;
 
-      preHook = commonPreHook + ''
-        export PATH_LOCALE=${pkgs.darwin.locale}/share/locale
-      '';
-
-      __stdenvImpureHostDeps = commonImpureHostDeps;
-      __extraImpureHostDeps = commonImpureHostDeps;
+      inherit config;
 
-      initialPath = import ../generic/common-path.nix { inherit pkgs; };
-      shell = "${pkgs.bash}/bin/bash";
+      preHook = (commonPreHook prevStage) + ''
+        stripDebugFlags="-S" # llvm-strip does not support "-p" for Mach-O
+        export PATH_LOCALE=${prevStage.darwin.locale}/share/locale
+      '';
 
-      cc = pkgs."${finalLlvmPackages}".libcxxClang;
+      initialPath = ((import ../generic/common-path.nix) { pkgs = prevStage; });
 
       extraNativeBuildInputs = lib.optionals localSystem.isAarch64 [
-        pkgs.updateAutotoolsGnuConfigScriptsHook
+        prevStage.updateAutotoolsGnuConfigScriptsHook
       ];
 
-      extraBuildInputs = [ pkgs.darwin.CF ];
+      extraBuildInputs = [ prevStage.darwin.CF ];
+
+      inherit cc;
+
+      shell = cc.shell;
+
+      inherit (prevStage.stdenv) fetchurlBoot;
 
       extraAttrs = {
-        libc = pkgs.darwin.Libsystem;
-        shellPackage = pkgs.bash;
         inherit bootstrapTools;
+        libc = prevStage.darwin.Libsystem;
+        shellPackage = prevStage.bash;
       } // lib.optionalAttrs useAppleSDKLibs {
         # This objc4 will be propagated to all builds using the final stdenv,
         # and we shouldn't mix different builds, because they would be
         # conflicting LLVM modules. Export it here so we can grab it later.
-        inherit (pkgs.darwin) objc4;
+        inherit (prevStage.darwin) objc4;
       };
 
-      allowedRequisites = (with pkgs; [
-        xz.out
-        xz.bin
-        gmp.out
-        gnumake
-        findutils
-        bzip2.out
+      disallowedRequisites = [ bootstrapTools.out ];
+
+      allowedRequisites = (with prevStage; [
+        bash
+        binutils.bintools
+        binutils.bintools.lib
         bzip2.bin
-        zlib.out
-        zlib.dev
-        libffi.out
+        bzip2.out
+        cc.expand-response-params
         coreutils
-        ed
+        darwin.binutils
+        darwin.binutils.bintools
         diffutils
-        gnutar
-        gzip
-        ncurses.out
-        ncurses.dev
-        ncurses.man
-        gnused
-        bash
+        ed
+        file
+        findutils
         gawk
+        gettext
+        gmp.out
         gnugrep
-        patch
         gnugrep.pcre2.out
-        gettext
-        binutils.bintools
-        binutils.bintools.lib
-        darwin.binutils
-        darwin.binutils.bintools
-        curl.out
-        zstd.out
-        libidn2.out
+        gnumake
+        gnused
+        gnutar
+        gzip
+        icu.out
+        libffi.out
+        libiconv
         libunistring.out
-        openssl.out
-        libssh2.out
-        nghttp2.lib
-        brotli.lib
-        cc.expand-response-params
         libxml2.out
-        file
-      ] ++ lib.optional haveKRB5 libkrb5
+        ncurses.dev
+        ncurses.man
+        ncurses.out
+        openbsm
+        openpam
+        patch
+        xz.bin
+        xz.out
+        zlib.dev
+        zlib.out
+      ]
+      ++ lib.optionals doSign [ openssl.out ])
       ++ lib.optionals localSystem.isAarch64 [
-        pkgs.updateAutotoolsGnuConfigScriptsHook
-        pkgs.gnu-config
-      ])
-      ++ (with pkgs."${finalLlvmPackages}"; [
+        prevStage.updateAutotoolsGnuConfigScriptsHook
+        prevStage.gnu-config
+      ]
+      ++ (with prevStage.llvmPackages; [
+        bintools-unwrapped
+        clang-unwrapped
+        clang-unwrapped.lib
+        compiler-rt
+        compiler-rt.dev
         libcxx
         libcxx.dev
         libcxxabi
         libcxxabi.dev
+        lld
         llvm
         llvm.lib
-        compiler-rt
-        compiler-rt.dev
-        clang-unwrapped
-        libclang.dev
-        libclang.lib
       ])
-      ++ (with pkgs.darwin; [
-        dyld
-        Libsystem
+      ++ (with prevStage.darwin; [
         CF
-        cctools
-        ICU
-        libiconv
-        locale
+        Libsystem
+        cctools-llvm
+        cctools-port
+        dyld
         libtapi
-      ] ++ lib.optional useAppleSDKLibs objc4
+        locale
+        system_cmds
+      ]
+      ++ lib.optional useAppleSDKLibs [ objc4 ]
       ++ lib.optionals doSign [ postLinkSignHook sigtool signingUtils ]);
 
-      overrides = lib.composeExtensions persistent (self: super: {
-        darwin = super.darwin.overrideScope (_: superDarwin: {
-          inherit (prevStage.darwin) CF darwin-stubs;
-          xnu = superDarwin.xnu.override { inherit (prevStage) python3; };
+      __stdenvImpureHostDeps = commonImpureHostDeps;
+      __extraImpureHostDeps = commonImpureHostDeps;
+
+      overrides = self: super: {
+        inherit (prevStage)
+          bash binutils brotli bzip2 coreutils curl diffutils ed file findutils gawk gettext
+          gmp gnugrep gnumake gnused gnutar gzip icu libffi libiconv libidn2 libssh2
+          libunistring libxml2 ncurses nghttp2 openbsm openpam openssl patch pcre xz zlib
+          zstd;
+
+        darwin = super.darwin.overrideScope (_: _: {
+          inherit (prevStage.darwin)
+            CF ICU Libsystem darwin-stubs dyld locale libobjc libtapi system_cmds xnu;
+        } // lib.optionalAttrs (super.stdenv.targetPlatform == localSystem) {
+          inherit (prevStage.darwin) binutils binutils-unwrapped cctools-llvm cctools-port;
         });
       } // lib.optionalAttrs (super.stdenv.targetPlatform == localSystem) {
-        clang = cc;
-        llvmPackages = super.llvmPackages // { clang = cc; };
-        inherit cc;
-      });
-    };
+        inherit (prevStage.llvmPackages) clang llvm;
 
-  stagesDarwin = [
-    ({}: stage0)
-    stage1
-    stage2
-    stage3
-    stage4
-    (prevStage: {
-      inherit config overlays;
-      stdenv = stdenvDarwin prevStage;
-    })
-  ];
-}
+        # Need to get rid of these when cross-compiling.
+        llvmPackages = super.llvmPackages // (
+          let
+            tools = super.llvmPackages.tools.extend (_: _: {
+              inherit (prevStage.llvmPackages) clang clang-unwrapped libclang libllvm llvm;
+            });
+            libraries = super.llvmPackages.libraries.extend (_: _: {
+              inherit (prevStage.llvmPackages) compiler-rt libcxx libcxxabi;
+            });
+          in
+          { inherit tools libraries; } // tools // libraries
+        );
+
+        inherit (prevStage) binutils binutils-unwrapped;
+      };
+    };
+  })
+
+  # This "no-op" stage is just a place to put the assertions about stage6.
+  (prevStage:
+    # previous final stage stdenv:
+    assert isBuiltByNixpkgsCompiler prevStage.darwin.sigtool;
+    assert isBuiltByNixpkgsCompiler prevStage.darwin.binutils-unwrapped;
+    assert isBuiltByNixpkgsCompiler prevStage.darwin.print-reexports;
+    assert isBuiltByNixpkgsCompiler prevStage.darwin.rewrite-tbd;
+    assert isBuiltByNixpkgsCompiler prevStage.darwin.cctools;
+
+    assert            isFromNixpkgs prevStage.darwin.CF;
+    assert            isFromNixpkgs prevStage.darwin.Libsystem;
+
+    assert isBuiltByNixpkgsCompiler prevStage.llvmPackages.clang-unwrapped;
+    assert isBuiltByNixpkgsCompiler prevStage.llvmPackages.libllvm;
+    assert isBuiltByNixpkgsCompiler prevStage.llvmPackages.libcxx;
+    assert isBuiltByNixpkgsCompiler prevStage.llvmPackages.libcxxabi;
+    assert isBuiltByNixpkgsCompiler prevStage.llvmPackages.compiler-rt;
+    { inherit (prevStage) config overlays stdenv; })
+]
diff --git a/pkgs/stdenv/default.nix b/pkgs/stdenv/default.nix
index 7a2ad665e09..6cc1339752a 100644
--- a/pkgs/stdenv/default.nix
+++ b/pkgs/stdenv/default.nix
@@ -28,7 +28,7 @@ let
   # the GNU C compiler, and so on.
   stagesLinux = import ./linux args;
 
-  inherit (import ./darwin args) stagesDarwin;
+  stagesDarwin = import ./darwin args;
 
   stagesCross = import ./cross args;