about summary refs log tree commit diff
path: root/pkgs/development/compilers/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/development/compilers/llvm')
-rw-r--r--pkgs/development/compilers/llvm/12/default.nix98
-rw-r--r--pkgs/development/compilers/llvm/12/lldb/gnu-install-dirs.patch19
-rw-r--r--pkgs/development/compilers/llvm/12/llvm/default.nix357
-rw-r--r--pkgs/development/compilers/llvm/13/default.nix97
-rw-r--r--pkgs/development/compilers/llvm/13/lldb/gnu-install-dirs.patch19
-rw-r--r--pkgs/development/compilers/llvm/13/llvm/default.nix315
-rw-r--r--pkgs/development/compilers/llvm/14/default.nix63
-rw-r--r--pkgs/development/compilers/llvm/14/llvm/default.nix323
-rw-r--r--pkgs/development/compilers/llvm/15/default.nix101
-rw-r--r--pkgs/development/compilers/llvm/15/llvm/default.nix442
-rw-r--r--pkgs/development/compilers/llvm/16/compiler-rt/asan-offset.patch11
-rw-r--r--pkgs/development/compilers/llvm/16/compiler-rt/freebsd-i386.patch21
-rw-r--r--pkgs/development/compilers/llvm/16/default.nix104
-rw-r--r--pkgs/development/compilers/llvm/16/llvm/default.nix435
-rw-r--r--pkgs/development/compilers/llvm/17/default.nix103
-rw-r--r--pkgs/development/compilers/llvm/17/llvm/default.nix431
-rw-r--r--pkgs/development/compilers/llvm/18/default.nix105
-rw-r--r--pkgs/development/compilers/llvm/common/clang-tools/default.nix59
-rwxr-xr-xpkgs/development/compilers/llvm/common/clang-tools/wrapper27
-rw-r--r--pkgs/development/compilers/llvm/common/clang/clang-6-10-LLVMgold-path.patch15
-rw-r--r--pkgs/development/compilers/llvm/common/clang/default.nix12
-rw-r--r--pkgs/development/compilers/llvm/common/compiler-rt/default.nix23
-rw-r--r--pkgs/development/compilers/llvm/common/compiler-rt/libsanitizer-no-cyclades-11.patch80
-rw-r--r--pkgs/development/compilers/llvm/common/libcxx/default.nix43
-rw-r--r--pkgs/development/compilers/llvm/common/libcxxabi/no-threads.patch12
-rw-r--r--pkgs/development/compilers/llvm/common/lld/default.nix2
-rw-r--r--pkgs/development/compilers/llvm/common/lldb.nix2
-rw-r--r--pkgs/development/compilers/llvm/common/lldb/gnu-install-dirs.patch19
-rw-r--r--pkgs/development/compilers/llvm/common/llvm/default.nix (renamed from pkgs/development/compilers/llvm/18/llvm/default.nix)367
-rw-r--r--pkgs/development/compilers/llvm/common/mlir/default.nix3
-rw-r--r--pkgs/development/compilers/llvm/git/clang/gnu-install-dirs.patch20
-rw-r--r--pkgs/development/compilers/llvm/git/default.nix109
-rw-r--r--pkgs/development/compilers/llvm/git/llvm/default.nix435
33 files changed, 1059 insertions, 3213 deletions
diff --git a/pkgs/development/compilers/llvm/12/default.nix b/pkgs/development/compilers/llvm/12/default.nix
index 45955dc5e1b36..c7c119a45b8ae 100644
--- a/pkgs/development/compilers/llvm/12/default.nix
+++ b/pkgs/development/compilers/llvm/12/default.nix
@@ -1,7 +1,7 @@
-{ lowPrio, newScope, pkgs, lib, stdenv, cmake
+{ lowPrio, newScope, pkgs, lib, stdenv
 , preLibcCrossHeaders
-, substitute, substituteAll, fetchFromGitHub, fetchpatch
-, libxml2, python3, isl, fetchurl, overrideCC, wrapCCWith, wrapBintoolsWith
+, substitute, substituteAll, fetchFromGitHub, fetchpatch, fetchurl
+, overrideCC, wrapCCWith, wrapBintoolsWith
 , buildLlvmTools # tools, but from the previous stage, for cross
 , targetLlvmLibraries # libraries, but from the next stage, for cross
 , targetLlvm
@@ -17,29 +17,36 @@
     then null
     else pkgs.bintools
 , darwin
-}:
+# Allows passthrough to packages via newScope. This makes it possible to
+# do `(llvmPackages.override { <someLlvmDependency> = bar; }).clang` and get
+# an llvmPackages whose packages are overridden in an internally consistent way.
+, ...
+}@args:
 
 let
-  release_version = "12.0.1";
   candidate = ""; # empty or "rcN"
   dash-candidate = lib.optionalString (candidate != "") "-${candidate}";
-  version = "${release_version}${dash-candidate}"; # differentiating these (variables) is important for RCs
 
-  fetch = name: sha256: fetchurl {
-    url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/${name}-${release_version}${candidate}.src.tar.xz";
-    inherit sha256;
+  metadata = rec {
+    release_version = "12.0.1";
+    version = "${release_version}${dash-candidate}"; # differentiating these (variables) is important for RCs
+    inherit (import ../common/common-let.nix { inherit lib release_version; }) llvm_meta;
+    fetch = name: sha256: fetchurl {
+      url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${metadata.version}/${name}-${metadata.release_version}${candidate}.src.tar.xz";
+      inherit sha256;
+    };
+    clang-tools-extra_src = fetch "clang-tools-extra" "1r9a4fdz9ci58b5z2inwvm4z4cdp6scrivnaw05dggkxz7yrwrb5";
   };
 
-  clang-tools-extra_src = fetch "clang-tools-extra" "1r9a4fdz9ci58b5z2inwvm4z4cdp6scrivnaw05dggkxz7yrwrb5";
+  inherit (metadata) fetch;
 
-  inherit (import ../common/common-let.nix { inherit lib release_version; }) llvm_meta;
 
   tools = lib.makeExtensible (tools: let
-    callPackage = newScope (tools // { inherit stdenv cmake libxml2 python3 isl release_version version fetch buildLlvmTools; });
+    callPackage = newScope (tools // args // metadata);
     mkExtraBuildCommands0 = cc: ''
       rsrc="$out/resource-root"
       mkdir "$rsrc"
-      ln -s "${cc.lib}/lib/clang/${release_version}/include" "$rsrc"
+      ln -s "${cc.lib}/lib/clang/${metadata.release_version}/include" "$rsrc"
       echo "-resource-dir=$rsrc" >> $out/nix-support/cc-cflags
     '';
     mkExtraBuildCommands = cc: mkExtraBuildCommands0 cc + ''
@@ -58,8 +65,52 @@ let
 
   in {
 
-    libllvm = callPackage ./llvm {
-      inherit llvm_meta;
+    libllvm = callPackage ../common/llvm {
+      src = fetch "llvm" "1pzx9zrmd7r3481sbhwvkms68fwhffpp4mmz45dgrkjpyl2q96kx";
+      polly_src = fetch "polly" "1yfm9ixda4a2sx7ak5vswijx4ydk5lv1c1xh39xmd2kh299y4m12";
+      patches = [
+        # When cross-compiling we configure llvm-config-native with an approximation
+        # of the flags used for the normal LLVM build. To avoid the need for building
+        # a native libLLVM.so (which would fail) we force llvm-config to be linked
+        # statically against the necessary LLVM components always.
+        ../common/llvm/llvm-config-link-static.patch
+        # Fix llvm being miscompiled by some gccs. See llvm/llvm-project#49955
+        # Fix llvm being miscompiled by some gccs. See https://github.com/llvm/llvm-project/issues/49955
+        ./llvm/fix-llvm-issue-49955.patch
+
+        ./llvm/gnu-install-dirs.patch
+        # On older CPUs (e.g. Hydra/wendy) we'd be getting an error in this test.
+        (fetchpatch {
+          name = "uops-CMOV16rm-noreg.diff";
+          url = "https://github.com/llvm/llvm-project/commit/9e9f991ac033.diff";
+          sha256 = "sha256:12s8vr6ibri8b48h2z38f3afhwam10arfiqfy4yg37bmc054p5hi";
+          stripLen = 1;
+        })
+
+        # Fix musl build.
+        (fetchpatch {
+          url = "https://github.com/llvm/llvm-project/commit/5cd554303ead0f8891eee3cd6d25cb07f5a7bf67.patch";
+          relative = "llvm";
+          hash = "sha256-XPbvNJ45SzjMGlNUgt/IgEvM2dHQpDOe6woUJY+nUYA=";
+        })
+
+        # Backport gcc-13 fixes with missing includes.
+        (fetchpatch {
+          name = "signals-gcc-13.patch";
+          url = "https://github.com/llvm/llvm-project/commit/ff1681ddb303223973653f7f5f3f3435b48a1983.patch";
+          hash = "sha256-CXwYxQezTq5vdmc8Yn88BUAEly6YZ5VEIA6X3y5NNOs=";
+          stripLen = 1;
+        })
+        (fetchpatch {
+          name = "base64-gcc-13.patch";
+          url = "https://github.com/llvm/llvm-project/commit/5e9be93566f39ee6cecd579401e453eccfbe81e5.patch";
+          hash = "sha256-PAwrVrvffPd7tphpwCkYiz+67szPRzRB2TXBvKfzQ7U=";
+          stripLen = 1;
+        })
+      ];
+      pollyPatches = [
+        ./llvm/gnu-install-dirs-polly.patch
+      ];
     };
 
     # `llvm` historically had the binaries.  When choosing an output explicitly,
@@ -77,7 +128,6 @@ let
           libllvmLibdir = "${tools.libllvm.lib}/lib";
         })
       ];
-      inherit clang-tools-extra_src llvm_meta;
     };
 
     clang-unwrapped = tools.libclang;
@@ -99,6 +149,9 @@ let
     #   python3 = pkgs.python3;  # don't use python-boot
     # });
 
+    # Wrapper for standalone command line utilities
+    clang-tools = callPackage ../common/clang-tools { };
+
     # pick clang appropriate for package set we are targeting
     clang =
       /**/ if stdenv.targetPlatform.libc == null then tools.clangNoLibc
@@ -130,7 +183,6 @@ let
       patches = [
         ./lld/gnu-install-dirs.patch
       ];
-      inherit llvm_meta;
       inherit (libraries) libunwind;
     };
 
@@ -151,7 +203,6 @@ let
           resourceDirPatch
           ./lldb/gnu-install-dirs.patch
         ];
-      inherit llvm_meta;
     };
 
     # Below, is the LLVM bootstrapping logic. It handles building a
@@ -242,7 +293,7 @@ let
   });
 
   libraries = lib.makeExtensible (libraries: let
-    callPackage = newScope (libraries // buildLlvmTools // { inherit stdenv cmake libxml2 python3 isl release_version version fetch; });
+    callPackage = newScope (libraries // buildLlvmTools // args // metadata);
   in {
 
     compiler-rt-libc = callPackage ../common/compiler-rt {
@@ -261,7 +312,6 @@ let
         ../common/compiler-rt/armv6-sync-ops-no-thumb.patch
         ../common/compiler-rt/armv6-no-ldrexd-strexd.patch
       ];
-      inherit llvm_meta;
       stdenv = if stdenv.hostPlatform.useLLVM or false
                then overrideCC stdenv buildLlvmTools.clangNoCompilerRtWithLibc
                else stdenv;
@@ -283,7 +333,6 @@ let
         ../common/compiler-rt/armv6-sync-ops-no-thumb.patch
         ../common/compiler-rt/armv6-no-ldrexd-strexd.patch
       ];
-      inherit llvm_meta;
       stdenv = if stdenv.hostPlatform.useLLVM or false
                then overrideCC stdenv buildLlvmTools.clangNoCompilerRt
                else stdenv;
@@ -302,7 +351,7 @@ let
       src = fetchFromGitHub {
         owner = "llvm";
         repo = "llvm-project";
-        rev = "refs/tags/llvmorg-${version}";
+        rev = "refs/tags/llvmorg-${metadata.version}";
         sparseCheckout = [
           "libcxx"
           "libcxxabi"
@@ -327,7 +376,6 @@ let
           ];
         })
       ];
-      inherit llvm_meta;
       stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
     };
 
@@ -336,7 +384,6 @@ let
       patches = [
         ./libunwind/gnu-install-dirs.patch
       ];
-      inherit llvm_meta;
       stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
     };
 
@@ -349,9 +396,8 @@ let
           hash = "sha256-UxIlAifXnexF/MaraPW0Ut6q+sf3e7y1fMdEv1q103A=";
         })
       ];
-      inherit llvm_meta targetLlvm;
     };
   });
   noExtend = extensible: lib.attrsets.removeAttrs extensible [ "extend" ];
 
-in { inherit tools libraries release_version; } // (noExtend libraries) // (noExtend tools)
+in { inherit tools libraries; inherit (metadata) release_version; } // (noExtend libraries) // (noExtend tools)
diff --git a/pkgs/development/compilers/llvm/12/lldb/gnu-install-dirs.patch b/pkgs/development/compilers/llvm/12/lldb/gnu-install-dirs.patch
index afc945ce26147..9a4d2b272acbe 100644
--- a/pkgs/development/compilers/llvm/12/lldb/gnu-install-dirs.patch
+++ b/pkgs/development/compilers/llvm/12/lldb/gnu-install-dirs.patch
@@ -89,3 +89,22 @@ index b5633e2..86e4738 100644
    endif()
    get_target_property(lldb_python_bindings_dir swig_wrapper_python BINARY_DIR)
    finish_swig_python("lldb-python" "${lldb_python_bindings_dir}" "${lldb_python_target_dir}")
+diff --git a/source/API/CMakeLists.txt b/source/API/CMakeLists.txt
+index b5633e2..86e4738 100644
+--- a/source/API/CMakeLists.txt	2024-05-30 19:08:14.241656491 -0700
++++ b/source/API/CMakeLists.txt	2024-05-30 19:08:48.218219667 -0700
+@@ -113,14 +113,6 @@
+   ${option_install_prefix}
+ )
+ 
+-# lib/pythonX.Y/dist-packages/lldb/_lldb.so is a symlink to lib/liblldb.so,
+-# which depends on lib/libLLVM*.so (BUILD_SHARED_LIBS) or lib/libLLVM-10git.so
+-# (LLVM_LINK_LLVM_DYLIB). Add an additional rpath $ORIGIN/../../../../lib so
+-# that _lldb.so can be loaded from Python.
+-if(LLDB_ENABLE_PYTHON AND (BUILD_SHARED_LIBS OR LLVM_LINK_LLVM_DYLIB) AND UNIX AND NOT APPLE)
+-  set_property(TARGET liblldb APPEND PROPERTY INSTALL_RPATH "\$ORIGIN/../../../../lib${LLVM_LIBDIR_SUFFIX}")
+-endif()
+-
+ if(Python3_RPATH)
+   set_property(TARGET liblldb APPEND PROPERTY INSTALL_RPATH "${Python3_RPATH}")
+   set_property(TARGET liblldb APPEND PROPERTY BUILD_RPATH   "${Python3_RPATH}")
diff --git a/pkgs/development/compilers/llvm/12/llvm/default.nix b/pkgs/development/compilers/llvm/12/llvm/default.nix
deleted file mode 100644
index 4745345a3f712..0000000000000
--- a/pkgs/development/compilers/llvm/12/llvm/default.nix
+++ /dev/null
@@ -1,357 +0,0 @@
-{ lib, stdenv, llvm_meta
-, pkgsBuildBuild
-, fetch
-, fetchpatch
-, cmake
-, python3
-, libffi
-, enableGoldPlugin ? libbfd.hasPluginAPI
-, libbfd
-, libpfm
-, libxml2
-, ncurses
-, version
-, release_version
-, zlib
-, buildLlvmTools
-, debugVersion ? false
-, doCheck ? stdenv.isLinux && (!stdenv.isx86_32) && (!stdenv.hostPlatform.isMusl)
-  && (stdenv.hostPlatform == stdenv.buildPlatform)
-, enableManpages ? false
-, enableSharedLibraries ? !stdenv.hostPlatform.isStatic
-# broken for Ampere eMAG 8180 (c2.large.arm on Packet) #56245
-# broken for the armv7l builder
-, enablePFM ? stdenv.isLinux && !stdenv.hostPlatform.isAarch
-, enablePolly ? false
-}:
-
-let
-  inherit (lib) optional optionals optionalString;
-
-  # Used when creating a version-suffixed symlink of libLLVM.dylib
-  shortVersion = with lib;
-    concatStringsSep "." (take 1 (splitString "." release_version));
-
-  # Ordinarily we would just the `doCheck` and `checkDeps` functionality
-  # `mkDerivation` gives us to manage our test dependencies (instead of breaking
-  # out `doCheck` as a package level attribute).
-  #
-  # Unfortunately `lit` does not forward `$PYTHONPATH` to children processes, in
-  # particular the children it uses to do feature detection.
-  #
-  # This means that python deps we add to `checkDeps` (which the python
-  # interpreter is made aware of via `$PYTHONPATH` – populated by the python
-  # setup hook) are not picked up by `lit` which causes it to skip tests.
-  #
-  # Adding `python3.withPackages (ps: [ ... ])` to `checkDeps` also doesn't work
-  # because this package is shadowed in `$PATH` by the regular `python3`
-  # package.
-  #
-  # So, we "manually" assemble one python derivation for the package to depend
-  # on, taking into account whether checks are enabled or not:
-  python = if doCheck then
-    let
-      checkDeps = ps: with ps; [ psutil ];
-    in python3.withPackages checkDeps
-  else python3;
-
-in stdenv.mkDerivation (rec {
-  pname = "llvm";
-  inherit version;
-
-  src = fetch pname "1pzx9zrmd7r3481sbhwvkms68fwhffpp4mmz45dgrkjpyl2q96kx";
-  polly_src = fetch "polly" "1yfm9ixda4a2sx7ak5vswijx4ydk5lv1c1xh39xmd2kh299y4m12";
-
-  unpackPhase = ''
-    unpackFile $src
-    mv llvm-${release_version}* llvm
-    sourceRoot=$PWD/llvm
-  '' + optionalString enablePolly ''
-    unpackFile $polly_src
-    mv polly-* $sourceRoot/tools/polly
-  '';
-
-  outputs = [ "out" "lib" "dev" "python" ];
-
-  nativeBuildInputs = [ cmake python ]
-    ++ optionals enableManpages [ python3.pkgs.sphinx python3.pkgs.recommonmark ];
-
-  buildInputs = [ libxml2 libffi ]
-    ++ optional enablePFM libpfm; # exegesis
-
-  propagatedBuildInputs = optionals (stdenv.buildPlatform == stdenv.hostPlatform) [ ncurses ]
-    ++ [ zlib ];
-
-  patches = [
-    # When cross-compiling we configure llvm-config-native with an approximation
-    # of the flags used for the normal LLVM build. To avoid the need for building
-    # a native libLLVM.so (which would fail) we force llvm-config to be linked
-    # statically against the necessary LLVM components always.
-    ../../common/llvm/llvm-config-link-static.patch
-    # Fix llvm being miscompiled by some gccs. See llvm/llvm-project#49955
-    # Fix llvm being miscompiled by some gccs. See https://github.com/llvm/llvm-project/issues/49955
-    ./fix-llvm-issue-49955.patch
-
-    ./gnu-install-dirs.patch
-    # On older CPUs (e.g. Hydra/wendy) we'd be getting an error in this test.
-    (fetchpatch {
-      name = "uops-CMOV16rm-noreg.diff";
-      url = "https://github.com/llvm/llvm-project/commit/9e9f991ac033.diff";
-      sha256 = "sha256:12s8vr6ibri8b48h2z38f3afhwam10arfiqfy4yg37bmc054p5hi";
-      stripLen = 1;
-    })
-
-    # Fix musl build.
-    (fetchpatch {
-      url = "https://github.com/llvm/llvm-project/commit/5cd554303ead0f8891eee3cd6d25cb07f5a7bf67.patch";
-      relative = "llvm";
-      hash = "sha256-XPbvNJ45SzjMGlNUgt/IgEvM2dHQpDOe6woUJY+nUYA=";
-    })
-
-    # Backport gcc-13 fixes with missing includes.
-    (fetchpatch {
-      name = "signals-gcc-13.patch";
-      url = "https://github.com/llvm/llvm-project/commit/ff1681ddb303223973653f7f5f3f3435b48a1983.patch";
-      hash = "sha256-CXwYxQezTq5vdmc8Yn88BUAEly6YZ5VEIA6X3y5NNOs=";
-      stripLen = 1;
-    })
-    (fetchpatch {
-      name = "base64-gcc-13.patch";
-      url = "https://github.com/llvm/llvm-project/commit/5e9be93566f39ee6cecd579401e453eccfbe81e5.patch";
-      hash = "sha256-PAwrVrvffPd7tphpwCkYiz+67szPRzRB2TXBvKfzQ7U=";
-      stripLen = 1;
-    })
-  ] ++ lib.optional enablePolly ./gnu-install-dirs-polly.patch;
-
-  postPatch = optionalString stdenv.isDarwin ''
-    substituteInPlace cmake/modules/AddLLVM.cmake \
-      --replace 'set(_install_name_dir INSTALL_NAME_DIR "@rpath")' "set(_install_name_dir)" \
-      --replace 'set(_install_rpath "@loader_path/../''${CMAKE_INSTALL_LIBDIR}''${LLVM_LIBDIR_SUFFIX}" ''${extra_libdir})' ""
-  '' + ''
-    # FileSystem permissions tests fail with various special bits
-    substituteInPlace unittests/Support/CMakeLists.txt \
-      --replace "Path.cpp" ""
-    rm unittests/Support/Path.cpp
-    substituteInPlace unittests/IR/CMakeLists.txt \
-      --replace "PassBuilderCallbacksTest.cpp" ""
-    rm unittests/IR/PassBuilderCallbacksTest.cpp
-    # TODO: Fix failing tests:
-    rm test/DebugInfo/X86/vla-multi.ll
-  '' + optionalString stdenv.hostPlatform.isMusl ''
-    patch -p1 -i ${../../common/llvm/TLI-musl.patch}
-    substituteInPlace unittests/Support/CMakeLists.txt \
-      --replace "add_subdirectory(DynamicLibrary)" ""
-    rm unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp
-    # valgrind unhappy with musl or glibc, but fails w/musl only
-    rm test/CodeGen/AArch64/wineh4.mir
-  '' + optionalString stdenv.hostPlatform.isAarch32 ''
-    # skip failing X86 test cases on 32-bit ARM
-    rm test/DebugInfo/X86/convert-debugloc.ll
-    rm test/DebugInfo/X86/convert-inlined.ll
-    rm test/DebugInfo/X86/convert-linked.ll
-    rm test/tools/dsymutil/X86/op-convert.test
-    rm test/tools/gold/X86/split-dwarf.ll
-    rm test/tools/llvm-objcopy/MachO/universal-object.test
-  '' + optionalString (stdenv.hostPlatform.system == "armv6l-linux") ''
-    # Seems to require certain floating point hardware (NEON?)
-    rm test/ExecutionEngine/frem.ll
-  '' + ''
-    patchShebangs test/BugPoint/compile-custom.ll.py
-  '' + ''
-    # Tweak tests to ignore namespace part of type to support
-    # gcc-12: https://gcc.gnu.org/PR103598.
-    # The change below mangles strings like:
-    #    CHECK-NEXT: Starting llvm::Function pass manager run.
-    # to:
-    #    CHECK-NEXT: Starting {{.*}}Function pass manager run.
-    for f in \
-      test/Other/new-pass-manager.ll \
-      test/Other/new-pm-O0-defaults.ll \
-      test/Other/new-pm-defaults.ll \
-      test/Other/new-pm-lto-defaults.ll \
-      test/Other/new-pm-thinlto-defaults.ll \
-      test/Other/pass-pipeline-parsing.ll \
-      test/Transforms/Inline/cgscc-incremental-invalidate.ll \
-      test/Transforms/Inline/clear-analyses.ll \
-      test/Transforms/LoopUnroll/unroll-loop-invalidation.ll \
-      test/Transforms/SCCP/ipsccp-preserve-analysis.ll \
-      test/Transforms/SCCP/preserve-analysis.ll \
-      test/Transforms/SROA/dead-inst.ll \
-      test/tools/gold/X86/new-pm.ll \
-      ; do
-      echo "PATCH: $f"
-      substituteInPlace $f \
-        --replace 'Starting llvm::' 'Starting {{.*}}' \
-        --replace 'Finished llvm::' 'Finished {{.*}}'
-    done
-  '' + ''
-    # gcc-13 fix
-    sed -i '/#include <string>/i#include <cstdint>' \
-      include/llvm/DebugInfo/Symbolize/DIPrinter.h
-  '';
-
-  preConfigure = ''
-    # Workaround for configure flags that need to have spaces
-    cmakeFlagsArray+=(
-      -DLLVM_LIT_ARGS='-svj''${NIX_BUILD_CORES} --no-progress-bar'
-    )
-  '';
-
-  # hacky fix: created binaries need to be run before installation
-  preBuild = ''
-    mkdir -p $out/
-    ln -sv $PWD/lib $out
-  '';
-
-  # E.g. mesa.drivers use the build-id as a cache key (see #93946):
-  LDFLAGS = optionalString (enableSharedLibraries && !stdenv.isDarwin) "-Wl,--build-id=sha1";
-
-  hardeningDisable = [ "trivialautovarinit" ];
-
-  cmakeBuildType = if debugVersion then "Debug" else "Release";
-
-  cmakeFlags = with stdenv; let
-    # These flags influence llvm-config's BuildVariables.inc in addition to the
-    # general build. We need to make sure these are also passed via
-    # CROSS_TOOLCHAIN_FLAGS_NATIVE when cross-compiling or llvm-config-native
-    # will return different results from the cross llvm-config.
-    #
-    # Some flags don't need to be repassed because LLVM already does so (like
-    # CMAKE_BUILD_TYPE), others are irrelevant to the result.
-    flagsForLlvmConfig = [
-      "-DLLVM_INSTALL_CMAKE_DIR=${placeholder "dev"}/lib/cmake/llvm/"
-      "-DLLVM_ENABLE_RTTI=ON"
-    ] ++ optionals enableSharedLibraries [
-      "-DLLVM_LINK_LLVM_DYLIB=ON"
-    ];
-  in flagsForLlvmConfig ++ [
-    "-DLLVM_INSTALL_UTILS=ON"  # Needed by rustc
-    "-DLLVM_BUILD_TESTS=${if doCheck then "ON" else "OFF"}"
-    "-DLLVM_ENABLE_FFI=ON"
-    "-DLLVM_HOST_TRIPLE=${stdenv.hostPlatform.config}"
-    "-DLLVM_DEFAULT_TARGET_TRIPLE=${stdenv.hostPlatform.config}"
-    "-DLLVM_ENABLE_DUMP=ON"
-  ] ++ optionals stdenv.hostPlatform.isStatic [
-    # Disables building of shared libs, -fPIC is still injected by cc-wrapper
-    "-DLLVM_ENABLE_PIC=OFF"
-    "-DLLVM_BUILD_STATIC=ON"
-    # libxml2 needs to be disabled because the LLVM build system ignores its .la
-    # file and doesn't link zlib as well.
-    # https://github.com/ClangBuiltLinux/tc-build/issues/150#issuecomment-845418812
-    "-DLLVM_ENABLE_LIBXML2=OFF"
-  ] ++ optionals enableManpages [
-    "-DLLVM_BUILD_DOCS=ON"
-    "-DLLVM_ENABLE_SPHINX=ON"
-    "-DSPHINX_OUTPUT_MAN=ON"
-    "-DSPHINX_OUTPUT_HTML=OFF"
-    "-DSPHINX_WARNINGS_AS_ERRORS=OFF"
-  ] ++ optionals (enableGoldPlugin) [
-    "-DLLVM_BINUTILS_INCDIR=${libbfd.dev}/include"
-  ] ++ optionals isDarwin [
-    "-DLLVM_ENABLE_LIBCXX=ON"
-    "-DCAN_TARGET_i386=false"
-  ] ++ optionals ((stdenv.hostPlatform != stdenv.buildPlatform) && !(stdenv.buildPlatform.canExecute stdenv.hostPlatform)) [
-    "-DCMAKE_CROSSCOMPILING=True"
-    "-DLLVM_TABLEGEN=${buildLlvmTools.llvm}/bin/llvm-tblgen"
-    (
-      let
-        nativeCC = pkgsBuildBuild.targetPackages.stdenv.cc;
-        nativeBintools = nativeCC.bintools.bintools;
-        nativeToolchainFlags = [
-          "-DCMAKE_C_COMPILER=${nativeCC}/bin/${nativeCC.targetPrefix}cc"
-          "-DCMAKE_CXX_COMPILER=${nativeCC}/bin/${nativeCC.targetPrefix}c++"
-          "-DCMAKE_AR=${nativeBintools}/bin/${nativeBintools.targetPrefix}ar"
-          "-DCMAKE_STRIP=${nativeBintools}/bin/${nativeBintools.targetPrefix}strip"
-          "-DCMAKE_RANLIB=${nativeBintools}/bin/${nativeBintools.targetPrefix}ranlib"
-        ];
-        # We need to repass the custom GNUInstallDirs values, otherwise CMake
-        # will choose them for us, leading to wrong results in llvm-config-native
-        nativeInstallFlags = [
-          "-DCMAKE_INSTALL_PREFIX=${placeholder "out"}"
-          "-DCMAKE_INSTALL_BINDIR=${placeholder "out"}/bin"
-          "-DCMAKE_INSTALL_INCLUDEDIR=${placeholder "dev"}/include"
-          "-DCMAKE_INSTALL_LIBDIR=${placeholder "lib"}/lib"
-          "-DCMAKE_INSTALL_LIBEXECDIR=${placeholder "lib"}/libexec"
-        ];
-      in "-DCROSS_TOOLCHAIN_FLAGS_NATIVE:list="
-      + lib.concatStringsSep ";" (lib.concatLists [
-        flagsForLlvmConfig
-        nativeToolchainFlags
-        nativeInstallFlags
-      ])
-    )
-  ];
-
-  postBuild = ''
-    rm -fR $out
-  '';
-
-  preCheck = ''
-    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH''${LD_LIBRARY_PATH:+:}$PWD/lib
-  '';
-
-  postInstall = ''
-    mkdir -p $python/share
-    mv $out/share/opt-viewer $python/share/opt-viewer
-    moveToOutput "bin/llvm-config*" "$dev"
-    substituteInPlace "$dev/lib/cmake/llvm/LLVMExports-${if debugVersion then "debug" else "release"}.cmake" \
-      --replace "\''${_IMPORT_PREFIX}/lib/lib" "$lib/lib/lib" \
-      --replace "$out/bin/llvm-config" "$dev/bin/llvm-config"
-    substituteInPlace "$dev/lib/cmake/llvm/LLVMConfig.cmake" \
-      --replace 'set(LLVM_BINARY_DIR "''${LLVM_INSTALL_PREFIX}")' 'set(LLVM_BINARY_DIR "''${LLVM_INSTALL_PREFIX}'"$lib"'")'
-  ''
-  + optionalString (stdenv.isDarwin && enableSharedLibraries) ''
-    ln -s $lib/lib/libLLVM.dylib $lib/lib/libLLVM-${shortVersion}.dylib
-    ln -s $lib/lib/libLLVM.dylib $lib/lib/libLLVM-${release_version}.dylib
-  ''
-  + optionalString (stdenv.buildPlatform != stdenv.hostPlatform) ''
-    cp NATIVE/bin/llvm-config $dev/bin/llvm-config-native
-  '';
-
-  inherit doCheck;
-
-  checkTarget = "check-all";
-
-  requiredSystemFeatures = [ "big-parallel" ];
-  meta = llvm_meta // {
-    homepage = "https://llvm.org/";
-    description = "A collection of modular and reusable compiler and toolchain technologies";
-    longDescription = ''
-      The LLVM Project is a collection of modular and reusable compiler and
-      toolchain technologies. Despite its name, LLVM has little to do with
-      traditional virtual machines. The name "LLVM" itself is not an acronym; it
-      is the full name of the project.
-      LLVM began as a research project at the University of Illinois, with the
-      goal of providing a modern, SSA-based compilation strategy capable of
-      supporting both static and dynamic compilation of arbitrary programming
-      languages. Since then, LLVM has grown to be an umbrella project consisting
-      of a number of subprojects, many of which are being used in production by
-      a wide variety of commercial and open source projects as well as being
-      widely used in academic research. Code in the LLVM project is licensed
-      under the "Apache 2.0 License with LLVM exceptions".
-    '';
-  };
-} // lib.optionalAttrs enableManpages {
-  pname = "llvm-manpages";
-
-  buildPhase = ''
-    make docs-llvm-man
-  '';
-
-  propagatedBuildInputs = [];
-
-  installPhase = ''
-    make -C docs install
-  '';
-
-  postPatch = null;
-  postInstall = null;
-
-  outputs = [ "out" ];
-
-  doCheck = false;
-
-  meta = llvm_meta // {
-    description = "man pages for LLVM ${version}";
-  };
-})
diff --git a/pkgs/development/compilers/llvm/13/default.nix b/pkgs/development/compilers/llvm/13/default.nix
index 018fb0c638505..ffbbe1deb0d4e 100644
--- a/pkgs/development/compilers/llvm/13/default.nix
+++ b/pkgs/development/compilers/llvm/13/default.nix
@@ -1,7 +1,7 @@
-{ lowPrio, newScope, pkgs, lib, stdenv, cmake
+{ lowPrio, newScope, pkgs, lib, stdenv
 , preLibcCrossHeaders
-, fetchpatch
-, libxml2, python3, isl, fetchFromGitHub, substitute, substituteAll, overrideCC, wrapCCWith, wrapBintoolsWith
+, substitute, substituteAll, fetchFromGitHub, fetchpatch
+, overrideCC, wrapCCWith, wrapBintoolsWith
 , buildLlvmTools # tools, but from the previous stage, for cross
 , targetLlvmLibraries # libraries, but from the next stage, for cross
 , targetLlvm
@@ -40,8 +40,11 @@
 # to you to make sure that the LLVM repo given matches the release configuration
 # specified.
 , monorepoSrc ? null
-
-}:
+# Allows passthrough to packages via newScope. This makes it possible to
+# do `(llvmPackages.override { <someLlvmDependency> = bar; }).clang` and get
+# an llvmPackages whose packages are overridden in an internally consistent way.
+, ...
+}@args:
 
 assert
   lib.assertMsg
@@ -53,19 +56,23 @@ assert
 let
   monorepoSrc' = monorepoSrc;
 in let
-  # Import releaseInfo separately to avoid infinite recursion
-  inherit (import ../common/common-let.nix { inherit lib gitRelease officialRelease; }) releaseInfo;
-  inherit (releaseInfo) release_version version;
-  inherit (import ../common/common-let.nix { inherit lib fetchFromGitHub release_version gitRelease officialRelease monorepoSrc'; }) llvm_meta monorepoSrc;
-
-  src = monorepoSrc;
+  metadata = rec {
+    # Import releaseInfo separately to avoid infinite recursion
+    inherit (import ../common/common-let.nix { inherit lib gitRelease officialRelease; }) releaseInfo;
+    inherit (releaseInfo) release_version version;
+    inherit (import ../common/common-let.nix { inherit lib fetchFromGitHub release_version gitRelease officialRelease monorepoSrc'; }) llvm_meta monorepoSrc;
+    src = monorepoSrc;
+  };
 
   tools = lib.makeExtensible (tools: let
-    callPackage = newScope (tools // { inherit stdenv cmake libxml2 python3 isl release_version version src buildLlvmTools; });
+    callPackage = newScope (tools // args // metadata
+      # Previously monorepoSrc was erroneously not being passed through.
+      // { monorepoSrc = null; } # Preserve a bug during #307211, TODO: remove; causes llvm 13 rebuild.
+    );
     mkExtraBuildCommands0 = cc: ''
       rsrc="$out/resource-root"
       mkdir "$rsrc"
-      ln -s "${cc.lib}/lib/clang/${release_version}/include" "$rsrc"
+      ln -s "${cc.lib}/lib/clang/${metadata.release_version}/include" "$rsrc"
       echo "-resource-dir=$rsrc" >> $out/nix-support/cc-cflags
     '';
     mkExtraBuildCommands = cc: mkExtraBuildCommands0 cc + ''
@@ -84,8 +91,47 @@ in let
 
   in {
 
-    libllvm = callPackage ./llvm {
-      inherit llvm_meta;
+    libllvm = callPackage ../common/llvm {
+      patches = [
+        # When cross-compiling we configure llvm-config-native with an approximation
+        # of the flags used for the normal LLVM build. To avoid the need for building
+        # a native libLLVM.so (which would fail) we force llvm-config to be linked
+        # statically against the necessary LLVM components always.
+        ../common/llvm/llvm-config-link-static.patch
+
+        ./llvm/gnu-install-dirs.patch
+
+        # Fix random compiler crashes: https://bugs.llvm.org/show_bug.cgi?id=50611
+        (fetchpatch {
+          url = "https://raw.githubusercontent.com/archlinux/svntogit-packages/4764a4f8c920912a2bfd8b0eea57273acfe0d8a8/trunk/no-strict-aliasing-DwarfCompileUnit.patch";
+          sha256 = "18l6mrvm2vmwm77ckcnbjvh6ybvn72rhrb799d4qzwac4x2ifl7g";
+          stripLen = 1;
+        })
+
+        # Fix musl build.
+        (fetchpatch {
+          url = "https://github.com/llvm/llvm-project/commit/5cd554303ead0f8891eee3cd6d25cb07f5a7bf67.patch";
+          relative = "llvm";
+          hash = "sha256-XPbvNJ45SzjMGlNUgt/IgEvM2dHQpDOe6woUJY+nUYA=";
+        })
+
+        # Backport gcc-13 fixes with missing includes.
+        (fetchpatch {
+          name = "signals-gcc-13.patch";
+          url = "https://github.com/llvm/llvm-project/commit/ff1681ddb303223973653f7f5f3f3435b48a1983.patch";
+          hash = "sha256-CXwYxQezTq5vdmc8Yn88BUAEly6YZ5VEIA6X3y5NNOs=";
+          stripLen = 1;
+        })
+        (fetchpatch {
+          name = "base64-gcc-13.patch";
+          url = "https://github.com/llvm/llvm-project/commit/5e9be93566f39ee6cecd579401e453eccfbe81e5.patch";
+          hash = "sha256-PAwrVrvffPd7tphpwCkYiz+67szPRzRB2TXBvKfzQ7U=";
+          stripLen = 1;
+        })
+      ];
+      pollyPatches = [
+        ./llvm/gnu-install-dirs-polly.patch
+      ];
     };
 
     # `llvm` historically had the binaries.  When choosing an output explicitly,
@@ -108,7 +154,6 @@ in let
           libllvmLibdir = "${tools.libllvm.lib}/lib";
         })
       ];
-      inherit llvm_meta;
     };
 
     clang-unwrapped = tools.libclang;
@@ -129,6 +174,9 @@ in let
     #   python3 = pkgs.python3;  # don't use python-boot
     # });
 
+    # Wrapper for standalone command line utilities
+    clang-tools = callPackage ../common/clang-tools { };
+
     # pick clang appropriate for package set we are targeting
     clang =
       /**/ if stdenv.targetPlatform.libc == null then tools.clangNoLibc
@@ -159,7 +207,6 @@ in let
       patches = [
         ./lld/gnu-install-dirs.patch
       ];
-      inherit llvm_meta;
     };
 
     lldb = callPackage ../common/lldb.nix {
@@ -192,7 +239,6 @@ in let
             && !stdenv.targetPlatform.isAarch64
             && (lib.versionOlder darwin.apple_sdk.sdk.version "11.0")
         ) ./lldb/cpu_subtype_arm64e_replacement.patch;
-      inherit llvm_meta;
     };
 
     # Below, is the LLVM bootstrapping logic. It handles building a
@@ -283,7 +329,10 @@ in let
   });
 
   libraries = lib.makeExtensible (libraries: let
-    callPackage = newScope (libraries // buildLlvmTools // { inherit stdenv cmake libxml2 python3 isl release_version version src; });
+    callPackage = newScope (libraries // buildLlvmTools // args // metadata
+      # Previously monorepoSrc was erroneously not being passed through.
+      // { monorepoSrc = null; } # Preserve a bug during #307211, TODO: remove; causes llvm 13 rebuild.
+    );
   in {
 
     compiler-rt-libc = callPackage ../common/compiler-rt {
@@ -304,7 +353,6 @@ in let
         ../common/compiler-rt/armv6-scudo-no-yield.patch
         ../common/compiler-rt/armv6-scudo-libatomic.patch
       ];
-      inherit llvm_meta;
       stdenv = if stdenv.hostPlatform.useLLVM or false
                then overrideCC stdenv buildLlvmTools.clangNoCompilerRtWithLibc
                else stdenv;
@@ -328,7 +376,6 @@ in let
         ../common/compiler-rt/armv6-scudo-no-yield.patch
         ../common/compiler-rt/armv6-scudo-libatomic.patch
       ];
-      inherit llvm_meta;
       stdenv = if stdenv.hostPlatform.useLLVM or false
                then overrideCC stdenv buildLlvmTools.clangNoCompilerRt
                else stdenv;
@@ -359,16 +406,15 @@ in let
           ];
         })
       ];
-      inherit llvm_meta;
       stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
-      monorepoSrc = src;
+      # TODO: remove this, causes LLVM 13 packages rebuild.
+      inherit (metadata) monorepoSrc; # Preserve bug during #307211 refactor.
     };
 
     libunwind = callPackage ../common/libunwind {
       patches = [
         ./libunwind/gnu-install-dirs.patch
       ];
-      inherit llvm_meta;
       stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
     };
 
@@ -380,9 +426,8 @@ in let
           hash = "sha256-UxIlAifXnexF/MaraPW0Ut6q+sf3e7y1fMdEv1q103A=";
         })
       ];
-      inherit llvm_meta targetLlvm;
     };
   });
   noExtend = extensible: lib.attrsets.removeAttrs extensible [ "extend" ];
 
-in { inherit tools libraries release_version; } // (noExtend libraries) // (noExtend tools)
+in { inherit tools libraries; inherit (metadata) release_version; } // (noExtend libraries) // (noExtend tools)
diff --git a/pkgs/development/compilers/llvm/13/lldb/gnu-install-dirs.patch b/pkgs/development/compilers/llvm/13/lldb/gnu-install-dirs.patch
index afc945ce26147..eba6fbabac626 100644
--- a/pkgs/development/compilers/llvm/13/lldb/gnu-install-dirs.patch
+++ b/pkgs/development/compilers/llvm/13/lldb/gnu-install-dirs.patch
@@ -89,3 +89,22 @@ index b5633e2..86e4738 100644
    endif()
    get_target_property(lldb_python_bindings_dir swig_wrapper_python BINARY_DIR)
    finish_swig_python("lldb-python" "${lldb_python_bindings_dir}" "${lldb_python_target_dir}")
+diff --git a/source/API/CMakeLists.txt b/source/API/CMakeLists.txt
+index b5633e2..86e4738 100644
+--- a/source/API/CMakeLists.txt	2024-05-30 21:38:39.829955586 -0700
++++ b/source/API/CMakeLists.txt	2024-05-30 21:38:48.015673758 -0700
+@@ -112,14 +112,6 @@
+   ${option_install_prefix}
+ )
+ 
+-# lib/pythonX.Y/dist-packages/lldb/_lldb.so is a symlink to lib/liblldb.so,
+-# which depends on lib/libLLVM*.so (BUILD_SHARED_LIBS) or lib/libLLVM-10git.so
+-# (LLVM_LINK_LLVM_DYLIB). Add an additional rpath $ORIGIN/../../../../lib so
+-# that _lldb.so can be loaded from Python.
+-if(LLDB_ENABLE_PYTHON AND (BUILD_SHARED_LIBS OR LLVM_LINK_LLVM_DYLIB) AND UNIX AND NOT APPLE)
+-  set_property(TARGET liblldb APPEND PROPERTY INSTALL_RPATH "\$ORIGIN/../../../../lib${LLVM_LIBDIR_SUFFIX}")
+-endif()
+-
+ if(Python3_RPATH)
+   set_property(TARGET liblldb APPEND PROPERTY INSTALL_RPATH "${Python3_RPATH}")
+   set_property(TARGET liblldb APPEND PROPERTY BUILD_RPATH   "${Python3_RPATH}")
diff --git a/pkgs/development/compilers/llvm/13/llvm/default.nix b/pkgs/development/compilers/llvm/13/llvm/default.nix
deleted file mode 100644
index 58e742b9b41ea..0000000000000
--- a/pkgs/development/compilers/llvm/13/llvm/default.nix
+++ /dev/null
@@ -1,315 +0,0 @@
-{ lib, stdenv, llvm_meta
-, pkgsBuildBuild
-, src
-, fetchpatch
-, cmake
-, python3
-, libffi
-, enableGoldPlugin ? libbfd.hasPluginAPI
-, libbfd
-, libpfm
-, libxml2
-, ncurses
-, version
-, release_version
-, zlib
-, which
-, buildLlvmTools
-, debugVersion ? false
-, doCheck ? stdenv.isLinux && (!stdenv.isx86_32) && (!stdenv.hostPlatform.isMusl)
-  && (stdenv.hostPlatform == stdenv.buildPlatform)
-, enableManpages ? false
-, enableSharedLibraries ? !stdenv.hostPlatform.isStatic
-# broken for Ampere eMAG 8180 (c2.large.arm on Packet) #56245
-# broken for the armv7l builder
-, enablePFM ? stdenv.isLinux && !stdenv.hostPlatform.isAarch
-, enablePolly ? false
-}:
-
-let
-  inherit (lib) optional optionals optionalString;
-
-  # Used when creating a version-suffixed symlink of libLLVM.dylib
-  shortVersion = with lib;
-    concatStringsSep "." (take 1 (splitString "." release_version));
-
-  # Ordinarily we would just the `doCheck` and `checkDeps` functionality
-  # `mkDerivation` gives us to manage our test dependencies (instead of breaking
-  # out `doCheck` as a package level attribute).
-  #
-  # Unfortunately `lit` does not forward `$PYTHONPATH` to children processes, in
-  # particular the children it uses to do feature detection.
-  #
-  # This means that python deps we add to `checkDeps` (which the python
-  # interpreter is made aware of via `$PYTHONPATH` – populated by the python
-  # setup hook) are not picked up by `lit` which causes it to skip tests.
-  #
-  # Adding `python3.withPackages (ps: [ ... ])` to `checkDeps` also doesn't work
-  # because this package is shadowed in `$PATH` by the regular `python3`
-  # package.
-  #
-  # So, we "manually" assemble one python derivation for the package to depend
-  # on, taking into account whether checks are enabled or not:
-  python = if doCheck then
-    let
-      checkDeps = ps: with ps; [ psutil ];
-    in python3.withPackages checkDeps
-  else python3;
-
-in stdenv.mkDerivation (rec {
-  pname = "llvm";
-  inherit version;
-
-  inherit src;
-  sourceRoot = "${src.name}/${pname}";
-
-  outputs = [ "out" "lib" "dev" "python" ];
-
-  nativeBuildInputs = [ cmake python ]
-    ++ optionals enableManpages [ python3.pkgs.sphinx python3.pkgs.recommonmark ];
-
-  buildInputs = [ libxml2 libffi ]
-    ++ optional enablePFM libpfm; # exegesis
-
-  propagatedBuildInputs = optionals (stdenv.hostPlatform == stdenv.buildPlatform) [ ncurses ]
-    ++ [ zlib ];
-
-  nativeCheckInputs = [ which ];
-
-  patches = [
-    # When cross-compiling we configure llvm-config-native with an approximation
-    # of the flags used for the normal LLVM build. To avoid the need for building
-    # a native libLLVM.so (which would fail) we force llvm-config to be linked
-    # statically against the necessary LLVM components always.
-    ../../common/llvm/llvm-config-link-static.patch
-
-    ./gnu-install-dirs.patch
-
-    # Fix random compiler crashes: https://bugs.llvm.org/show_bug.cgi?id=50611
-    (fetchpatch {
-      url = "https://raw.githubusercontent.com/archlinux/svntogit-packages/4764a4f8c920912a2bfd8b0eea57273acfe0d8a8/trunk/no-strict-aliasing-DwarfCompileUnit.patch";
-      sha256 = "18l6mrvm2vmwm77ckcnbjvh6ybvn72rhrb799d4qzwac4x2ifl7g";
-      stripLen = 1;
-    })
-
-    # Fix musl build.
-    (fetchpatch {
-      url = "https://github.com/llvm/llvm-project/commit/5cd554303ead0f8891eee3cd6d25cb07f5a7bf67.patch";
-      relative = "llvm";
-      hash = "sha256-XPbvNJ45SzjMGlNUgt/IgEvM2dHQpDOe6woUJY+nUYA=";
-    })
-
-    # Backport gcc-13 fixes with missing includes.
-    (fetchpatch {
-      name = "signals-gcc-13.patch";
-      url = "https://github.com/llvm/llvm-project/commit/ff1681ddb303223973653f7f5f3f3435b48a1983.patch";
-      hash = "sha256-CXwYxQezTq5vdmc8Yn88BUAEly6YZ5VEIA6X3y5NNOs=";
-      stripLen = 1;
-    })
-    (fetchpatch {
-      name = "base64-gcc-13.patch";
-      url = "https://github.com/llvm/llvm-project/commit/5e9be93566f39ee6cecd579401e453eccfbe81e5.patch";
-      hash = "sha256-PAwrVrvffPd7tphpwCkYiz+67szPRzRB2TXBvKfzQ7U=";
-      stripLen = 1;
-    })
-  ] ++ lib.optional enablePolly ./gnu-install-dirs-polly.patch;
-
-  postPatch = optionalString stdenv.isDarwin ''
-    substituteInPlace cmake/modules/AddLLVM.cmake \
-      --replace 'set(_install_name_dir INSTALL_NAME_DIR "@rpath")' "set(_install_name_dir)" \
-      --replace 'set(_install_rpath "@loader_path/../''${CMAKE_INSTALL_LIBDIR}''${LLVM_LIBDIR_SUFFIX}" ''${extra_libdir})' ""
-  '' + ''
-    # FileSystem permissions tests fail with various special bits
-    substituteInPlace unittests/Support/CMakeLists.txt \
-      --replace "Path.cpp" ""
-    rm unittests/Support/Path.cpp
-    substituteInPlace unittests/IR/CMakeLists.txt \
-      --replace "PassBuilderCallbacksTest.cpp" ""
-    rm unittests/IR/PassBuilderCallbacksTest.cpp
-    rm test/tools/llvm-objcopy/ELF/mirror-permissions-unix.test
-  '' + optionalString stdenv.hostPlatform.isMusl ''
-    patch -p1 -i ${../../common/llvm/TLI-musl.patch}
-    substituteInPlace unittests/Support/CMakeLists.txt \
-      --replace "add_subdirectory(DynamicLibrary)" ""
-    rm unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp
-    # valgrind unhappy with musl or glibc, but fails w/musl only
-    rm test/CodeGen/AArch64/wineh4.mir
-  '' + optionalString stdenv.hostPlatform.isAarch32 ''
-    # skip failing X86 test cases on 32-bit ARM
-    rm test/DebugInfo/X86/convert-debugloc.ll
-    rm test/DebugInfo/X86/convert-inlined.ll
-    rm test/DebugInfo/X86/convert-linked.ll
-    rm test/tools/dsymutil/X86/op-convert.test
-    rm test/tools/gold/X86/split-dwarf.ll
-  '' + optionalString (stdenv.hostPlatform.system == "armv6l-linux") ''
-    # Seems to require certain floating point hardware (NEON?)
-    rm test/ExecutionEngine/frem.ll
-  '' + ''
-    patchShebangs test/BugPoint/compile-custom.ll.py
-  '';
-
-  preConfigure = ''
-    # Workaround for configure flags that need to have spaces
-    cmakeFlagsArray+=(
-      -DLLVM_LIT_ARGS='-svj''${NIX_BUILD_CORES} --no-progress-bar'
-    )
-  '';
-
-  # hacky fix: created binaries need to be run before installation
-  preBuild = ''
-    mkdir -p $out/
-    ln -sv $PWD/lib $out
-  '';
-
-  # E.g. mesa.drivers use the build-id as a cache key (see #93946):
-  LDFLAGS = optionalString (enableSharedLibraries && !stdenv.isDarwin) "-Wl,--build-id=sha1";
-
-  hardeningDisable = [ "trivialautovarinit" ];
-
-  cmakeBuildType = if debugVersion then "Debug" else "Release";
-
-  cmakeFlags = with stdenv; let
-    # These flags influence llvm-config's BuildVariables.inc in addition to the
-    # general build. We need to make sure these are also passed via
-    # CROSS_TOOLCHAIN_FLAGS_NATIVE when cross-compiling or llvm-config-native
-    # will return different results from the cross llvm-config.
-    #
-    # Some flags don't need to be repassed because LLVM already does so (like
-    # CMAKE_BUILD_TYPE), others are irrelevant to the result.
-    flagsForLlvmConfig = [
-      "-DLLVM_INSTALL_CMAKE_DIR=${placeholder "dev"}/lib/cmake/llvm/"
-      "-DLLVM_ENABLE_RTTI=ON"
-    ] ++ optionals enableSharedLibraries [
-      "-DLLVM_LINK_LLVM_DYLIB=ON"
-    ];
-  in flagsForLlvmConfig ++ [
-    "-DLLVM_INSTALL_UTILS=ON"  # Needed by rustc
-    "-DLLVM_BUILD_TESTS=${if doCheck then "ON" else "OFF"}"
-    "-DLLVM_ENABLE_FFI=ON"
-    "-DLLVM_HOST_TRIPLE=${stdenv.hostPlatform.config}"
-    "-DLLVM_DEFAULT_TARGET_TRIPLE=${stdenv.hostPlatform.config}"
-    "-DLLVM_ENABLE_DUMP=ON"
-  ] ++ optionals stdenv.hostPlatform.isStatic [
-    # Disables building of shared libs, -fPIC is still injected by cc-wrapper
-    "-DLLVM_ENABLE_PIC=OFF"
-    "-DLLVM_BUILD_STATIC=ON"
-    # libxml2 needs to be disabled because the LLVM build system ignores its .la
-    # file and doesn't link zlib as well.
-    # https://github.com/ClangBuiltLinux/tc-build/issues/150#issuecomment-845418812
-    "-DLLVM_ENABLE_LIBXML2=OFF"
-  ] ++ optionals enableManpages [
-    "-DLLVM_BUILD_DOCS=ON"
-    "-DLLVM_ENABLE_SPHINX=ON"
-    "-DSPHINX_OUTPUT_MAN=ON"
-    "-DSPHINX_OUTPUT_HTML=OFF"
-    "-DSPHINX_WARNINGS_AS_ERRORS=OFF"
-  ] ++ optionals (enableGoldPlugin) [
-    "-DLLVM_BINUTILS_INCDIR=${libbfd.dev}/include"
-  ] ++ optionals isDarwin [
-    "-DLLVM_ENABLE_LIBCXX=ON"
-    "-DCAN_TARGET_i386=false"
-  ] ++ optionals ((stdenv.hostPlatform != stdenv.buildPlatform) && !(stdenv.buildPlatform.canExecute stdenv.hostPlatform)) [
-    "-DCMAKE_CROSSCOMPILING=True"
-    "-DLLVM_TABLEGEN=${buildLlvmTools.llvm}/bin/llvm-tblgen"
-    (
-      let
-        nativeCC = pkgsBuildBuild.targetPackages.stdenv.cc;
-        nativeBintools = nativeCC.bintools.bintools;
-        nativeToolchainFlags = [
-          "-DCMAKE_C_COMPILER=${nativeCC}/bin/${nativeCC.targetPrefix}cc"
-          "-DCMAKE_CXX_COMPILER=${nativeCC}/bin/${nativeCC.targetPrefix}c++"
-          "-DCMAKE_AR=${nativeBintools}/bin/${nativeBintools.targetPrefix}ar"
-          "-DCMAKE_STRIP=${nativeBintools}/bin/${nativeBintools.targetPrefix}strip"
-          "-DCMAKE_RANLIB=${nativeBintools}/bin/${nativeBintools.targetPrefix}ranlib"
-        ];
-        # We need to repass the custom GNUInstallDirs values, otherwise CMake
-        # will choose them for us, leading to wrong results in llvm-config-native
-        nativeInstallFlags = [
-          "-DCMAKE_INSTALL_PREFIX=${placeholder "out"}"
-          "-DCMAKE_INSTALL_BINDIR=${placeholder "out"}/bin"
-          "-DCMAKE_INSTALL_INCLUDEDIR=${placeholder "dev"}/include"
-          "-DCMAKE_INSTALL_LIBDIR=${placeholder "lib"}/lib"
-          "-DCMAKE_INSTALL_LIBEXECDIR=${placeholder "lib"}/libexec"
-        ];
-      in "-DCROSS_TOOLCHAIN_FLAGS_NATIVE:list="
-      + lib.concatStringsSep ";" (lib.concatLists [
-        flagsForLlvmConfig
-        nativeToolchainFlags
-        nativeInstallFlags
-      ])
-    )
-  ];
-
-  postBuild = ''
-    rm -fR $out
-  '';
-
-  preCheck = ''
-    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH''${LD_LIBRARY_PATH:+:}$PWD/lib
-  '';
-
-  postInstall = ''
-    mkdir -p $python/share
-    mv $out/share/opt-viewer $python/share/opt-viewer
-    moveToOutput "bin/llvm-config*" "$dev"
-    substituteInPlace "$dev/lib/cmake/llvm/LLVMExports-${if debugVersion then "debug" else "release"}.cmake" \
-      --replace "\''${_IMPORT_PREFIX}/lib/lib" "$lib/lib/lib" \
-      --replace "$out/bin/llvm-config" "$dev/bin/llvm-config"
-    substituteInPlace "$dev/lib/cmake/llvm/LLVMConfig.cmake" \
-      --replace 'set(LLVM_BINARY_DIR "''${LLVM_INSTALL_PREFIX}")' 'set(LLVM_BINARY_DIR "''${LLVM_INSTALL_PREFIX}'"$lib"'")'
-  ''
-  + optionalString (stdenv.isDarwin && enableSharedLibraries) ''
-    ln -s $lib/lib/libLLVM.dylib $lib/lib/libLLVM-${shortVersion}.dylib
-    ln -s $lib/lib/libLLVM.dylib $lib/lib/libLLVM-${release_version}.dylib
-  ''
-  + optionalString (stdenv.buildPlatform != stdenv.hostPlatform) ''
-    cp NATIVE/bin/llvm-config $dev/bin/llvm-config-native
-  '';
-
-  inherit doCheck;
-
-  checkTarget = "check-all";
-
-  requiredSystemFeatures = [ "big-parallel" ];
-  meta = llvm_meta // {
-    homepage = "https://llvm.org/";
-    description = "A collection of modular and reusable compiler and toolchain technologies";
-    longDescription = ''
-      The LLVM Project is a collection of modular and reusable compiler and
-      toolchain technologies. Despite its name, LLVM has little to do with
-      traditional virtual machines. The name "LLVM" itself is not an acronym; it
-      is the full name of the project.
-      LLVM began as a research project at the University of Illinois, with the
-      goal of providing a modern, SSA-based compilation strategy capable of
-      supporting both static and dynamic compilation of arbitrary programming
-      languages. Since then, LLVM has grown to be an umbrella project consisting
-      of a number of subprojects, many of which are being used in production by
-      a wide variety of commercial and open source projects as well as being
-      widely used in academic research. Code in the LLVM project is licensed
-      under the "Apache 2.0 License with LLVM exceptions".
-    '';
-  };
-} // lib.optionalAttrs enableManpages {
-  pname = "llvm-manpages";
-
-  buildPhase = ''
-    make docs-llvm-man
-  '';
-
-  propagatedBuildInputs = [];
-
-  installPhase = ''
-    make -C docs install
-  '';
-
-  postPatch = null;
-  postInstall = null;
-
-  outputs = [ "out" ];
-
-  doCheck = false;
-
-  meta = llvm_meta // {
-    description = "man pages for LLVM ${version}";
-  };
-})
diff --git a/pkgs/development/compilers/llvm/14/default.nix b/pkgs/development/compilers/llvm/14/default.nix
index 588dc8fffefdd..06972af065c98 100644
--- a/pkgs/development/compilers/llvm/14/default.nix
+++ b/pkgs/development/compilers/llvm/14/default.nix
@@ -1,6 +1,7 @@
-{ lowPrio, newScope, pkgs, lib, stdenv, cmake
+{ lowPrio, newScope, pkgs, lib, stdenv
 , preLibcCrossHeaders
-, libxml2, python3, fetchFromGitHub, substitute, substituteAll, overrideCC, wrapCCWith, wrapBintoolsWith
+, substitute, substituteAll, fetchFromGitHub, fetchpatch
+, overrideCC, wrapCCWith, wrapBintoolsWith
 , buildLlvmTools # tools, but from the previous stage, for cross
 , targetLlvmLibraries # libraries, but from the next stage, for cross
 , targetLlvm
@@ -39,7 +40,11 @@
 # to you to make sure that the LLVM repo given matches the release configuration
 # specified.
 , monorepoSrc ? null
-}:
+# Allows passthrough to packages via newScope. This makes it possible to
+# do `(llvmPackages.override { <someLlvmDependency> = bar; }).clang` and get
+# an llvmPackages whose packages are overridden in an internally consistent way.
+, ...
+}@args:
 
 assert
   lib.assertMsg
@@ -51,17 +56,20 @@ assert
 let
   monorepoSrc' = monorepoSrc;
 in let
-  # Import releaseInfo separately to avoid infinite recursion
-  inherit (import ../common/common-let.nix { inherit lib gitRelease officialRelease; }) releaseInfo;
-  inherit (releaseInfo) release_version version;
-  inherit (import ../common/common-let.nix { inherit lib fetchFromGitHub release_version gitRelease officialRelease monorepoSrc'; }) llvm_meta monorepoSrc;
+
+  metadata = rec {
+    # Import releaseInfo separately to avoid infinite recursion
+    inherit (import ../common/common-let.nix { inherit lib gitRelease officialRelease; }) releaseInfo;
+    inherit (releaseInfo) release_version version;
+    inherit (import ../common/common-let.nix { inherit lib fetchFromGitHub release_version gitRelease officialRelease monorepoSrc'; }) llvm_meta monorepoSrc;
+  };
 
   tools = lib.makeExtensible (tools: let
-    callPackage = newScope (tools // { inherit stdenv cmake libxml2 python3 release_version version monorepoSrc buildLlvmTools; });
+    callPackage = newScope (tools // args // metadata);
     mkExtraBuildCommands0 = cc: ''
       rsrc="$out/resource-root"
       mkdir "$rsrc"
-      ln -s "${cc.lib}/lib/clang/${release_version}/include" "$rsrc"
+      ln -s "${cc.lib}/lib/clang/${metadata.release_version}/include" "$rsrc"
       echo "-resource-dir=$rsrc" >> $out/nix-support/cc-cflags
     '';
     mkExtraBuildCommands = cc: mkExtraBuildCommands0 cc + ''
@@ -80,8 +88,26 @@ in let
 
   in {
 
-    libllvm = callPackage ./llvm {
-      inherit llvm_meta;
+    libllvm = callPackage ../common/llvm {
+      patches = [
+        ./llvm/gnu-install-dirs.patch
+
+        # Fix musl build.
+        (fetchpatch {
+          url = "https://github.com/llvm/llvm-project/commit/5cd554303ead0f8891eee3cd6d25cb07f5a7bf67.patch";
+          relative = "llvm";
+          hash = "sha256-XPbvNJ45SzjMGlNUgt/IgEvM2dHQpDOe6woUJY+nUYA=";
+        })
+        # fix RuntimeDyld usage on aarch64-linux (e.g. python312Packages.numba tests)
+        (fetchpatch {
+          url = "https://github.com/llvm/llvm-project/commit/2e1b838a889f9793d4bcd5dbfe10db9796b77143.patch";
+          relative = "llvm";
+          hash = "sha256-Ot45P/iwaR4hkcM3xtLwfryQNgHI6pv6ADjv98tgdZA=";
+        })
+      ];
+      pollyPatches = [
+        ./llvm/gnu-install-dirs-polly.patch
+      ];
     };
 
     # `llvm` historically had the binaries.  When choosing an output explicitly,
@@ -99,7 +125,6 @@ in let
           libllvmLibdir = "${tools.libllvm.lib}/lib";
         })
       ];
-      inherit llvm_meta;
     };
 
     clang-unwrapped = tools.libclang;
@@ -120,6 +145,9 @@ in let
     #   python3 = pkgs.python3;  # don't use python-boot
     # });
 
+    # Wrapper for standalone command line utilities
+    clang-tools = callPackage ../common/clang-tools { };
+
     # pick clang appropriate for package set we are targeting
     clang =
       /**/ if stdenv.targetPlatform.libc == null then tools.clangNoLibc
@@ -151,7 +179,6 @@ in let
         ./lld/gnu-install-dirs.patch
         ./lld/fix-root-src-dir.patch
       ];
-      inherit llvm_meta;
     };
 
     lldb = callPackage ../common/lldb.nix {
@@ -184,7 +211,6 @@ in let
             && !stdenv.targetPlatform.isAarch64
             && (lib.versionOlder darwin.apple_sdk.sdk.version "11.0")
         ) ./lldb/cpu_subtype_arm64e_replacement.patch;
-      inherit llvm_meta;
     };
 
     # Below, is the LLVM bootstrapping logic. It handles building a
@@ -277,7 +303,7 @@ in let
   });
 
   libraries = lib.makeExtensible (libraries: let
-    callPackage = newScope (libraries // buildLlvmTools // { inherit stdenv cmake libxml2 python3 release_version version monorepoSrc; });
+    callPackage = newScope (libraries // buildLlvmTools // args // metadata);
   in {
 
     compiler-rt-libc = callPackage ../common/compiler-rt {
@@ -299,7 +325,6 @@ in let
         ../common/compiler-rt/armv6-scudo-no-yield.patch
         ../common/compiler-rt/armv6-scudo-libatomic.patch
       ];
-      inherit llvm_meta;
       stdenv = if stdenv.hostPlatform.useLLVM or false
                then overrideCC stdenv buildLlvmTools.clangNoCompilerRtWithLibc
                else stdenv;
@@ -324,7 +349,6 @@ in let
         ../common/compiler-rt/armv6-scudo-no-yield.patch
         ../common/compiler-rt/armv6-scudo-libatomic.patch
       ];
-      inherit llvm_meta;
       stdenv = if stdenv.hostPlatform.useLLVM or false
                then overrideCC stdenv buildLlvmTools.clangNoCompilerRt
                else stdenv;
@@ -355,7 +379,6 @@ in let
           ];
         })
       ];
-      inherit llvm_meta;
       stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
     };
 
@@ -363,7 +386,6 @@ in let
       patches = [
         ./libunwind/gnu-install-dirs.patch
       ];
-      inherit llvm_meta;
       stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
     };
 
@@ -372,9 +394,8 @@ in let
         ./openmp/gnu-install-dirs.patch
         ./openmp/run-lit-directly.patch
       ];
-      inherit llvm_meta targetLlvm;
     };
   });
   noExtend = extensible: lib.attrsets.removeAttrs extensible [ "extend" ];
 
-in { inherit tools libraries release_version; } // (noExtend libraries) // (noExtend tools)
+in { inherit tools libraries; inherit (metadata) release_version; } // (noExtend libraries) // (noExtend tools)
diff --git a/pkgs/development/compilers/llvm/14/llvm/default.nix b/pkgs/development/compilers/llvm/14/llvm/default.nix
deleted file mode 100644
index 124d07e4bb2b1..0000000000000
--- a/pkgs/development/compilers/llvm/14/llvm/default.nix
+++ /dev/null
@@ -1,323 +0,0 @@
-{ lib, stdenv, llvm_meta
-, pkgsBuildBuild
-, monorepoSrc
-, runCommand
-, fetchpatch
-, cmake
-, python3
-, libffi
-, enableGoldPlugin ? libbfd.hasPluginAPI
-, libbfd
-, libpfm
-, libxml2
-, ncurses
-, version
-, release_version
-, zlib
-, which
-, buildLlvmTools
-, debugVersion ? false
-, doCheck ? stdenv.isLinux && (!stdenv.isx86_32) && (!stdenv.hostPlatform.isMusl)
-  && (stdenv.hostPlatform == stdenv.buildPlatform)
-, enableManpages ? false
-, enableSharedLibraries ? !stdenv.hostPlatform.isStatic
-# broken for Ampere eMAG 8180 (c2.large.arm on Packet) #56245
-# broken for the armv7l builder
-, enablePFM ? stdenv.isLinux && !stdenv.hostPlatform.isAarch
-, enablePolly ? true
-}:
-
-let
-  inherit (lib) optional optionals optionalString;
-
-  # Used when creating a version-suffixed symlink of libLLVM.dylib
-  shortVersion = with lib;
-    concatStringsSep "." (take 1 (splitString "." release_version));
-
-  # Ordinarily we would just the `doCheck` and `checkDeps` functionality
-  # `mkDerivation` gives us to manage our test dependencies (instead of breaking
-  # out `doCheck` as a package level attribute).
-  #
-  # Unfortunately `lit` does not forward `$PYTHONPATH` to children processes, in
-  # particular the children it uses to do feature detection.
-  #
-  # This means that python deps we add to `checkDeps` (which the python
-  # interpreter is made aware of via `$PYTHONPATH` – populated by the python
-  # setup hook) are not picked up by `lit` which causes it to skip tests.
-  #
-  # Adding `python3.withPackages (ps: [ ... ])` to `checkDeps` also doesn't work
-  # because this package is shadowed in `$PATH` by the regular `python3`
-  # package.
-  #
-  # So, we "manually" assemble one python derivation for the package to depend
-  # on, taking into account whether checks are enabled or not:
-  python = if doCheck then
-    let
-      checkDeps = ps: with ps; [ psutil ];
-    in python3.withPackages checkDeps
-  else python3;
-
-in stdenv.mkDerivation (rec {
-  pname = "llvm";
-  inherit version;
-
-  src = runCommand "${pname}-src-${version}" {} (''
-    mkdir -p "$out"
-    cp -r ${monorepoSrc}/cmake "$out"
-    cp -r ${monorepoSrc}/${pname} "$out"
-    cp -r ${monorepoSrc}/third-party "$out"
-  '' + lib.optionalString enablePolly ''
-    chmod u+w "$out/${pname}/tools"
-    cp -r ${monorepoSrc}/polly "$out/${pname}/tools"
-  '');
-
-  sourceRoot = "${src.name}/${pname}";
-
-  outputs = [ "out" "lib" "dev" "python" ];
-
-  nativeBuildInputs = [ cmake python ]
-    ++ optionals enableManpages [ python3.pkgs.sphinx python3.pkgs.recommonmark ];
-
-  buildInputs = [ libxml2 libffi ]
-    ++ optional enablePFM libpfm; # exegesis
-
-  propagatedBuildInputs = [ ncurses zlib ];
-
-  nativeCheckInputs = [ which ];
-
-  patches = [
-    ./gnu-install-dirs.patch
-
-    # Fix musl build.
-    (fetchpatch {
-      url = "https://github.com/llvm/llvm-project/commit/5cd554303ead0f8891eee3cd6d25cb07f5a7bf67.patch";
-      relative = "llvm";
-      hash = "sha256-XPbvNJ45SzjMGlNUgt/IgEvM2dHQpDOe6woUJY+nUYA=";
-    })
-    # fix RuntimeDyld usage on aarch64-linux (e.g. python312Packages.numba tests)
-    (fetchpatch {
-      url = "https://github.com/llvm/llvm-project/commit/2e1b838a889f9793d4bcd5dbfe10db9796b77143.patch";
-      relative = "llvm";
-      hash = "sha256-Ot45P/iwaR4hkcM3xtLwfryQNgHI6pv6ADjv98tgdZA=";
-    })
-  ] ++ lib.optional enablePolly ./gnu-install-dirs-polly.patch;
-
-  postPatch = optionalString stdenv.isDarwin ''
-    substituteInPlace cmake/modules/AddLLVM.cmake \
-      --replace 'set(_install_name_dir INSTALL_NAME_DIR "@rpath")' "set(_install_name_dir)" \
-      --replace 'set(_install_rpath "@loader_path/../''${CMAKE_INSTALL_LIBDIR}''${LLVM_LIBDIR_SUFFIX}" ''${extra_libdir})' ""
-  '' + ''
-    # FileSystem permissions tests fail with various special bits
-    substituteInPlace unittests/Support/CMakeLists.txt \
-      --replace "Path.cpp" ""
-    rm unittests/Support/Path.cpp
-    substituteInPlace unittests/IR/CMakeLists.txt \
-      --replace "PassBuilderCallbacksTest.cpp" ""
-    rm unittests/IR/PassBuilderCallbacksTest.cpp
-    rm test/tools/llvm-objcopy/ELF/mirror-permissions-unix.test
-  '' + optionalString stdenv.hostPlatform.isMusl ''
-    patch -p1 -i ${../../common/llvm/TLI-musl.patch}
-    substituteInPlace unittests/Support/CMakeLists.txt \
-      --replace "add_subdirectory(DynamicLibrary)" ""
-    rm unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp
-    # valgrind unhappy with musl or glibc, but fails w/musl only
-    rm test/CodeGen/AArch64/wineh4.mir
-  '' + optionalString stdenv.hostPlatform.isAarch32 ''
-    # skip failing X86 test cases on 32-bit ARM
-    rm test/DebugInfo/X86/convert-debugloc.ll
-    rm test/DebugInfo/X86/convert-inlined.ll
-    rm test/DebugInfo/X86/convert-linked.ll
-    rm test/tools/dsymutil/X86/op-convert.test
-    rm test/tools/gold/X86/split-dwarf.ll
-    rm test/tools/llvm-dwarfdump/X86/prettyprint_types.s
-    rm test/tools/llvm-dwarfdump/X86/simplified-template-names.s
-  '' + optionalString (stdenv.hostPlatform.system == "armv6l-linux") ''
-    # Seems to require certain floating point hardware (NEON?)
-    rm test/ExecutionEngine/frem.ll
-  '' + optionalString stdenv.hostPlatform.isRiscV ''
-    rm test/ExecutionEngine/frem.ll
-    rm test/ExecutionEngine/mov64zext32.ll
-    rm test/ExecutionEngine/test-interp-vec-arithm_float.ll
-    rm test/ExecutionEngine/test-interp-vec-arithm_int.ll
-    rm test/ExecutionEngine/test-interp-vec-logical.ll
-    rm test/ExecutionEngine/test-interp-vec-setcond-fp.ll
-    rm test/ExecutionEngine/test-interp-vec-setcond-int.ll
-    substituteInPlace unittests/Support/CMakeLists.txt \
-      --replace "CrashRecoveryTest.cpp" ""
-    rm unittests/Support/CrashRecoveryTest.cpp
-    substituteInPlace unittests/ExecutionEngine/Orc/CMakeLists.txt \
-      --replace "OrcCAPITest.cpp" ""
-    rm unittests/ExecutionEngine/Orc/OrcCAPITest.cpp
-  '' + ''
-    patchShebangs test/BugPoint/compile-custom.ll.py
-  '';
-
-  preConfigure = ''
-    # Workaround for configure flags that need to have spaces
-    cmakeFlagsArray+=(
-      -DLLVM_LIT_ARGS='-svj''${NIX_BUILD_CORES} --no-progress-bar'
-    )
-  '';
-
-  # hacky fix: created binaries need to be run before installation
-  preBuild = ''
-    mkdir -p $out/
-    ln -sv $PWD/lib $out
-  '';
-
-  # E.g. mesa.drivers use the build-id as a cache key (see #93946):
-  LDFLAGS = optionalString (enableSharedLibraries && !stdenv.isDarwin) "-Wl,--build-id=sha1";
-
-  hardeningDisable = [ "trivialautovarinit" ];
-
-  cmakeBuildType = if debugVersion then "Debug" else "Release";
-
-  cmakeFlags = with stdenv; let
-    # These flags influence llvm-config's BuildVariables.inc in addition to the
-    # general build. We need to make sure these are also passed via
-    # CROSS_TOOLCHAIN_FLAGS_NATIVE when cross-compiling or llvm-config-native
-    # will return different results from the cross llvm-config.
-    #
-    # Some flags don't need to be repassed because LLVM already does so (like
-    # CMAKE_BUILD_TYPE), others are irrelevant to the result.
-    flagsForLlvmConfig = [
-      "-DLLVM_INSTALL_CMAKE_DIR=${placeholder "dev"}/lib/cmake/llvm/"
-      "-DLLVM_ENABLE_RTTI=ON"
-    ] ++ optionals enableSharedLibraries [
-      "-DLLVM_LINK_LLVM_DYLIB=ON"
-    ];
-  in flagsForLlvmConfig ++ [
-    "-DLLVM_INSTALL_UTILS=ON"  # Needed by rustc
-    "-DLLVM_BUILD_TESTS=${if doCheck then "ON" else "OFF"}"
-    "-DLLVM_ENABLE_FFI=ON"
-    "-DLLVM_HOST_TRIPLE=${stdenv.hostPlatform.config}"
-    "-DLLVM_DEFAULT_TARGET_TRIPLE=${stdenv.hostPlatform.config}"
-    "-DLLVM_ENABLE_DUMP=ON"
-  ] ++ optionals stdenv.hostPlatform.isStatic [
-    # Disables building of shared libs, -fPIC is still injected by cc-wrapper
-    "-DLLVM_ENABLE_PIC=OFF"
-    "-DLLVM_BUILD_STATIC=ON"
-    "-DLLVM_LINK_LLVM_DYLIB=off"
-    # libxml2 needs to be disabled because the LLVM build system ignores its .la
-    # file and doesn't link zlib as well.
-    # https://github.com/ClangBuiltLinux/tc-build/issues/150#issuecomment-845418812
-    "-DLLVM_ENABLE_LIBXML2=OFF"
-  ] ++ optionals enableManpages [
-    "-DLLVM_BUILD_DOCS=ON"
-    "-DLLVM_ENABLE_SPHINX=ON"
-    "-DSPHINX_OUTPUT_MAN=ON"
-    "-DSPHINX_OUTPUT_HTML=OFF"
-    "-DSPHINX_WARNINGS_AS_ERRORS=OFF"
-  ] ++ optionals (enableGoldPlugin) [
-    "-DLLVM_BINUTILS_INCDIR=${libbfd.dev}/include"
-  ] ++ optionals isDarwin [
-    "-DLLVM_ENABLE_LIBCXX=ON"
-    "-DCAN_TARGET_i386=false"
-  ] ++ optionals ((stdenv.hostPlatform != stdenv.buildPlatform) && !(stdenv.buildPlatform.canExecute stdenv.hostPlatform)) [
-    "-DCMAKE_CROSSCOMPILING=True"
-    "-DLLVM_TABLEGEN=${buildLlvmTools.llvm}/bin/llvm-tblgen"
-    (
-      let
-        nativeCC = pkgsBuildBuild.targetPackages.stdenv.cc;
-        nativeBintools = nativeCC.bintools.bintools;
-        nativeToolchainFlags = [
-          "-DCMAKE_C_COMPILER=${nativeCC}/bin/${nativeCC.targetPrefix}cc"
-          "-DCMAKE_CXX_COMPILER=${nativeCC}/bin/${nativeCC.targetPrefix}c++"
-          "-DCMAKE_AR=${nativeBintools}/bin/${nativeBintools.targetPrefix}ar"
-          "-DCMAKE_STRIP=${nativeBintools}/bin/${nativeBintools.targetPrefix}strip"
-          "-DCMAKE_RANLIB=${nativeBintools}/bin/${nativeBintools.targetPrefix}ranlib"
-        ];
-        # We need to repass the custom GNUInstallDirs values, otherwise CMake
-        # will choose them for us, leading to wrong results in llvm-config-native
-        nativeInstallFlags = [
-          "-DCMAKE_INSTALL_PREFIX=${placeholder "out"}"
-          "-DCMAKE_INSTALL_BINDIR=${placeholder "out"}/bin"
-          "-DCMAKE_INSTALL_INCLUDEDIR=${placeholder "dev"}/include"
-          "-DCMAKE_INSTALL_LIBDIR=${placeholder "lib"}/lib"
-          "-DCMAKE_INSTALL_LIBEXECDIR=${placeholder "lib"}/libexec"
-        ];
-      in "-DCROSS_TOOLCHAIN_FLAGS_NATIVE:list="
-      + lib.concatStringsSep ";" (lib.concatLists [
-        flagsForLlvmConfig
-        nativeToolchainFlags
-        nativeInstallFlags
-      ])
-    )
-  ];
-
-  postBuild = ''
-    rm -fR $out
-  '';
-
-  preCheck = ''
-    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH''${LD_LIBRARY_PATH:+:}$PWD/lib
-  '';
-
-  postInstall = ''
-    mkdir -p $python/share
-    mv $out/share/opt-viewer $python/share/opt-viewer
-    moveToOutput "bin/llvm-config*" "$dev"
-    substituteInPlace "$dev/lib/cmake/llvm/LLVMExports-${if debugVersion then "debug" else "release"}.cmake" \
-      --replace "\''${_IMPORT_PREFIX}/lib/lib" "$lib/lib/lib" \
-      --replace "$out/bin/llvm-config" "$dev/bin/llvm-config"
-    substituteInPlace "$dev/lib/cmake/llvm/LLVMConfig.cmake" \
-      --replace 'set(LLVM_BINARY_DIR "''${LLVM_INSTALL_PREFIX}")' 'set(LLVM_BINARY_DIR "''${LLVM_INSTALL_PREFIX}'"$lib"'")'
-  ''
-  + optionalString (stdenv.isDarwin && enableSharedLibraries) ''
-    ln -s $lib/lib/libLLVM.dylib $lib/lib/libLLVM-${shortVersion}.dylib
-    ln -s $lib/lib/libLLVM.dylib $lib/lib/libLLVM-${release_version}.dylib
-  ''
-  + optionalString (stdenv.buildPlatform != stdenv.hostPlatform) ''
-    cp NATIVE/bin/llvm-config $dev/bin/llvm-config-native
-  '';
-
-  inherit doCheck;
-
-  checkTarget = "check-all";
-
-  # For the update script:
-  passthru.monorepoSrc = monorepoSrc;
-
-  requiredSystemFeatures = [ "big-parallel" ];
-  meta = llvm_meta // {
-    homepage = "https://llvm.org/";
-    description = "A collection of modular and reusable compiler and toolchain technologies";
-    longDescription = ''
-      The LLVM Project is a collection of modular and reusable compiler and
-      toolchain technologies. Despite its name, LLVM has little to do with
-      traditional virtual machines. The name "LLVM" itself is not an acronym; it
-      is the full name of the project.
-      LLVM began as a research project at the University of Illinois, with the
-      goal of providing a modern, SSA-based compilation strategy capable of
-      supporting both static and dynamic compilation of arbitrary programming
-      languages. Since then, LLVM has grown to be an umbrella project consisting
-      of a number of subprojects, many of which are being used in production by
-      a wide variety of commercial and open source projects as well as being
-      widely used in academic research. Code in the LLVM project is licensed
-      under the "Apache 2.0 License with LLVM exceptions".
-    '';
-  };
-} // lib.optionalAttrs enableManpages {
-  pname = "llvm-manpages";
-
-  buildPhase = ''
-    make docs-llvm-man
-  '';
-
-  propagatedBuildInputs = [];
-
-  installPhase = ''
-    make -C docs install
-  '';
-
-  postPatch = null;
-  postInstall = null;
-
-  outputs = [ "out" ];
-
-  doCheck = false;
-
-  meta = llvm_meta // {
-    description = "man pages for LLVM ${version}";
-  };
-})
diff --git a/pkgs/development/compilers/llvm/15/default.nix b/pkgs/development/compilers/llvm/15/default.nix
index bfcbe2b86e247..e50e35b2c4eb0 100644
--- a/pkgs/development/compilers/llvm/15/default.nix
+++ b/pkgs/development/compilers/llvm/15/default.nix
@@ -1,6 +1,7 @@
-{ lowPrio, newScope, pkgs, lib, stdenv, cmake, ninja
+{ lowPrio, newScope, pkgs, lib, stdenv
 , preLibcCrossHeaders
-, libxml2, python3, fetchFromGitHub, fetchpatch, substitute, substituteAll, overrideCC, wrapCCWith, wrapBintoolsWith
+, substitute, substituteAll, fetchFromGitHub, fetchpatch
+, overrideCC, wrapCCWith, wrapBintoolsWith
 , buildLlvmTools # tools, but from the previous stage, for cross
 , targetLlvmLibraries # libraries, but from the next stage, for cross
 , targetLlvm
@@ -39,7 +40,11 @@
 # to you to make sure that the LLVM repo given matches the release configuration
 # specified.
 , monorepoSrc ? null
-}:
+# Allows passthrough to packages via newScope. This makes it possible to
+# do `(llvmPackages.override { <someLlvmDependency> = bar; }).clang` and get
+# an llvmPackages whose packages are overridden in an internally consistent way.
+, ...
+}@args:
 
 assert
   lib.assertMsg
@@ -51,10 +56,13 @@ assert
 let
   monorepoSrc' = monorepoSrc;
 in let
-  # Import releaseInfo separately to avoid infinite recursion
-  inherit (import ../common/common-let.nix { inherit lib gitRelease officialRelease; }) releaseInfo;
-  inherit (releaseInfo) release_version version;
-  inherit (import ../common/common-let.nix { inherit lib fetchFromGitHub release_version gitRelease officialRelease monorepoSrc'; }) llvm_meta monorepoSrc;
+
+  metadata = rec {
+    # Import releaseInfo separately to avoid infinite recursion
+    inherit (import ../common/common-let.nix { inherit lib gitRelease officialRelease; }) releaseInfo;
+    inherit (releaseInfo) release_version version;
+    inherit (import ../common/common-let.nix { inherit lib fetchFromGitHub release_version gitRelease officialRelease monorepoSrc'; }) llvm_meta monorepoSrc;
+  };
 
   lldbPlugins = lib.makeExtensible (lldbPlugins: let
     callPackage = newScope (lldbPlugins // { inherit stdenv; inherit (tools) lldb; });
@@ -63,11 +71,11 @@ in let
   });
 
   tools = lib.makeExtensible (tools: let
-    callPackage = newScope (tools // { inherit stdenv cmake ninja libxml2 python3 release_version version monorepoSrc buildLlvmTools; });
+    callPackage = newScope (tools // args // metadata);
     mkExtraBuildCommands0 = cc: ''
       rsrc="$out/resource-root"
       mkdir "$rsrc"
-      ln -s "${cc.lib}/lib/clang/${release_version}/include" "$rsrc"
+      ln -s "${cc.lib}/lib/clang/${metadata.release_version}/include" "$rsrc"
       echo "-resource-dir=$rsrc" >> $out/nix-support/cc-cflags
     '';
     mkExtraBuildCommands = cc: mkExtraBuildCommands0 cc + ''
@@ -86,8 +94,64 @@ in let
 
   in {
 
-    libllvm = callPackage ./llvm {
-      inherit llvm_meta;
+    libllvm = callPackage ../common/llvm {
+      patches = [
+        ./llvm/gnu-install-dirs.patch
+
+        # Running the tests involves invoking binaries (like `opt`) that depend on
+        # the LLVM dylibs and reference them by absolute install path (i.e. their
+        # nix store path).
+        #
+        # Because we have not yet run the install phase (we're running these tests
+        # as part of `checkPhase` instead of `installCheckPhase`) these absolute
+        # paths do not exist yet; to work around this we point the loader (`ld` on
+        # unix, `dyld` on macOS) at the `lib` directory which will later become this
+        # package's `lib` output.
+        #
+        # Previously we would just set `LD_LIBRARY_PATH` to include the build `lib`
+        # dir but:
+        #   - this doesn't generalize well to other platforms; `lit` doesn't forward
+        #     `DYLD_LIBRARY_PATH` (macOS):
+        #     + https://github.com/llvm/llvm-project/blob/0d89963df354ee309c15f67dc47c8ab3cb5d0fb2/llvm/utils/lit/lit/TestingConfig.py#L26
+        #   - even if `lit` forwarded this env var, we actually cannot set
+        #     `DYLD_LIBRARY_PATH` in the child processes `lit` launches because
+        #     `DYLD_LIBRARY_PATH` (and `DYLD_FALLBACK_LIBRARY_PATH`) is cleared for
+        #     "protected processes" (i.e. the python interpreter that runs `lit`):
+        #     https://stackoverflow.com/a/35570229
+        #   - other LLVM subprojects deal with this issue by having their `lit`
+        #     configuration set these env vars for us; it makes sense to do the same
+        #     for LLVM:
+        #     + https://github.com/llvm/llvm-project/blob/4c106cfdf7cf7eec861ad3983a3dd9a9e8f3a8ae/clang-tools-extra/test/Unit/lit.cfg.py#L22-L31
+        #
+        # !!! TODO: look into upstreaming this patch
+        ./llvm/llvm-lit-cfg-add-libs-to-dylib-path.patch
+
+        # `lit` has a mode where it executes run lines as a shell script which is
+        # constructs; this is problematic for macOS because it means that there's
+        # another process in between `lit` and the binaries being tested. As noted
+        # above, this means that `DYLD_LIBRARY_PATH` is cleared which means that our
+        # tests fail with dyld errors.
+        #
+        # To get around this we patch `lit` to reintroduce `DYLD_LIBRARY_PATH`, when
+        # present in the test configuration.
+        #
+        # It's not clear to me why this isn't an issue for LLVM developers running
+        # on macOS (nothing about this _seems_ nix specific)..
+        ./llvm/lit-shell-script-runner-set-dyld-library-path.patch
+
+        # Fix musl build.
+        (fetchpatch {
+          url = "https://github.com/llvm/llvm-project/commit/5cd554303ead0f8891eee3cd6d25cb07f5a7bf67.patch";
+          relative = "llvm";
+          hash = "sha256-XPbvNJ45SzjMGlNUgt/IgEvM2dHQpDOe6woUJY+nUYA=";
+        })
+      ];
+      pollyPatches = [
+        ./llvm/gnu-install-dirs-polly.patch
+
+        # Just like the `llvm-lit-cfg` patch, but for `polly`.
+        ./llvm/polly-lit-cfg-add-libs-to-dylib-path.patch
+      ];
     };
 
     # `llvm` historically had the binaries.  When choosing an output explicitly,
@@ -105,7 +169,6 @@ in let
           libllvmLibdir = "${tools.libllvm.lib}/lib";
         })
       ];
-      inherit llvm_meta;
     };
 
     clang-unwrapped = tools.libclang;
@@ -125,6 +188,9 @@ in let
       python3 = pkgs.python3;  # don't use python-boot
     });
 
+    # Wrapper for standalone command line utilities
+    clang-tools = callPackage ../common/clang-tools { };
+
     # pick clang appropriate for package set we are targeting
     clang =
       /**/ if stdenv.targetPlatform.libc == null then tools.clangNoLibc
@@ -155,7 +221,6 @@ in let
       patches = [
         ./lld/gnu-install-dirs.patch
       ];
-      inherit llvm_meta;
     };
 
     lldb = callPackage ../common/lldb.nix {
@@ -188,7 +253,6 @@ in let
             && !stdenv.targetPlatform.isAarch64
             && (lib.versionOlder darwin.apple_sdk.sdk.version "11.0")
         ) ./lldb/cpu_subtype_arm64e_replacement.patch;
-      inherit llvm_meta;
     };
 
     # Below, is the LLVM bootstrapping logic. It handles building a
@@ -291,7 +355,7 @@ in let
   });
 
   libraries = lib.makeExtensible (libraries: let
-    callPackage = newScope (libraries // buildLlvmTools // { inherit stdenv cmake ninja libxml2 python3 release_version version monorepoSrc; });
+    callPackage = newScope (libraries // buildLlvmTools // args // metadata);
   in {
 
     compiler-rt-libc = callPackage ../common/compiler-rt {
@@ -308,7 +372,6 @@ in let
         # See: https://github.com/NixOS/nixpkgs/pull/194634#discussion_r999829893
         ../common/compiler-rt/armv7l-15.patch
       ];
-      inherit llvm_meta;
       stdenv = if stdenv.hostPlatform.useLLVM or false
                then overrideCC stdenv buildLlvmTools.clangNoCompilerRtWithLibc
                else stdenv;
@@ -328,7 +391,6 @@ in let
         # See: https://github.com/NixOS/nixpkgs/pull/194634#discussion_r999829893
         ../common/compiler-rt/armv7l-15.patch
       ];
-      inherit llvm_meta;
       stdenv = if stdenv.hostPlatform.useLLVM or false
                then overrideCC stdenv buildLlvmTools.clangNoCompilerRt
                else stdenv;
@@ -370,7 +432,6 @@ in let
           ];
         })
       ];
-      inherit llvm_meta;
       stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
     };
 
@@ -378,7 +439,6 @@ in let
       patches = [
         ./libunwind/gnu-install-dirs.patch
       ];
-      inherit llvm_meta;
       stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
     };
 
@@ -388,9 +448,8 @@ in let
         ./openmp/gnu-install-dirs.patch
         ./openmp/run-lit-directly.patch
       ];
-      inherit llvm_meta targetLlvm;
     };
   });
   noExtend = extensible: lib.attrsets.removeAttrs extensible [ "extend" ];
 
-in { inherit tools libraries release_version lldbPlugins; } // (noExtend libraries) // (noExtend tools)
+in { inherit tools libraries lldbPlugins; inherit (metadata) release_version; } // (noExtend libraries) // (noExtend tools)
diff --git a/pkgs/development/compilers/llvm/15/llvm/default.nix b/pkgs/development/compilers/llvm/15/llvm/default.nix
deleted file mode 100644
index d7ebcbcf8b760..0000000000000
--- a/pkgs/development/compilers/llvm/15/llvm/default.nix
+++ /dev/null
@@ -1,442 +0,0 @@
-{ lib, stdenv, llvm_meta
-, pkgsBuildBuild
-, monorepoSrc
-, runCommand
-, fetchpatch
-, cmake
-, darwin
-, ninja
-, python3
-, python3Packages
-, libffi
-, enableGoldPlugin ? libbfd.hasPluginAPI
-, libbfd
-, libpfm
-, libxml2
-, ncurses
-, version
-, release_version
-, zlib
-, which
-, sysctl
-, buildLlvmTools
-, debugVersion ? false
-, doCheck ? (!stdenv.isx86_32 /* TODO: why */) && (!stdenv.hostPlatform.isMusl)
-  && (stdenv.hostPlatform == stdenv.buildPlatform)
-, enableManpages ? false
-, enableSharedLibraries ? !stdenv.hostPlatform.isStatic
-, enablePFM ? stdenv.isLinux /* PFM only supports Linux */
-  # broken for Ampere eMAG 8180 (c2.large.arm on Packet) #56245
-  # broken for the armv7l builder
-  && !stdenv.hostPlatform.isAarch
-, enablePolly ? true
-}:
-
-let
-  inherit (lib) optional optionals optionalString;
-
-  # Used when creating a version-suffixed symlink of libLLVM.dylib
-  shortVersion = with lib;
-    concatStringsSep "." (take 1 (splitString "." release_version));
-
-  # Ordinarily we would just the `doCheck` and `checkDeps` functionality
-  # `mkDerivation` gives us to manage our test dependencies (instead of breaking
-  # out `doCheck` as a package level attribute).
-  #
-  # Unfortunately `lit` does not forward `$PYTHONPATH` to children processes, in
-  # particular the children it uses to do feature detection.
-  #
-  # This means that python deps we add to `checkDeps` (which the python
-  # interpreter is made aware of via `$PYTHONPATH` – populated by the python
-  # setup hook) are not picked up by `lit` which causes it to skip tests.
-  #
-  # Adding `python3.withPackages (ps: [ ... ])` to `checkDeps` also doesn't work
-  # because this package is shadowed in `$PATH` by the regular `python3`
-  # package.
-  #
-  # So, we "manually" assemble one python derivation for the package to depend
-  # on, taking into account whether checks are enabled or not:
-  python = if doCheck then
-    # Note that we _explicitly_ ask for a python interpreter for our host
-    # platform here; the splicing that would ordinarily take care of this for
-    # us does not seem to work once we use `withPackages`.
-    let
-      checkDeps = ps: with ps; [ psutil ];
-    in pkgsBuildBuild.targetPackages.python3.withPackages checkDeps
-  else python3;
-
-in stdenv.mkDerivation (rec {
-  pname = "llvm";
-  inherit version;
-
-  src = runCommand "${pname}-src-${version}" {} (''
-    mkdir -p "$out"
-    cp -r ${monorepoSrc}/cmake "$out"
-    cp -r ${monorepoSrc}/${pname} "$out"
-    cp -r ${monorepoSrc}/third-party "$out"
-  '' + lib.optionalString enablePolly ''
-    chmod u+w "$out/${pname}/tools"
-    cp -r ${monorepoSrc}/polly "$out/${pname}/tools"
-  '');
-
-  sourceRoot = "${src.name}/${pname}";
-
-  outputs = [ "out" "lib" "dev" "python" ];
-
-  nativeBuildInputs = [ cmake ninja python ]
-    ++ optionals enableManpages [
-      # Note: we intentionally use `python3Packages` instead of `python3.pkgs`;
-      # splicing does *not* work with the latter. (TODO: fix)
-      python3Packages.sphinx python3Packages.recommonmark
-    ];
-
-  buildInputs = [ libxml2 libffi ]
-    ++ optional enablePFM libpfm; # exegesis
-
-  propagatedBuildInputs = [ ncurses zlib ];
-
-  nativeCheckInputs = [
-    which
-  ] ++ lib.optional stdenv.isDarwin sysctl;
-
-  patches = [
-    ./gnu-install-dirs.patch
-
-    # Running the tests involves invoking binaries (like `opt`) that depend on
-    # the LLVM dylibs and reference them by absolute install path (i.e. their
-    # nix store path).
-    #
-    # Because we have not yet run the install phase (we're running these tests
-    # as part of `checkPhase` instead of `installCheckPhase`) these absolute
-    # paths do not exist yet; to work around this we point the loader (`ld` on
-    # unix, `dyld` on macOS) at the `lib` directory which will later become this
-    # package's `lib` output.
-    #
-    # Previously we would just set `LD_LIBRARY_PATH` to include the build `lib`
-    # dir but:
-    #   - this doesn't generalize well to other platforms; `lit` doesn't forward
-    #     `DYLD_LIBRARY_PATH` (macOS):
-    #     + https://github.com/llvm/llvm-project/blob/0d89963df354ee309c15f67dc47c8ab3cb5d0fb2/llvm/utils/lit/lit/TestingConfig.py#L26
-    #   - even if `lit` forwarded this env var, we actually cannot set
-    #     `DYLD_LIBRARY_PATH` in the child processes `lit` launches because
-    #     `DYLD_LIBRARY_PATH` (and `DYLD_FALLBACK_LIBRARY_PATH`) is cleared for
-    #     "protected processes" (i.e. the python interpreter that runs `lit`):
-    #     https://stackoverflow.com/a/35570229
-    #   - other LLVM subprojects deal with this issue by having their `lit`
-    #     configuration set these env vars for us; it makes sense to do the same
-    #     for LLVM:
-    #     + https://github.com/llvm/llvm-project/blob/4c106cfdf7cf7eec861ad3983a3dd9a9e8f3a8ae/clang-tools-extra/test/Unit/lit.cfg.py#L22-L31
-    #
-    # !!! TODO: look into upstreaming this patch
-    ./llvm-lit-cfg-add-libs-to-dylib-path.patch
-
-    # `lit` has a mode where it executes run lines as a shell script which is
-    # constructs; this is problematic for macOS because it means that there's
-    # another process in between `lit` and the binaries being tested. As noted
-    # above, this means that `DYLD_LIBRARY_PATH` is cleared which means that our
-    # tests fail with dyld errors.
-    #
-    # To get around this we patch `lit` to reintroduce `DYLD_LIBRARY_PATH`, when
-    # present in the test configuration.
-    #
-    # It's not clear to me why this isn't an issue for LLVM developers running
-    # on macOS (nothing about this _seems_ nix specific)..
-    ./lit-shell-script-runner-set-dyld-library-path.patch
-
-    # Fix musl build.
-    (fetchpatch {
-      url = "https://github.com/llvm/llvm-project/commit/5cd554303ead0f8891eee3cd6d25cb07f5a7bf67.patch";
-      relative = "llvm";
-      hash = "sha256-XPbvNJ45SzjMGlNUgt/IgEvM2dHQpDOe6woUJY+nUYA=";
-    })
-  ] ++ lib.optionals enablePolly [
-    ./gnu-install-dirs-polly.patch
-
-    # Just like the `llvm-lit-cfg` patch, but for `polly`.
-    ./polly-lit-cfg-add-libs-to-dylib-path.patch
-  ];
-
-  postPatch = optionalString stdenv.isDarwin ''
-    substituteInPlace cmake/modules/AddLLVM.cmake \
-      --replace 'set(_install_name_dir INSTALL_NAME_DIR "@rpath")' "set(_install_name_dir)" \
-      --replace 'set(_install_rpath "@loader_path/../''${CMAKE_INSTALL_LIBDIR}''${LLVM_LIBDIR_SUFFIX}" ''${extra_libdir})' ""
-
-    # As of LLVM 15, marked as XFAIL on arm64 macOS but lit doesn't seem to pick
-    # this up: https://github.com/llvm/llvm-project/blob/c344d97a125b18f8fed0a64aace73c49a870e079/llvm/test/MC/ELF/cfi-version.ll#L7
-    rm test/MC/ELF/cfi-version.ll
-
-    # This test tries to call `sw_vers` by absolute path (`/usr/bin/sw_vers`)
-    # and thus fails under the sandbox:
-    substituteInPlace unittests/Support/Host.cpp \
-      --replace '/usr/bin/sw_vers' "${(builtins.toString darwin.DarwinTools) + "/bin/sw_vers" }"
-  '' + optionalString (stdenv.isDarwin && stdenv.hostPlatform.isx86) ''
-    # This test tries to call the intrinsics `@llvm.roundeven.f32` and
-    # `@llvm.roundeven.f64` which seem to (incorrectly?) lower to `roundevenf`
-    # and `roundeven` on x86_64 macOS.
-    #
-    # However these functions are glibc specific so the test fails:
-    #   - https://www.gnu.org/software/gnulib/manual/html_node/roundevenf.html
-    #   - https://www.gnu.org/software/gnulib/manual/html_node/roundeven.html
-    #
-    # TODO(@rrbutani): this seems to run fine on `aarch64-darwin`, why does it
-    # pass there?
-    substituteInPlace test/ExecutionEngine/Interpreter/intrinsics.ll \
-      --replace "%roundeven32 = call float @llvm.roundeven.f32(float 0.000000e+00)" "" \
-      --replace "%roundeven64 = call double @llvm.roundeven.f64(double 0.000000e+00)" ""
-
-    # This test fails on darwin x86_64 because `sw_vers` reports a different
-    # macOS version than what LLVM finds by reading
-    # `/System/Library/CoreServices/SystemVersion.plist` (which is passed into
-    # the sandbox on macOS).
-    #
-    # The `sw_vers` provided by nixpkgs reports the macOS version associated
-    # with the `CoreFoundation` framework with which it was built. Because
-    # nixpkgs pins the SDK for `aarch64-darwin` and `x86_64-darwin` what
-    # `sw_vers` reports is not guaranteed to match the macOS version of the host
-    # that's building this derivation.
-    #
-    # Astute readers will note that we only _patch_ this test on aarch64-darwin
-    # (to use the nixpkgs provided `sw_vers`) instead of disabling it outright.
-    # So why does this test pass on aarch64?
-    #
-    # Well, it seems that `sw_vers` on aarch64 actually links against the _host_
-    # CoreFoundation framework instead of the nixpkgs provided one.
-    #
-    # Not entirely sure what the right fix is here. I'm assuming aarch64
-    # `sw_vers` doesn't intentionally link against the host `CoreFoundation`
-    # (still digging into how this ends up happening, will follow up) but that
-    # aside I think the more pertinent question is: should we be patching LLVM's
-    # macOS version detection logic to use `sw_vers` instead of reading host
-    # paths? This *is* a way in which details about builder machines can creep
-    # into the artifacts that are produced, affecting reproducibility, but it's
-    # not clear to me when/where/for what this even gets used in LLVM.
-    #
-    # TODO(@rrbutani): fix/follow-up
-    substituteInPlace unittests/Support/Host.cpp \
-      --replace "getMacOSHostVersion" "DISABLED_getMacOSHostVersion"
-
-    # This test fails with a `dysmutil` crash; have not yet dug into what's
-    # going on here (TODO(@rrbutani)).
-    rm test/tools/dsymutil/ARM/obfuscated.test
-  '' + ''
-    # FileSystem permissions tests fail with various special bits
-    substituteInPlace unittests/Support/CMakeLists.txt \
-      --replace "Path.cpp" ""
-    rm unittests/Support/Path.cpp
-    substituteInPlace unittests/IR/CMakeLists.txt \
-      --replace "PassBuilderCallbacksTest.cpp" ""
-    rm unittests/IR/PassBuilderCallbacksTest.cpp
-    rm test/tools/llvm-objcopy/ELF/mirror-permissions-unix.test
-    # timing-based tests are trouble
-    rm utils/lit/tests/googletest-timeout.py
-  '' + optionalString stdenv.hostPlatform.isMusl ''
-    patch -p1 -i ${../../common/llvm/TLI-musl.patch}
-    substituteInPlace unittests/Support/CMakeLists.txt \
-      --replace "add_subdirectory(DynamicLibrary)" ""
-    rm unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp
-    # valgrind unhappy with musl or glibc, but fails w/musl only
-    rm test/CodeGen/AArch64/wineh4.mir
-  '' + optionalString stdenv.hostPlatform.isAarch32 ''
-    # skip failing X86 test cases on 32-bit ARM
-    rm test/DebugInfo/X86/convert-debugloc.ll
-    rm test/DebugInfo/X86/convert-inlined.ll
-    rm test/DebugInfo/X86/convert-linked.ll
-    rm test/tools/dsymutil/X86/op-convert.test
-    rm test/tools/gold/X86/split-dwarf.ll
-    rm test/tools/llvm-dwarfdump/X86/prettyprint_types.s
-    rm test/tools/llvm-dwarfdump/X86/simplified-template-names.s
-
-    # !!! Note: these tests are removed in LLVM 16.
-    #
-    # See here for context: https://github.com/NixOS/nixpkgs/pull/194634#discussion_r999790443
-    rm test/CodeGen/RISCV/rv32zbp.ll
-    rm test/CodeGen/RISCV/rv64zbp.ll
-  '' + optionalString (stdenv.hostPlatform.system == "armv6l-linux") ''
-    # Seems to require certain floating point hardware (NEON?)
-    rm test/ExecutionEngine/frem.ll
-  '' + ''
-    patchShebangs test/BugPoint/compile-custom.ll.py
-  '';
-
-  preConfigure = ''
-    # Workaround for configure flags that need to have spaces
-    cmakeFlagsArray+=(
-      -DLLVM_LIT_ARGS="-svj''${NIX_BUILD_CORES} --no-progress-bar"
-    )
-  '';
-
-  # Defensive check: some paths (that we make symlinks to) depend on the release
-  # version, for example:
-  #  - https://github.com/llvm/llvm-project/blob/406bde9a15136254f2b10d9ef3a42033b3cb1b16/clang/lib/Headers/CMakeLists.txt#L185
-  #
-  # So we want to sure that the version in the source matches the release
-  # version we were given.
-  #
-  # We do this check here, in the LLVM build, because it happens early.
-  postConfigure = let
-    v = lib.versions;
-    major = v.major release_version;
-    minor = v.minor release_version;
-    patch = v.patch release_version;
-  in ''
-    # $1: part, $2: expected
-    check_version() {
-      part="''${1^^}"
-      part="$(cat include/llvm/Config/llvm-config.h  | grep "#define LLVM_VERSION_''${part} " | cut -d' ' -f3)"
-
-      if [[ "$part" != "$2" ]]; then
-        echo >&2 \
-          "mismatch in the $1 version! we have version ${release_version}" \
-          "and expected the $1 version to be '$2'; the source has '$part' instead"
-        exit 3
-      fi
-    }
-
-    check_version major ${major}
-    check_version minor ${minor}
-    check_version patch ${patch}
-  '';
-
-  # E.g. mesa.drivers use the build-id as a cache key (see #93946):
-  LDFLAGS = optionalString (enableSharedLibraries && !stdenv.isDarwin) "-Wl,--build-id=sha1";
-
-  hardeningDisable = [ "trivialautovarinit" ];
-
-  cmakeBuildType = if debugVersion then "Debug" else "Release";
-
-  cmakeFlags = with stdenv; let
-    # These flags influence llvm-config's BuildVariables.inc in addition to the
-    # general build. We need to make sure these are also passed via
-    # CROSS_TOOLCHAIN_FLAGS_NATIVE when cross-compiling or llvm-config-native
-    # will return different results from the cross llvm-config.
-    #
-    # Some flags don't need to be repassed because LLVM already does so (like
-    # CMAKE_BUILD_TYPE), others are irrelevant to the result.
-    flagsForLlvmConfig = [
-      "-DLLVM_INSTALL_PACKAGE_DIR=${placeholder "dev"}/lib/cmake/llvm"
-      "-DLLVM_ENABLE_RTTI=ON"
-    ] ++ optionals enableSharedLibraries [
-      "-DLLVM_LINK_LLVM_DYLIB=ON"
-    ];
-  in flagsForLlvmConfig ++ [
-    "-DLLVM_INSTALL_UTILS=ON"  # Needed by rustc
-    "-DLLVM_BUILD_TESTS=${if doCheck then "ON" else "OFF"}"
-    "-DLLVM_ENABLE_FFI=ON"
-    "-DLLVM_HOST_TRIPLE=${stdenv.hostPlatform.config}"
-    "-DLLVM_DEFAULT_TARGET_TRIPLE=${stdenv.hostPlatform.config}"
-    "-DLLVM_ENABLE_DUMP=ON"
-  ] ++ optionals stdenv.hostPlatform.isStatic [
-    # Disables building of shared libs, -fPIC is still injected by cc-wrapper
-    "-DLLVM_ENABLE_PIC=OFF"
-    "-DLLVM_BUILD_STATIC=ON"
-    "-DLLVM_LINK_LLVM_DYLIB=off"
-    # libxml2 needs to be disabled because the LLVM build system ignores its .la
-    # file and doesn't link zlib as well.
-    # https://github.com/ClangBuiltLinux/tc-build/issues/150#issuecomment-845418812
-    "-DLLVM_ENABLE_LIBXML2=OFF"
-  ] ++ optionals enableManpages [
-    "-DLLVM_BUILD_DOCS=ON"
-    "-DLLVM_ENABLE_SPHINX=ON"
-    "-DSPHINX_OUTPUT_MAN=ON"
-    "-DSPHINX_OUTPUT_HTML=OFF"
-    "-DSPHINX_WARNINGS_AS_ERRORS=OFF"
-  ] ++ optionals (enableGoldPlugin) [
-    "-DLLVM_BINUTILS_INCDIR=${libbfd.dev}/include"
-  ] ++ optionals isDarwin [
-    "-DLLVM_ENABLE_LIBCXX=ON"
-    "-DCAN_TARGET_i386=false"
-  ] ++ optionals ((stdenv.hostPlatform != stdenv.buildPlatform) && !(stdenv.buildPlatform.canExecute stdenv.hostPlatform)) [
-    "-DCMAKE_CROSSCOMPILING=True"
-    "-DLLVM_TABLEGEN=${buildLlvmTools.llvm}/bin/llvm-tblgen"
-    (
-      let
-        nativeCC = pkgsBuildBuild.targetPackages.stdenv.cc;
-        nativeBintools = nativeCC.bintools.bintools;
-        nativeToolchainFlags = [
-          "-DCMAKE_C_COMPILER=${nativeCC}/bin/${nativeCC.targetPrefix}cc"
-          "-DCMAKE_CXX_COMPILER=${nativeCC}/bin/${nativeCC.targetPrefix}c++"
-          "-DCMAKE_AR=${nativeBintools}/bin/${nativeBintools.targetPrefix}ar"
-          "-DCMAKE_STRIP=${nativeBintools}/bin/${nativeBintools.targetPrefix}strip"
-          "-DCMAKE_RANLIB=${nativeBintools}/bin/${nativeBintools.targetPrefix}ranlib"
-        ];
-        # We need to repass the custom GNUInstallDirs values, otherwise CMake
-        # will choose them for us, leading to wrong results in llvm-config-native
-        nativeInstallFlags = [
-          "-DCMAKE_INSTALL_PREFIX=${placeholder "out"}"
-          "-DCMAKE_INSTALL_BINDIR=${placeholder "out"}/bin"
-          "-DCMAKE_INSTALL_INCLUDEDIR=${placeholder "dev"}/include"
-          "-DCMAKE_INSTALL_LIBDIR=${placeholder "lib"}/lib"
-          "-DCMAKE_INSTALL_LIBEXECDIR=${placeholder "lib"}/libexec"
-        ];
-      in "-DCROSS_TOOLCHAIN_FLAGS_NATIVE:list="
-      + lib.concatStringsSep ";" (lib.concatLists [
-        flagsForLlvmConfig
-        nativeToolchainFlags
-        nativeInstallFlags
-      ])
-    )
-  ];
-
-  postInstall = ''
-    mkdir -p $python/share
-    mv $out/share/opt-viewer $python/share/opt-viewer
-    moveToOutput "bin/llvm-config*" "$dev"
-    substituteInPlace "$dev/lib/cmake/llvm/LLVMExports-${if debugVersion then "debug" else "release"}.cmake" \
-      --replace "\''${_IMPORT_PREFIX}/lib/lib" "$lib/lib/lib" \
-      --replace "$out/bin/llvm-config" "$dev/bin/llvm-config"
-    substituteInPlace "$dev/lib/cmake/llvm/LLVMConfig.cmake" \
-      --replace 'set(LLVM_BINARY_DIR "''${LLVM_INSTALL_PREFIX}")' 'set(LLVM_BINARY_DIR "'"$lib"'")'
-  ''
-  + optionalString (stdenv.isDarwin && enableSharedLibraries) ''
-    ln -s $lib/lib/libLLVM.dylib $lib/lib/libLLVM-${shortVersion}.dylib
-    ln -s $lib/lib/libLLVM.dylib $lib/lib/libLLVM-${release_version}.dylib
-  ''
-  + optionalString (stdenv.buildPlatform != stdenv.hostPlatform) ''
-    cp NATIVE/bin/llvm-config $dev/bin/llvm-config-native
-  '';
-
-  inherit doCheck;
-
-  checkTarget = "check-all";
-
-  # For the update script:
-  passthru.monorepoSrc = monorepoSrc;
-
-  requiredSystemFeatures = [ "big-parallel" ];
-  meta = llvm_meta // {
-    homepage = "https://llvm.org/";
-    description = "A collection of modular and reusable compiler and toolchain technologies";
-    longDescription = ''
-      The LLVM Project is a collection of modular and reusable compiler and
-      toolchain technologies. Despite its name, LLVM has little to do with
-      traditional virtual machines. The name "LLVM" itself is not an acronym; it
-      is the full name of the project.
-      LLVM began as a research project at the University of Illinois, with the
-      goal of providing a modern, SSA-based compilation strategy capable of
-      supporting both static and dynamic compilation of arbitrary programming
-      languages. Since then, LLVM has grown to be an umbrella project consisting
-      of a number of subprojects, many of which are being used in production by
-      a wide variety of commercial and open source projects as well as being
-      widely used in academic research. Code in the LLVM project is licensed
-      under the "Apache 2.0 License with LLVM exceptions".
-    '';
-  };
-} // lib.optionalAttrs enableManpages {
-  pname = "llvm-manpages";
-
-  propagatedBuildInputs = [];
-
-  ninjaFlags = [ "docs-llvm-man" ];
-  installTargets = [ "install-docs-llvm-man" ];
-
-  postPatch = null;
-  postInstall = null;
-
-  outputs = [ "out" ];
-
-  doCheck = false;
-
-  meta = llvm_meta // {
-    description = "man pages for LLVM ${version}";
-  };
-})
diff --git a/pkgs/development/compilers/llvm/16/compiler-rt/asan-offset.patch b/pkgs/development/compilers/llvm/16/compiler-rt/asan-offset.patch
new file mode 100644
index 0000000000000..46afe5c007347
--- /dev/null
+++ b/pkgs/development/compilers/llvm/16/compiler-rt/asan-offset.patch
@@ -0,0 +1,11 @@
+--- a/lib/asan/CMakeLists.txt        2022-06-22 16:46:24.000000000 +0000
++++ b/lib/asan/CMakeLists.txt
+@@ -46,7 +46,7 @@ set(ASAN_STATIC_SOURCES
+   asan_rtl_static.cpp
+   )
+ 
+-if (NOT WIN32 AND NOT APPLE)
++if (LINUX)
+   list(APPEND ASAN_STATIC_SOURCES
+     asan_rtl_x86_64.S
+   )
diff --git a/pkgs/development/compilers/llvm/16/compiler-rt/freebsd-i386.patch b/pkgs/development/compilers/llvm/16/compiler-rt/freebsd-i386.patch
new file mode 100644
index 0000000000000..0a221750552a0
--- /dev/null
+++ b/pkgs/development/compilers/llvm/16/compiler-rt/freebsd-i386.patch
@@ -0,0 +1,21 @@
+--- a/lib/builtins/fp_lib.h	1969-12-31 16:00:01.000000000 -0800
++++ b/lib/builtins/fp_lib.h	2023-12-21 23:39:36.066927293 -0800
+@@ -26,18 +26,6 @@
+ #include <stdbool.h>
+ #include <stdint.h>
+ 
+-// x86_64 FreeBSD prior v9.3 define fixed-width types incorrectly in
+-// 32-bit mode.
+-#if defined(__FreeBSD__) && defined(__i386__)
+-#include <sys/param.h>
+-#if __FreeBSD_version < 903000 // v9.3
+-#define uint64_t unsigned long long
+-#define int64_t long long
+-#undef UINT64_C
+-#define UINT64_C(c) (c##ULL)
+-#endif
+-#endif
+-
+ #if defined SINGLE_PRECISION
+ 
+ typedef uint16_t half_rep_t;
diff --git a/pkgs/development/compilers/llvm/16/default.nix b/pkgs/development/compilers/llvm/16/default.nix
index 5dd07d77cf8c6..80b2424b14cc0 100644
--- a/pkgs/development/compilers/llvm/16/default.nix
+++ b/pkgs/development/compilers/llvm/16/default.nix
@@ -1,6 +1,7 @@
-{ lowPrio, newScope, pkgs, lib, stdenv, cmake, ninja
+{ lowPrio, newScope, pkgs, lib, stdenv
 , preLibcCrossHeaders
-, libxml2, python3, fetchFromGitHub, substituteAll, overrideCC, wrapCCWith, wrapBintoolsWith
+, substitute, substituteAll, fetchFromGitHub
+, overrideCC, wrapCCWith, wrapBintoolsWith
 , buildLlvmTools # tools, but from the previous stage, for cross
 , targetLlvmLibraries # libraries, but from the next stage, for cross
 , targetLlvm
@@ -39,7 +40,11 @@
 # to you to make sure that the LLVM repo given matches the release configuration
 # specified.
 , monorepoSrc ? null
-}:
+# Allows passthrough to packages via newScope. This makes it possible to
+# do `(llvmPackages.override { <someLlvmDependency> = bar; }).clang` and get
+# an llvmPackages whose packages are overridden in an internally consistent way.
+, ...
+}@args:
 
 assert
   lib.assertMsg
@@ -51,10 +56,13 @@ assert
 let
   monorepoSrc' = monorepoSrc;
 in let
-  # Import releaseInfo separately to avoid infinite recursion
-  inherit (import ../common/common-let.nix { inherit lib gitRelease officialRelease; }) releaseInfo;
-  inherit (releaseInfo) release_version version;
-  inherit (import ../common/common-let.nix { inherit lib fetchFromGitHub release_version gitRelease officialRelease monorepoSrc'; }) llvm_meta monorepoSrc;
+
+  metadata = rec {
+    # Import releaseInfo separately to avoid infinite recursion
+    inherit (import ../common/common-let.nix { inherit lib gitRelease officialRelease; }) releaseInfo;
+    inherit (releaseInfo) release_version version;
+    inherit (import ../common/common-let.nix { inherit lib fetchFromGitHub release_version gitRelease officialRelease monorepoSrc'; }) llvm_meta monorepoSrc;
+  };
 
   lldbPlugins = lib.makeExtensible (lldbPlugins: let
     callPackage = newScope (lldbPlugins // { inherit stdenv; inherit (tools) lldb; });
@@ -63,8 +71,8 @@ in let
   });
 
   tools = lib.makeExtensible (tools: let
-    callPackage = newScope (tools // { inherit stdenv cmake ninja libxml2 python3 release_version version monorepoSrc buildLlvmTools; });
-    major = lib.versions.major release_version;
+    callPackage = newScope (tools // args // metadata);
+    major = lib.versions.major metadata.release_version;
     mkExtraBuildCommands0 = cc: ''
       rsrc="$out/resource-root"
       mkdir "$rsrc"
@@ -87,8 +95,57 @@ in let
 
   in {
 
-    libllvm = callPackage ./llvm {
-      inherit llvm_meta;
+    libllvm = callPackage ../common/llvm {
+      patches = [
+        ./llvm/gnu-install-dirs.patch
+
+        # Running the tests involves invoking binaries (like `opt`) that depend on
+        # the LLVM dylibs and reference them by absolute install path (i.e. their
+        # nix store path).
+        #
+        # Because we have not yet run the install phase (we're running these tests
+        # as part of `checkPhase` instead of `installCheckPhase`) these absolute
+        # paths do not exist yet; to work around this we point the loader (`ld` on
+        # unix, `dyld` on macOS) at the `lib` directory which will later become this
+        # package's `lib` output.
+        #
+        # Previously we would just set `LD_LIBRARY_PATH` to include the build `lib`
+        # dir but:
+        #   - this doesn't generalize well to other platforms; `lit` doesn't forward
+        #     `DYLD_LIBRARY_PATH` (macOS):
+        #     + https://github.com/llvm/llvm-project/blob/0d89963df354ee309c15f67dc47c8ab3cb5d0fb2/llvm/utils/lit/lit/TestingConfig.py#L26
+        #   - even if `lit` forwarded this env var, we actually cannot set
+        #     `DYLD_LIBRARY_PATH` in the child processes `lit` launches because
+        #     `DYLD_LIBRARY_PATH` (and `DYLD_FALLBACK_LIBRARY_PATH`) is cleared for
+        #     "protected processes" (i.e. the python interpreter that runs `lit`):
+        #     https://stackoverflow.com/a/35570229
+        #   - other LLVM subprojects deal with this issue by having their `lit`
+        #     configuration set these env vars for us; it makes sense to do the same
+        #     for LLVM:
+        #     + https://github.com/llvm/llvm-project/blob/4c106cfdf7cf7eec861ad3983a3dd9a9e8f3a8ae/clang-tools-extra/test/Unit/lit.cfg.py#L22-L31
+        #
+        # !!! TODO: look into upstreaming this patch
+        ./llvm/llvm-lit-cfg-add-libs-to-dylib-path.patch
+
+        # `lit` has a mode where it executes run lines as a shell script which is
+        # constructs; this is problematic for macOS because it means that there's
+        # another process in between `lit` and the binaries being tested. As noted
+        # above, this means that `DYLD_LIBRARY_PATH` is cleared which means that our
+        # tests fail with dyld errors.
+        #
+        # To get around this we patch `lit` to reintroduce `DYLD_LIBRARY_PATH`, when
+        # present in the test configuration.
+        #
+        # It's not clear to me why this isn't an issue for LLVM developers running
+        # on macOS (nothing about this _seems_ nix specific)..
+        ./llvm/lit-shell-script-runner-set-dyld-library-path.patch
+      ];
+      pollyPatches = [
+        ./llvm/gnu-install-dirs-polly.patch
+
+        # Just like the `llvm-lit-cfg` patch, but for `polly`.
+        ./llvm/polly-lit-cfg-add-libs-to-dylib-path.patch
+      ];
     };
 
     # `llvm` historically had the binaries.  When choosing an output explicitly,
@@ -106,7 +163,6 @@ in let
           libllvmLibdir = "${tools.libllvm.lib}/lib";
         })
       ];
-      inherit llvm_meta;
     };
 
     clang-unwrapped = tools.libclang;
@@ -126,6 +182,9 @@ in let
       python3 = pkgs.python3;  # don't use python-boot
     });
 
+    # Wrapper for standalone command line utilities
+    clang-tools = callPackage ../common/clang-tools { };
+
     # pick clang appropriate for package set we are targeting
     clang =
       /**/ if stdenv.targetPlatform.useLLVM or false then tools.clangUseLLVM
@@ -156,15 +215,12 @@ in let
         ./lld/gnu-install-dirs.patch
         ./lld/add-table-base.patch
       ];
-      inherit llvm_meta;
     };
 
-    mlir = callPackage ../common/mlir {
-      inherit llvm_meta;
-    };
+    mlir = callPackage ../common/mlir {};
 
     lldb = callPackage ../common/lldb.nix {
-      src = callPackage ({ runCommand }: runCommand "lldb-src-${version}" {} ''
+      src = callPackage ({ runCommand }: runCommand "lldb-src-${metadata.version}" {} ''
         mkdir -p "$out"
         cp -r ${monorepoSrc}/cmake "$out"
         cp -r ${monorepoSrc}/lldb "$out"
@@ -198,7 +254,6 @@ in let
             && !stdenv.targetPlatform.isAarch64
             && (lib.versionOlder darwin.apple_sdk.sdk.version "11.0")
         ) ./lldb/cpu_subtype_arm64e_replacement.patch;
-      inherit llvm_meta;
     };
 
     # Below, is the LLVM bootstrapping logic. It handles building a
@@ -301,13 +356,11 @@ in let
     # Has to be in tools despite mostly being a library,
     # because we use a native helper executable from a
     # non-cross build in cross builds.
-    libclc = callPackage ../common/libclc.nix {
-      inherit buildLlvmTools;
-    };
+    libclc = callPackage ../common/libclc.nix {};
   });
 
   libraries = lib.makeExtensible (libraries: let
-    callPackage = newScope (libraries // buildLlvmTools // { inherit stdenv cmake ninja libxml2 python3 release_version version monorepoSrc; });
+    callPackage = newScope (libraries // buildLlvmTools // args // metadata);
   in {
 
     compiler-rt-libc = callPackage ../common/compiler-rt {
@@ -324,7 +377,6 @@ in let
         # See: https://github.com/NixOS/nixpkgs/pull/194634#discussion_r999829893
         # ../common/compiler-rt/armv7l-15.patch
       ];
-      inherit llvm_meta;
       stdenv = if stdenv.hostPlatform.useLLVM or false || (stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isStatic)
                then overrideCC stdenv buildLlvmTools.clangNoCompilerRtWithLibc
                else stdenv;
@@ -344,7 +396,6 @@ in let
         # See: https://github.com/NixOS/nixpkgs/pull/194634#discussion_r999829893
         # ../common/compiler-rt/armv7l-15.patch
       ];
-      inherit llvm_meta;
       stdenv = if stdenv.hostPlatform.useLLVM or false
                then overrideCC stdenv buildLlvmTools.clangNoCompilerRt
                else stdenv;
@@ -363,7 +414,6 @@ in let
     # so: we use the clang from this LLVM package set instead of the regular
     # stdenv's compiler.
     libcxx = callPackage ../common/libcxx {
-      inherit llvm_meta;
       stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
     };
 
@@ -371,7 +421,6 @@ in let
       patches = [
         ./libunwind/gnu-install-dirs.patch
       ];
-      inherit llvm_meta;
       stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
     };
 
@@ -381,9 +430,8 @@ in let
         ./openmp/gnu-install-dirs.patch
         ./openmp/run-lit-directly.patch
       ];
-      inherit llvm_meta targetLlvm;
     };
   });
   noExtend = extensible: lib.attrsets.removeAttrs extensible [ "extend" ];
 
-in { inherit tools libraries release_version lldbPlugins; } // (noExtend libraries) // (noExtend tools)
+in { inherit tools libraries lldbPlugins; inherit (metadata) release_version; } // (noExtend libraries) // (noExtend tools)
diff --git a/pkgs/development/compilers/llvm/16/llvm/default.nix b/pkgs/development/compilers/llvm/16/llvm/default.nix
deleted file mode 100644
index 0a8d877ba83c8..0000000000000
--- a/pkgs/development/compilers/llvm/16/llvm/default.nix
+++ /dev/null
@@ -1,435 +0,0 @@
-{ lib, stdenv, llvm_meta
-, pkgsBuildBuild
-, monorepoSrc
-, runCommand
-, cmake
-, darwin
-, ninja
-, python3
-, python3Packages
-, libffi
-# TODO: Gold plugin on LLVM16 has a severe memory corruption bug: https://github.com/llvm/llvm-project/issues/61350.
-, enableGoldPlugin ? false
-, libbfd
-, libpfm
-, libxml2
-, ncurses
-, version
-, release_version
-, zlib
-, which
-, sysctl
-, buildLlvmTools
-, debugVersion ? false
-, doCheck ? (!stdenv.isx86_32 /* TODO: why */) && (!stdenv.hostPlatform.isMusl)
-  && (stdenv.hostPlatform == stdenv.buildPlatform)
-, enableManpages ? false
-, enableSharedLibraries ? !stdenv.hostPlatform.isStatic
-, enablePFM ? stdenv.isLinux /* PFM only supports Linux */
-  # broken for Ampere eMAG 8180 (c2.large.arm on Packet) #56245
-  # broken for the armv7l builder
-  && !stdenv.hostPlatform.isAarch
-, enablePolly ? true
-}:
-
-let
-  inherit (lib) optional optionals optionalString;
-
-  # Used when creating a version-suffixed symlink of libLLVM.dylib
-  shortVersion = with lib;
-    concatStringsSep "." (take 1 (splitString "." release_version));
-
-  # Ordinarily we would just the `doCheck` and `checkDeps` functionality
-  # `mkDerivation` gives us to manage our test dependencies (instead of breaking
-  # out `doCheck` as a package level attribute).
-  #
-  # Unfortunately `lit` does not forward `$PYTHONPATH` to children processes, in
-  # particular the children it uses to do feature detection.
-  #
-  # This means that python deps we add to `checkDeps` (which the python
-  # interpreter is made aware of via `$PYTHONPATH` – populated by the python
-  # setup hook) are not picked up by `lit` which causes it to skip tests.
-  #
-  # Adding `python3.withPackages (ps: [ ... ])` to `checkDeps` also doesn't work
-  # because this package is shadowed in `$PATH` by the regular `python3`
-  # package.
-  #
-  # So, we "manually" assemble one python derivation for the package to depend
-  # on, taking into account whether checks are enabled or not:
-  python = if doCheck then
-    # Note that we _explicitly_ ask for a python interpreter for our host
-    # platform here; the splicing that would ordinarily take care of this for
-    # us does not seem to work once we use `withPackages`.
-    let
-      checkDeps = ps: with ps; [ psutil ];
-    in pkgsBuildBuild.targetPackages.python3.withPackages checkDeps
-  else python3;
-
-in
-  assert (lib.assertMsg (!enableGoldPlugin) "Gold plugin cannot be enabled on LLVM16 due to a upstream issue: https://github.com/llvm/llvm-project/issues/61350");
-  stdenv.mkDerivation (rec {
-  pname = "llvm";
-  inherit version;
-
-  src = runCommand "${pname}-src-${version}" {} (''
-    mkdir -p "$out"
-    cp -r ${monorepoSrc}/cmake "$out"
-    cp -r ${monorepoSrc}/${pname} "$out"
-    cp -r ${monorepoSrc}/third-party "$out"
-  '' + lib.optionalString enablePolly ''
-    chmod u+w "$out/${pname}/tools"
-    cp -r ${monorepoSrc}/polly "$out/${pname}/tools"
-  '');
-
-  sourceRoot = "${src.name}/${pname}";
-
-  outputs = [ "out" "lib" "dev" "python" ];
-
-  nativeBuildInputs = [ cmake ninja python ]
-    ++ optionals enableManpages [
-      # Note: we intentionally use `python3Packages` instead of `python3.pkgs`;
-      # splicing does *not* work with the latter. (TODO: fix)
-      python3Packages.sphinx python3Packages.recommonmark
-    ];
-
-  buildInputs = [ libxml2 libffi ]
-    ++ optional enablePFM libpfm; # exegesis
-
-  propagatedBuildInputs = [ ncurses zlib ];
-
-  nativeCheckInputs = [
-    which
-  ] ++ lib.optional stdenv.isDarwin sysctl;
-
-  patches = [
-    ./gnu-install-dirs.patch
-
-    # Running the tests involves invoking binaries (like `opt`) that depend on
-    # the LLVM dylibs and reference them by absolute install path (i.e. their
-    # nix store path).
-    #
-    # Because we have not yet run the install phase (we're running these tests
-    # as part of `checkPhase` instead of `installCheckPhase`) these absolute
-    # paths do not exist yet; to work around this we point the loader (`ld` on
-    # unix, `dyld` on macOS) at the `lib` directory which will later become this
-    # package's `lib` output.
-    #
-    # Previously we would just set `LD_LIBRARY_PATH` to include the build `lib`
-    # dir but:
-    #   - this doesn't generalize well to other platforms; `lit` doesn't forward
-    #     `DYLD_LIBRARY_PATH` (macOS):
-    #     + https://github.com/llvm/llvm-project/blob/0d89963df354ee309c15f67dc47c8ab3cb5d0fb2/llvm/utils/lit/lit/TestingConfig.py#L26
-    #   - even if `lit` forwarded this env var, we actually cannot set
-    #     `DYLD_LIBRARY_PATH` in the child processes `lit` launches because
-    #     `DYLD_LIBRARY_PATH` (and `DYLD_FALLBACK_LIBRARY_PATH`) is cleared for
-    #     "protected processes" (i.e. the python interpreter that runs `lit`):
-    #     https://stackoverflow.com/a/35570229
-    #   - other LLVM subprojects deal with this issue by having their `lit`
-    #     configuration set these env vars for us; it makes sense to do the same
-    #     for LLVM:
-    #     + https://github.com/llvm/llvm-project/blob/4c106cfdf7cf7eec861ad3983a3dd9a9e8f3a8ae/clang-tools-extra/test/Unit/lit.cfg.py#L22-L31
-    #
-    # !!! TODO: look into upstreaming this patch
-    ./llvm-lit-cfg-add-libs-to-dylib-path.patch
-
-    # `lit` has a mode where it executes run lines as a shell script which is
-    # constructs; this is problematic for macOS because it means that there's
-    # another process in between `lit` and the binaries being tested. As noted
-    # above, this means that `DYLD_LIBRARY_PATH` is cleared which means that our
-    # tests fail with dyld errors.
-    #
-    # To get around this we patch `lit` to reintroduce `DYLD_LIBRARY_PATH`, when
-    # present in the test configuration.
-    #
-    # It's not clear to me why this isn't an issue for LLVM developers running
-    # on macOS (nothing about this _seems_ nix specific)..
-    ./lit-shell-script-runner-set-dyld-library-path.patch
-  ] ++ lib.optionals enablePolly [
-    ./gnu-install-dirs-polly.patch
-
-    # Just like the `llvm-lit-cfg` patch, but for `polly`.
-    ./polly-lit-cfg-add-libs-to-dylib-path.patch
-  ];
-
-  postPatch = optionalString stdenv.isDarwin ''
-    substituteInPlace cmake/modules/AddLLVM.cmake \
-      --replace 'set(_install_name_dir INSTALL_NAME_DIR "@rpath")' "set(_install_name_dir)" \
-      --replace 'set(_install_rpath "@loader_path/../''${CMAKE_INSTALL_LIBDIR}''${LLVM_LIBDIR_SUFFIX}" ''${extra_libdir})' ""
-
-    # As of LLVM 15, marked as XFAIL on arm64 macOS but lit doesn't seem to pick
-    # this up: https://github.com/llvm/llvm-project/blob/c344d97a125b18f8fed0a64aace73c49a870e079/llvm/test/MC/ELF/cfi-version.ll#L7
-    rm test/MC/ELF/cfi-version.ll
-
-    # This test tries to call `sw_vers` by absolute path (`/usr/bin/sw_vers`)
-    # and thus fails under the sandbox:
-    substituteInPlace unittests/TargetParser/Host.cpp \
-      --replace '/usr/bin/sw_vers' "${(builtins.toString darwin.DarwinTools) + "/bin/sw_vers" }"
-
-    # This test tries to call the intrinsics `@llvm.roundeven.f32` and
-    # `@llvm.roundeven.f64` which seem to (incorrectly?) lower to `roundevenf`
-    # and `roundeven` on macOS.
-    #
-    # However these functions are glibc specific so the test fails:
-    #   - https://www.gnu.org/software/gnulib/manual/html_node/roundevenf.html
-    #   - https://www.gnu.org/software/gnulib/manual/html_node/roundeven.html
-    #
-    substituteInPlace test/ExecutionEngine/Interpreter/intrinsics.ll \
-      --replace "%roundeven32 = call float @llvm.roundeven.f32(float 0.000000e+00)" "" \
-      --replace "%roundeven64 = call double @llvm.roundeven.f64(double 0.000000e+00)" ""
-  '' + optionalString (stdenv.isDarwin && stdenv.hostPlatform.isx86) ''
-    # This test fails on darwin x86_64 because `sw_vers` reports a different
-    # macOS version than what LLVM finds by reading
-    # `/System/Library/CoreServices/SystemVersion.plist` (which is passed into
-    # the sandbox on macOS).
-    #
-    # The `sw_vers` provided by nixpkgs reports the macOS version associated
-    # with the `CoreFoundation` framework with which it was built. Because
-    # nixpkgs pins the SDK for `aarch64-darwin` and `x86_64-darwin` what
-    # `sw_vers` reports is not guaranteed to match the macOS version of the host
-    # that's building this derivation.
-    #
-    # Astute readers will note that we only _patch_ this test on aarch64-darwin
-    # (to use the nixpkgs provided `sw_vers`) instead of disabling it outright.
-    # So why does this test pass on aarch64?
-    #
-    # Well, it seems that `sw_vers` on aarch64 actually links against the _host_
-    # CoreFoundation framework instead of the nixpkgs provided one.
-    #
-    # Not entirely sure what the right fix is here. I'm assuming aarch64
-    # `sw_vers` doesn't intentionally link against the host `CoreFoundation`
-    # (still digging into how this ends up happening, will follow up) but that
-    # aside I think the more pertinent question is: should we be patching LLVM's
-    # macOS version detection logic to use `sw_vers` instead of reading host
-    # paths? This *is* a way in which details about builder machines can creep
-    # into the artifacts that are produced, affecting reproducibility, but it's
-    # not clear to me when/where/for what this even gets used in LLVM.
-    #
-    # TODO(@rrbutani): fix/follow-up
-    substituteInPlace unittests/TargetParser/Host.cpp \
-      --replace "getMacOSHostVersion" "DISABLED_getMacOSHostVersion"
-
-    # This test fails with a `dysmutil` crash; have not yet dug into what's
-    # going on here (TODO(@rrbutani)).
-    rm test/tools/dsymutil/ARM/obfuscated.test
-  '' + ''
-    # FileSystem permissions tests fail with various special bits
-    substituteInPlace unittests/Support/CMakeLists.txt \
-      --replace "Path.cpp" ""
-    rm unittests/Support/Path.cpp
-    substituteInPlace unittests/IR/CMakeLists.txt \
-      --replace "PassBuilderCallbacksTest.cpp" ""
-    rm unittests/IR/PassBuilderCallbacksTest.cpp
-    rm test/tools/llvm-objcopy/ELF/mirror-permissions-unix.test
-
-    # Fails in the presence of anti-virus software or other intrusion-detection software that
-    # modifies the atime when run. See #284056.
-    rm test/tools/llvm-objcopy/ELF/strip-preserve-atime.test
-
-    # timing-based tests are trouble
-    rm utils/lit/tests/googletest-timeout.py
-  '' + optionalString stdenv.hostPlatform.isMusl ''
-    patch -p1 -i ${../../common/llvm/TLI-musl.patch}
-    substituteInPlace unittests/Support/CMakeLists.txt \
-      --replace "add_subdirectory(DynamicLibrary)" ""
-    rm unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp
-    # valgrind unhappy with musl or glibc, but fails w/musl only
-    rm test/CodeGen/AArch64/wineh4.mir
-  '' + optionalString stdenv.hostPlatform.isAarch32 ''
-    # skip failing X86 test cases on 32-bit ARM
-    rm test/DebugInfo/X86/convert-debugloc.ll
-    rm test/DebugInfo/X86/convert-inlined.ll
-    rm test/DebugInfo/X86/convert-linked.ll
-    rm test/tools/dsymutil/X86/op-convert.test
-    rm test/tools/gold/X86/split-dwarf.ll
-    rm test/tools/llvm-dwarfdump/X86/prettyprint_types.s
-    rm test/tools/llvm-dwarfdump/X86/simplified-template-names.s
-  '' + optionalString (stdenv.hostPlatform.system == "armv6l-linux") ''
-    # Seems to require certain floating point hardware (NEON?)
-    rm test/ExecutionEngine/frem.ll
-  '' + ''
-    patchShebangs test/BugPoint/compile-custom.ll.py
-  '';
-
-  preConfigure = ''
-    # Workaround for configure flags that need to have spaces
-    cmakeFlagsArray+=(
-      -DLLVM_LIT_ARGS="-svj''${NIX_BUILD_CORES} --no-progress-bar"
-    )
-  '';
-
-  # Defensive check: some paths (that we make symlinks to) depend on the release
-  # version, for example:
-  #  - https://github.com/llvm/llvm-project/blob/406bde9a15136254f2b10d9ef3a42033b3cb1b16/clang/lib/Headers/CMakeLists.txt#L185
-  #
-  # So we want to sure that the version in the source matches the release
-  # version we were given.
-  #
-  # We do this check here, in the LLVM build, because it happens early.
-  postConfigure = let
-    v = lib.versions;
-    major = v.major release_version;
-    minor = v.minor release_version;
-    patch = v.patch release_version;
-  in ''
-    # $1: part, $2: expected
-    check_version() {
-      part="''${1^^}"
-      part="$(cat include/llvm/Config/llvm-config.h  | grep "#define LLVM_VERSION_''${part} " | cut -d' ' -f3)"
-
-      if [[ "$part" != "$2" ]]; then
-        echo >&2 \
-          "mismatch in the $1 version! we have version ${release_version}" \
-          "and expected the $1 version to be '$2'; the source has '$part' instead"
-        exit 3
-      fi
-    }
-
-    check_version major ${major}
-    check_version minor ${minor}
-    check_version patch ${patch}
-  '';
-
-  # E.g. mesa.drivers use the build-id as a cache key (see #93946):
-  LDFLAGS = optionalString (enableSharedLibraries && !stdenv.isDarwin) "-Wl,--build-id=sha1";
-
-  hardeningDisable = [ "trivialautovarinit" ];
-
-  cmakeBuildType = if debugVersion then "Debug" else "Release";
-
-  cmakeFlags = with stdenv; let
-    # These flags influence llvm-config's BuildVariables.inc in addition to the
-    # general build. We need to make sure these are also passed via
-    # CROSS_TOOLCHAIN_FLAGS_NATIVE when cross-compiling or llvm-config-native
-    # will return different results from the cross llvm-config.
-    #
-    # Some flags don't need to be repassed because LLVM already does so (like
-    # CMAKE_BUILD_TYPE), others are irrelevant to the result.
-    flagsForLlvmConfig = [
-      "-DLLVM_INSTALL_PACKAGE_DIR=${placeholder "dev"}/lib/cmake/llvm"
-      "-DLLVM_ENABLE_RTTI=ON"
-    ] ++ optionals enableSharedLibraries [
-      "-DLLVM_LINK_LLVM_DYLIB=ON"
-    ];
-  in flagsForLlvmConfig ++ [
-    "-DLLVM_INSTALL_UTILS=ON"  # Needed by rustc
-    "-DLLVM_BUILD_TESTS=${if doCheck then "ON" else "OFF"}"
-    "-DLLVM_ENABLE_FFI=ON"
-    "-DLLVM_HOST_TRIPLE=${stdenv.hostPlatform.config}"
-    "-DLLVM_DEFAULT_TARGET_TRIPLE=${stdenv.hostPlatform.config}"
-    "-DLLVM_ENABLE_DUMP=ON"
-  ] ++ optionals stdenv.hostPlatform.isStatic [
-    # Disables building of shared libs, -fPIC is still injected by cc-wrapper
-    "-DLLVM_ENABLE_PIC=OFF"
-    "-DLLVM_BUILD_STATIC=ON"
-    "-DLLVM_LINK_LLVM_DYLIB=off"
-    # libxml2 needs to be disabled because the LLVM build system ignores its .la
-    # file and doesn't link zlib as well.
-    # https://github.com/ClangBuiltLinux/tc-build/issues/150#issuecomment-845418812
-    "-DLLVM_ENABLE_LIBXML2=OFF"
-  ] ++ optionals enableManpages [
-    "-DLLVM_BUILD_DOCS=ON"
-    "-DLLVM_ENABLE_SPHINX=ON"
-    "-DSPHINX_OUTPUT_MAN=ON"
-    "-DSPHINX_OUTPUT_HTML=OFF"
-    "-DSPHINX_WARNINGS_AS_ERRORS=OFF"
-  ] ++ optionals enableGoldPlugin [
-    # For LLVMgold plugin
-    "-DLLVM_BINUTILS_INCDIR=${libbfd.dev}/include"
-  ] ++ optionals isDarwin [
-    "-DLLVM_ENABLE_LIBCXX=ON"
-    "-DCAN_TARGET_i386=false"
-  ] ++ optionals ((stdenv.hostPlatform != stdenv.buildPlatform) && !(stdenv.buildPlatform.canExecute stdenv.hostPlatform)) [
-    "-DCMAKE_CROSSCOMPILING=True"
-    "-DLLVM_TABLEGEN=${buildLlvmTools.llvm}/bin/llvm-tblgen"
-    (
-      let
-        nativeCC = pkgsBuildBuild.targetPackages.stdenv.cc;
-        nativeBintools = nativeCC.bintools.bintools;
-        nativeToolchainFlags = [
-          "-DCMAKE_C_COMPILER=${nativeCC}/bin/${nativeCC.targetPrefix}cc"
-          "-DCMAKE_CXX_COMPILER=${nativeCC}/bin/${nativeCC.targetPrefix}c++"
-          "-DCMAKE_AR=${nativeBintools}/bin/${nativeBintools.targetPrefix}ar"
-          "-DCMAKE_STRIP=${nativeBintools}/bin/${nativeBintools.targetPrefix}strip"
-          "-DCMAKE_RANLIB=${nativeBintools}/bin/${nativeBintools.targetPrefix}ranlib"
-        ];
-        # We need to repass the custom GNUInstallDirs values, otherwise CMake
-        # will choose them for us, leading to wrong results in llvm-config-native
-        nativeInstallFlags = [
-          "-DCMAKE_INSTALL_PREFIX=${placeholder "out"}"
-          "-DCMAKE_INSTALL_BINDIR=${placeholder "out"}/bin"
-          "-DCMAKE_INSTALL_INCLUDEDIR=${placeholder "dev"}/include"
-          "-DCMAKE_INSTALL_LIBDIR=${placeholder "lib"}/lib"
-          "-DCMAKE_INSTALL_LIBEXECDIR=${placeholder "lib"}/libexec"
-        ];
-      in "-DCROSS_TOOLCHAIN_FLAGS_NATIVE:list="
-      + lib.concatStringsSep ";" (lib.concatLists [
-        flagsForLlvmConfig
-        nativeToolchainFlags
-        nativeInstallFlags
-      ])
-    )
-  ];
-
-  postInstall = ''
-    mkdir -p $python/share
-    mv $out/share/opt-viewer $python/share/opt-viewer
-    moveToOutput "bin/llvm-config*" "$dev"
-    substituteInPlace "$dev/lib/cmake/llvm/LLVMExports-${if debugVersion then "debug" else "release"}.cmake" \
-      --replace "\''${_IMPORT_PREFIX}/lib/lib" "$lib/lib/lib" \
-      --replace "$out/bin/llvm-config" "$dev/bin/llvm-config"
-    substituteInPlace "$dev/lib/cmake/llvm/LLVMConfig.cmake" \
-      --replace 'set(LLVM_BINARY_DIR "''${LLVM_INSTALL_PREFIX}")' 'set(LLVM_BINARY_DIR "'"$lib"'")'
-  ''
-  + optionalString (stdenv.isDarwin && enableSharedLibraries) ''
-    ln -s $lib/lib/libLLVM.dylib $lib/lib/libLLVM-${shortVersion}.dylib
-    ln -s $lib/lib/libLLVM.dylib $lib/lib/libLLVM-${release_version}.dylib
-  ''
-  + optionalString (stdenv.buildPlatform != stdenv.hostPlatform) ''
-    cp NATIVE/bin/llvm-config $dev/bin/llvm-config-native
-  '';
-
-  inherit doCheck;
-
-  checkTarget = "check-all";
-
-  # For the update script:
-  passthru.monorepoSrc = monorepoSrc;
-
-  requiredSystemFeatures = [ "big-parallel" ];
-  meta = llvm_meta // {
-    homepage = "https://llvm.org/";
-    description = "A collection of modular and reusable compiler and toolchain technologies";
-    longDescription = ''
-      The LLVM Project is a collection of modular and reusable compiler and
-      toolchain technologies. Despite its name, LLVM has little to do with
-      traditional virtual machines. The name "LLVM" itself is not an acronym; it
-      is the full name of the project.
-      LLVM began as a research project at the University of Illinois, with the
-      goal of providing a modern, SSA-based compilation strategy capable of
-      supporting both static and dynamic compilation of arbitrary programming
-      languages. Since then, LLVM has grown to be an umbrella project consisting
-      of a number of subprojects, many of which are being used in production by
-      a wide variety of commercial and open source projects as well as being
-      widely used in academic research. Code in the LLVM project is licensed
-      under the "Apache 2.0 License with LLVM exceptions".
-    '';
-  };
-} // lib.optionalAttrs enableManpages {
-  pname = "llvm-manpages";
-
-  propagatedBuildInputs = [];
-
-  ninjaFlags = [ "docs-llvm-man" ];
-  installTargets = [ "install-docs-llvm-man" ];
-
-  postPatch = null;
-  postInstall = null;
-
-  outputs = [ "out" ];
-
-  doCheck = false;
-
-  meta = llvm_meta // {
-    description = "man pages for LLVM ${version}";
-  };
-})
diff --git a/pkgs/development/compilers/llvm/17/default.nix b/pkgs/development/compilers/llvm/17/default.nix
index 9f4be2261b0cf..84979d24b1971 100644
--- a/pkgs/development/compilers/llvm/17/default.nix
+++ b/pkgs/development/compilers/llvm/17/default.nix
@@ -1,6 +1,7 @@
-{ lowPrio, newScope, pkgs, lib, stdenv, cmake, ninja
+{ lowPrio, newScope, pkgs, lib, stdenv
 , preLibcCrossHeaders
-, libxml2, python3, fetchFromGitHub, fetchpatch, substituteAll, overrideCC, wrapCCWith, wrapBintoolsWith
+, substitute, substituteAll, fetchFromGitHub, fetchpatch
+, overrideCC, wrapCCWith, wrapBintoolsWith
 , buildLlvmTools # tools, but from the previous stage, for cross
 , targetLlvmLibraries # libraries, but from the next stage, for cross
 , targetLlvm
@@ -39,7 +40,11 @@
 # to you to make sure that the LLVM repo given matches the release configuration
 # specified.
 , monorepoSrc ? null
-}:
+# Allows passthrough to packages via newScope. This makes it possible to
+# do `(llvmPackages.override { <someLlvmDependency> = bar; }).clang` and get
+# an llvmPackages whose packages are overridden in an internally consistent way.
+, ...
+}@args:
 
 assert
   lib.assertMsg
@@ -51,15 +56,17 @@ assert
 let
   monorepoSrc' = monorepoSrc;
 in let
-  inherit (import ../common/common-let.nix { inherit lib gitRelease officialRelease; }) releaseInfo;
 
-  inherit (releaseInfo) release_version version;
-
-  inherit (import ../common/common-let.nix { inherit lib fetchFromGitHub release_version gitRelease officialRelease monorepoSrc'; }) llvm_meta monorepoSrc;
+  metadata = rec {
+    # Import releaseInfo separately to avoid infinite recursion
+    inherit (import ../common/common-let.nix { inherit lib gitRelease officialRelease; }) releaseInfo;
+    inherit (releaseInfo) release_version version;
+    inherit (import ../common/common-let.nix { inherit lib fetchFromGitHub gitRelease release_version officialRelease monorepoSrc'; }) llvm_meta monorepoSrc;
+  };
 
   tools = lib.makeExtensible (tools: let
-    callPackage = newScope (tools // { inherit stdenv cmake ninja libxml2 python3 release_version version monorepoSrc buildLlvmTools; });
-    major = lib.versions.major release_version;
+    callPackage = newScope (tools // args // metadata);
+    major = lib.versions.major metadata.release_version;
     mkExtraBuildCommands0 = cc: ''
       rsrc="$out/resource-root"
       mkdir "$rsrc"
@@ -82,8 +89,57 @@ in let
 
   in {
 
-    libllvm = callPackage ./llvm {
-      inherit llvm_meta;
+    libllvm = callPackage ../common/llvm {
+      patches = [
+        ./llvm/gnu-install-dirs.patch
+
+        # Running the tests involves invoking binaries (like `opt`) that depend on
+        # the LLVM dylibs and reference them by absolute install path (i.e. their
+        # nix store path).
+        #
+        # Because we have not yet run the install phase (we're running these tests
+        # as part of `checkPhase` instead of `installCheckPhase`) these absolute
+        # paths do not exist yet; to work around this we point the loader (`ld` on
+        # unix, `dyld` on macOS) at the `lib` directory which will later become this
+        # package's `lib` output.
+        #
+        # Previously we would just set `LD_LIBRARY_PATH` to include the build `lib`
+        # dir but:
+        #   - this doesn't generalize well to other platforms; `lit` doesn't forward
+        #     `DYLD_LIBRARY_PATH` (macOS):
+        #     + https://github.com/llvm/llvm-project/blob/0d89963df354ee309c15f67dc47c8ab3cb5d0fb2/llvm/utils/lit/lit/TestingConfig.py#L26
+        #   - even if `lit` forwarded this env var, we actually cannot set
+        #     `DYLD_LIBRARY_PATH` in the child processes `lit` launches because
+        #     `DYLD_LIBRARY_PATH` (and `DYLD_FALLBACK_LIBRARY_PATH`) is cleared for
+        #     "protected processes" (i.e. the python interpreter that runs `lit`):
+        #     https://stackoverflow.com/a/35570229
+        #   - other LLVM subprojects deal with this issue by having their `lit`
+        #     configuration set these env vars for us; it makes sense to do the same
+        #     for LLVM:
+        #     + https://github.com/llvm/llvm-project/blob/4c106cfdf7cf7eec861ad3983a3dd9a9e8f3a8ae/clang-tools-extra/test/Unit/lit.cfg.py#L22-L31
+        #
+        # !!! TODO: look into upstreaming this patch
+        ./llvm/llvm-lit-cfg-add-libs-to-dylib-path.patch
+
+        # `lit` has a mode where it executes run lines as a shell script which is
+        # constructs; this is problematic for macOS because it means that there's
+        # another process in between `lit` and the binaries being tested. As noted
+        # above, this means that `DYLD_LIBRARY_PATH` is cleared which means that our
+        # tests fail with dyld errors.
+        #
+        # To get around this we patch `lit` to reintroduce `DYLD_LIBRARY_PATH`, when
+        # present in the test configuration.
+        #
+        # It's not clear to me why this isn't an issue for LLVM developers running
+        # on macOS (nothing about this _seems_ nix specific)..
+        ./llvm/lit-shell-script-runner-set-dyld-library-path.patch
+      ];
+      pollyPatches = [
+        ./llvm/gnu-install-dirs-polly.patch
+
+        # Just like the `llvm-lit-cfg` patch, but for `polly`.
+        ./llvm/polly-lit-cfg-add-libs-to-dylib-path.patch
+      ];
     };
 
     # `llvm` historically had the binaries.  When choosing an output explicitly,
@@ -101,7 +157,6 @@ in let
           libllvmLibdir = "${tools.libllvm.lib}/lib";
         })
       ];
-      inherit llvm_meta;
     };
 
     clang-unwrapped = tools.libclang;
@@ -121,6 +176,9 @@ in let
       python3 = pkgs.python3;  # don't use python-boot
     });
 
+    # Wrapper for standalone command line utilities
+    clang-tools = callPackage ../common/clang-tools { };
+
     # pick clang appropriate for package set we are targeting
     clang =
       /**/ if stdenv.targetPlatform.useLLVM or false then tools.clangUseLLVM
@@ -151,15 +209,12 @@ in let
         ./lld/gnu-install-dirs.patch
         ./lld/add-table-base.patch
       ];
-      inherit llvm_meta;
     };
 
-    mlir = callPackage ../common/mlir {
-      inherit llvm_meta;
-    };
+    mlir = callPackage ../common/mlir {};
 
     lldb = callPackage ../common/lldb.nix {
-      src = callPackage ({ runCommand }: runCommand "lldb-src-${version}" {} ''
+      src = callPackage ({ runCommand }: runCommand "lldb-src-${metadata.version}" {} ''
         mkdir -p "$out"
         cp -r ${monorepoSrc}/cmake "$out"
         cp -r ${monorepoSrc}/lldb "$out"
@@ -183,7 +238,6 @@ in let
             && !stdenv.targetPlatform.isAarch64
             && (lib.versionOlder darwin.apple_sdk.sdk.version "11.0")
         ) ./lldb/cpu_subtype_arm64e_replacement.patch;
-      inherit llvm_meta;
     };
 
     # Below, is the LLVM bootstrapping logic. It handles building a
@@ -286,13 +340,11 @@ in let
     # Has to be in tools despite mostly being a library,
     # because we use a native helper executable from a
     # non-cross build in cross builds.
-    libclc = callPackage ../common/libclc.nix {
-      inherit buildLlvmTools;
-    };
+    libclc = callPackage ../common/libclc.nix {};
   });
 
   libraries = lib.makeExtensible (libraries: let
-    callPackage = newScope (libraries // buildLlvmTools // { inherit stdenv cmake ninja libxml2 python3 release_version version monorepoSrc; });
+    callPackage = newScope (libraries // buildLlvmTools // args // metadata);
   in {
 
     compiler-rt-libc = callPackage ../common/compiler-rt {
@@ -309,7 +361,6 @@ in let
         # See: https://github.com/NixOS/nixpkgs/pull/194634#discussion_r999829893
         # ../common/compiler-rt/armv7l-15.patch
       ];
-      inherit llvm_meta;
       stdenv = if stdenv.hostPlatform.useLLVM or false || (stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isStatic)
                then overrideCC stdenv buildLlvmTools.clangNoCompilerRtWithLibc
                else stdenv;
@@ -329,7 +380,6 @@ in let
         # See: https://github.com/NixOS/nixpkgs/pull/194634#discussion_r999829893
         # ../common/compiler-rt/armv7l-15.patch
       ];
-      inherit llvm_meta;
       stdenv = if stdenv.hostPlatform.useLLVM or false
                then overrideCC stdenv buildLlvmTools.clangNoCompilerRt
                else stdenv;
@@ -356,12 +406,10 @@ in let
           hash = "sha256-jo+DYA6zuSv9OH3A0bYwY5TlkWprup4OKQ7rfK1WHBI=";
         })
       ];
-      inherit llvm_meta;
       stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
     };
 
     libunwind = callPackage ../common/libunwind {
-      inherit llvm_meta;
       stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
     };
 
@@ -371,9 +419,8 @@ in let
         ./openmp/gnu-install-dirs.patch
         ./openmp/run-lit-directly.patch
       ];
-      inherit llvm_meta targetLlvm;
     };
   });
   noExtend = extensible: lib.attrsets.removeAttrs extensible [ "extend" ];
 
-in { inherit tools libraries release_version; } // (noExtend libraries) // (noExtend tools)
+in { inherit tools libraries; inherit (metadata) release_version; } // (noExtend libraries) // (noExtend tools)
diff --git a/pkgs/development/compilers/llvm/17/llvm/default.nix b/pkgs/development/compilers/llvm/17/llvm/default.nix
deleted file mode 100644
index a045bea9f4728..0000000000000
--- a/pkgs/development/compilers/llvm/17/llvm/default.nix
+++ /dev/null
@@ -1,431 +0,0 @@
-{ lib, stdenv, llvm_meta
-, pkgsBuildBuild
-, monorepoSrc
-, runCommand
-, cmake
-, darwin
-, ninja
-, python3
-, python3Packages
-, libffi
-, enableGoldPlugin ? libbfd.hasPluginAPI
-, libbfd
-, libpfm
-, libxml2
-, ncurses
-, version
-, release_version
-, zlib
-, which
-, sysctl
-, buildLlvmTools
-, debugVersion ? false
-, doCheck ? (!stdenv.isx86_32 /* TODO: why */) && (!stdenv.hostPlatform.isMusl)
-  && (stdenv.hostPlatform == stdenv.buildPlatform)
-, enableManpages ? false
-, enableSharedLibraries ? !stdenv.hostPlatform.isStatic
-, enablePFM ? stdenv.isLinux /* PFM only supports Linux */
-  # broken for Ampere eMAG 8180 (c2.large.arm on Packet) #56245
-  # broken for the armv7l builder
-  && !stdenv.hostPlatform.isAarch
-, enablePolly ? true
-}:
-
-let
-  inherit (lib) optional optionals optionalString;
-
-  # Used when creating a version-suffixed symlink of libLLVM.dylib
-  shortVersion = with lib;
-    concatStringsSep "." (take 1 (splitString "." release_version));
-
-  # Ordinarily we would just the `doCheck` and `checkDeps` functionality
-  # `mkDerivation` gives us to manage our test dependencies (instead of breaking
-  # out `doCheck` as a package level attribute).
-  #
-  # Unfortunately `lit` does not forward `$PYTHONPATH` to children processes, in
-  # particular the children it uses to do feature detection.
-  #
-  # This means that python deps we add to `checkDeps` (which the python
-  # interpreter is made aware of via `$PYTHONPATH` – populated by the python
-  # setup hook) are not picked up by `lit` which causes it to skip tests.
-  #
-  # Adding `python3.withPackages (ps: [ ... ])` to `checkDeps` also doesn't work
-  # because this package is shadowed in `$PATH` by the regular `python3`
-  # package.
-  #
-  # So, we "manually" assemble one python derivation for the package to depend
-  # on, taking into account whether checks are enabled or not:
-  python = if doCheck then
-    # Note that we _explicitly_ ask for a python interpreter for our host
-    # platform here; the splicing that would ordinarily take care of this for
-    # us does not seem to work once we use `withPackages`.
-    let
-      checkDeps = ps: with ps; [ psutil ];
-    in pkgsBuildBuild.targetPackages.python3.withPackages checkDeps
-  else python3;
-
-in
-
-stdenv.mkDerivation (rec {
-  pname = "llvm";
-  inherit version;
-
-  src = runCommand "${pname}-src-${version}" {} (''
-    mkdir -p "$out"
-    cp -r ${monorepoSrc}/cmake "$out"
-    cp -r ${monorepoSrc}/${pname} "$out"
-    cp -r ${monorepoSrc}/third-party "$out"
-  '' + lib.optionalString enablePolly ''
-    chmod u+w "$out/${pname}/tools"
-    cp -r ${monorepoSrc}/polly "$out/${pname}/tools"
-  '');
-
-  sourceRoot = "${src.name}/${pname}";
-
-  outputs = [ "out" "lib" "dev" "python" ];
-
-  nativeBuildInputs = [ cmake ninja python ]
-    ++ optionals enableManpages [
-      # Note: we intentionally use `python3Packages` instead of `python3.pkgs`;
-      # splicing does *not* work with the latter. (TODO: fix)
-      python3Packages.sphinx python3Packages.recommonmark
-    ];
-
-  buildInputs = [ libxml2 libffi ]
-    ++ optional enablePFM libpfm; # exegesis
-
-  propagatedBuildInputs = [ ncurses zlib ];
-
-  nativeCheckInputs = [
-    which
-  ] ++ lib.optional stdenv.isDarwin sysctl;
-
-  patches = [
-    ./gnu-install-dirs.patch
-
-    # Running the tests involves invoking binaries (like `opt`) that depend on
-    # the LLVM dylibs and reference them by absolute install path (i.e. their
-    # nix store path).
-    #
-    # Because we have not yet run the install phase (we're running these tests
-    # as part of `checkPhase` instead of `installCheckPhase`) these absolute
-    # paths do not exist yet; to work around this we point the loader (`ld` on
-    # unix, `dyld` on macOS) at the `lib` directory which will later become this
-    # package's `lib` output.
-    #
-    # Previously we would just set `LD_LIBRARY_PATH` to include the build `lib`
-    # dir but:
-    #   - this doesn't generalize well to other platforms; `lit` doesn't forward
-    #     `DYLD_LIBRARY_PATH` (macOS):
-    #     + https://github.com/llvm/llvm-project/blob/0d89963df354ee309c15f67dc47c8ab3cb5d0fb2/llvm/utils/lit/lit/TestingConfig.py#L26
-    #   - even if `lit` forwarded this env var, we actually cannot set
-    #     `DYLD_LIBRARY_PATH` in the child processes `lit` launches because
-    #     `DYLD_LIBRARY_PATH` (and `DYLD_FALLBACK_LIBRARY_PATH`) is cleared for
-    #     "protected processes" (i.e. the python interpreter that runs `lit`):
-    #     https://stackoverflow.com/a/35570229
-    #   - other LLVM subprojects deal with this issue by having their `lit`
-    #     configuration set these env vars for us; it makes sense to do the same
-    #     for LLVM:
-    #     + https://github.com/llvm/llvm-project/blob/4c106cfdf7cf7eec861ad3983a3dd9a9e8f3a8ae/clang-tools-extra/test/Unit/lit.cfg.py#L22-L31
-    #
-    # !!! TODO: look into upstreaming this patch
-    ./llvm-lit-cfg-add-libs-to-dylib-path.patch
-
-    # `lit` has a mode where it executes run lines as a shell script which is
-    # constructs; this is problematic for macOS because it means that there's
-    # another process in between `lit` and the binaries being tested. As noted
-    # above, this means that `DYLD_LIBRARY_PATH` is cleared which means that our
-    # tests fail with dyld errors.
-    #
-    # To get around this we patch `lit` to reintroduce `DYLD_LIBRARY_PATH`, when
-    # present in the test configuration.
-    #
-    # It's not clear to me why this isn't an issue for LLVM developers running
-    # on macOS (nothing about this _seems_ nix specific)..
-    ./lit-shell-script-runner-set-dyld-library-path.patch
-  ] ++ lib.optionals enablePolly [
-    ./gnu-install-dirs-polly.patch
-
-    # Just like the `llvm-lit-cfg` patch, but for `polly`.
-    ./polly-lit-cfg-add-libs-to-dylib-path.patch
-  ];
-
-  postPatch = optionalString stdenv.isDarwin ''
-    substituteInPlace cmake/modules/AddLLVM.cmake \
-      --replace 'set(_install_name_dir INSTALL_NAME_DIR "@rpath")' "set(_install_name_dir)" \
-      --replace 'set(_install_rpath "@loader_path/../''${CMAKE_INSTALL_LIBDIR}''${LLVM_LIBDIR_SUFFIX}" ''${extra_libdir})' ""
-
-    # As of LLVM 15, marked as XFAIL on arm64 macOS but lit doesn't seem to pick
-    # this up: https://github.com/llvm/llvm-project/blob/c344d97a125b18f8fed0a64aace73c49a870e079/llvm/test/MC/ELF/cfi-version.ll#L7
-    rm test/MC/ELF/cfi-version.ll
-
-    # This test tries to call `sw_vers` by absolute path (`/usr/bin/sw_vers`)
-    # and thus fails under the sandbox:
-    substituteInPlace unittests/TargetParser/Host.cpp \
-      --replace '/usr/bin/sw_vers' "${(builtins.toString darwin.DarwinTools) + "/bin/sw_vers" }"
-
-    # This test tries to call the intrinsics `@llvm.roundeven.f32` and
-    # `@llvm.roundeven.f64` which seem to (incorrectly?) lower to `roundevenf`
-    # and `roundeven` on macOS.
-    #
-    # However these functions are glibc specific so the test fails:
-    #   - https://www.gnu.org/software/gnulib/manual/html_node/roundevenf.html
-    #   - https://www.gnu.org/software/gnulib/manual/html_node/roundeven.html
-    #
-    substituteInPlace test/ExecutionEngine/Interpreter/intrinsics.ll \
-      --replace "%roundeven32 = call float @llvm.roundeven.f32(float 0.000000e+00)" "" \
-      --replace "%roundeven64 = call double @llvm.roundeven.f64(double 0.000000e+00)" ""
-  '' + optionalString (stdenv.isDarwin && stdenv.hostPlatform.isx86) ''
-    # This test fails on darwin x86_64 because `sw_vers` reports a different
-    # macOS version than what LLVM finds by reading
-    # `/System/Library/CoreServices/SystemVersion.plist` (which is passed into
-    # the sandbox on macOS).
-    #
-    # The `sw_vers` provided by nixpkgs reports the macOS version associated
-    # with the `CoreFoundation` framework with which it was built. Because
-    # nixpkgs pins the SDK for `aarch64-darwin` and `x86_64-darwin` what
-    # `sw_vers` reports is not guaranteed to match the macOS version of the host
-    # that's building this derivation.
-    #
-    # Astute readers will note that we only _patch_ this test on aarch64-darwin
-    # (to use the nixpkgs provided `sw_vers`) instead of disabling it outright.
-    # So why does this test pass on aarch64?
-    #
-    # Well, it seems that `sw_vers` on aarch64 actually links against the _host_
-    # CoreFoundation framework instead of the nixpkgs provided one.
-    #
-    # Not entirely sure what the right fix is here. I'm assuming aarch64
-    # `sw_vers` doesn't intentionally link against the host `CoreFoundation`
-    # (still digging into how this ends up happening, will follow up) but that
-    # aside I think the more pertinent question is: should we be patching LLVM's
-    # macOS version detection logic to use `sw_vers` instead of reading host
-    # paths? This *is* a way in which details about builder machines can creep
-    # into the artifacts that are produced, affecting reproducibility, but it's
-    # not clear to me when/where/for what this even gets used in LLVM.
-    #
-    # TODO(@rrbutani): fix/follow-up
-    substituteInPlace unittests/TargetParser/Host.cpp \
-      --replace "getMacOSHostVersion" "DISABLED_getMacOSHostVersion"
-
-    # This test fails with a `dysmutil` crash; have not yet dug into what's
-    # going on here (TODO(@rrbutani)).
-    rm test/tools/dsymutil/ARM/obfuscated.test
-  '' + ''
-    # FileSystem permissions tests fail with various special bits
-    substituteInPlace unittests/Support/CMakeLists.txt \
-      --replace "Path.cpp" ""
-    rm unittests/Support/Path.cpp
-    substituteInPlace unittests/IR/CMakeLists.txt \
-      --replace "PassBuilderCallbacksTest.cpp" ""
-    rm unittests/IR/PassBuilderCallbacksTest.cpp
-    rm test/tools/llvm-objcopy/ELF/mirror-permissions-unix.test
-
-    # Fails in the presence of anti-virus software or other intrusion-detection software that
-    # modifies the atime when run. See #284056.
-    rm test/tools/llvm-objcopy/ELF/strip-preserve-atime.test
-  '' + optionalString stdenv.hostPlatform.isMusl ''
-    patch -p1 -i ${../../common/llvm/TLI-musl.patch}
-    substituteInPlace unittests/Support/CMakeLists.txt \
-      --replace "add_subdirectory(DynamicLibrary)" ""
-    rm unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp
-    # valgrind unhappy with musl or glibc, but fails w/musl only
-    rm test/CodeGen/AArch64/wineh4.mir
-  '' + optionalString stdenv.hostPlatform.isAarch32 ''
-    # skip failing X86 test cases on 32-bit ARM
-    rm test/DebugInfo/X86/convert-debugloc.ll
-    rm test/DebugInfo/X86/convert-inlined.ll
-    rm test/DebugInfo/X86/convert-linked.ll
-    rm test/tools/dsymutil/X86/op-convert.test
-    rm test/tools/gold/X86/split-dwarf.ll
-    rm test/tools/llvm-dwarfdump/X86/prettyprint_types.s
-    rm test/tools/llvm-dwarfdump/X86/simplified-template-names.s
-    rm test/CodeGen/RISCV/attributes.ll
-    rm test/CodeGen/RISCV/xtheadmempair.ll
-  '' + optionalString (stdenv.hostPlatform.system == "armv6l-linux") ''
-    # Seems to require certain floating point hardware (NEON?)
-    rm test/ExecutionEngine/frem.ll
-  '' + ''
-    patchShebangs test/BugPoint/compile-custom.ll.py
-  '';
-
-  preConfigure = ''
-    # Workaround for configure flags that need to have spaces
-    cmakeFlagsArray+=(
-      -DLLVM_LIT_ARGS="-svj''${NIX_BUILD_CORES} --no-progress-bar"
-    )
-  '';
-
-  # Defensive check: some paths (that we make symlinks to) depend on the release
-  # version, for example:
-  #  - https://github.com/llvm/llvm-project/blob/406bde9a15136254f2b10d9ef3a42033b3cb1b16/clang/lib/Headers/CMakeLists.txt#L185
-  #
-  # So we want to sure that the version in the source matches the release
-  # version we were given.
-  #
-  # We do this check here, in the LLVM build, because it happens early.
-  postConfigure = let
-    v = lib.versions;
-    major = v.major release_version;
-    minor = v.minor release_version;
-    patch = v.patch release_version;
-  in ''
-    # $1: part, $2: expected
-    check_version() {
-      part="''${1^^}"
-      part="$(cat include/llvm/Config/llvm-config.h  | grep "#define LLVM_VERSION_''${part} " | cut -d' ' -f3)"
-
-      if [[ "$part" != "$2" ]]; then
-        echo >&2 \
-          "mismatch in the $1 version! we have version ${release_version}" \
-          "and expected the $1 version to be '$2'; the source has '$part' instead"
-        exit 3
-      fi
-    }
-
-    check_version major ${major}
-    check_version minor ${minor}
-    check_version patch ${patch}
-  '';
-
-  # E.g. mesa.drivers use the build-id as a cache key (see #93946):
-  LDFLAGS = optionalString (enableSharedLibraries && !stdenv.isDarwin) "-Wl,--build-id=sha1";
-
-  cmakeBuildType = if debugVersion then "Debug" else "Release";
-
-  cmakeFlags = with stdenv; let
-    # These flags influence llvm-config's BuildVariables.inc in addition to the
-    # general build. We need to make sure these are also passed via
-    # CROSS_TOOLCHAIN_FLAGS_NATIVE when cross-compiling or llvm-config-native
-    # will return different results from the cross llvm-config.
-    #
-    # Some flags don't need to be repassed because LLVM already does so (like
-    # CMAKE_BUILD_TYPE), others are irrelevant to the result.
-    flagsForLlvmConfig = [
-      "-DLLVM_INSTALL_PACKAGE_DIR=${placeholder "dev"}/lib/cmake/llvm"
-      "-DLLVM_ENABLE_RTTI=ON"
-    ] ++ optionals enableSharedLibraries [
-      "-DLLVM_LINK_LLVM_DYLIB=ON"
-    ];
-  in flagsForLlvmConfig ++ [
-    "-DLLVM_INSTALL_UTILS=ON"  # Needed by rustc
-    "-DLLVM_BUILD_TESTS=${if doCheck then "ON" else "OFF"}"
-    "-DLLVM_ENABLE_FFI=ON"
-    "-DLLVM_HOST_TRIPLE=${stdenv.hostPlatform.config}"
-    "-DLLVM_DEFAULT_TARGET_TRIPLE=${stdenv.hostPlatform.config}"
-    "-DLLVM_ENABLE_DUMP=ON"
-  ] ++ optionals stdenv.hostPlatform.isStatic [
-    # Disables building of shared libs, -fPIC is still injected by cc-wrapper
-    "-DLLVM_ENABLE_PIC=OFF"
-    "-DLLVM_BUILD_STATIC=ON"
-    "-DLLVM_LINK_LLVM_DYLIB=off"
-    # libxml2 needs to be disabled because the LLVM build system ignores its .la
-    # file and doesn't link zlib as well.
-    # https://github.com/ClangBuiltLinux/tc-build/issues/150#issuecomment-845418812
-    "-DLLVM_ENABLE_LIBXML2=OFF"
-  ] ++ optionals enableManpages [
-    "-DLLVM_BUILD_DOCS=ON"
-    "-DLLVM_ENABLE_SPHINX=ON"
-    "-DSPHINX_OUTPUT_MAN=ON"
-    "-DSPHINX_OUTPUT_HTML=OFF"
-    "-DSPHINX_WARNINGS_AS_ERRORS=OFF"
-  ] ++ optionals enableGoldPlugin [
-    # For LLVMgold plugin
-    "-DLLVM_BINUTILS_INCDIR=${libbfd.dev}/include"
-  ] ++ optionals isDarwin [
-    "-DLLVM_ENABLE_LIBCXX=ON"
-    "-DCAN_TARGET_i386=false"
-  ] ++ optionals ((stdenv.hostPlatform != stdenv.buildPlatform) && !(stdenv.buildPlatform.canExecute stdenv.hostPlatform)) [
-    "-DCMAKE_CROSSCOMPILING=True"
-    "-DLLVM_TABLEGEN=${buildLlvmTools.llvm}/bin/llvm-tblgen"
-    (
-      let
-        nativeCC = pkgsBuildBuild.targetPackages.stdenv.cc;
-        nativeBintools = nativeCC.bintools.bintools;
-        nativeToolchainFlags = [
-          "-DCMAKE_C_COMPILER=${nativeCC}/bin/${nativeCC.targetPrefix}cc"
-          "-DCMAKE_CXX_COMPILER=${nativeCC}/bin/${nativeCC.targetPrefix}c++"
-          "-DCMAKE_AR=${nativeBintools}/bin/${nativeBintools.targetPrefix}ar"
-          "-DCMAKE_STRIP=${nativeBintools}/bin/${nativeBintools.targetPrefix}strip"
-          "-DCMAKE_RANLIB=${nativeBintools}/bin/${nativeBintools.targetPrefix}ranlib"
-        ];
-        # We need to repass the custom GNUInstallDirs values, otherwise CMake
-        # will choose them for us, leading to wrong results in llvm-config-native
-        nativeInstallFlags = [
-          "-DCMAKE_INSTALL_PREFIX=${placeholder "out"}"
-          "-DCMAKE_INSTALL_BINDIR=${placeholder "out"}/bin"
-          "-DCMAKE_INSTALL_INCLUDEDIR=${placeholder "dev"}/include"
-          "-DCMAKE_INSTALL_LIBDIR=${placeholder "lib"}/lib"
-          "-DCMAKE_INSTALL_LIBEXECDIR=${placeholder "lib"}/libexec"
-        ];
-      in "-DCROSS_TOOLCHAIN_FLAGS_NATIVE:list="
-      + lib.concatStringsSep ";" (lib.concatLists [
-        flagsForLlvmConfig
-        nativeToolchainFlags
-        nativeInstallFlags
-      ])
-    )
-  ];
-
-  postInstall = ''
-    mkdir -p $python/share
-    mv $out/share/opt-viewer $python/share/opt-viewer
-    moveToOutput "bin/llvm-config*" "$dev"
-    substituteInPlace "$dev/lib/cmake/llvm/LLVMExports-${if debugVersion then "debug" else "release"}.cmake" \
-      --replace "\''${_IMPORT_PREFIX}/lib/lib" "$lib/lib/lib" \
-      --replace "$out/bin/llvm-config" "$dev/bin/llvm-config"
-    substituteInPlace "$dev/lib/cmake/llvm/LLVMConfig.cmake" \
-      --replace 'set(LLVM_BINARY_DIR "''${LLVM_INSTALL_PREFIX}")' 'set(LLVM_BINARY_DIR "'"$lib"'")'
-  ''
-  + optionalString (stdenv.isDarwin && enableSharedLibraries) ''
-    ln -s $lib/lib/libLLVM.dylib $lib/lib/libLLVM-${shortVersion}.dylib
-    ln -s $lib/lib/libLLVM.dylib $lib/lib/libLLVM-${release_version}.dylib
-  ''
-  + optionalString (stdenv.buildPlatform != stdenv.hostPlatform) ''
-    cp NATIVE/bin/llvm-config $dev/bin/llvm-config-native
-  '';
-
-  inherit doCheck;
-
-  checkTarget = "check-all";
-
-  # For the update script:
-  passthru.monorepoSrc = monorepoSrc;
-
-  requiredSystemFeatures = [ "big-parallel" ];
-  meta = llvm_meta // {
-    homepage = "https://llvm.org/";
-    description = "A collection of modular and reusable compiler and toolchain technologies";
-    longDescription = ''
-      The LLVM Project is a collection of modular and reusable compiler and
-      toolchain technologies. Despite its name, LLVM has little to do with
-      traditional virtual machines. The name "LLVM" itself is not an acronym; it
-      is the full name of the project.
-      LLVM began as a research project at the University of Illinois, with the
-      goal of providing a modern, SSA-based compilation strategy capable of
-      supporting both static and dynamic compilation of arbitrary programming
-      languages. Since then, LLVM has grown to be an umbrella project consisting
-      of a number of subprojects, many of which are being used in production by
-      a wide variety of commercial and open source projects as well as being
-      widely used in academic research. Code in the LLVM project is licensed
-      under the "Apache 2.0 License with LLVM exceptions".
-    '';
-  };
-} // lib.optionalAttrs enableManpages {
-  pname = "llvm-manpages";
-
-  propagatedBuildInputs = [];
-
-  ninjaFlags = [ "docs-llvm-man" ];
-  installTargets = [ "install-docs-llvm-man" ];
-
-  postPatch = null;
-  postInstall = null;
-
-  outputs = [ "out" ];
-
-  doCheck = false;
-
-  meta = llvm_meta // {
-    description = "man pages for LLVM ${version}";
-  };
-})
diff --git a/pkgs/development/compilers/llvm/18/default.nix b/pkgs/development/compilers/llvm/18/default.nix
index 3c78cd44fdf58..878f1e3a8e7e4 100644
--- a/pkgs/development/compilers/llvm/18/default.nix
+++ b/pkgs/development/compilers/llvm/18/default.nix
@@ -1,6 +1,7 @@
-{ lowPrio, newScope, pkgs, lib, stdenv, cmake, ninja
+{ lowPrio, newScope, pkgs, lib, stdenv
 , preLibcCrossHeaders
-, libxml2, python3, fetchFromGitHub, substituteAll, overrideCC, wrapCCWith, wrapBintoolsWith
+, substitute, substituteAll, fetchFromGitHub
+, overrideCC, wrapCCWith, wrapBintoolsWith
 , buildLlvmTools # tools, but from the previous stage, for cross
 , targetLlvmLibraries # libraries, but from the next stage, for cross
 , targetLlvm
@@ -25,7 +26,7 @@
   #   rev-version = /* human readable version; i.e. "unstable-2022-26-07" */;
   #   sha256 = /* checksum for this release, can omit if specifying your own `monorepoSrc` */;
   # }
-, officialRelease ? { version = "18.1.4"; sha256 = "sha256-LyQEb4ZJXm2hkPOM9XITIploMT2VKIQWxUFio7SXrc0="; }
+, officialRelease ? { version = "18.1.7"; sha256 = "sha256-qBL/1zh2YFabiPAyHehvzDSDfnwnCvyH6nY/pzG757A="; }
   # i.e.:
   # {
   #   version = /* i.e. "15.0.0" */;
@@ -39,7 +40,11 @@
 # to you to make sure that the LLVM repo given matches the release configuration
 # specified.
 , monorepoSrc ? null
-}:
+# Allows passthrough to packages via newScope. This makes it possible to
+# do `(llvmPackages.override { <someLlvmDependency> = bar; }).clang` and get
+# an llvmPackages whose packages are overridden in an internally consistent way.
+, ...
+}@args:
 
 assert
   lib.assertMsg
@@ -51,15 +56,17 @@ assert
 let
   monorepoSrc' = monorepoSrc;
 in let
-  inherit (import ../common/common-let.nix { inherit lib gitRelease officialRelease; }) releaseInfo;
 
-  inherit (releaseInfo) release_version version;
-
-  inherit (import ../common/common-let.nix { inherit lib fetchFromGitHub release_version gitRelease officialRelease monorepoSrc'; }) llvm_meta monorepoSrc;
+  metadata = rec {
+    # Import releaseInfo separately to avoid infinite recursion
+    inherit (import ../common/common-let.nix { inherit lib gitRelease officialRelease; }) releaseInfo;
+    inherit (releaseInfo) release_version version;
+    inherit (import ../common/common-let.nix { inherit lib fetchFromGitHub gitRelease release_version officialRelease monorepoSrc'; }) llvm_meta monorepoSrc;
+  };
 
   tools = lib.makeExtensible (tools: let
-    callPackage = newScope (tools // { inherit stdenv cmake ninja libxml2 python3 release_version version monorepoSrc buildLlvmTools; });
-    major = lib.versions.major release_version;
+    callPackage = newScope (tools // args // metadata);
+    major = lib.versions.major metadata.release_version;
     mkExtraBuildCommands0 = cc: ''
       rsrc="$out/resource-root"
       mkdir "$rsrc"
@@ -82,8 +89,57 @@ in let
 
   in {
 
-    libllvm = callPackage ./llvm {
-      inherit llvm_meta;
+    libllvm = callPackage ../common/llvm {
+      patches = [
+        ./llvm/gnu-install-dirs.patch
+
+        # Running the tests involves invoking binaries (like `opt`) that depend on
+        # the LLVM dylibs and reference them by absolute install path (i.e. their
+        # nix store path).
+        #
+        # Because we have not yet run the install phase (we're running these tests
+        # as part of `checkPhase` instead of `installCheckPhase`) these absolute
+        # paths do not exist yet; to work around this we point the loader (`ld` on
+        # unix, `dyld` on macOS) at the `lib` directory which will later become this
+        # package's `lib` output.
+        #
+        # Previously we would just set `LD_LIBRARY_PATH` to include the build `lib`
+        # dir but:
+        #   - this doesn't generalize well to other platforms; `lit` doesn't forward
+        #     `DYLD_LIBRARY_PATH` (macOS):
+        #     + https://github.com/llvm/llvm-project/blob/0d89963df354ee309c15f67dc47c8ab3cb5d0fb2/llvm/utils/lit/lit/TestingConfig.py#L26
+        #   - even if `lit` forwarded this env var, we actually cannot set
+        #     `DYLD_LIBRARY_PATH` in the child processes `lit` launches because
+        #     `DYLD_LIBRARY_PATH` (and `DYLD_FALLBACK_LIBRARY_PATH`) is cleared for
+        #     "protected processes" (i.e. the python interpreter that runs `lit`):
+        #     https://stackoverflow.com/a/35570229
+        #   - other LLVM subprojects deal with this issue by having their `lit`
+        #     configuration set these env vars for us; it makes sense to do the same
+        #     for LLVM:
+        #     + https://github.com/llvm/llvm-project/blob/4c106cfdf7cf7eec861ad3983a3dd9a9e8f3a8ae/clang-tools-extra/test/Unit/lit.cfg.py#L22-L31
+        #
+        # !!! TODO: look into upstreaming this patch
+        ./llvm/llvm-lit-cfg-add-libs-to-dylib-path.patch
+
+        # `lit` has a mode where it executes run lines as a shell script which is
+        # constructs; this is problematic for macOS because it means that there's
+        # another process in between `lit` and the binaries being tested. As noted
+        # above, this means that `DYLD_LIBRARY_PATH` is cleared which means that our
+        # tests fail with dyld errors.
+        #
+        # To get around this we patch `lit` to reintroduce `DYLD_LIBRARY_PATH`, when
+        # present in the test configuration.
+        #
+        # It's not clear to me why this isn't an issue for LLVM developers running
+        # on macOS (nothing about this _seems_ nix specific)..
+        ./llvm/lit-shell-script-runner-set-dyld-library-path.patch
+      ];
+      pollyPatches = [
+        ./llvm/gnu-install-dirs-polly.patch
+
+        # Just like the `llvm-lit-cfg` patch, but for `polly`.
+        ./llvm/polly-lit-cfg-add-libs-to-dylib-path.patch
+      ];
     };
 
     # `llvm` historically had the binaries.  When choosing an output explicitly,
@@ -101,7 +157,6 @@ in let
           libllvmLibdir = "${tools.libllvm.lib}/lib";
         })
       ];
-      inherit llvm_meta;
     };
 
     clang-unwrapped = tools.libclang;
@@ -121,6 +176,9 @@ in let
       python3 = pkgs.python3;  # don't use python-boot
     });
 
+    # Wrapper for standalone command line utilities
+    clang-tools = callPackage ../common/clang-tools { };
+
     # pick clang appropriate for package set we are targeting
     clang =
       /**/ if stdenv.targetPlatform.useLLVM or false then tools.clangUseLLVM
@@ -150,15 +208,12 @@ in let
       patches = [
         ./lld/gnu-install-dirs.patch
       ];
-      inherit llvm_meta;
     };
 
-    mlir = callPackage ../common/mlir {
-      inherit llvm_meta;
-    };
+    mlir = callPackage ../common/mlir {};
 
     lldb = callPackage ../common/lldb.nix {
-      src = callPackage ({ runCommand }: runCommand "lldb-src-${version}" {} ''
+      src = callPackage ({ runCommand }: runCommand "lldb-src-${metadata.version}" {} ''
         mkdir -p "$out"
         cp -r ${monorepoSrc}/cmake "$out"
         cp -r ${monorepoSrc}/lldb "$out"
@@ -182,7 +237,6 @@ in let
             && !stdenv.targetPlatform.isAarch64
             && (lib.versionOlder darwin.apple_sdk.sdk.version "11.0")
         ) ./lldb/cpu_subtype_arm64e_replacement.patch;
-      inherit llvm_meta;
     };
 
     # Below, is the LLVM bootstrapping logic. It handles building a
@@ -285,13 +339,11 @@ in let
     # Has to be in tools despite mostly being a library,
     # because we use a native helper executable from a
     # non-cross build in cross builds.
-    libclc = callPackage ../common/libclc.nix {
-      inherit buildLlvmTools;
-    };
+    libclc = callPackage ../common/libclc.nix {};
   });
 
   libraries = lib.makeExtensible (libraries: let
-    callPackage = newScope (libraries // buildLlvmTools // { inherit stdenv cmake ninja libxml2 python3 release_version version monorepoSrc; });
+    callPackage = newScope (libraries // buildLlvmTools // args // metadata);
   in {
 
     compiler-rt-libc = callPackage ../common/compiler-rt {
@@ -305,7 +357,6 @@ in let
         # See: https://github.com/NixOS/nixpkgs/pull/194634#discussion_r999829893
         # ../common/compiler-rt/armv7l-15.patch
       ];
-      inherit llvm_meta;
       stdenv = if stdenv.hostPlatform.useLLVM or false || (stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isStatic)
                then overrideCC stdenv buildLlvmTools.clangNoCompilerRtWithLibc
                else stdenv;
@@ -322,7 +373,6 @@ in let
         # See: https://github.com/NixOS/nixpkgs/pull/194634#discussion_r999829893
         # ../common/compiler-rt/armv7l-15.patch
       ];
-      inherit llvm_meta;
       stdenv = if stdenv.hostPlatform.useLLVM or false
                then overrideCC stdenv buildLlvmTools.clangNoCompilerRt
                else stdenv;
@@ -345,12 +395,10 @@ in let
         # https://github.com/llvm/llvm-project/issues/64226
         ./libcxx/0001-darwin-10.12-mbstate_t-fix.patch
       ];
-      inherit llvm_meta;
       stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
     };
 
     libunwind = callPackage ../common/libunwind {
-      inherit llvm_meta;
       stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
     };
 
@@ -359,9 +407,8 @@ in let
         ./openmp/fix-find-tool.patch
         ./openmp/run-lit-directly.patch
       ];
-      inherit llvm_meta targetLlvm;
     };
   });
   noExtend = extensible: lib.attrsets.removeAttrs extensible [ "extend" ];
 
-in { inherit tools libraries release_version; } // (noExtend libraries) // (noExtend tools)
+in { inherit tools libraries; inherit (metadata) release_version; } // (noExtend libraries) // (noExtend tools)
diff --git a/pkgs/development/compilers/llvm/common/clang-tools/default.nix b/pkgs/development/compilers/llvm/common/clang-tools/default.nix
new file mode 100644
index 0000000000000..7ecf0c5c431de
--- /dev/null
+++ b/pkgs/development/compilers/llvm/common/clang-tools/default.nix
@@ -0,0 +1,59 @@
+{
+  lib,
+  stdenv,
+  clang-unwrapped,
+  clang,
+  libcxxClang,
+  llvm_meta,
+  # enableLibcxx will use the c++ headers from clang instead of gcc.
+  # This shouldn't have any effect on platforms that use clang as the default compiler already.
+  enableLibcxx ? false,
+}:
+
+stdenv.mkDerivation {
+  unwrapped = clang-unwrapped;
+
+  pname = "clang-tools";
+  version = lib.getVersion clang-unwrapped;
+  dontUnpack = true;
+  clang = if enableLibcxx then libcxxClang else clang;
+
+  installPhase = ''
+    runHook preInstall
+
+    mkdir -p $out/bin
+
+    for tool in $unwrapped/bin/clang-*; do
+      tool=$(basename "$tool")
+
+      # Compilers have their own derivation, no need to include them here:
+      if [[ $tool == "clang-cl" || $tool == "clang-cpp" ]]; then
+        continue
+      fi
+
+      # Clang's derivation produces a lot of binaries, but the tools we are
+      # interested in follow the `clang-something` naming convention - except
+      # for clang-$version (e.g. clang-13), which is the compiler again:
+      if [[ ! $tool =~ ^clang\-[a-zA-Z_\-]+$ ]]; then
+        continue
+      fi
+
+      ln -s $out/bin/clangd $out/bin/$tool
+    done
+
+    if [[ -z "$(ls -A $out/bin)" ]]; then
+      echo "Found no binaries - maybe their location or naming convention changed?"
+      exit 1
+    fi
+
+    substituteAll ${./wrapper} $out/bin/clangd
+    chmod +x $out/bin/clangd
+
+    runHook postInstall
+  '';
+
+  meta = llvm_meta // {
+    description = "Standalone command line tools for C++ development";
+    maintainers = with lib.maintainers; [ patryk27 ];
+  };
+}
diff --git a/pkgs/development/compilers/llvm/common/clang-tools/wrapper b/pkgs/development/compilers/llvm/common/clang-tools/wrapper
new file mode 100755
index 0000000000000..1008023fdc0d1
--- /dev/null
+++ b/pkgs/development/compilers/llvm/common/clang-tools/wrapper
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+buildcpath() {
+  local path after
+  while (( $# )); do
+    case $1 in
+        -isystem)
+            shift
+            path=$path${path:+':'}$1
+            ;;
+        -idirafter)
+            shift
+            after=$after${after:+':'}$1
+            ;;
+    esac
+    shift
+  done
+  echo $path${after:+':'}$after
+}
+
+export CPATH=${CPATH}${CPATH:+':'}$(buildcpath ${NIX_CFLAGS_COMPILE} \
+                                               $(<@clang@/nix-support/libc-cflags)):@clang@/resource-root/include
+export CPLUS_INCLUDE_PATH=${CPLUS_INCLUDE_PATH}${CPLUS_INCLUDE_PATH:+':'}$(buildcpath ${NIX_CFLAGS_COMPILE} \
+                                                                                      $(<@clang@/nix-support/libcxx-cxxflags) \
+                                                                                      $(<@clang@/nix-support/libc-cflags)):@clang@/resource-root/include
+
+exec -a "$0" @unwrapped@/bin/$(basename $0) "$@"
diff --git a/pkgs/development/compilers/llvm/common/clang/clang-6-10-LLVMgold-path.patch b/pkgs/development/compilers/llvm/common/clang/clang-6-10-LLVMgold-path.patch
deleted file mode 100644
index 93504316edf30..0000000000000
--- a/pkgs/development/compilers/llvm/common/clang/clang-6-10-LLVMgold-path.patch
+++ /dev/null
@@ -1,15 +0,0 @@
-diff --git a/lib/Driver/ToolChains/CommonArgs.cpp b/lib/Driver/ToolChains/CommonArgs.cpp
-index 37ec73468570..b73e75aa6e59 100644
---- a/lib/Driver/ToolChains/CommonArgs.cpp
-+++ b/lib/Driver/ToolChains/CommonArgs.cpp
-@@ -370,8 +370,8 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args,
- #endif
- 
-   SmallString<1024> Plugin;
--  llvm::sys::path::native(Twine(ToolChain.getDriver().Dir) +
--                              "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold" +
-+  llvm::sys::path::native(Twine("@libllvmLibdir@"
-+                                "/LLVMgold") +
-                               Suffix,
-                           Plugin);
-   CmdArgs.push_back(Args.MakeArgString(Plugin));
diff --git a/pkgs/development/compilers/llvm/common/clang/default.nix b/pkgs/development/compilers/llvm/common/clang/default.nix
index 2373795b49fd8..dc175e085f0b6 100644
--- a/pkgs/development/compilers/llvm/common/clang/default.nix
+++ b/pkgs/development/compilers/llvm/common/clang/default.nix
@@ -71,7 +71,11 @@ let
       "-DCLANG_PSEUDO_GEN=${buildLlvmTools.libclang.dev}/bin/clang-pseudo-gen"
     ]);
 
-    postPatch = (if lib.versionOlder release_version "13" then ''
+    postPatch = ''
+      # Make sure clang passes the correct location of libLTO to ld64
+      substituteInPlace lib/Driver/ToolChains/Darwin.cpp \
+        --replace-fail 'StringRef P = llvm::sys::path::parent_path(D.Dir);' 'StringRef P = "${lib.getLib libllvm}";'
+    '' + (if lib.versionOlder release_version "13" then ''
       sed -i -e 's/DriverArgs.hasArg(options::OPT_nostdlibinc)/true/' \
              -e 's/Args.hasArg(options::OPT_nostdlibinc)/true/' \
              lib/Driver/ToolChains/*.cpp
@@ -89,6 +93,8 @@ let
 
       mkdir -p $lib/lib/clang
       mv $lib/lib/17 $lib/lib/clang/17
+    '') + (lib.optionalString (lib.versionAtLeast release_version "19") ''
+      mv $out/lib/clang $lib/lib/clang
     '') + ''
 
       # Move libclang to 'lib' output
@@ -143,7 +149,7 @@ let
 
     meta = llvm_meta // {
       homepage = "https://clang.llvm.org/";
-      description = "A C language family frontend for LLVM";
+      description = "C language family frontend for LLVM";
       longDescription = ''
         The Clang project provides a language front-end and tooling
         infrastructure for languages in the C language family (C, C++, Objective
@@ -192,7 +198,7 @@ let
       '';
     })
   // (lib.optionalAttrs (lib.versionAtLeast release_version "15") {
-    env = lib.optionalAttrs (stdenv.buildPlatform != stdenv.hostPlatform) {
+    env = lib.optionalAttrs (stdenv.buildPlatform != stdenv.hostPlatform && !stdenv.hostPlatform.useLLVM) {
       # The following warning is triggered with (at least) gcc >=
       # 12, but appears to occur only for cross compiles.
       NIX_CFLAGS_COMPILE = "-Wno-maybe-uninitialized";
diff --git a/pkgs/development/compilers/llvm/common/compiler-rt/default.nix b/pkgs/development/compilers/llvm/common/compiler-rt/default.nix
index 4f44d6396d301..23a966ce238f6 100644
--- a/pkgs/development/compilers/llvm/common/compiler-rt/default.nix
+++ b/pkgs/development/compilers/llvm/common/compiler-rt/default.nix
@@ -14,7 +14,18 @@
 , libllvm
 , linuxHeaders
 , libxcrypt
+
+# Some platforms have switched to using compiler-rt, but still want a
+# libgcc.a for ABI compat purposes. The use case would be old code that
+# expects to link `-lgcc` but doesn't care exactly what its contents
+# are, so long as it provides some builtins.
 , doFakeLibgcc ? stdenv.hostPlatform.isFreeBSD
+
+# In recent releases, the compiler-rt build seems to produce
+# many `libclang_rt*` libraries, but not a single unified
+# `libcompiler_rt` library, at least under certain configurations. Some
+# platforms stil expect this, however, so we symlink one into place.
+, forceLinkCompilerRt ? stdenv.hostPlatform.isOpenBSD
 }:
 
 let
@@ -128,11 +139,17 @@ stdenv.mkDerivation ({
   '') + ''
     substituteInPlace lib/builtins/int_util.c \
       --replace "#include <stdlib.h>" ""
+  '' + (if stdenv.hostPlatform.isFreeBSD then
+    # As per above, but in FreeBSD assert is a macro and simply allowing it to be implicitly declared causes Issues!!!!!
+    ''
+    substituteInPlace lib/builtins/clear_cache.c lib/builtins/cpu_model.c \
+      --replace "#include <assert.h>" "#define assert(e) ((e)?(void)0:__assert(__FUNCTION__,__FILE__,__LINE__,#e))"
+    '' else ''
     substituteInPlace lib/builtins/clear_cache.c \
       --replace "#include <assert.h>" ""
     substituteInPlace lib/builtins/cpu_model${lib.optionalString (lib.versionAtLeast version "18") "/x86"}.c \
       --replace "#include <assert.h>" ""
-  '');
+  ''));
 
   # Hack around weird upsream RPATH bug
   postInstall = lib.optionalString (stdenv.hostPlatform.isDarwin) ''
@@ -149,7 +166,9 @@ stdenv.mkDerivation ({
     ln -s $out/lib/*/clang_rt.crtbegin_shared-*.o $out/lib/crtbeginS.o
     ln -s $out/lib/*/clang_rt.crtend_shared-*.o $out/lib/crtendS.o
   '' + lib.optionalString doFakeLibgcc ''
-     ln -s $out/lib/freebsd/libclang_rt.builtins-*.a $out/lib/libgcc.a
+     ln -s $out/lib/*/libclang_rt.builtins-*.a $out/lib/libgcc.a
+  '' + lib.optionalString forceLinkCompilerRt ''
+     ln -s $out/lib/*/libclang_rt.builtins-*.a $out/lib/libcompiler_rt.a
   '';
 
   meta = llvm_meta // {
diff --git a/pkgs/development/compilers/llvm/common/compiler-rt/libsanitizer-no-cyclades-11.patch b/pkgs/development/compilers/llvm/common/compiler-rt/libsanitizer-no-cyclades-11.patch
deleted file mode 100644
index 890230cc14ee9..0000000000000
--- a/pkgs/development/compilers/llvm/common/compiler-rt/libsanitizer-no-cyclades-11.patch
+++ /dev/null
@@ -1,80 +0,0 @@
-https://github.com/llvm/llvm-project/commit/68d5235cb58f988c71b403334cd9482d663841ab.patch
-https://reviews.llvm.org/D102059
---- a/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
-+++ b/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
-@@ -370,15 +370,6 @@ static void ioctl_table_fill() {
- 
- #if SANITIZER_GLIBC
-   // _(SIOCDEVPLIP, WRITE, struct_ifreq_sz); // the same as EQL_ENSLAVE
--  _(CYGETDEFTHRESH, WRITE, sizeof(int));
--  _(CYGETDEFTIMEOUT, WRITE, sizeof(int));
--  _(CYGETMON, WRITE, struct_cyclades_monitor_sz);
--  _(CYGETTHRESH, WRITE, sizeof(int));
--  _(CYGETTIMEOUT, WRITE, sizeof(int));
--  _(CYSETDEFTHRESH, NONE, 0);
--  _(CYSETDEFTIMEOUT, NONE, 0);
--  _(CYSETTHRESH, NONE, 0);
--  _(CYSETTIMEOUT, NONE, 0);
-   _(EQL_EMANCIPATE, WRITE, struct_ifreq_sz);
-   _(EQL_ENSLAVE, WRITE, struct_ifreq_sz);
-   _(EQL_GETMASTRCFG, WRITE, struct_ifreq_sz);
---- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp
-+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp
-@@ -143,7 +143,6 @@ typedef struct user_fpregs elf_fpregset_t;
- # include <sys/procfs.h>
- #endif
- #include <sys/user.h>
--#include <linux/cyclades.h>
- #include <linux/if_eql.h>
- #include <linux/if_plip.h>
- #include <linux/lp.h>
-@@ -460,7 +459,6 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
- 
- #if SANITIZER_GLIBC
-   unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct);
--  unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor);
- #if EV_VERSION > (0x010000)
-   unsigned struct_input_keymap_entry_sz = sizeof(struct input_keymap_entry);
- #else
-@@ -824,15 +822,6 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
- #endif // SANITIZER_LINUX
- 
- #if SANITIZER_LINUX && !SANITIZER_ANDROID
--  unsigned IOCTL_CYGETDEFTHRESH = CYGETDEFTHRESH;
--  unsigned IOCTL_CYGETDEFTIMEOUT = CYGETDEFTIMEOUT;
--  unsigned IOCTL_CYGETMON = CYGETMON;
--  unsigned IOCTL_CYGETTHRESH = CYGETTHRESH;
--  unsigned IOCTL_CYGETTIMEOUT = CYGETTIMEOUT;
--  unsigned IOCTL_CYSETDEFTHRESH = CYSETDEFTHRESH;
--  unsigned IOCTL_CYSETDEFTIMEOUT = CYSETDEFTIMEOUT;
--  unsigned IOCTL_CYSETTHRESH = CYSETTHRESH;
--  unsigned IOCTL_CYSETTIMEOUT = CYSETTIMEOUT;
-   unsigned IOCTL_EQL_EMANCIPATE = EQL_EMANCIPATE;
-   unsigned IOCTL_EQL_ENSLAVE = EQL_ENSLAVE;
-   unsigned IOCTL_EQL_GETMASTRCFG = EQL_GETMASTRCFG;
---- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h
-+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
-@@ -983,7 +983,6 @@ extern unsigned struct_vt_mode_sz;
- 
- #if SANITIZER_LINUX && !SANITIZER_ANDROID
- extern unsigned struct_ax25_parms_struct_sz;
--extern unsigned struct_cyclades_monitor_sz;
- extern unsigned struct_input_keymap_entry_sz;
- extern unsigned struct_ipx_config_data_sz;
- extern unsigned struct_kbdiacrs_sz;
-@@ -1328,15 +1327,6 @@ extern unsigned IOCTL_VT_WAITACTIVE;
- #endif  // SANITIZER_LINUX
- 
- #if SANITIZER_LINUX && !SANITIZER_ANDROID
--extern unsigned IOCTL_CYGETDEFTHRESH;
--extern unsigned IOCTL_CYGETDEFTIMEOUT;
--extern unsigned IOCTL_CYGETMON;
--extern unsigned IOCTL_CYGETTHRESH;
--extern unsigned IOCTL_CYGETTIMEOUT;
--extern unsigned IOCTL_CYSETDEFTHRESH;
--extern unsigned IOCTL_CYSETDEFTIMEOUT;
--extern unsigned IOCTL_CYSETTHRESH;
--extern unsigned IOCTL_CYSETTIMEOUT;
- extern unsigned IOCTL_EQL_EMANCIPATE;
- extern unsigned IOCTL_EQL_ENSLAVE;
- extern unsigned IOCTL_EQL_GETMASTRCFG;
diff --git a/pkgs/development/compilers/llvm/common/libcxx/default.nix b/pkgs/development/compilers/llvm/common/libcxx/default.nix
index 0e91f50551c55..b2c23f35f0a18 100644
--- a/pkgs/development/compilers/llvm/common/libcxx/default.nix
+++ b/pkgs/development/compilers/llvm/common/libcxx/default.nix
@@ -13,12 +13,16 @@
 , python3
 , fixDarwinDylibNames
 , version
-, cxxabi ? if stdenv.hostPlatform.isFreeBSD then libcxxrt else null
+, cxxabi ? null
 , libcxxrt
 , libunwind
 , enableShared ? !stdenv.hostPlatform.isStatic
 }:
 
+# note: our setup using libcxxabi instead of libcxxrt on FreeBSD diverges from
+# normal FreeBSD. This may cause issues with binary patching down the line.
+# If this becomes an issue, try adding as symlink libcxxrt.so -> libc++abi.so
+
 # external cxxabi is not supported on Darwin as the build will not link libcxx
 # properly and not re-export the cxxabi symbols into libcxx
 # https://github.com/NixOS/nixpkgs/issues/166205
@@ -67,6 +71,12 @@ let
 
   cxxCMakeFlags = [
     "-DLIBCXX_CXX_ABI=${cxxabiName}"
+  ] ++ lib.optionals (cxxabi == null && lib.versionAtLeast release_version "16") [
+    # Note: llvm < 16 doesn't support this flag (or it's broken); handled in postInstall instead.
+    # Include libc++abi symbols within libc++.a for static linking libc++;
+    # dynamic linking includes them through libc++.so being a linker script
+    # which includes both shared objects.
+    "-DLIBCXX_STATICALLY_LINK_ABI_IN_STATIC_LIBRARY=ON"
   ] ++ lib.optionals (cxxabi != null) [
     "-DLIBCXX_CXX_ABI_INCLUDE_PATHS=${lib.getDev cxxabi}/include"
   ] ++ lib.optionals (stdenv.hostPlatform.isMusl || stdenv.hostPlatform.isWasi) [
@@ -87,12 +97,6 @@ let
 
   cmakeFlags = [
     "-DLLVM_ENABLE_RUNTIMES=${lib.concatStringsSep ";" runtimes}"
-  ] ++ lib.optionals (useLLVM && !stdenv.hostPlatform.isWasm) [
-    # libcxxabi's CMake looks as though it treats -nostdlib++ as implying -nostdlib,
-    # but that does not appear to be the case for example when building
-    # pkgsLLVM.libcxxabi (which uses clangNoCompilerRtWithLibc).
-    "-DCMAKE_EXE_LINKER_FLAGS=-nostdlib"
-    "-DCMAKE_SHARED_LINKER_FLAGS=-nostdlib"
   ] ++ lib.optionals stdenv.hostPlatform.isWasm [
     "-DCMAKE_C_COMPILER_WORKS=ON"
     "-DCMAKE_CXX_COMPILER_WORKS=ON"
@@ -126,6 +130,31 @@ stdenv.mkDerivation (rec {
   postInstall = lib.optionalString (cxxabi != null) ''
     lndir ${lib.getDev cxxabi}/include $dev/include/c++/v1
     lndir ${lib.getLib cxxabi}/lib $out/lib
+    libcxxabi=$out/lib/lib${cxxabi.libName}.a
+  ''
+  # LIBCXX_STATICALLY_LINK_ABI_IN_STATIC_LIBRARY=ON doesn't work for LLVM < 16 or
+  # external cxxabi libraries so merge libc++abi.a into libc++.a ourselves.
+
+  # GNU binutils emits objects in LIFO order in MRI scripts so after the merge
+  # the objects are in reversed order so a second MRI script is required so the
+  # objects in the archive are listed in proper order (libc++.a, libc++abi.a)
+  + lib.optionalString (cxxabi != null || lib.versionOlder release_version "16") ''
+    libcxxabi=''${libcxxabi-$out/lib/libc++abi.a}
+    if [[ -f $out/lib/libc++.a && -e $libcxxabi ]]; then
+      $AR -M <<MRI
+        create $out/lib/libc++.a
+        addlib $out/lib/libc++.a
+        addlib $libcxxabi
+        save
+        end
+    MRI
+      $AR -M <<MRI
+        create $out/lib/libc++.a
+        addlib $out/lib/libc++.a
+        save
+        end
+    MRI
+    fi
   '';
 
   passthru = {
diff --git a/pkgs/development/compilers/llvm/common/libcxxabi/no-threads.patch b/pkgs/development/compilers/llvm/common/libcxxabi/no-threads.patch
deleted file mode 100644
index 787f3e16500e2..0000000000000
--- a/pkgs/development/compilers/llvm/common/libcxxabi/no-threads.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff --git a/CMakeLists.txt b/CMakeLists.txt
-index 4138acf..41b4763 100644
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
-@@ -362,6 +362,7 @@ if (NOT LIBCXXABI_ENABLE_THREADS)
-                         " is also set to ON.")
-   endif()
-   add_definitions(-D_LIBCXXABI_HAS_NO_THREADS)
-+  add_definitions(-D_LIBCPP_HAS_NO_THREADS)
- endif()
- 
- if (LIBCXXABI_HAS_EXTERNAL_THREAD_API)
diff --git a/pkgs/development/compilers/llvm/common/lld/default.nix b/pkgs/development/compilers/llvm/common/lld/default.nix
index be296be91e770..99bb150a817dc 100644
--- a/pkgs/development/compilers/llvm/common/lld/default.nix
+++ b/pkgs/development/compilers/llvm/common/lld/default.nix
@@ -64,7 +64,7 @@ stdenv.mkDerivation (rec {
 
   meta = llvm_meta // {
     homepage = "https://lld.llvm.org/";
-    description = "The LLVM linker (unwrapped)";
+    description = "LLVM linker (unwrapped)";
     longDescription = ''
       LLD is a linker from the LLVM project that is a drop-in replacement for
       system linkers and runs much faster than them. It also provides features
diff --git a/pkgs/development/compilers/llvm/common/lldb.nix b/pkgs/development/compilers/llvm/common/lldb.nix
index 59e427e846c46..71afcb159a440 100644
--- a/pkgs/development/compilers/llvm/common/lldb.nix
+++ b/pkgs/development/compilers/llvm/common/lldb.nix
@@ -174,7 +174,7 @@ stdenv.mkDerivation (rec {
 
   meta = llvm_meta // {
     homepage = "https://lldb.llvm.org/";
-    description = "A next-generation high-performance debugger";
+    description = "Next-generation high-performance debugger";
     longDescription = ''
       LLDB is a next generation, high-performance debugger. It is built as a set
       of reusable components which highly leverage existing libraries in the
diff --git a/pkgs/development/compilers/llvm/common/lldb/gnu-install-dirs.patch b/pkgs/development/compilers/llvm/common/lldb/gnu-install-dirs.patch
index 093b9a8ba3ec3..ec550764be818 100644
--- a/pkgs/development/compilers/llvm/common/lldb/gnu-install-dirs.patch
+++ b/pkgs/development/compilers/llvm/common/lldb/gnu-install-dirs.patch
@@ -47,3 +47,22 @@ index 7d48491ec89a..c04543585588 100644
  install(TARGETS lldbIntelFeatures
 -  LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX})
 +  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX})
+diff --git a/source/API/CMakeLists.txt b/source/API/CMakeLists.txt
+index 7d48491ec89a..c04543585588 100644
+--- a/source/API/CMakeLists.txt	2024-05-30 18:59:13.449269853 -0700
++++ b/source/API/CMakeLists.txt	2024-05-30 19:00:33.721858164 -0700
+@@ -115,14 +115,6 @@
+   ${option_install_prefix}
+ )
+ 
+-# lib/pythonX.Y/dist-packages/lldb/_lldb.so is a symlink to lib/liblldb.so,
+-# which depends on lib/libLLVM*.so (BUILD_SHARED_LIBS) or lib/libLLVM-10git.so
+-# (LLVM_LINK_LLVM_DYLIB). Add an additional rpath $ORIGIN/../../../../lib so
+-# that _lldb.so can be loaded from Python.
+-if(LLDB_ENABLE_PYTHON AND (BUILD_SHARED_LIBS OR LLVM_LINK_LLVM_DYLIB) AND UNIX AND NOT APPLE)
+-  set_property(TARGET liblldb APPEND PROPERTY INSTALL_RPATH "\$ORIGIN/../../../../lib${LLVM_LIBDIR_SUFFIX}")
+-endif()
+-
+ if(Python3_RPATH)
+   set_property(TARGET liblldb APPEND PROPERTY INSTALL_RPATH "${Python3_RPATH}")
+   set_property(TARGET liblldb APPEND PROPERTY BUILD_RPATH   "${Python3_RPATH}")
diff --git a/pkgs/development/compilers/llvm/18/llvm/default.nix b/pkgs/development/compilers/llvm/common/llvm/default.nix
index a9732763e9d7b..89ea8f6e7a564 100644
--- a/pkgs/development/compilers/llvm/18/llvm/default.nix
+++ b/pkgs/development/compilers/llvm/common/llvm/default.nix
@@ -1,6 +1,12 @@
-{ lib, stdenv, llvm_meta
+{ lib
+, stdenv
+, llvm_meta
 , pkgsBuildBuild
-, monorepoSrc
+, pollyPatches ? []
+, patches ? []
+, polly_src ? null
+, src ? null
+, monorepoSrc ? null
 , runCommand
 , cmake
 , darwin
@@ -8,6 +14,8 @@
 , python3
 , python3Packages
 , libffi
+  # TODO: Can this memory corruption bug still occur?
+  # <https://github.com/llvm/llvm-project/issues/61350>
 , enableGoldPlugin ? libbfd.hasPluginAPI
 , libbfd
 , libpfm
@@ -20,7 +28,9 @@
 , sysctl
 , buildLlvmTools
 , debugVersion ? false
-, doCheck ? (!stdenv.isx86_32 /* TODO: why */) && (!stdenv.hostPlatform.isMusl)
+, doCheck ? !stdenv.isAarch32 && (if lib.versionOlder release_version "15" then stdenv.isLinux else true)
+  && (!stdenv.isx86_32 /* TODO: why */) && (!stdenv.hostPlatform.isMusl)
+  && !(stdenv.hostPlatform.isPower64 && stdenv.hostPlatform.isBigEndian)
   && (stdenv.hostPlatform == stdenv.buildPlatform)
 , enableManpages ? false
 , enableSharedLibraries ? !stdenv.hostPlatform.isStatic
@@ -28,7 +38,8 @@
   # broken for Ampere eMAG 8180 (c2.large.arm on Packet) #56245
   # broken for the armv7l builder
   && !stdenv.hostPlatform.isAarch
-, enablePolly ? true
+, enablePolly ? lib.versionAtLeast release_version "14"
+, enableTerminfo ? true
 }:
 
 let
@@ -64,27 +75,36 @@ let
     in pkgsBuildBuild.targetPackages.python3.withPackages checkDeps
   else python3;
 
+  pname = "llvm";
+
+  src' = if monorepoSrc != null then
+    runCommand "${pname}-src-${version}" {} (''
+      mkdir -p "$out"
+      cp -r ${monorepoSrc}/cmake "$out"
+      cp -r ${monorepoSrc}/${pname} "$out"
+      cp -r ${monorepoSrc}/third-party "$out"
+    '' + lib.optionalString enablePolly ''
+      chmod u+w "$out/${pname}/tools"
+      cp -r ${monorepoSrc}/polly "$out/${pname}/tools"
+    '') else src;
+
+  patches' = patches ++ lib.optionals enablePolly pollyPatches;
 in
 
 stdenv.mkDerivation (rec {
-  pname = "llvm";
-  inherit version;
+  inherit pname version;
 
-  src = runCommand "${pname}-src-${version}" {} (''
-    mkdir -p "$out"
-    cp -r ${monorepoSrc}/cmake "$out"
-    cp -r ${monorepoSrc}/${pname} "$out"
-    cp -r ${monorepoSrc}/third-party "$out"
-  '' + lib.optionalString enablePolly ''
-    chmod u+w "$out/${pname}/tools"
-    cp -r ${monorepoSrc}/polly "$out/${pname}/tools"
-  '');
+  src = src';
+  patches = patches';
 
-  sourceRoot = "${src.name}/${pname}";
+  sourceRoot = if lib.versionOlder release_version "13" then null
+    else "${src.name}/${pname}";
 
   outputs = [ "out" "lib" "dev" "python" ];
 
-  nativeBuildInputs = [ cmake ninja python ]
+  nativeBuildInputs = [ cmake ]
+    ++ (lib.optional (lib.versionAtLeast release_version "15") ninja)
+    ++ [ python ]
     ++ optionals enableManpages [
     # Note: we intentionally use `python3Packages` instead of `python3.pkgs`;
     # splicing does *not* work with the latter. (TODO: fix)
@@ -98,92 +118,61 @@ stdenv.mkDerivation (rec {
   buildInputs = [ libxml2 libffi ]
     ++ optional enablePFM libpfm; # exegesis
 
-  propagatedBuildInputs = [ ncurses zlib ];
-
-  nativeCheckInputs = [
-    which
-  ] ++ lib.optional stdenv.isDarwin sysctl;
+  propagatedBuildInputs = (lib.optional (lib.versionAtLeast release_version "14" || stdenv.buildPlatform == stdenv.hostPlatform) ncurses)
+    ++ [ zlib ];
 
-  patches = [
-    ./gnu-install-dirs.patch
-
-    # Running the tests involves invoking binaries (like `opt`) that depend on
-    # the LLVM dylibs and reference them by absolute install path (i.e. their
-    # nix store path).
-    #
-    # Because we have not yet run the install phase (we're running these tests
-    # as part of `checkPhase` instead of `installCheckPhase`) these absolute
-    # paths do not exist yet; to work around this we point the loader (`ld` on
-    # unix, `dyld` on macOS) at the `lib` directory which will later become this
-    # package's `lib` output.
-    #
-    # Previously we would just set `LD_LIBRARY_PATH` to include the build `lib`
-    # dir but:
-    #   - this doesn't generalize well to other platforms; `lit` doesn't forward
-    #     `DYLD_LIBRARY_PATH` (macOS):
-    #     + https://github.com/llvm/llvm-project/blob/0d89963df354ee309c15f67dc47c8ab3cb5d0fb2/llvm/utils/lit/lit/TestingConfig.py#L26
-    #   - even if `lit` forwarded this env var, we actually cannot set
-    #     `DYLD_LIBRARY_PATH` in the child processes `lit` launches because
-    #     `DYLD_LIBRARY_PATH` (and `DYLD_FALLBACK_LIBRARY_PATH`) is cleared for
-    #     "protected processes" (i.e. the python interpreter that runs `lit`):
-    #     https://stackoverflow.com/a/35570229
-    #   - other LLVM subprojects deal with this issue by having their `lit`
-    #     configuration set these env vars for us; it makes sense to do the same
-    #     for LLVM:
-    #     + https://github.com/llvm/llvm-project/blob/4c106cfdf7cf7eec861ad3983a3dd9a9e8f3a8ae/clang-tools-extra/test/Unit/lit.cfg.py#L22-L31
-    #
-    # !!! TODO: look into upstreaming this patch
-    ./llvm-lit-cfg-add-libs-to-dylib-path.patch
-
-    # `lit` has a mode where it executes run lines as a shell script which is
-    # constructs; this is problematic for macOS because it means that there's
-    # another process in between `lit` and the binaries being tested. As noted
-    # above, this means that `DYLD_LIBRARY_PATH` is cleared which means that our
-    # tests fail with dyld errors.
-    #
-    # To get around this we patch `lit` to reintroduce `DYLD_LIBRARY_PATH`, when
-    # present in the test configuration.
-    #
-    # It's not clear to me why this isn't an issue for LLVM developers running
-    # on macOS (nothing about this _seems_ nix specific)..
-    ./lit-shell-script-runner-set-dyld-library-path.patch
-  ] ++ lib.optionals enablePolly [
-    ./gnu-install-dirs-polly.patch
-
-    # Just like the `llvm-lit-cfg` patch, but for `polly`.
-    ./polly-lit-cfg-add-libs-to-dylib-path.patch
-  ];
-
-  postPatch = optionalString stdenv.isDarwin ''
+  postPatch = optionalString stdenv.isDarwin (''
     substituteInPlace cmake/modules/AddLLVM.cmake \
       --replace 'set(_install_name_dir INSTALL_NAME_DIR "@rpath")' "set(_install_name_dir)" \
       --replace 'set(_install_rpath "@loader_path/../''${CMAKE_INSTALL_LIBDIR}''${LLVM_LIBDIR_SUFFIX}" ''${extra_libdir})' ""
-
+  '' +
     # As of LLVM 15, marked as XFAIL on arm64 macOS but lit doesn't seem to pick
     # this up: https://github.com/llvm/llvm-project/blob/c344d97a125b18f8fed0a64aace73c49a870e079/llvm/test/MC/ELF/cfi-version.ll#L7
+    (optionalString (lib.versionAtLeast release_version "15") (''
     rm test/MC/ELF/cfi-version.ll
 
+  '' +
     # This test tries to call `sw_vers` by absolute path (`/usr/bin/sw_vers`)
     # and thus fails under the sandbox:
+    (if lib.versionAtLeast release_version "16" then ''
     substituteInPlace unittests/TargetParser/Host.cpp \
       --replace '/usr/bin/sw_vers' "${(builtins.toString darwin.DarwinTools) + "/bin/sw_vers" }"
-
+  '' else ''
+    substituteInPlace unittests/Support/Host.cpp \
+      --replace '/usr/bin/sw_vers' "${(builtins.toString darwin.DarwinTools) + "/bin/sw_vers" }"
+  '') +
     # This test tries to call the intrinsics `@llvm.roundeven.f32` and
     # `@llvm.roundeven.f64` which seem to (incorrectly?) lower to `roundevenf`
-    # and `roundeven` on macOS.
+    # and `roundeven` on macOS and FreeBSD.
     #
     # However these functions are glibc specific so the test fails:
     #   - https://www.gnu.org/software/gnulib/manual/html_node/roundevenf.html
     #   - https://www.gnu.org/software/gnulib/manual/html_node/roundeven.html
     #
+    # TODO(@rrbutani): this seems to run fine on `aarch64-darwin`, why does it
+    # pass there?
+    optionalString (lib.versionAtLeast release_version "16") ''
+    substituteInPlace test/ExecutionEngine/Interpreter/intrinsics.ll \
+      --replace "%roundeven32 = call float @llvm.roundeven.f32(float 0.000000e+00)" "" \
+      --replace "%roundeven64 = call double @llvm.roundeven.f64(double 0.000000e+00)" ""
+  '' +
+    # fails when run in sandbox
+    optionalString (!stdenv.hostPlatform.isx86 && lib.versionAtLeast release_version "18") ''
+    substituteInPlace unittests/Support/VirtualFileSystemTest.cpp \
+      --replace "PhysicalFileSystemWorkingDirFailure" "DISABLED_PhysicalFileSystemWorkingDirFailure"
+  ''))) +
+    # dup of above patch with different conditions
+    optionalString (stdenv.isDarwin && stdenv.hostPlatform.isx86 && lib.versionAtLeast release_version "15") (optionalString (lib.versionOlder release_version "16") ''
     substituteInPlace test/ExecutionEngine/Interpreter/intrinsics.ll \
       --replace "%roundeven32 = call float @llvm.roundeven.f32(float 0.000000e+00)" "" \
       --replace "%roundeven64 = call double @llvm.roundeven.f64(double 0.000000e+00)" ""
 
+  '' +
     # fails when run in sandbox
+    ((optionalString (lib.versionAtLeast release_version "18") ''
     substituteInPlace unittests/Support/VirtualFileSystemTest.cpp \
       --replace "PhysicalFileSystemWorkingDirFailure" "DISABLED_PhysicalFileSystemWorkingDirFailure"
-  '' + optionalString (stdenv.isDarwin && stdenv.hostPlatform.isx86) ''
+  '') +
     # This test fails on darwin x86_64 because `sw_vers` reports a different
     # macOS version than what LLVM finds by reading
     # `/System/Library/CoreServices/SystemVersion.plist` (which is passed into
@@ -212,31 +201,49 @@ stdenv.mkDerivation (rec {
     # not clear to me when/where/for what this even gets used in LLVM.
     #
     # TODO(@rrbutani): fix/follow-up
+    (if lib.versionAtLeast release_version "16" then ''
     substituteInPlace unittests/TargetParser/Host.cpp \
       --replace "getMacOSHostVersion" "DISABLED_getMacOSHostVersion"
-
+  '' else ''
+    substituteInPlace unittests/Support/Host.cpp \
+      --replace "getMacOSHostVersion" "DISABLED_getMacOSHostVersion"
+  '') +
     # This test fails with a `dysmutil` crash; have not yet dug into what's
     # going on here (TODO(@rrbutani)).
+    lib.optionalString (lib.versionOlder release_version "19") ''
     rm test/tools/dsymutil/ARM/obfuscated.test
-  '' + ''
+  '')) +
     # FileSystem permissions tests fail with various special bits
+  ''
     substituteInPlace unittests/Support/CMakeLists.txt \
       --replace "Path.cpp" ""
     rm unittests/Support/Path.cpp
     substituteInPlace unittests/IR/CMakeLists.txt \
       --replace "PassBuilderCallbacksTest.cpp" ""
     rm unittests/IR/PassBuilderCallbacksTest.cpp
+  '' + lib.optionalString (lib.versionAtLeast release_version "13") ''
     rm test/tools/llvm-objcopy/ELF/mirror-permissions-unix.test
-
+  '' + lib.optionalString (lib.versionOlder release_version "13") ''
+    # TODO: Fix failing tests:
+    rm test/DebugInfo/X86/vla-multi.ll
+  '' +
     # Fails in the presence of anti-virus software or other intrusion-detection software that
     # modifies the atime when run. See #284056.
+    lib.optionalString (lib.versionAtLeast release_version "16") (''
     rm test/tools/llvm-objcopy/ELF/strip-preserve-atime.test
-  '' + optionalString stdenv.hostPlatform.isMusl ''
-    patch -p1 -i ${../../common/llvm/TLI-musl.patch}
+  '' + lib.optionalString (lib.versionOlder release_version "17") ''
+
+  '') +
+    # timing-based tests are trouble
+    lib.optionalString (lib.versionAtLeast release_version "15" && lib.versionOlder release_version "17") ''
+    rm utils/lit/tests/googletest-timeout.py
+  '' +
+    # valgrind unhappy with musl or glibc, but fails w/musl only
+    optionalString stdenv.hostPlatform.isMusl ''
+    patch -p1 -i ${./TLI-musl.patch}
     substituteInPlace unittests/Support/CMakeLists.txt \
       --replace "add_subdirectory(DynamicLibrary)" ""
     rm unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp
-    # valgrind unhappy with musl or glibc, but fails w/musl only
     rm test/CodeGen/AArch64/wineh4.mir
   '' + optionalString stdenv.hostPlatform.isAarch32 ''
     # skip failing X86 test cases on 32-bit ARM
@@ -245,61 +252,70 @@ stdenv.mkDerivation (rec {
     rm test/DebugInfo/X86/convert-linked.ll
     rm test/tools/dsymutil/X86/op-convert.test
     rm test/tools/gold/X86/split-dwarf.ll
-    rm test/tools/llvm-dwarfdump/X86/prettyprint_types.s
-    rm test/tools/llvm-dwarfdump/X86/simplified-template-names.s
-    rm test/CodeGen/RISCV/attributes.ll
-    rm test/CodeGen/RISCV/xtheadmempair.ll
-  '' + optionalString (stdenv.hostPlatform.system == "armv6l-linux") ''
+    rm test/tools/llvm-objcopy/MachO/universal-object.test
+  '' +
     # Seems to require certain floating point hardware (NEON?)
+    optionalString (stdenv.hostPlatform.system == "armv6l-linux") ''
     rm test/ExecutionEngine/frem.ll
+  '' +
+    # 1. TODO: Why does this test fail on FreeBSD?
+    # It seems to reference /usr/local/lib/libfile.a, which is clearly a problem.
+    # 2. This test fails for the same reason it fails on MacOS, but the fix is
+    # not trivial to apply.
+    optionalString stdenv.isFreeBSD ''
+    rm test/tools/llvm-libtool-darwin/L-and-l.test
+    rm test/ExecutionEngine/Interpreter/intrinsics.ll
   '' + ''
     patchShebangs test/BugPoint/compile-custom.ll.py
-  '';
+  '' +
+    # Tweak tests to ignore namespace part of type to support
+    # gcc-12: https://gcc.gnu.org/PR103598.
+    # The change below mangles strings like:
+    #    CHECK-NEXT: Starting llvm::Function pass manager run.
+    # to:
+    #    CHECK-NEXT: Starting {{.*}}Function pass manager run.
+    (lib.optionalString (lib.versionOlder release_version "13") (''
+    for f in \
+      test/Other/new-pass-manager.ll \
+      test/Other/new-pm-O0-defaults.ll \
+      test/Other/new-pm-defaults.ll \
+      test/Other/new-pm-lto-defaults.ll \
+      test/Other/new-pm-thinlto-defaults.ll \
+      test/Other/pass-pipeline-parsing.ll \
+      test/Transforms/Inline/cgscc-incremental-invalidate.ll \
+      test/Transforms/Inline/clear-analyses.ll \
+      test/Transforms/LoopUnroll/unroll-loop-invalidation.ll \
+      test/Transforms/SCCP/ipsccp-preserve-analysis.ll \
+      test/Transforms/SCCP/preserve-analysis.ll \
+      test/Transforms/SROA/dead-inst.ll \
+      test/tools/gold/X86/new-pm.ll \
+      ; do
+      echo "PATCH: $f"
+      substituteInPlace $f \
+        --replace 'Starting llvm::' 'Starting {{.*}}' \
+        --replace 'Finished llvm::' 'Finished {{.*}}'
+    done
+  '' +
+    # gcc-13 fix
+  ''
+    sed -i '/#include <string>/i#include <cstdint>' \
+      include/llvm/DebugInfo/Symbolize/DIPrinter.h
+  ''));
 
-  preConfigure = ''
-    # Workaround for configure flags that need to have spaces
+  # Workaround for configure flags that need to have spaces
+  preConfigure = if lib.versionAtLeast release_version "15" then ''
     cmakeFlagsArray+=(
       -DLLVM_LIT_ARGS="-svj''${NIX_BUILD_CORES} --no-progress-bar"
     )
-  '';
-
-  # Defensive check: some paths (that we make symlinks to) depend on the release
-  # version, for example:
-  #  - https://github.com/llvm/llvm-project/blob/406bde9a15136254f2b10d9ef3a42033b3cb1b16/clang/lib/Headers/CMakeLists.txt#L185
-  #
-  # So we want to sure that the version in the source matches the release
-  # version we were given.
-  #
-  # We do this check here, in the LLVM build, because it happens early.
-  postConfigure = let
-    v = lib.versions;
-    major = v.major release_version;
-    minor = v.minor release_version;
-    patch = v.patch release_version;
-  in ''
-    # $1: part, $2: expected
-    check_version() {
-      part="''${1^^}"
-      part="$(cat include/llvm/Config/llvm-config.h  | grep "#define LLVM_VERSION_''${part} " | cut -d' ' -f3)"
-
-      if [[ "$part" != "$2" ]]; then
-        echo >&2 \
-          "mismatch in the $1 version! we have version ${release_version}" \
-          "and expected the $1 version to be '$2'; the source has '$part' instead"
-        exit 3
-      fi
-    }
-
-    check_version major ${major}
-    check_version minor ${minor}
-    check_version patch ${patch}
+  '' else ''
+    cmakeFlagsArray+=(
+      -DLLVM_LIT_ARGS='-svj''${NIX_BUILD_CORES} --no-progress-bar'
+    )
   '';
 
   # E.g. mesa.drivers use the build-id as a cache key (see #93946):
   LDFLAGS = optionalString (enableSharedLibraries && !stdenv.isDarwin) "-Wl,--build-id=sha1";
 
-  hardeningDisable = [ "trivialautovarinit" ];
-
   cmakeBuildType = if debugVersion then "Debug" else "Release";
 
   cmakeFlags = with stdenv; let
@@ -310,8 +326,11 @@ stdenv.mkDerivation (rec {
     #
     # Some flags don't need to be repassed because LLVM already does so (like
     # CMAKE_BUILD_TYPE), others are irrelevant to the result.
-    flagsForLlvmConfig = [
+    flagsForLlvmConfig = (if lib.versionOlder release_version "15" then [
+      "-DLLVM_INSTALL_CMAKE_DIR=${placeholder "dev"}/lib/cmake/llvm/"
+    ] else [
       "-DLLVM_INSTALL_PACKAGE_DIR=${placeholder "dev"}/lib/cmake/llvm"
+    ]) ++ [
       "-DLLVM_ENABLE_RTTI=ON"
     ] ++ optionals enableSharedLibraries [
       "-DLLVM_LINK_LLVM_DYLIB=ON"
@@ -323,11 +342,14 @@ stdenv.mkDerivation (rec {
     "-DLLVM_HOST_TRIPLE=${stdenv.hostPlatform.config}"
     "-DLLVM_DEFAULT_TARGET_TRIPLE=${stdenv.hostPlatform.config}"
     "-DLLVM_ENABLE_DUMP=ON"
+    (lib.cmakeBool "LLVM_ENABLE_TERMINFO" enableTerminfo)
+  ] ++ optionals (!doCheck) [
+    "-DLLVM_INCLUDE_TESTS=OFF"
   ] ++ optionals stdenv.hostPlatform.isStatic [
     # Disables building of shared libs, -fPIC is still injected by cc-wrapper
     "-DLLVM_ENABLE_PIC=OFF"
+    "-DCMAKE_SKIP_INSTALL_RPATH=ON"
     "-DLLVM_BUILD_STATIC=ON"
-    "-DLLVM_LINK_LLVM_DYLIB=off"
     # libxml2 needs to be disabled because the LLVM build system ignores its .la
     # file and doesn't link zlib as well.
     # https://github.com/ClangBuiltLinux/tc-build/issues/150#issuecomment-845418812
@@ -338,7 +360,7 @@ stdenv.mkDerivation (rec {
     "-DSPHINX_OUTPUT_MAN=ON"
     "-DSPHINX_OUTPUT_HTML=OFF"
     "-DSPHINX_WARNINGS_AS_ERRORS=OFF"
-  ] ++ optionals enableGoldPlugin [
+  ] ++ optionals (enableGoldPlugin) [
     "-DLLVM_BINUTILS_INCDIR=${libbfd.dev}/include"
   ] ++ optionals isDarwin [
     "-DLLVM_ENABLE_LIBCXX=ON"
@@ -382,8 +404,15 @@ stdenv.mkDerivation (rec {
     substituteInPlace "$dev/lib/cmake/llvm/LLVMExports-${if debugVersion then "debug" else "release"}.cmake" \
       --replace "\''${_IMPORT_PREFIX}/lib/lib" "$lib/lib/lib" \
       --replace "$out/bin/llvm-config" "$dev/bin/llvm-config"
+  '' + (if lib.versionOlder release_version "15" then ''
+    substituteInPlace "$dev/lib/cmake/llvm/LLVMConfig.cmake" \
+      --replace 'set(LLVM_BINARY_DIR "''${LLVM_INSTALL_PREFIX}")' 'set(LLVM_BINARY_DIR "''${LLVM_INSTALL_PREFIX}'"$lib"'")'
+  '' else ''
     substituteInPlace "$dev/lib/cmake/llvm/LLVMConfig.cmake" \
       --replace 'set(LLVM_BINARY_DIR "''${LLVM_INSTALL_PREFIX}")' 'set(LLVM_BINARY_DIR "'"$lib"'")'
+  '')
+  + optionalString (stdenv.isDarwin && enableSharedLibraries && lib.versionOlder release_version "18") ''
+    ln -s $lib/lib/libLLVM.dylib $lib/lib/libLLVM-${shortVersion}.dylib
   ''
   + optionalString (stdenv.isDarwin && enableSharedLibraries) ''
     ln -s $lib/lib/libLLVM.dylib $lib/lib/libLLVM-${release_version}.dylib
@@ -402,7 +431,7 @@ stdenv.mkDerivation (rec {
   requiredSystemFeatures = [ "big-parallel" ];
   meta = llvm_meta // {
     homepage = "https://llvm.org/";
-    description = "A collection of modular and reusable compiler and toolchain technologies";
+    description = "Collection of modular and reusable compiler and toolchain technologies";
     longDescription = ''
       The LLVM Project is a collection of modular and reusable compiler and
       toolchain technologies. Despite its name, LLVM has little to do with
@@ -418,14 +447,11 @@ stdenv.mkDerivation (rec {
       under the "Apache 2.0 License with LLVM exceptions".
     '';
   };
-} // lib.optionalAttrs enableManpages {
+} // lib.optionalAttrs enableManpages ({
   pname = "llvm-manpages";
 
   propagatedBuildInputs = [];
 
-  ninjaFlags = [ "docs-llvm-man" ];
-  installTargets = [ "install-docs-llvm-man" ];
-
   postPatch = null;
   postInstall = null;
 
@@ -436,4 +462,79 @@ stdenv.mkDerivation (rec {
   meta = llvm_meta // {
     description = "man pages for LLVM ${version}";
   };
+} // (if lib.versionOlder release_version "15" then {
+  buildPhase = ''
+    make docs-llvm-man
+  '';
+
+  installPhase = ''
+    make -C docs install
+  '';
+} else {
+  ninjaFlags = [ "docs-llvm-man" ];
+  installTargets = [ "install-docs-llvm-man" ];
+
+  postPatch = null;
+  postInstall = null;
+})) // lib.optionalAttrs (lib.versionOlder release_version "13") {
+  inherit polly_src;
+
+  unpackPhase = ''
+    unpackFile $src
+    mv llvm-${release_version}* llvm
+    sourceRoot=$PWD/llvm
+  '' + optionalString enablePolly ''
+    unpackFile $polly_src
+    mv polly-* $sourceRoot/tools/polly
+  '';
+} // lib.optionalAttrs (lib.versionAtLeast release_version "13") {
+  nativeCheckInputs = [ which ] ++ lib.optional (stdenv.isDarwin && lib.versionAtLeast release_version "15") sysctl;
+} // lib.optionalAttrs (lib.versionOlder release_version "15") {
+  # hacky fix: created binaries need to be run before installation
+  preBuild = ''
+    mkdir -p $out/
+    ln -sv $PWD/lib $out
+  '';
+
+  postBuild = ''
+    rm -fR $out
+  '';
+
+  preCheck = ''
+    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH''${LD_LIBRARY_PATH:+:}$PWD/lib
+  '';
+} // lib.optionalAttrs (lib.versionAtLeast release_version "15") {
+  # Defensive check: some paths (that we make symlinks to) depend on the release
+  # version, for example:
+  #  - https://github.com/llvm/llvm-project/blob/406bde9a15136254f2b10d9ef3a42033b3cb1b16/clang/lib/Headers/CMakeLists.txt#L185
+  #
+  # So we want to sure that the version in the source matches the release
+  # version we were given.
+  #
+  # We do this check here, in the LLVM build, because it happens early.
+  postConfigure = let
+    v = lib.versions;
+    major = v.major release_version;
+    minor = v.minor release_version;
+    patch = v.patch release_version;
+  in ''
+    # $1: part, $2: expected
+    check_version() {
+      part="''${1^^}"
+      part="$(cat include/llvm/Config/llvm-config.h  | grep "#define LLVM_VERSION_''${part} " | cut -d' ' -f3)"
+
+      if [[ "$part" != "$2" ]]; then
+        echo >&2 \
+          "mismatch in the $1 version! we have version ${release_version}" \
+          "and expected the $1 version to be '$2'; the source has '$part' instead"
+        exit 3
+      fi
+    }
+
+    check_version major ${major}
+    check_version minor ${minor}
+    check_version patch ${patch}
+  '';
+} // lib.optionalAttrs (lib.versionOlder release_version "17" || lib.versionAtLeast release_version "18") {
+  hardeningDisable = [ "trivialautovarinit" ];
 })
diff --git a/pkgs/development/compilers/llvm/common/mlir/default.nix b/pkgs/development/compilers/llvm/common/mlir/default.nix
index 044e5c673108b..891e66b1d57c5 100644
--- a/pkgs/development/compilers/llvm/common/mlir/default.nix
+++ b/pkgs/development/compilers/llvm/common/mlir/default.nix
@@ -48,7 +48,8 @@ stdenv.mkDerivation rec {
     "-DLLVM_INSTALL_TOOLCHAIN_ONLY=OFF"
     "-DMLIR_TOOLS_INSTALL_DIR=${placeholder "out"}/bin/"
     "-DLLVM_ENABLE_IDE=OFF"
-    "-DMLIR_INSTALL_PACKAGE_DIR=${placeholder "out"}/lib/cmake/mlir"
+    "-DMLIR_INSTALL_PACKAGE_DIR=${placeholder "dev"}/lib/cmake/mlir"
+    "-DMLIR_INSTALL_CMAKE_DIR=${placeholder "dev"}/lib/cmake/mlir"
     "-DLLVM_BUILD_TESTS=${if doCheck then "ON" else "OFF"}"
     "-DLLVM_ENABLE_FFI=ON"
     "-DLLVM_HOST_TRIPLE=${stdenv.hostPlatform.config}"
diff --git a/pkgs/development/compilers/llvm/git/clang/gnu-install-dirs.patch b/pkgs/development/compilers/llvm/git/clang/gnu-install-dirs.patch
index 9517df973ad09..b8c1c110cf22d 100644
--- a/pkgs/development/compilers/llvm/git/clang/gnu-install-dirs.patch
+++ b/pkgs/development/compilers/llvm/git/clang/gnu-install-dirs.patch
@@ -1,5 +1,5 @@
 diff --git a/cmake/modules/AddClang.cmake b/cmake/modules/AddClang.cmake
-index 75b0080f6715..c895b884cd27 100644
+index 75b0080f6..c895b884c 100644
 --- a/cmake/modules/AddClang.cmake
 +++ b/cmake/modules/AddClang.cmake
 @@ -119,8 +119,8 @@ macro(add_clang_library name)
@@ -14,22 +14,22 @@ index 75b0080f6715..c895b884cd27 100644
  
          if (NOT LLVM_ENABLE_IDE)
 diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
-index f2b0c5cddcbb..52f37fc368ce 100644
+index e6ae4e19e..5ef01aea2 100644
 --- a/lib/Headers/CMakeLists.txt
 +++ b/lib/Headers/CMakeLists.txt
-@@ -473,6 +473,7 @@ add_header_target("windows-resource-headers" ${windows_only_files})
- add_header_target("utility-resource-headers" ${utility_files})
+@@ -337,6 +337,7 @@ set(llvm_libc_wrapper_files
  
- get_clang_resource_dir(header_install_dir SUBDIR include)
+ include(GetClangResourceDir)
+ get_clang_resource_dir(output_dir PREFIX ${LLVM_LIBRARY_OUTPUT_INTDIR}/.. SUBDIR include)
 +set(header_install_dir ${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION_MAJOR}/include)
+ set(out_files)
+ set(generated_files)
  
- #############################################################
- # Install rules for the catch-all clang-resource-headers target
 diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
-index 4f23065a2472..6a0f55991e24 100644
+index b5b6d2807..6b592d255 100644
 --- a/tools/libclang/CMakeLists.txt
 +++ b/tools/libclang/CMakeLists.txt
-@@ -234,7 +234,7 @@ foreach(PythonVersion ${CLANG_PYTHON_BINDINGS_VERSIONS})
+@@ -246,7 +246,7 @@ foreach(PythonVersion ${CLANG_PYTHON_BINDINGS_VERSIONS})
            COMPONENT
              libclang-python-bindings
            DESTINATION
@@ -39,7 +39,7 @@ index 4f23065a2472..6a0f55991e24 100644
  if(NOT LLVM_ENABLE_IDE)
    add_custom_target(libclang-python-bindings)
 diff --git a/tools/scan-build-py/CMakeLists.txt b/tools/scan-build-py/CMakeLists.txt
-index 3aca22c0b0a8..3115353e3fe3 100644
+index 3aca22c0b..3115353e3 100644
 --- a/tools/scan-build-py/CMakeLists.txt
 +++ b/tools/scan-build-py/CMakeLists.txt
 @@ -88,7 +88,7 @@ foreach(lib ${LibScanbuild})
diff --git a/pkgs/development/compilers/llvm/git/default.nix b/pkgs/development/compilers/llvm/git/default.nix
index 1a34130679db2..786bd82fa648c 100644
--- a/pkgs/development/compilers/llvm/git/default.nix
+++ b/pkgs/development/compilers/llvm/git/default.nix
@@ -1,6 +1,7 @@
-{ lowPrio, newScope, pkgs, lib, stdenv, cmake, ninja
+{ lowPrio, newScope, pkgs, lib, stdenv
 , preLibcCrossHeaders
-, libxml2, python3, fetchFromGitHub, substituteAll, overrideCC, wrapCCWith, wrapBintoolsWith
+, substitute, substituteAll, fetchFromGitHub, fetchpatch
+, overrideCC, wrapCCWith, wrapBintoolsWith
 , buildLlvmTools # tools, but from the previous stage, for cross
 , targetLlvmLibraries # libraries, but from the next stage, for cross
 , targetLlvm
@@ -19,9 +20,9 @@
 # LLVM release information; specify one of these but not both:
 , gitRelease ? {
     version = "19.0.0-git";
-    rev = "cebf77fb936a7270c7e3fa5c4a7e76216321d385";
-    rev-version = "19.0.0-unstable-2024-04-07";
-    sha256 = "sha256-616tscgsiFgHQcXW4KzK5srrudYizQFnJVM6K0qRf+I=";
+    rev = "78ee473784e5ef6f0b19ce4cb111fb6e4d23c6b2";
+    rev-version = "19.0.0-unstable-2024-06-12";
+    sha256 = "sha256-oLVMwWjo6Nt8ZsTnDTfoiM5U0+1lVIc1NO+4qBNYlzs=";
 }
   # i.e.:
   # {
@@ -44,7 +45,11 @@
 # to you to make sure that the LLVM repo given matches the release configuration
 # specified.
 , monorepoSrc ? null
-}:
+# Allows passthrough to packages via newScope. This makes it possible to
+# do `(llvmPackages.override { <someLlvmDependency> = bar; }).clang` and get
+# an llvmPackages whose packages are overridden in an internally consistent way.
+, ...
+}@args:
 
 assert
   lib.assertMsg
@@ -56,15 +61,17 @@ assert
 let
   monorepoSrc' = monorepoSrc;
 in let
-  inherit (import ../common/common-let.nix { inherit lib gitRelease officialRelease; }) releaseInfo;
 
-  inherit (releaseInfo) release_version version;
-
-  inherit (import ../common/common-let.nix { inherit lib fetchFromGitHub release_version gitRelease officialRelease monorepoSrc'; }) llvm_meta monorepoSrc;
+  metadata = rec {
+    # Import releaseInfo separately to avoid infinite recursion
+    inherit (import ../common/common-let.nix { inherit lib gitRelease officialRelease; }) releaseInfo;
+    inherit (releaseInfo) release_version version;
+    inherit (import ../common/common-let.nix { inherit lib fetchFromGitHub gitRelease release_version officialRelease monorepoSrc'; }) llvm_meta monorepoSrc;
+  };
 
   tools = lib.makeExtensible (tools: let
-    callPackage = newScope (tools // { inherit stdenv cmake ninja libxml2 python3 release_version version monorepoSrc buildLlvmTools; });
-    major = lib.versions.major release_version;
+    callPackage = newScope (tools // args // metadata);
+    major = lib.versions.major metadata.release_version;
     mkExtraBuildCommands0 = cc: ''
       rsrc="$out/resource-root"
       mkdir "$rsrc"
@@ -87,8 +94,57 @@ in let
 
   in {
 
-    libllvm = callPackage ./llvm {
-      inherit llvm_meta;
+    libllvm = callPackage ../common/llvm {
+      patches = [
+        ./llvm/gnu-install-dirs.patch
+
+        # Running the tests involves invoking binaries (like `opt`) that depend on
+        # the LLVM dylibs and reference them by absolute install path (i.e. their
+        # nix store path).
+        #
+        # Because we have not yet run the install phase (we're running these tests
+        # as part of `checkPhase` instead of `installCheckPhase`) these absolute
+        # paths do not exist yet; to work around this we point the loader (`ld` on
+        # unix, `dyld` on macOS) at the `lib` directory which will later become this
+        # package's `lib` output.
+        #
+        # Previously we would just set `LD_LIBRARY_PATH` to include the build `lib`
+        # dir but:
+        #   - this doesn't generalize well to other platforms; `lit` doesn't forward
+        #     `DYLD_LIBRARY_PATH` (macOS):
+        #     + https://github.com/llvm/llvm-project/blob/0d89963df354ee309c15f67dc47c8ab3cb5d0fb2/llvm/utils/lit/lit/TestingConfig.py#L26
+        #   - even if `lit` forwarded this env var, we actually cannot set
+        #     `DYLD_LIBRARY_PATH` in the child processes `lit` launches because
+        #     `DYLD_LIBRARY_PATH` (and `DYLD_FALLBACK_LIBRARY_PATH`) is cleared for
+        #     "protected processes" (i.e. the python interpreter that runs `lit`):
+        #     https://stackoverflow.com/a/35570229
+        #   - other LLVM subprojects deal with this issue by having their `lit`
+        #     configuration set these env vars for us; it makes sense to do the same
+        #     for LLVM:
+        #     + https://github.com/llvm/llvm-project/blob/4c106cfdf7cf7eec861ad3983a3dd9a9e8f3a8ae/clang-tools-extra/test/Unit/lit.cfg.py#L22-L31
+        #
+        # !!! TODO: look into upstreaming this patch
+        ./llvm/llvm-lit-cfg-add-libs-to-dylib-path.patch
+
+        # `lit` has a mode where it executes run lines as a shell script which is
+        # constructs; this is problematic for macOS because it means that there's
+        # another process in between `lit` and the binaries being tested. As noted
+        # above, this means that `DYLD_LIBRARY_PATH` is cleared which means that our
+        # tests fail with dyld errors.
+        #
+        # To get around this we patch `lit` to reintroduce `DYLD_LIBRARY_PATH`, when
+        # present in the test configuration.
+        #
+        # It's not clear to me why this isn't an issue for LLVM developers running
+        # on macOS (nothing about this _seems_ nix specific)..
+        ./llvm/lit-shell-script-runner-set-dyld-library-path.patch
+      ];
+      pollyPatches = [
+        ./llvm/gnu-install-dirs-polly.patch
+
+        # Just like the `llvm-lit-cfg` patch, but for `polly`.
+        ./llvm/polly-lit-cfg-add-libs-to-dylib-path.patch
+      ];
     };
 
     # `llvm` historically had the binaries.  When choosing an output explicitly,
@@ -106,7 +162,6 @@ in let
           libllvmLibdir = "${tools.libllvm.lib}/lib";
         })
       ];
-      inherit llvm_meta;
     };
 
     clang-unwrapped = tools.libclang;
@@ -126,6 +181,9 @@ in let
       python3 = pkgs.python3;  # don't use python-boot
     });
 
+    # Wrapper for standalone command line utilities
+    clang-tools = callPackage ../common/clang-tools { };
+
     # pick clang appropriate for package set we are targeting
     clang =
       /**/ if stdenv.targetPlatform.useLLVM or false then tools.clangUseLLVM
@@ -155,15 +213,12 @@ in let
       patches = [
         ./lld/gnu-install-dirs.patch
       ];
-      inherit llvm_meta;
     };
 
-    mlir = callPackage ../common/mlir {
-      inherit llvm_meta;
-    };
+    mlir = callPackage ../common/mlir {};
 
     lldb = callPackage ../common/lldb.nix {
-      src = callPackage ({ runCommand }: runCommand "lldb-src-${version}" {} ''
+      src = callPackage ({ runCommand }: runCommand "lldb-src-${metadata.version}" {} ''
         mkdir -p "$out"
         cp -r ${monorepoSrc}/cmake "$out"
         cp -r ${monorepoSrc}/lldb "$out"
@@ -187,7 +242,6 @@ in let
             && !stdenv.targetPlatform.isAarch64
             && (lib.versionOlder darwin.apple_sdk.sdk.version "11.0")
         ) ./lldb/cpu_subtype_arm64e_replacement.patch;
-      inherit llvm_meta;
     };
 
     # Below, is the LLVM bootstrapping logic. It handles building a
@@ -290,13 +344,11 @@ in let
     # Has to be in tools despite mostly being a library,
     # because we use a native helper executable from a
     # non-cross build in cross builds.
-    libclc = callPackage ../common/libclc.nix {
-      inherit buildLlvmTools;
-    };
+    libclc = callPackage ../common/libclc.nix {};
   });
 
   libraries = lib.makeExtensible (libraries: let
-    callPackage = newScope (libraries // buildLlvmTools // { inherit stdenv cmake ninja libxml2 python3 release_version version monorepoSrc; });
+    callPackage = newScope (libraries // buildLlvmTools // args // metadata);
   in {
 
     compiler-rt-libc = callPackage ../common/compiler-rt {
@@ -310,7 +362,6 @@ in let
         # See: https://github.com/NixOS/nixpkgs/pull/194634#discussion_r999829893
         # ../common/compiler-rt/armv7l-15.patch
       ];
-      inherit llvm_meta;
       stdenv = if stdenv.hostPlatform.useLLVM or false || (stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isStatic)
                then overrideCC stdenv buildLlvmTools.clangNoCompilerRtWithLibc
                else stdenv;
@@ -327,7 +378,6 @@ in let
         # See: https://github.com/NixOS/nixpkgs/pull/194634#discussion_r999829893
         # ../common/compiler-rt/armv7l-15.patch
       ];
-      inherit llvm_meta;
       stdenv = if stdenv.hostPlatform.useLLVM or false
                then overrideCC stdenv buildLlvmTools.clangNoCompilerRt
                else stdenv;
@@ -350,12 +400,10 @@ in let
         # https://github.com/llvm/llvm-project/issues/64226
         ./libcxx/0001-darwin-10.12-mbstate_t-fix.patch
       ];
-      inherit llvm_meta;
       stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
     };
 
     libunwind = callPackage ../common/libunwind {
-      inherit llvm_meta;
       stdenv = overrideCC stdenv buildLlvmTools.clangNoLibcxx;
     };
 
@@ -364,9 +412,8 @@ in let
         ./openmp/fix-find-tool.patch
         ./openmp/run-lit-directly.patch
       ];
-      inherit llvm_meta targetLlvm;
     };
   });
   noExtend = extensible: lib.attrsets.removeAttrs extensible [ "extend" ];
 
-in { inherit tools libraries release_version; } // (noExtend libraries) // (noExtend tools)
+in { inherit tools libraries; inherit (metadata) release_version; } // (noExtend libraries) // (noExtend tools)
diff --git a/pkgs/development/compilers/llvm/git/llvm/default.nix b/pkgs/development/compilers/llvm/git/llvm/default.nix
deleted file mode 100644
index 8987103e22fe5..0000000000000
--- a/pkgs/development/compilers/llvm/git/llvm/default.nix
+++ /dev/null
@@ -1,435 +0,0 @@
-{ lib, stdenv, llvm_meta
-, pkgsBuildBuild
-, monorepoSrc
-, runCommand
-, cmake
-, darwin
-, ninja
-, python3
-, python3Packages
-, libffi
-, enableGoldPlugin ? libbfd.hasPluginAPI
-, libbfd
-, libpfm
-, libxml2
-, ncurses
-, version
-, release_version
-, zlib
-, which
-, sysctl
-, buildLlvmTools
-, debugVersion ? false
-, doCheck ? (!stdenv.isx86_32 /* TODO: why */) && (!stdenv.hostPlatform.isMusl)
-  && (stdenv.hostPlatform == stdenv.buildPlatform)
-, enableManpages ? false
-, enableSharedLibraries ? !stdenv.hostPlatform.isStatic
-, enablePFM ? stdenv.isLinux /* PFM only supports Linux */
-  # broken for Ampere eMAG 8180 (c2.large.arm on Packet) #56245
-  # broken for the armv7l builder
-  && !stdenv.hostPlatform.isAarch
-, enablePolly ? true
-}:
-
-let
-  inherit (lib) optional optionals optionalString;
-
-  # Used when creating a version-suffixed symlink of libLLVM.dylib
-  shortVersion = with lib;
-    concatStringsSep "." (take 1 (splitString "." release_version));
-
-  # Ordinarily we would just the `doCheck` and `checkDeps` functionality
-  # `mkDerivation` gives us to manage our test dependencies (instead of breaking
-  # out `doCheck` as a package level attribute).
-  #
-  # Unfortunately `lit` does not forward `$PYTHONPATH` to children processes, in
-  # particular the children it uses to do feature detection.
-  #
-  # This means that python deps we add to `checkDeps` (which the python
-  # interpreter is made aware of via `$PYTHONPATH` – populated by the python
-  # setup hook) are not picked up by `lit` which causes it to skip tests.
-  #
-  # Adding `python3.withPackages (ps: [ ... ])` to `checkDeps` also doesn't work
-  # because this package is shadowed in `$PATH` by the regular `python3`
-  # package.
-  #
-  # So, we "manually" assemble one python derivation for the package to depend
-  # on, taking into account whether checks are enabled or not:
-  python = if doCheck then
-    # Note that we _explicitly_ ask for a python interpreter for our host
-    # platform here; the splicing that would ordinarily take care of this for
-    # us does not seem to work once we use `withPackages`.
-    let
-      checkDeps = ps: with ps; [ psutil ];
-    in pkgsBuildBuild.targetPackages.python3.withPackages checkDeps
-  else python3;
-
-in
-
-stdenv.mkDerivation (rec {
-  pname = "llvm";
-  inherit version;
-
-  src = runCommand "${pname}-src-${version}" {} (''
-    mkdir -p "$out"
-    cp -r ${monorepoSrc}/cmake "$out"
-    cp -r ${monorepoSrc}/${pname} "$out"
-    cp -r ${monorepoSrc}/third-party "$out"
-  '' + lib.optionalString enablePolly ''
-    chmod u+w "$out/${pname}/tools"
-    cp -r ${monorepoSrc}/polly "$out/${pname}/tools"
-  '');
-
-  sourceRoot = "${src.name}/${pname}";
-
-  outputs = [ "out" "lib" "dev" "python" ];
-
-  nativeBuildInputs = [ cmake ninja python ]
-    ++ optionals enableManpages [
-    # Note: we intentionally use `python3Packages` instead of `python3.pkgs`;
-    # splicing does *not* work with the latter. (TODO: fix)
-    python3Packages.sphinx
-  ] ++ optionals (lib.versionOlder version "18" && enableManpages) [
-    python3Packages.recommonmark
-  ] ++ optionals (lib.versionAtLeast version "18" && enableManpages) [
-    python3Packages.myst-parser
-  ];
-
-  buildInputs = [ libxml2 libffi ]
-    ++ optional enablePFM libpfm; # exegesis
-
-  propagatedBuildInputs = [ ncurses zlib ];
-
-  nativeCheckInputs = [
-    which
-  ] ++ lib.optional stdenv.isDarwin sysctl;
-
-  patches = [
-    ./gnu-install-dirs.patch
-
-    # Running the tests involves invoking binaries (like `opt`) that depend on
-    # the LLVM dylibs and reference them by absolute install path (i.e. their
-    # nix store path).
-    #
-    # Because we have not yet run the install phase (we're running these tests
-    # as part of `checkPhase` instead of `installCheckPhase`) these absolute
-    # paths do not exist yet; to work around this we point the loader (`ld` on
-    # unix, `dyld` on macOS) at the `lib` directory which will later become this
-    # package's `lib` output.
-    #
-    # Previously we would just set `LD_LIBRARY_PATH` to include the build `lib`
-    # dir but:
-    #   - this doesn't generalize well to other platforms; `lit` doesn't forward
-    #     `DYLD_LIBRARY_PATH` (macOS):
-    #     + https://github.com/llvm/llvm-project/blob/0d89963df354ee309c15f67dc47c8ab3cb5d0fb2/llvm/utils/lit/lit/TestingConfig.py#L26
-    #   - even if `lit` forwarded this env var, we actually cannot set
-    #     `DYLD_LIBRARY_PATH` in the child processes `lit` launches because
-    #     `DYLD_LIBRARY_PATH` (and `DYLD_FALLBACK_LIBRARY_PATH`) is cleared for
-    #     "protected processes" (i.e. the python interpreter that runs `lit`):
-    #     https://stackoverflow.com/a/35570229
-    #   - other LLVM subprojects deal with this issue by having their `lit`
-    #     configuration set these env vars for us; it makes sense to do the same
-    #     for LLVM:
-    #     + https://github.com/llvm/llvm-project/blob/4c106cfdf7cf7eec861ad3983a3dd9a9e8f3a8ae/clang-tools-extra/test/Unit/lit.cfg.py#L22-L31
-    #
-    # !!! TODO: look into upstreaming this patch
-    ./llvm-lit-cfg-add-libs-to-dylib-path.patch
-
-    # `lit` has a mode where it executes run lines as a shell script which is
-    # constructs; this is problematic for macOS because it means that there's
-    # another process in between `lit` and the binaries being tested. As noted
-    # above, this means that `DYLD_LIBRARY_PATH` is cleared which means that our
-    # tests fail with dyld errors.
-    #
-    # To get around this we patch `lit` to reintroduce `DYLD_LIBRARY_PATH`, when
-    # present in the test configuration.
-    #
-    # It's not clear to me why this isn't an issue for LLVM developers running
-    # on macOS (nothing about this _seems_ nix specific)..
-    ./lit-shell-script-runner-set-dyld-library-path.patch
-  ] ++ lib.optionals enablePolly [
-    ./gnu-install-dirs-polly.patch
-
-    # Just like the `llvm-lit-cfg` patch, but for `polly`.
-    ./polly-lit-cfg-add-libs-to-dylib-path.patch
-  ];
-
-  postPatch = optionalString stdenv.isDarwin ''
-    substituteInPlace cmake/modules/AddLLVM.cmake \
-      --replace 'set(_install_name_dir INSTALL_NAME_DIR "@rpath")' "set(_install_name_dir)" \
-      --replace 'set(_install_rpath "@loader_path/../''${CMAKE_INSTALL_LIBDIR}''${LLVM_LIBDIR_SUFFIX}" ''${extra_libdir})' ""
-
-    # As of LLVM 15, marked as XFAIL on arm64 macOS but lit doesn't seem to pick
-    # this up: https://github.com/llvm/llvm-project/blob/c344d97a125b18f8fed0a64aace73c49a870e079/llvm/test/MC/ELF/cfi-version.ll#L7
-    rm test/MC/ELF/cfi-version.ll
-
-    # This test tries to call `sw_vers` by absolute path (`/usr/bin/sw_vers`)
-    # and thus fails under the sandbox:
-    substituteInPlace unittests/TargetParser/Host.cpp \
-      --replace '/usr/bin/sw_vers' "${(builtins.toString darwin.DarwinTools) + "/bin/sw_vers" }"
-
-    # This test tries to call the intrinsics `@llvm.roundeven.f32` and
-    # `@llvm.roundeven.f64` which seem to (incorrectly?) lower to `roundevenf`
-    # and `roundeven` on macOS.
-    #
-    # However these functions are glibc specific so the test fails:
-    #   - https://www.gnu.org/software/gnulib/manual/html_node/roundevenf.html
-    #   - https://www.gnu.org/software/gnulib/manual/html_node/roundeven.html
-    #
-    substituteInPlace test/ExecutionEngine/Interpreter/intrinsics.ll \
-      --replace "%roundeven32 = call float @llvm.roundeven.f32(float 0.000000e+00)" "" \
-      --replace "%roundeven64 = call double @llvm.roundeven.f64(double 0.000000e+00)" ""
-
-    # fails when run in sandbox
-    substituteInPlace unittests/Support/VirtualFileSystemTest.cpp \
-      --replace "PhysicalFileSystemWorkingDirFailure" "DISABLED_PhysicalFileSystemWorkingDirFailure"
-  '' + optionalString (stdenv.isDarwin && stdenv.hostPlatform.isx86) ''
-    # This test fails on darwin x86_64 because `sw_vers` reports a different
-    # macOS version than what LLVM finds by reading
-    # `/System/Library/CoreServices/SystemVersion.plist` (which is passed into
-    # the sandbox on macOS).
-    #
-    # The `sw_vers` provided by nixpkgs reports the macOS version associated
-    # with the `CoreFoundation` framework with which it was built. Because
-    # nixpkgs pins the SDK for `aarch64-darwin` and `x86_64-darwin` what
-    # `sw_vers` reports is not guaranteed to match the macOS version of the host
-    # that's building this derivation.
-    #
-    # Astute readers will note that we only _patch_ this test on aarch64-darwin
-    # (to use the nixpkgs provided `sw_vers`) instead of disabling it outright.
-    # So why does this test pass on aarch64?
-    #
-    # Well, it seems that `sw_vers` on aarch64 actually links against the _host_
-    # CoreFoundation framework instead of the nixpkgs provided one.
-    #
-    # Not entirely sure what the right fix is here. I'm assuming aarch64
-    # `sw_vers` doesn't intentionally link against the host `CoreFoundation`
-    # (still digging into how this ends up happening, will follow up) but that
-    # aside I think the more pertinent question is: should we be patching LLVM's
-    # macOS version detection logic to use `sw_vers` instead of reading host
-    # paths? This *is* a way in which details about builder machines can creep
-    # into the artifacts that are produced, affecting reproducibility, but it's
-    # not clear to me when/where/for what this even gets used in LLVM.
-    #
-    # TODO(@rrbutani): fix/follow-up
-    substituteInPlace unittests/TargetParser/Host.cpp \
-      --replace "getMacOSHostVersion" "DISABLED_getMacOSHostVersion"
-  '' + ''
-    # FileSystem permissions tests fail with various special bits
-    substituteInPlace unittests/Support/CMakeLists.txt \
-      --replace "Path.cpp" ""
-    rm unittests/Support/Path.cpp
-    substituteInPlace unittests/IR/CMakeLists.txt \
-      --replace "PassBuilderCallbacksTest.cpp" ""
-    rm unittests/IR/PassBuilderCallbacksTest.cpp
-    rm test/tools/llvm-objcopy/ELF/mirror-permissions-unix.test
-
-    # Fails in the presence of anti-virus software or other intrusion-detection software that
-    # modifies the atime when run. See #284056.
-    rm test/tools/llvm-objcopy/ELF/strip-preserve-atime.test
-  '' + optionalString stdenv.hostPlatform.isMusl ''
-    patch -p1 -i ${../../common/llvm/TLI-musl.patch}
-    substituteInPlace unittests/Support/CMakeLists.txt \
-      --replace "add_subdirectory(DynamicLibrary)" ""
-    rm unittests/Support/DynamicLibrary/DynamicLibraryTest.cpp
-    # valgrind unhappy with musl or glibc, but fails w/musl only
-    rm test/CodeGen/AArch64/wineh4.mir
-  '' + optionalString stdenv.hostPlatform.isAarch32 ''
-    # skip failing X86 test cases on 32-bit ARM
-    rm test/DebugInfo/X86/convert-debugloc.ll
-    rm test/DebugInfo/X86/convert-inlined.ll
-    rm test/DebugInfo/X86/convert-linked.ll
-    rm test/tools/dsymutil/X86/op-convert.test
-    rm test/tools/gold/X86/split-dwarf.ll
-    rm test/tools/llvm-dwarfdump/X86/prettyprint_types.s
-    rm test/tools/llvm-dwarfdump/X86/simplified-template-names.s
-    rm test/CodeGen/RISCV/attributes.ll
-    rm test/CodeGen/RISCV/xtheadmempair.ll
-  '' + optionalString (stdenv.hostPlatform.system == "armv6l-linux") ''
-    # Seems to require certain floating point hardware (NEON?)
-    rm test/ExecutionEngine/frem.ll
-  '' + ''
-    patchShebangs test/BugPoint/compile-custom.ll.py
-  '';
-
-  preConfigure = ''
-    # Workaround for configure flags that need to have spaces
-    cmakeFlagsArray+=(
-      -DLLVM_LIT_ARGS="-svj''${NIX_BUILD_CORES} --no-progress-bar"
-    )
-  '';
-
-  # Defensive check: some paths (that we make symlinks to) depend on the release
-  # version, for example:
-  #  - https://github.com/llvm/llvm-project/blob/406bde9a15136254f2b10d9ef3a42033b3cb1b16/clang/lib/Headers/CMakeLists.txt#L185
-  #
-  # So we want to sure that the version in the source matches the release
-  # version we were given.
-  #
-  # We do this check here, in the LLVM build, because it happens early.
-  postConfigure = let
-    v = lib.versions;
-    major = v.major release_version;
-    minor = v.minor release_version;
-    patch = v.patch release_version;
-  in ''
-    # $1: part, $2: expected
-    check_version() {
-      part="''${1^^}"
-      part="$(cat include/llvm/Config/llvm-config.h  | grep "#define LLVM_VERSION_''${part} " | cut -d' ' -f3)"
-
-      if [[ "$part" != "$2" ]]; then
-        echo >&2 \
-          "mismatch in the $1 version! we have version ${release_version}" \
-          "and expected the $1 version to be '$2'; the source has '$part' instead"
-        exit 3
-      fi
-    }
-
-    check_version major ${major}
-    check_version minor ${minor}
-    check_version patch ${patch}
-  '';
-
-  # E.g. mesa.drivers use the build-id as a cache key (see #93946):
-  LDFLAGS = optionalString (enableSharedLibraries && !stdenv.isDarwin) "-Wl,--build-id=sha1";
-
-  hardeningDisable = [ "trivialautovarinit" ];
-
-  cmakeBuildType = if debugVersion then "Debug" else "Release";
-
-  cmakeFlags = with stdenv; let
-    # These flags influence llvm-config's BuildVariables.inc in addition to the
-    # general build. We need to make sure these are also passed via
-    # CROSS_TOOLCHAIN_FLAGS_NATIVE when cross-compiling or llvm-config-native
-    # will return different results from the cross llvm-config.
-    #
-    # Some flags don't need to be repassed because LLVM already does so (like
-    # CMAKE_BUILD_TYPE), others are irrelevant to the result.
-    flagsForLlvmConfig = [
-      "-DLLVM_INSTALL_PACKAGE_DIR=${placeholder "dev"}/lib/cmake/llvm"
-      "-DLLVM_ENABLE_RTTI=ON"
-    ] ++ optionals enableSharedLibraries [
-      "-DLLVM_LINK_LLVM_DYLIB=ON"
-    ];
-  in flagsForLlvmConfig ++ [
-    "-DLLVM_INSTALL_UTILS=ON"  # Needed by rustc
-    "-DLLVM_BUILD_TESTS=${if doCheck then "ON" else "OFF"}"
-    "-DLLVM_ENABLE_FFI=ON"
-    "-DLLVM_HOST_TRIPLE=${stdenv.hostPlatform.config}"
-    "-DLLVM_DEFAULT_TARGET_TRIPLE=${stdenv.hostPlatform.config}"
-    "-DLLVM_ENABLE_DUMP=ON"
-  ] ++ optionals stdenv.hostPlatform.isStatic [
-    # Disables building of shared libs, -fPIC is still injected by cc-wrapper
-    "-DLLVM_ENABLE_PIC=OFF"
-    "-DLLVM_BUILD_STATIC=ON"
-    "-DLLVM_LINK_LLVM_DYLIB=off"
-    # libxml2 needs to be disabled because the LLVM build system ignores its .la
-    # file and doesn't link zlib as well.
-    # https://github.com/ClangBuiltLinux/tc-build/issues/150#issuecomment-845418812
-    "-DLLVM_ENABLE_LIBXML2=OFF"
-  ] ++ optionals enableManpages [
-    "-DLLVM_BUILD_DOCS=ON"
-    "-DLLVM_ENABLE_SPHINX=ON"
-    "-DSPHINX_OUTPUT_MAN=ON"
-    "-DSPHINX_OUTPUT_HTML=OFF"
-    "-DSPHINX_WARNINGS_AS_ERRORS=OFF"
-  ] ++ optionals enableGoldPlugin [
-    "-DLLVM_BINUTILS_INCDIR=${libbfd.dev}/include"
-  ] ++ optionals isDarwin [
-    "-DLLVM_ENABLE_LIBCXX=ON"
-    "-DCAN_TARGET_i386=false"
-  ] ++ optionals ((stdenv.hostPlatform != stdenv.buildPlatform) && !(stdenv.buildPlatform.canExecute stdenv.hostPlatform)) [
-    "-DCMAKE_CROSSCOMPILING=True"
-    "-DLLVM_TABLEGEN=${buildLlvmTools.llvm}/bin/llvm-tblgen"
-    (
-      let
-        nativeCC = pkgsBuildBuild.targetPackages.stdenv.cc;
-        nativeBintools = nativeCC.bintools.bintools;
-        nativeToolchainFlags = [
-          "-DCMAKE_C_COMPILER=${nativeCC}/bin/${nativeCC.targetPrefix}cc"
-          "-DCMAKE_CXX_COMPILER=${nativeCC}/bin/${nativeCC.targetPrefix}c++"
-          "-DCMAKE_AR=${nativeBintools}/bin/${nativeBintools.targetPrefix}ar"
-          "-DCMAKE_STRIP=${nativeBintools}/bin/${nativeBintools.targetPrefix}strip"
-          "-DCMAKE_RANLIB=${nativeBintools}/bin/${nativeBintools.targetPrefix}ranlib"
-        ];
-        # We need to repass the custom GNUInstallDirs values, otherwise CMake
-        # will choose them for us, leading to wrong results in llvm-config-native
-        nativeInstallFlags = [
-          "-DCMAKE_INSTALL_PREFIX=${placeholder "out"}"
-          "-DCMAKE_INSTALL_BINDIR=${placeholder "out"}/bin"
-          "-DCMAKE_INSTALL_INCLUDEDIR=${placeholder "dev"}/include"
-          "-DCMAKE_INSTALL_LIBDIR=${placeholder "lib"}/lib"
-          "-DCMAKE_INSTALL_LIBEXECDIR=${placeholder "lib"}/libexec"
-        ];
-      in "-DCROSS_TOOLCHAIN_FLAGS_NATIVE:list="
-      + lib.concatStringsSep ";" (lib.concatLists [
-        flagsForLlvmConfig
-        nativeToolchainFlags
-        nativeInstallFlags
-      ])
-    )
-  ];
-
-  postInstall = ''
-    mkdir -p $python/share
-    mv $out/share/opt-viewer $python/share/opt-viewer
-    moveToOutput "bin/llvm-config*" "$dev"
-    substituteInPlace "$dev/lib/cmake/llvm/LLVMExports-${if debugVersion then "debug" else "release"}.cmake" \
-      --replace "\''${_IMPORT_PREFIX}/lib/lib" "$lib/lib/lib" \
-      --replace "$out/bin/llvm-config" "$dev/bin/llvm-config"
-    substituteInPlace "$dev/lib/cmake/llvm/LLVMConfig.cmake" \
-      --replace 'set(LLVM_BINARY_DIR "''${LLVM_INSTALL_PREFIX}")' 'set(LLVM_BINARY_DIR "'"$lib"'")'
-  ''
-  + optionalString (stdenv.isDarwin && enableSharedLibraries) ''
-    ln -s $lib/lib/libLLVM.dylib $lib/lib/libLLVM-${release_version}.dylib
-  ''
-  + optionalString (stdenv.buildPlatform != stdenv.hostPlatform) ''
-    cp NATIVE/bin/llvm-config $dev/bin/llvm-config-native
-  '';
-
-  inherit doCheck;
-
-  checkTarget = "check-all";
-
-  # For the update script:
-  passthru.monorepoSrc = monorepoSrc;
-
-  requiredSystemFeatures = [ "big-parallel" ];
-  meta = llvm_meta // {
-    homepage = "https://llvm.org/";
-    description = "A collection of modular and reusable compiler and toolchain technologies";
-    longDescription = ''
-      The LLVM Project is a collection of modular and reusable compiler and
-      toolchain technologies. Despite its name, LLVM has little to do with
-      traditional virtual machines. The name "LLVM" itself is not an acronym; it
-      is the full name of the project.
-      LLVM began as a research project at the University of Illinois, with the
-      goal of providing a modern, SSA-based compilation strategy capable of
-      supporting both static and dynamic compilation of arbitrary programming
-      languages. Since then, LLVM has grown to be an umbrella project consisting
-      of a number of subprojects, many of which are being used in production by
-      a wide variety of commercial and open source projects as well as being
-      widely used in academic research. Code in the LLVM project is licensed
-      under the "Apache 2.0 License with LLVM exceptions".
-    '';
-  };
-} // lib.optionalAttrs enableManpages {
-  pname = "llvm-manpages";
-
-  propagatedBuildInputs = [];
-
-  ninjaFlags = [ "docs-llvm-man" ];
-  installTargets = [ "install-docs-llvm-man" ];
-
-  postPatch = null;
-  postInstall = null;
-
-  outputs = [ "out" ];
-
-  doCheck = false;
-
-  meta = llvm_meta // {
-    description = "man pages for LLVM ${version}";
-  };
-})