about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--pkgs/os-specific/darwin/swift-corelibs/0002-Add-missing-launchd-header.patch11
-rw-r--r--pkgs/os-specific/darwin/swift-corelibs/0003-Fix-incompatible-pointer-conversion.patch25
-rw-r--r--pkgs/os-specific/darwin/swift-corelibs/0004-Fix-Darwin-cmake-build.patch66
-rw-r--r--pkgs/os-specific/darwin/swift-corelibs/0005-Fix-framework-installation-path.patch23
-rw-r--r--pkgs/os-specific/darwin/swift-corelibs/0006-System-CF-framework-compatibility.patch84
-rw-r--r--pkgs/os-specific/darwin/swift-corelibs/0007-Use-nixpkgs-icu.patch31
-rw-r--r--pkgs/os-specific/darwin/swift-corelibs/0008-Dont-link-libcurl.patch46
-rw-r--r--pkgs/os-specific/darwin/swift-corelibs/corefoundation.nix104
-rw-r--r--pkgs/stdenv/darwin/README.md26
-rw-r--r--pkgs/stdenv/darwin/default.nix1679
-rw-r--r--pkgs/stdenv/default.nix2
-rw-r--r--pkgs/top-level/darwin-packages.nix2
12 files changed, 1479 insertions, 620 deletions
diff --git a/pkgs/os-specific/darwin/swift-corelibs/0002-Add-missing-launchd-header.patch b/pkgs/os-specific/darwin/swift-corelibs/0002-Add-missing-launchd-header.patch
new file mode 100644
index 0000000000000..b1187c56587e0
--- /dev/null
+++ b/pkgs/os-specific/darwin/swift-corelibs/0002-Add-missing-launchd-header.patch
@@ -0,0 +1,11 @@
+--- a/CoreFoundation/RunLoop.subproj/CFMessagePort.c	1969-12-31 19:00:01.000000000 -0500
++++ b/CoreFoundation/RunLoop.subproj/CFMessagePort.c	2023-06-09 20:25:28.599209755 -0400
+@@ -28,6 +28,8 @@
+ #endif
+ #endif
+ 
++#include <bootstrap.h>
++
+ extern pid_t getpid(void);
+ 
+ #define __kCFMessagePortMaxNameLengthMax 255
diff --git a/pkgs/os-specific/darwin/swift-corelibs/0003-Fix-incompatible-pointer-conversion.patch b/pkgs/os-specific/darwin/swift-corelibs/0003-Fix-incompatible-pointer-conversion.patch
new file mode 100644
index 0000000000000..910b622ed3ce2
--- /dev/null
+++ b/pkgs/os-specific/darwin/swift-corelibs/0003-Fix-incompatible-pointer-conversion.patch
@@ -0,0 +1,25 @@
+diff -u a/CoreFoundation/URL.subproj/CFURLComponents.c b/CoreFoundation/URL.subproj/CFURLComponents.c
+--- a/CoreFoundation/URL.subproj/CFURLComponents.c	1969-12-31 19:00:01.000000000 -0500
++++ b/CoreFoundation/URL.subproj/CFURLComponents.c	2023-06-09 20:36:52.995514573 -0400
+@@ -66,7 +66,8 @@
+     return CFRetain(CFSTR("A really nice CFURLComponents object"));
+ }
+ 
+-CF_CROSS_PLATFORM_EXPORT void __CFURLComponentsDeallocate(CFURLComponentsRef instance) {
++CF_CROSS_PLATFORM_EXPORT void __CFURLComponentsDeallocate(CFTypeRef cf) {
++    CFURLComponentsRef instance = (CFURLComponentsRef)cf;
+     __CFGenericValidateType(instance, _CFURLComponentsGetTypeID());
+     
+     if (instance->_urlString) CFRelease(instance->_urlString);
+diff -u a/CoreFoundation/URL.subproj/CFURLComponents.h b/CoreFoundation/URL.subproj/CFURLComponents.h
+--- a/CoreFoundation/URL.subproj/CFURLComponents.h	1969-12-31 19:00:01.000000000 -0500
++++ b/CoreFoundation/URL.subproj/CFURLComponents.h	2023-06-09 20:39:36.967857713 -0400
+@@ -38,7 +38,7 @@
+ 
+ CF_EXPORT CFTypeID _CFURLComponentsGetTypeID(void);
+ 
+-CF_CROSS_PLATFORM_EXPORT void __CFURLComponentsDeallocate(CFURLComponentsRef);
++CF_CROSS_PLATFORM_EXPORT void __CFURLComponentsDeallocate(CFTypeRef);
+ 
+ // URLComponents are always mutable.
+ CF_EXPORT _Nullable CFURLComponentsRef _CFURLComponentsCreate(CFAllocatorRef alloc);
diff --git a/pkgs/os-specific/darwin/swift-corelibs/0004-Fix-Darwin-cmake-build.patch b/pkgs/os-specific/darwin/swift-corelibs/0004-Fix-Darwin-cmake-build.patch
new file mode 100644
index 0000000000000..afffa1abc8e02
--- /dev/null
+++ b/pkgs/os-specific/darwin/swift-corelibs/0004-Fix-Darwin-cmake-build.patch
@@ -0,0 +1,66 @@
+--- a/CoreFoundation/CMakeLists.txt	1969-12-31 19:00:01.000000000 -0500
++++ b/CoreFoundation/CMakeLists.txt	2023-06-29 18:52:49.096019700 -0400
+@@ -129,7 +129,7 @@
+                 Base.subproj/CFByteOrder.h
+                 Base.subproj/CFUUID.h
+                 Base.subproj/CFUtilities.h
+-                Base.subproj/SwiftRuntime/CoreFoundation.h
++                Base.subproj/CoreFoundation.h  # The SwiftRuntime version of this file causes linker errors and is not correct for standalone CF.
+                 Base.subproj/SwiftRuntime/TargetConditionals.h
+                 # Collections
+                 Collections.subproj/CFArray.h
+@@ -245,6 +245,8 @@
+                 # RunLoop
+                 RunLoop.subproj/CFRunLoop.c
+                 RunLoop.subproj/CFSocket.c
++                RunLoop.subproj/CFMachPort.c   # These files are missing from the upstream `CMakeLists.txt` but required to build on Darwin.
++                RunLoop.subproj/CFMessagePort.c
+                 # Stream
+                 Stream.subproj/CFConcreteStreams.c
+                 Stream.subproj/CFSocketStream.c
+@@ -336,6 +338,11 @@
+   target_include_directories(CoreFoundation
+                              PRIVATE
+                                ${CURL_INCLUDE_DIRS})
++elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
++  find_package(CURL REQUIRED)
++  target_include_directories(CoreFoundation PRIVATE ${CURL_INCLUDE_DIRS})
++  find_package(LibXml2 REQUIRED)
++  target_include_directories(CoreFoundation PRIVATE ${LIBXML2_INCLUDE_DIR})
+ else()
+   target_include_directories(CoreFoundation
+                              PRIVATE
+@@ -365,6 +372,10 @@
+                         PRIVATE
+                           ${CURL_LIBRARIES}
+                           ${LIBXML2_LIBRARIES})
++elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
++  target_link_libraries(CoreFoundation PRIVATE
++    ${CURL_LIBRARIES}
++    ${LIBXML2_LIBRARIES})
+ else()
+   target_link_libraries(CoreFoundation
+                         PRIVATE
+@@ -398,9 +400,19 @@
+   target_link_libraries(CoreFoundation
+                         PRIVATE
+                           icucore)
+-  set_target_properties(CoreFoundation
+-                        PROPERTIES LINK_FLAGS
+-                          -Xlinker;-alias_list;-Xlinker;Base.subproj/DarwinSymbolAliases;-twolevel_namespace;-sectcreate;__UNICODE;__csbitmaps;CharacterSets/CFCharacterSetBitmaps.bitmap;-sectcreate;__UNICODE;__properties;CharacterSets/CFUniCharPropertyDatabase.data;-sectcreate;__UNICODE;__data;CharacterSets/CFUnicodeData-L.mapping;-segprot;__UNICODE;r;r)
++  target_link_options(CoreFoundation
++                      PUBLIC
++                      "LINKER:-alias_list,../Base.subproj/DarwinSymbolAliases"
++                      "LINKER:-twolevel_namespace"
++                      "LINKER:-sectcreate,__UNICODE,__csbitmaps,../CharacterSets/CFCharacterSetBitmaps.bitmap"
++                      "LINKER:-sectcreate,__UNICODE,__properties,../CharacterSets/CFUniCharPropertyDatabase.data"
++                      "LINKER:-sectcreate,__UNICODE,__data,../CharacterSets/CFUnicodeData-L.mapping"
++                      "LINKER:-segprot,__UNICODE,r,r"
++                      "LINKER:-current_version,1454.90.0"
++                      "LINKER:-compatibility_version,150.0.0"
++                      "LINKER:-init,___CFInitialize")
++  set(CMAKE_SHARED_LIBRARY_PREFIX "")
++  set(CMAKE_SHARED_LIBRARY_SUFFIX "")
+ endif()
+ 
+ install(TARGETS
diff --git a/pkgs/os-specific/darwin/swift-corelibs/0005-Fix-framework-installation-path.patch b/pkgs/os-specific/darwin/swift-corelibs/0005-Fix-framework-installation-path.patch
new file mode 100644
index 0000000000000..e771ab3c66f29
--- /dev/null
+++ b/pkgs/os-specific/darwin/swift-corelibs/0005-Fix-framework-installation-path.patch
@@ -0,0 +1,23 @@
+diff -u aa/CoreFoundation/CMakeLists.txt b/CoreFoundation/CMakeLists.txt
+--- a/CoreFoundation/CMakeLists.txt	1969-12-31 19:00:01.000000000 -0500
++++ b/CoreFoundation/CMakeLists.txt	2023-06-29 18:59:19.492601179 -0400
+
+@@ -424,16 +424,11 @@
+   set(CMAKE_SHARED_LIBRARY_SUFFIX "")
+ endif()
+ 
+-install(TARGETS
+-          CoreFoundation
+-        DESTINATION
+-          "${CMAKE_INSTALL_FULL_LIBDIR}")
+ install(DIRECTORY
+           ${CoreFoundation_FRAMEWORK_DIRECTORY}
+         DESTINATION
+-          ${CMAKE_INSTALL_PREFIX}/System/Library/Frameworks
+-        USE_SOURCE_PERMISSIONS
+-        PATTERN PrivateHeaders EXCLUDE)
++          ${CMAKE_INSTALL_PREFIX}/Library/Frameworks
++        USE_SOURCE_PERMISSIONS)
+ 
+ 
+ # TODO(compnerd) formalize this
diff --git a/pkgs/os-specific/darwin/swift-corelibs/0006-System-CF-framework-compatibility.patch b/pkgs/os-specific/darwin/swift-corelibs/0006-System-CF-framework-compatibility.patch
new file mode 100644
index 0000000000000..248cb5f600370
--- /dev/null
+++ b/pkgs/os-specific/darwin/swift-corelibs/0006-System-CF-framework-compatibility.patch
@@ -0,0 +1,84 @@
+diff -u a/CoreFoundation/CMakeLists.txt b/CoreFoundation/CMakeLists.txt
+--- a/CoreFoundation/CMakeLists.txt	1969-12-31 19:00:01.000000000 -0500
++++ b/CoreFoundation/CMakeLists.txt	2023-06-29 18:59:08.659632504 -0400
+@@ -1,5 +1,5 @@
+ 
+-cmake_minimum_required(VERSION 3.4.3)
++cmake_minimum_required(VERSION 3.14)
+ list(APPEND CMAKE_MODULE_PATH
+      "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
+ 
+@@ -45,6 +45,8 @@
+                 ${FRAMEWORK_LIBRARY_TYPE}
+               FRAMEWORK_DIRECTORY
+                 CoreFoundation_FRAMEWORK_DIRECTORY
++              VERSION
++                A
+               MODULE_MAP
+                 Base.subproj/module.modulemap
+               PRIVATE_HEADERS
+diff -u a/CoreFoundation/cmake/modules/CoreFoundationAddFramework.cmake b/CoreFoundation/cmake/modules/CoreFoundationAddFramework.cmake
+--- a/CoreFoundation/cmake/modules/CoreFoundationAddFramework.cmake	1969-12-31 19:00:01.000000000 -0500
++++ b/CoreFoundation/cmake/modules/CoreFoundationAddFramework.cmake	2023-06-29 18:57:55.792860996 -0400
+@@ -3,7 +3,7 @@
+ 
+ function(add_framework NAME)
+   set(options STATIC SHARED)
+-  set(single_value_args MODULE_MAP FRAMEWORK_DIRECTORY)
++  set(single_value_args MODULE_MAP FRAMEWORK_DIRECTORY VERSION)
+   set(multiple_value_args PRIVATE_HEADERS PUBLIC_HEADERS SOURCES)
+   cmake_parse_arguments(AF "${options}" "${single_value_args}" "${multiple_value_args}" ${ARGN})
+ 
+@@ -14,26 +14,32 @@
+     set(AF_TYPE SHARED)
+   endif()
+ 
++  file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/${NAME}.framework/Versions/${AF_VERSION})
++  file(CREATE_LINK ${AF_VERSION} ${CMAKE_BINARY_DIR}/${NAME}.framework/Versions/Current SYMBOLIC)
++
+   if(AF_MODULE_MAP)
+     file(COPY
+            ${AF_MODULE_MAP}
+          DESTINATION
+-           ${CMAKE_BINARY_DIR}/${NAME}.framework/Modules
++           ${CMAKE_BINARY_DIR}/${NAME}.framework/Versions/Current/Modules
+          NO_SOURCE_PERMISSIONS)
++    file(CREATE_LINK Versions/Current/Modules ${CMAKE_BINARY_DIR}/${NAME}.framework/Modules SYMBOLIC)
+   endif()
+   if(AF_PUBLIC_HEADERS)
+     file(COPY
+            ${AF_PUBLIC_HEADERS}
+          DESTINATION
+-           ${CMAKE_BINARY_DIR}/${NAME}.framework/Headers
++           ${CMAKE_BINARY_DIR}/${NAME}.framework/Versions/Current/Headers
+          NO_SOURCE_PERMISSIONS)
++    file(CREATE_LINK Versions/Current/Headers ${CMAKE_BINARY_DIR}/${NAME}.framework/Headers SYMBOLIC)
+   endif()
+   if(AF_PRIVATE_HEADERS)
+     file(COPY
+            ${AF_PRIVATE_HEADERS}
+          DESTINATION
+-           ${CMAKE_BINARY_DIR}/${NAME}.framework/PrivateHeaders
++           ${CMAKE_BINARY_DIR}/${NAME}.framework/Versions/Current/PrivateHeaders
+          NO_SOURCE_PERMISSIONS)
++    file(CREATE_LINK Versions/Current/PrivateHeaders ${CMAKE_BINARY_DIR}/${NAME}.framework/PrivateHeaders SYMBOLIC)
+   endif()
+   add_custom_target(${NAME}_POPULATE_HEADERS
+                     DEPENDS
+@@ -51,13 +57,15 @@
+   set_target_properties(${NAME}
+                         PROPERTIES
+                           LIBRARY_OUTPUT_DIRECTORY
+-                              ${CMAKE_BINARY_DIR}/${NAME}.framework)
++                              ${CMAKE_BINARY_DIR}/${NAME}.framework/Versions/Current)
+   target_compile_options(${NAME}
+                          PRIVATE
+                            -F;${CMAKE_BINARY_DIR}
+                            -I;${CMAKE_BINARY_DIR}/${NAME}.framework/PrivateHeaders)
+   add_dependencies(${NAME} ${NAME}_POPULATE_HEADERS)
+ 
++  file(CREATE_LINK Versions/Current/${NAME} ${CMAKE_BINARY_DIR}/${NAME}.framework/${NAME} SYMBOLIC)
++
+   if(AF_FRAMEWORK_DIRECTORY)
+     set(${AF_FRAMEWORK_DIRECTORY} ${CMAKE_BINARY_DIR}/${NAME}.framework PARENT_SCOPE)
+   endif()
diff --git a/pkgs/os-specific/darwin/swift-corelibs/0007-Use-nixpkgs-icu.patch b/pkgs/os-specific/darwin/swift-corelibs/0007-Use-nixpkgs-icu.patch
new file mode 100644
index 0000000000000..78fa517ce76d6
--- /dev/null
+++ b/pkgs/os-specific/darwin/swift-corelibs/0007-Use-nixpkgs-icu.patch
@@ -0,0 +1,31 @@
+diff -ur d/CoreFoundation/CMakeLists.txt e/CoreFoundation/CMakeLists.txt
+--- d/CoreFoundation/CMakeLists.txt	1969-12-31 19:00:01.000000000 -0500
++++ e/CoreFoundation/CMakeLists.txt	2023-06-29 19:13:15.561253229 -0400
+@@ -343,6 +343,7 @@
+ elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+   find_package(CURL REQUIRED)
+   target_include_directories(CoreFoundation PRIVATE ${CURL_INCLUDE_DIRS})
++  find_package(ICU COMPONENTS uc i18n data REQUIRED)
+   find_package(LibXml2 REQUIRED)
+   target_include_directories(CoreFoundation PRIVATE ${LIBXML2_INCLUDE_DIR})
+ else()
+@@ -377,6 +378,9 @@
+ elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+   target_link_libraries(CoreFoundation PRIVATE
+     ${CURL_LIBRARIES}
++    ICU::uc
++    ICU::i18n
++    ICU::data
+     ${LIBXML2_LIBRARIES})
+ else()
+   target_link_libraries(CoreFoundation
+@@ -408,9 +412,6 @@
+                         PROPERTIES LINK_FLAGS
+                           -Xlinker;@${CMAKE_SOURCE_DIR}/linux.ld;-Bsymbolic)
+ elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+-  target_link_libraries(CoreFoundation
+-                        PRIVATE
+-                          icucore)
+   target_link_options(CoreFoundation
+                       PUBLIC
+                       "LINKER:-alias_list,../Base.subproj/DarwinSymbolAliases"
diff --git a/pkgs/os-specific/darwin/swift-corelibs/0008-Dont-link-libcurl.patch b/pkgs/os-specific/darwin/swift-corelibs/0008-Dont-link-libcurl.patch
new file mode 100644
index 0000000000000..4207bf1a82f59
--- /dev/null
+++ b/pkgs/os-specific/darwin/swift-corelibs/0008-Dont-link-libcurl.patch
@@ -0,0 +1,46 @@
+diff -u a/CoreFoundation/CMakeLists.txt b/CoreFoundation/CMakeLists.txt
+--- a/CoreFoundation/CMakeLists.txt	1969-12-31 19:00:01.000000000 -0500
++++ b/CoreFoundation/CMakeLists.txt	2023-06-29 19:39:30.074449222 -0400
+@@ -104,7 +104,6 @@
+                 # URL
+                 URL.subproj/CFURL.inc.h
+                 URL.subproj/CFURLPriv.h
+-                URL.subproj/CFURLSessionInterface.h
+               PUBLIC_HEADERS
+                 # FIXME: PrivateHeaders referenced by public headers
+                 Base.subproj/CFKnownLocations.h
+@@ -120,7 +119,6 @@
+                 String.subproj/CFRegularExpression.h
+                 String.subproj/CFRunArray.h
+                 URL.subproj/CFURLPriv.h
+-                URL.subproj/CFURLSessionInterface.h
+ 
+                 # AppServices
+                 AppServices.subproj/CFNotificationCenter.h
+@@ -280,8 +278,7 @@
+                 URL.subproj/CFURL.c
+                 URL.subproj/CFURLAccess.c
+                 URL.subproj/CFURLComponents.c
+-                URL.subproj/CFURLComponents_URIParser.c
+-                URL.subproj/CFURLSessionInterface.c)
++                URL.subproj/CFURLComponents_URIParser.c)
+ if(CMAKE_SYSTEM_NAME STREQUAL Linux OR CMAKE_SYSTEM_NAME STREQUAL Android)
+   target_compile_definitions(CoreFoundation
+                              PRIVATE
+@@ -341,8 +338,6 @@
+                              PRIVATE
+                                ${CURL_INCLUDE_DIRS})
+ elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+-  find_package(CURL REQUIRED)
+-  target_include_directories(CoreFoundation PRIVATE ${CURL_INCLUDE_DIRS})
+   find_package(ICU COMPONENTS uc i18n data REQUIRED)
+   find_package(LibXml2 REQUIRED)
+   target_include_directories(CoreFoundation PRIVATE ${LIBXML2_INCLUDE_DIR})
+@@ -377,7 +372,6 @@
+                           ${LIBXML2_LIBRARIES})
+ elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+   target_link_libraries(CoreFoundation PRIVATE
+-    ${CURL_LIBRARIES}
+     ICU::uc
+     ICU::i18n
+     ICU::data
diff --git a/pkgs/os-specific/darwin/swift-corelibs/corefoundation.nix b/pkgs/os-specific/darwin/swift-corelibs/corefoundation.nix
index 1e7aeb3689ea9..d77976773c66d 100644
--- a/pkgs/os-specific/darwin/swift-corelibs/corefoundation.nix
+++ b/pkgs/os-specific/darwin/swift-corelibs/corefoundation.nix
@@ -1,4 +1,4 @@
-{ lib, stdenv, fetchFromGitHub, fetchurl, makeSetupHook, ninja, python3, curl, libxml2, objc4, ICU }:
+{ lib, stdenv, fetchFromGitHub, fetchurl, makeSetupHook, cmake, ninja, pkg-config, launchd, libdispatch, python3, libxml2, objc4, icu }:
 
 let
   # 10.12 adds a new sysdir.h that our version of CF in the main derivation depends on, but
@@ -21,29 +21,39 @@ stdenv.mkDerivation {
     sha256 = "17kpql0f27xxz4jjw84vpas5f5sn4vdqwv10g151rc3rswbwln1z";
   };
 
-  nativeBuildInputs = [ ninja python3 ];
-  buildInputs = [ curl libxml2 objc4 ICU ];
-
-  patches = [ ./0001-Add-missing-TARGET_OS_-defines.patch ];
+  nativeBuildInputs = [ cmake ninja pkg-config python3 ];
+  buildInputs = [ (lib.getDev launchd) libdispatch libxml2 objc4 icu ];
+
+  patches = [
+    ./0001-Add-missing-TARGET_OS_-defines.patch
+    # CFMessagePort.h uses `bootstrap_check_in` without declaring it, which is defined in the launchd headers.
+    ./0002-Add-missing-launchd-header.patch
+    # CFURLComponents fails to build with clang 16 due to an invalid pointer conversion. This is fixed upstream.
+    ./0003-Fix-incompatible-pointer-conversion.patch
+    # Fix `CMakeLists.txt` to allow it to be used instead of `build.py` to build on Darwin.
+    ./0004-Fix-Darwin-cmake-build.patch
+    # Install CF framework in `$out/Library/Frameworks` instead of `$out/System/Frameworks`.
+    ./0005-Fix-framework-installation-path.patch
+    # Build a framework that matches the contents of the system CoreFoundation. This patch adds
+    # versioning and drops the prefix and suffix, so the dynamic library is named `CoreFoundation`
+    # instead of `libCoreFoundation.dylib`.
+    ./0006-System-CF-framework-compatibility.patch
+    # Link against the nixpkgs ICU instead of using Apple’s vendored version.
+    ./0007-Use-nixpkgs-icu.patch
+    # Don’t link against libcurl. This breaks a cycle between CF and curl, which depends on CF and
+    # uses the SystemConfiguration framework to support NAT64.
+    # This is safe because the symbols provided in CFURLSessionInterface are not provided by the
+    # system CoreFoundation. They are meant to be used by the implementation of `NSURLSession` in
+    # swift-corelibs-foundation, which is not built because it is not fully compatible with the
+    # system Foundation used on Darwin.
+    ./0008-Dont-link-libcurl.patch
+  ];
 
   postPatch = ''
     cd CoreFoundation
 
     cp ${sysdir-free-system-directories} Base.subproj/CFSystemDirectories.c
 
-    # In order, since I can't comment individual lines:
-    # 1. Disable dispatch support for now
-    # 2. For the linker too
-    # 3. Use the legit CoreFoundation.h, not the one telling you not to use it because of Swift
-    substituteInPlace build.py \
-      --replace "cf.CFLAGS += '-DDEPLOYMENT" '#' \
-      --replace "cf.LDFLAGS += '-ldispatch" '#'
-
-    # Fix sandbox impurities.
-    substituteInPlace ../lib/script.py \
-      --replace '/bin/cp' cp
-    patchShebangs --build ../configure
-
     # Includes xpc for some initialization routine that they don't define anyway, so no harm here
     substituteInPlace PlugIn.subproj/CFBundlePriv.h \
       --replace '#if (TARGET_OS_MAC' '#if (0'
@@ -55,55 +65,27 @@ stdenv.mkDerivation {
     # The MIN macro doesn't seem to be defined sensibly for us. Not sure if our stdenv or their bug
     substituteInPlace Base.subproj/CoreFoundation_Prefix.h \
       --replace '#if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX' '#if 1'
-
-    # Somehow our ICU doesn't have this, probably because it's too old (we'll update it soon when we update the rest of the SDK)
-    substituteInPlace Locale.subproj/CFLocale.c \
-      --replace '#if U_ICU_VERSION_MAJOR_NUM' '#if 0 //'
   '';
 
-  BUILD_DIR = "./Build";
-  CFLAGS = "-DINCLUDE_OBJC -I${libxml2.dev}/include/libxml2"; # They seem to assume we include objc in some places and not in others, make a PR; also not sure why but libxml2 include path isn't getting picked up from buildInputs
+  env.NIX_CFLAGS_COMPILE = toString [
+    # Silence warnings regarding other targets
+    "-Wno-error=undef-prefix"
+    # Avoid redefinitions when including objc headers
+    "-DINCLUDE_OBJC=1"
+  ];
 
-  # I'm guessing at the version here. https://github.com/apple/swift-corelibs-foundation/commit/df3ec55fe6c162d590a7653d89ad669c2b9716b1 imported "high sierra"
-  # and this version is a version from there. No idea how accurate it is.
-  LDFLAGS = "-current_version 1454.90.0 -compatibility_version 150.0.0 -init ___CFInitialize";
-
-  configurePhase = ''
-    ../configure release --sysroot UNUSED
-  '';
+  cmakeFlags = [
+    "-DBUILD_SHARED_LIBS=ON"
+    "-DCF_ENABLE_LIBDISPATCH=OFF"
+  ];
 
   enableParallelBuilding = true;
 
-  buildPhase = ''
-    runHook preBuild
+  postInstall = ''
+    install_name_tool -id '@rpath/CoreFoundation.framework/Versions/A/CoreFoundation' \
+      "$out/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
 
-    ninja -j $NIX_BUILD_CORES
-
-    runHook postBuild
+    mkdir -p "$out/nix-support"
+    substituteAll ${./pure-corefoundation-hook.sh} "$out/nix-support/setup-hook"
   '';
-
-  # TODO: their build system sorta kinda can do this, but it doesn't seem to work right now
-  # Also, this includes a bunch of private headers in the framework, which is not what we want
-  installPhase = ''
-    base="$out/Library/Frameworks/CoreFoundation.framework"
-    mkdir -p $base/Versions/A/{Headers,PrivateHeaders,Modules}
-
-    cp ./Build/CoreFoundation/libCoreFoundation.dylib $base/Versions/A/CoreFoundation
-
-    # Note that this could easily live in the ldflags above as `-install_name @rpath/...` but
-    # https://github.com/NixOS/nixpkgs/issues/46434 thwarts that, so for now I'm hacking it up
-    # after the fact.
-    install_name_tool -id '@rpath/CoreFoundation.framework/Versions/A/CoreFoundation' $base/Versions/A/CoreFoundation
-
-    cp ./Build/CoreFoundation/usr/include/CoreFoundation/*.h $base/Versions/A/Headers
-    cp ./Build/CoreFoundation/usr/include/CoreFoundation/module.modulemap $base/Versions/A/Modules
-
-    ln -s A $base/Versions/Current
-
-    for i in CoreFoundation Headers Modules; do
-      ln -s Versions/Current/$i $base/$i
-    done
-  '';
-
-    darwinEnvHook = makeSetupHook { name = "darwin-env-hook"; } ./pure-corefoundation-hook.sh;
 }
diff --git a/pkgs/stdenv/darwin/README.md b/pkgs/stdenv/darwin/README.md
new file mode 100644
index 0000000000000..75d30b96a7f6b
--- /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 1e7945d816ab1..8595cc72b43e2 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 7a2ad665e09d7..6cc1339752afd 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;
 
diff --git a/pkgs/top-level/darwin-packages.nix b/pkgs/top-level/darwin-packages.nix
index fa03c385e4f34..d1ce4a1290232 100644
--- a/pkgs/top-level/darwin-packages.nix
+++ b/pkgs/top-level/darwin-packages.nix
@@ -100,7 +100,7 @@ impure-cmds // appleSourcePackages // chooseLibs // {
     bintools = self.binutils-unwrapped;
   };
 
-  cctools = self.cctools-port;
+  cctools = self.cctools-llvm;
 
   cctools-apple = callPackage ../os-specific/darwin/cctools/apple.nix {
     stdenv = if stdenv.isDarwin then stdenv else pkgs.libcxxStdenv;