Merge topic 'jsonstate-fileapi'

d3ccd49eeb cmFileAPI: Use cmJSONState to read client queries

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !12317
diff --git a/Help/cpack_gen/deb.rst b/Help/cpack_gen/deb.rst
index d738804..c3f60c6 100644
--- a/Help/cpack_gen/deb.rst
+++ b/Help/cpack_gen/deb.rst
@@ -290,13 +290,13 @@
  Possible values are:
 
   ``lzma``
-    Lempel–Ziv–Markov chain algorithm
+    Lempel-Ziv-Markov chain algorithm
 
   ``xz``
-    XZ Utils LZMA2 (Lempel–Ziv–Markov chain algorithm, version 2) compression
+    XZ Utils LZMA2 (Lempel-Ziv-Markov chain algorithm, version 2) compression
 
   ``bzip2``
-    bzip2 Burrows–Wheeler algorithm
+    bzip2 Burrows-Wheeler algorithm
 
   ``gzip``
     GNU Gzip Deflate compression
@@ -323,11 +323,11 @@
 
  The valid range and interpretation depend on the selected compression type:
 
-  - ``gzip``  – level 1–9
-  - ``bzip2`` – level 1–9
-  - ``xz``    – level 1–9
-  - ``lzma``  – level 1–9
-  - ``zstd``  – level 1–19
+  - ``gzip``  - level 1-9
+  - ``bzip2`` - level 1-9
+  - ``xz``    - level 1-9
+  - ``lzma``  - level 1-9
+  - ``zstd``  - level 1-19
 
  Example usage:
 
diff --git a/Help/cpack_gen/rpm.rst b/Help/cpack_gen/rpm.rst
index a30b481..5e64803 100644
--- a/Help/cpack_gen/rpm.rst
+++ b/Help/cpack_gen/rpm.rst
@@ -252,13 +252,13 @@
  Possible values are:
 
   ``lzma``
-    Lempel–Ziv–Markov chain algorithm
+    Lempel-Ziv-Markov chain algorithm
 
   ``xz``
-    XZ Utils LZMA2 (Lempel–Ziv–Markov chain algorithm, version 2) compression
+    XZ Utils LZMA2 (Lempel-Ziv-Markov chain algorithm, version 2) compression
 
   ``bzip2``
-    bzip2 Burrows–Wheeler algorithm
+    bzip2 Burrows-Wheeler algorithm
 
   ``gzip``
     GNU Gzip Deflate compression
diff --git a/Help/generator/FASTBuild.rst b/Help/generator/FASTBuild.rst
index f16b166..e42ab36 100644
--- a/Help/generator/FASTBuild.rst
+++ b/Help/generator/FASTBuild.rst
@@ -23,8 +23,8 @@
    This generator also produces IDE project files for Visual Studio and Xcode,
    which are placed under:
 
-   * ``<path-to-build>/VisualStudio`` – Visual Studio solution and projects
-   * ``<path-to-build>/XCode`` – Xcode workspace and projects
+   * ``<path-to-build>/VisualStudio`` - Visual Studio solution and projects
+   * ``<path-to-build>/XCode`` - Xcode workspace and projects
 
    These IDE files can be generated by building ``xcode`` or ``solution`` targets
    and will build using FASTBuild as the backend.
@@ -77,9 +77,9 @@
 The following target properties can be used to fine-tune behavior on a
 per-target basis:
 
-* :prop_tgt:`FASTBUILD_CACHING` –
+* :prop_tgt:`FASTBUILD_CACHING` -
   disables caching for a specific target.
-* :prop_tgt:`FASTBUILD_DISTRIBUTION` –
+* :prop_tgt:`FASTBUILD_DISTRIBUTION` -
   disables distributed compilation for a specific target.
 
 Notes
diff --git a/Help/prop_tgt/AUTOMOC.rst b/Help/prop_tgt/AUTOMOC.rst
index 25c5632..1ec36f8 100644
--- a/Help/prop_tgt/AUTOMOC.rst
+++ b/Help/prop_tgt/AUTOMOC.rst
@@ -228,8 +228,8 @@
 The generation of this file can be enabled or disabled in this target property.
 
 :prop_tgt:`AUTOMOC_INCLUDE_DIRECTORIES`:
-Specifies one or more include directories for ``AUTOMOC`` to pass explicitly to ``moc``
-instead of automatically discovering a target’s include directories.
+Specifies one or more include directories for ``AUTOMOC`` to pass explicitly
+to ``moc`` instead of automatically discovering a target's include directories.
 
 :prop_sf:`SKIP_AUTOMOC`:
 Sources and headers can be excluded from ``AUTOMOC`` processing by
diff --git a/Help/prop_tgt/AUTOMOC_INCLUDE_DIRECTORIES.rst b/Help/prop_tgt/AUTOMOC_INCLUDE_DIRECTORIES.rst
index a280ce1..70e34e3 100644
--- a/Help/prop_tgt/AUTOMOC_INCLUDE_DIRECTORIES.rst
+++ b/Help/prop_tgt/AUTOMOC_INCLUDE_DIRECTORIES.rst
@@ -4,7 +4,7 @@
 .. versionadded:: 4.1
 
 Specifies zero or more include directories for AUTOMOC to pass explicitly to
-the Qt Meta‑Object Compiler (``moc``) instead of automatically discovering a
+the Qt Meta-Object Compiler (``moc``) instead of automatically discovering a
 target's include directories.
 
 When this property is set on a target, only the directories listed here will be
diff --git a/Help/prop_tgt/SKIP_LINTING.rst b/Help/prop_tgt/SKIP_LINTING.rst
index 996c4ee..14437a2 100644
--- a/Help/prop_tgt/SKIP_LINTING.rst
+++ b/Help/prop_tgt/SKIP_LINTING.rst
@@ -16,7 +16,7 @@
 This is a convenience alternative to setting the :prop_sf:`SKIP_LINTING`
 source file property individually on each source.  If either the target's
 :prop_tgt:`SKIP_LINTING` or file set's :prop_fs:`SKIP_LINTING` including this
-source or a source’s :prop_sf:`SKIP_LINTING` is enabled, that source will be
+source or a source's :prop_sf:`SKIP_LINTING` is enabled, that source will be
 excluded from linting.
 
 The property has no effect on targets that do not have sources.
diff --git a/Help/variable/CMAKE_AUTOMOC_INCLUDE_DIRECTORIES.rst b/Help/variable/CMAKE_AUTOMOC_INCLUDE_DIRECTORIES.rst
index 2146f00..da55c60 100644
--- a/Help/variable/CMAKE_AUTOMOC_INCLUDE_DIRECTORIES.rst
+++ b/Help/variable/CMAKE_AUTOMOC_INCLUDE_DIRECTORIES.rst
@@ -4,7 +4,7 @@
 .. versionadded:: 4.1
 
 Specifies zero or more include directories for AUTOMOC to pass explicitly to
-the Qt Meta‑Object Compiler (``moc``) instead of automatically discovering
+the Qt Meta-Object Compiler (``moc``) instead of automatically discovering
 each target's include directories.
 
 The directories listed here will replace any include paths discovered from
diff --git a/Help/variable/CMAKE_FASTBUILD_TRACK_BYPRODUCTS_AS_OUTPUT.rst b/Help/variable/CMAKE_FASTBUILD_TRACK_BYPRODUCTS_AS_OUTPUT.rst
index 07da28d..3328e6b 100644
--- a/Help/variable/CMAKE_FASTBUILD_TRACK_BYPRODUCTS_AS_OUTPUT.rst
+++ b/Help/variable/CMAKE_FASTBUILD_TRACK_BYPRODUCTS_AS_OUTPUT.rst
@@ -11,7 +11,7 @@
 .. note::
 
    When this variable is ``OFF`` (the default), ``BYPRODUCTS`` are treated
-   similarly to how Ninja handles them — as opaque side effects — and the
+   similarly to how Ninja handles them - as opaque side effects - and the
    generator emits ``ExecAlways`` nodes to ensure they always run.
 
 Defaults to ``OFF``.
diff --git a/Help/variable/CMAKE_FASTBUILD_USE_LIGHTCACHE.rst b/Help/variable/CMAKE_FASTBUILD_USE_LIGHTCACHE.rst
index e3498d9..187a411 100644
--- a/Help/variable/CMAKE_FASTBUILD_USE_LIGHTCACHE.rst
+++ b/Help/variable/CMAKE_FASTBUILD_USE_LIGHTCACHE.rst
@@ -3,7 +3,7 @@
 
 .. versionadded:: 4.2
 
-Enables FASTBuild’s *light caching* mode, which accelerates cache lookups by
+Enables FASTBuild's *light caching* mode, which accelerates cache lookups by
 parsing source files directly (instead of invoking the compiler preprocessor).
 
 See the `FASTBuild Compiler() documentation <https://www.fastbuild.org/docs/functions/compiler.html>`_
diff --git a/Modules/GNUInstallDirs.cmake b/Modules/GNUInstallDirs.cmake
index c2aa29a..d626688 100644
--- a/Modules/GNUInstallDirs.cmake
+++ b/Modules/GNUInstallDirs.cmake
@@ -84,8 +84,11 @@
 ``LIBDIR``
   object code libraries (``lib`` or ``lib64``)
 
+  On Linux, when not cross-compiling, the default is the distro's
+  arch-specific library directory, such as ``lib`` or ``lib64``.
   On Debian, this may be ``lib/<multiarch-tuple>`` when
   :variable:`CMAKE_INSTALL_PREFIX` is ``/usr``.
+  When cross-compiling, the default is ``lib``.
 
   .. note::
 
@@ -441,31 +444,28 @@
 function(_GNUInstallDirs_LIBDIR_get_default out_var install_prefix)
   set(${out_var} "${_GNUInstallDirs_LIBDIR_DEFAULT}")
 
-  # Override this default 'lib' with 'lib64' iff:
-  #  - we are on Linux system but NOT cross-compiling
-  #  - we are NOT on debian
-  #  - we are NOT building for conda
-  #  - we are on a 64 bits system
-  # reason is: amd64 ABI: https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI
-  # For Debian with multiarch, use 'lib/${CMAKE_LIBRARY_ARCHITECTURE}' if
-  # CMAKE_LIBRARY_ARCHITECTURE is set (which contains e.g. "i386-linux-gnu"
-  # and CMAKE_INSTALL_PREFIX is "/usr"
-  # See http://wiki.debian.org/Multiarch
   if (NOT DEFINED CMAKE_SYSTEM_NAME OR NOT DEFINED CMAKE_SIZEOF_VOID_P)
     message(AUTHOR_WARNING
       "Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
       "Please enable at least one language before including GNUInstallDirs.")
   endif()
+
+  # When not cross-compiling, detect the host distro's arch-specific 'lib'.
+  # When cross-compiling, the host's distro is meaningless to the target,
+  # so it is up to the caller to specify the correct 'lib' directory.
   if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|GNU)$" AND NOT CMAKE_CROSSCOMPILING)
     _GNUInstallDirs_get_system_type_for_install(system_type)
     if(system_type STREQUAL "debian")
+      # For Debian with multiarch, use 'lib/${CMAKE_LIBRARY_ARCHITECTURE}' if
+      # CMAKE_INSTALL_PREFIX is "/usr".  See http://wiki.debian.org/Multiarch
       if(CMAKE_LIBRARY_ARCHITECTURE)
         if("${install_prefix}" MATCHES "^/usr/?$")
           set(${out_var} "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
         endif()
       endif()
     elseif(NOT DEFINED system_type)
-      # not debian, alpine, arch, or conda so rely on CMAKE_SIZEOF_VOID_P:
+      # This host system uses a 'lib64' directory for 64-bit architectures.
+      # See https://gitlab.com/x86-psABIs/x86-64-ABI
       if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
         set(${out_var} "lib64")
       endif()
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index c4c0e09..c6a4d19 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 4)
 set(CMake_VERSION_MINOR 4)
-set(CMake_VERSION_PATCH 20260723)
+set(CMake_VERSION_PATCH 20260727)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
diff --git a/Source/Modules/CMakeBuildUtilities.cmake b/Source/Modules/CMakeBuildUtilities.cmake
index 15bc35b..a6578eb 100644
--- a/Source/Modules/CMakeBuildUtilities.cmake
+++ b/Source/Modules/CMakeBuildUtilities.cmake
@@ -103,6 +103,12 @@
 endif()
 
 #---------------------------------------------------------------------
+# rapidhash is a header-only hashing library used to speed up
+# string-keyed hash tables (e.g. cmDefinitions).  No system option is
+# provided because it has no conventional system package.
+add_subdirectory(Utilities/cmrapidhash)
+
+#---------------------------------------------------------------------
 # Build zlib library for Curl, CMake, and CTest.
 if(CMAKE_USE_SYSTEM_ZLIB)
   find_package(ZLIB)
diff --git a/Source/cmBuildSbomGenerator.h b/Source/cmBuildSbomGenerator.h
index 9beaedd..957d9c9 100644
--- a/Source/cmBuildSbomGenerator.h
+++ b/Source/cmBuildSbomGenerator.h
@@ -20,7 +20,7 @@
  *
  * Stored on cmMakefile at configure time.  At generate time,
  * ComputeBuildFileGenerators() calls Compute(lg) to resolve export set
- * targets and supply the local generator — mirroring
+ * targets and supply the local generator - mirroring
  * cmExportBuildFileGenerator.
  */
 class cmBuildSbomGenerator
diff --git a/Source/cmCxxModuleMetadata.cxx b/Source/cmCxxModuleMetadata.cxx
index 869e4c5..322b5a1 100644
--- a/Source/cmCxxModuleMetadata.cxx
+++ b/Source/cmCxxModuleMetadata.cxx
@@ -464,13 +464,19 @@
 
   props.MetadataDir = cmSystemTools::GetFilenamePath(meta.MetadataFilePath);
 
+#ifndef _WIN32
+  props.BaseDirs.insert("/");
+#endif
+
   for (auto const& module : meta.Modules) {
     std::string sourcePath = props.NormalizePath(module.SourcePath);
     props.Sources.insert(sourcePath);
 
-    // Module metadata files can reference files in different roots,
-    // just use the immediate parent directory as a base directory
-    props.BaseDirs.insert(cmSystemTools::GetFilenamePath(sourcePath));
+#ifdef _WIN32
+    std::string root;
+    cmSystemTools::SplitPathRootComponent(sourcePath, &root);
+    props.BaseDirs.insert(root);
+#endif
 
     if (module.LocalArguments) {
       for (auto const& incDir : module.LocalArguments->IncludeDirectories) {
diff --git a/Source/cmCxxModuleUsageEffects.cxx b/Source/cmCxxModuleUsageEffects.cxx
index 9684309..1130c37 100644
--- a/Source/cmCxxModuleUsageEffects.cxx
+++ b/Source/cmCxxModuleUsageEffects.cxx
@@ -4,15 +4,16 @@
 
 #include <algorithm>
 #include <set>
+#include <utility>
 #include <vector>
 
 #include <cm/string_view>
+#include <cmext/string_view>
 
 #include "cmCryptoHash.h"
 #include "cmGeneratorTarget.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
-#include "cmRange.h"
 #include "cmStringAlgorithms.h"
 #include "cmTarget.h"
 #include "cmValue.h"
@@ -70,34 +71,6 @@
   return long_names.find(flag) != long_names.end();
 }
 
-bool UnknownFilter(cm::string_view)
-{
-  return false;
-}
-
-using FlagFilter = bool (*)(cm::string_view flag);
-
-FlagFilter GetFlagFilter(cmGeneratorTarget const* gt)
-{
-  static FlagFilter filter = nullptr;
-  if (filter) {
-    return filter;
-  }
-
-  cmValue frontendVariant =
-    gt->Makefile->GetDefinition("CMAKE_CXX_COMPILER_FRONTEND_VARIANT");
-
-  if (frontendVariant == "GNU") {
-    filter = IsGNUWarning;
-  } else if (frontendVariant == "MSVC") {
-    filter = IsMSVCWarning;
-  } else {
-    filter = UnknownFilter;
-  }
-
-  return filter;
-}
-
 void AppendUsage(std::string& usageHashInput, std::string const& entry)
 {
   usageHashInput += entry;
@@ -121,28 +94,216 @@
 
   usageHashInput.push_back('\0');
 }
+
+enum class CompileOptionUsage
+{
+  Hash,
+  Ignore,
+  SavePreprocessor,
+};
+
+struct CompileOptionClassification
+{
+  CompileOptionClassification(
+    CompileOptionUsage usage = CompileOptionUsage::Hash,
+    bool saveFollowingArgument = false)
+    : Usage(usage)
+    , SaveFollowingArgument(saveFollowingArgument)
+  {
+  }
+
+  CompileOptionUsage Usage = CompileOptionUsage::Hash;
+  bool SaveFollowingArgument = false;
+};
+
+CompileOptionClassification SaveIfStartsWith(cm::string_view flag,
+                                             cm::string_view prefix)
+{
+  if (flag.rfind(prefix, 0) == 0) {
+    return { CompileOptionUsage::SavePreprocessor,
+             flag.size() == prefix.size() };
+  }
+
+  return {};
+}
+
+CompileOptionClassification ClassifyGNUCompileOption(cm::string_view flag)
+{
+  if (IsGNUWarning(flag)) {
+    return { CompileOptionUsage::Ignore, false };
+  }
+
+  if (flag.size() < 2 || flag.front() != '-') {
+    return {};
+  }
+
+  flag.remove_prefix(1);
+  switch (flag.front()) {
+    case 'D':
+    case 'I':
+    case 'U':
+      return { CompileOptionUsage::SavePreprocessor, flag.size() == 1 };
+    case 'i': {
+      CompileOptionClassification classification =
+        SaveIfStartsWith(flag, "isystem"_s);
+      if (classification.Usage != CompileOptionUsage::Hash) {
+        return classification;
+      }
+    }
+      {
+        CompileOptionClassification classification =
+          SaveIfStartsWith(flag, "iquote"_s);
+        if (classification.Usage != CompileOptionUsage::Hash) {
+          return classification;
+        }
+      }
+      {
+        CompileOptionClassification classification =
+          SaveIfStartsWith(flag, "idirafter"_s);
+        if (classification.Usage != CompileOptionUsage::Hash) {
+          return classification;
+        }
+      }
+      {
+        CompileOptionClassification classification =
+          SaveIfStartsWith(flag, "include"_s);
+        if (classification.Usage != CompileOptionUsage::Hash) {
+          return classification;
+        }
+      }
+      {
+        CompileOptionClassification classification =
+          SaveIfStartsWith(flag, "imacros"_s);
+        if (classification.Usage != CompileOptionUsage::Hash) {
+          return classification;
+        }
+      }
+      break;
+    case '-':
+      flag.remove_prefix(1);
+      return SaveIfStartsWith(flag, "embed-dir"_s);
+    default:
+      break;
+  }
+
+  return {};
+}
+
+CompileOptionClassification ClassifyMSVCCompileOption(cm::string_view flag)
+{
+  if (IsMSVCWarning(flag)) {
+    return { CompileOptionUsage::Ignore, false };
+  }
+
+  if (flag.size() < 2 || (flag.front() != '/' && flag.front() != '-')) {
+    return {};
+  }
+
+  flag.remove_prefix(1);
+  switch (flag.front()) {
+    case 'D':
+    case 'I':
+    case 'U':
+      return { CompileOptionUsage::SavePreprocessor, flag.size() == 1 };
+    default:
+      break;
+  }
+
+  return {};
+}
+
+CompileOptionClassification ClassifyUnknownCompileOption(cm::string_view flag)
+{
+  static_cast<void>(flag);
+  return {};
+}
+
+using CompileOptionClassifier =
+  CompileOptionClassification (*)(cm::string_view flag);
+
+CompileOptionClassifier GetCompileOptionClassifier(cmGeneratorTarget const* gt)
+{
+  static CompileOptionClassifier classifier = nullptr;
+  if (classifier) {
+    return classifier;
+  }
+
+  cmValue frontendVariant =
+    gt->Makefile->GetDefinition("CMAKE_CXX_COMPILER_FRONTEND_VARIANT");
+
+  if (frontendVariant == "GNU") {
+    classifier = ClassifyGNUCompileOption;
+  } else if (frontendVariant == "MSVC") {
+    classifier = ClassifyMSVCCompileOption;
+  } else {
+    classifier = ClassifyUnknownCompileOption;
+  }
+
+  return classifier;
+}
+
+struct SplitCompileOptionsResult
+{
+  std::vector<BT<std::string>> HashEntries;
+  std::vector<BT<std::string>> PreprocessorEntries;
+};
+
+template <typename Range>
+SplitCompileOptionsResult SplitCompileOptions(Range const& entries,
+                                              CompileOptionClassifier classify)
+{
+  SplitCompileOptionsResult result;
+
+  for (auto it = entries.begin(); it != entries.end(); ++it) {
+    BT<std::string> const& option = *it;
+    auto const classification = classify(option.Value);
+
+    switch (classification.Usage) {
+      case CompileOptionUsage::Ignore:
+        continue;
+      case CompileOptionUsage::SavePreprocessor:
+        result.PreprocessorEntries.push_back(option);
+        if (classification.SaveFollowingArgument) {
+          auto next = it;
+          ++next;
+          if (next != entries.end()) {
+            result.PreprocessorEntries.push_back(*next);
+            it = next;
+          }
+        }
+        continue;
+      case CompileOptionUsage::Hash:
+        break;
+    }
+
+    result.HashEntries.push_back(option);
+  }
+
+  return result;
+}
 }
 
 cmCxxModuleUsageEffects::cmCxxModuleUsageEffects(cmGeneratorTarget const* gt,
                                                  std::string const& config)
 {
   auto const* tgt = gt->Target;
-  auto const filter = GetFlagFilter(gt);
+  auto const classify = GetCompileOptionClassifier(gt);
 
   std::string usageHashInput;
   if (tgt->IsImported()) {
     AppendUsageEntries(usageHashInput,
                        tgt->GetImportedCxxModulesCompileFeaturesEntries());
-    AppendUsageEntries(
-      usageHashInput,
-      tgt->GetImportedCxxModulesCompileOptionsEntries().filter(
-        [&](const BT<std::string>& flag) { return !filter(flag.Value); }));
+    auto compileOptions = SplitCompileOptions(
+      tgt->GetImportedCxxModulesCompileOptionsEntries(), classify);
+    this->PreprocessorCompileOptions =
+      std::move(compileOptions.PreprocessorEntries);
+    AppendUsageEntries(usageHashInput, compileOptions.HashEntries);
   } else {
-    AppendUsageEntries(usageHashInput,
-                       cmMakeRange(gt->GetCompileOptions(config, "CXX"))
-                         .filter([&](const BT<std::string>& flag) {
-                           return !filter(flag.Value);
-                         }));
+    auto compileOptions =
+      SplitCompileOptions(gt->GetCompileOptions(config, "CXX"), classify);
+    this->PreprocessorCompileOptions =
+      std::move(compileOptions.PreprocessorEntries);
+    AppendUsageEntries(usageHashInput, compileOptions.HashEntries);
 
     cmValue langStd = gt->GetLanguageStandard("CXX", config);
     if (!langStd) {
@@ -167,3 +328,9 @@
 {
   return this->Hash;
 }
+
+std::vector<BT<std::string>> const&
+cmCxxModuleUsageEffects::GetPreprocessorCompileOptions() const
+{
+  return this->PreprocessorCompileOptions;
+}
diff --git a/Source/cmCxxModuleUsageEffects.h b/Source/cmCxxModuleUsageEffects.h
index 1fd190f..8b8c50f 100644
--- a/Source/cmCxxModuleUsageEffects.h
+++ b/Source/cmCxxModuleUsageEffects.h
@@ -5,6 +5,9 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <string>
+#include <vector>
+
+#include "cmListFileCache.h"
 
 class cmGeneratorTarget;
 
@@ -14,7 +17,9 @@
   cmCxxModuleUsageEffects(cmGeneratorTarget const* gt,
                           std::string const& config);
   std::string const& GetHash() const;
+  std::vector<BT<std::string>> const& GetPreprocessorCompileOptions() const;
 
 private:
   std::string Hash;
+  std::vector<BT<std::string>> PreprocessorCompileOptions;
 };
diff --git a/Source/cmExportInstallPackageInfoGenerator.cxx b/Source/cmExportInstallPackageInfoGenerator.cxx
index a892856..8f55bdc 100644
--- a/Source/cmExportInstallPackageInfoGenerator.cxx
+++ b/Source/cmExportInstallPackageInfoGenerator.cxx
@@ -120,14 +120,9 @@
     this->GenerateTargetFileSets(*component, gt, te);
   }
 
-  this->GeneratePackageRequires(root);
-
-  // Write the primary packing information file.
-  this->WritePackageInfo(root, os);
-
+  // Generate per-configuration files before the main file so that
+  // processing link-dependent targets populates package requirements.
   bool result = true;
-
-  // Generate an import file for each configuration.
   if (this->RequiresConfigFiles) {
     for (std::string const& c : this->Configurations) {
       if (!this->GenerateImportFileConfig(c)) {
@@ -136,6 +131,11 @@
     }
   }
 
+  this->GeneratePackageRequires(root);
+
+  // Write the primary packing information file.
+  this->WritePackageInfo(root, os);
+
   return result;
 }
 
diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx
index 64fc7d6..d86560c 100644
--- a/Source/cmFindProgramCommand.cxx
+++ b/Source/cmFindProgramCommand.cxx
@@ -312,7 +312,7 @@
     kCFAllocatorDefault, bundlePath.c_str(), kCFStringEncodingUTF8);
 
   // Make a CFURLRef from the CFString representation of the
-  // bundle’s path.
+  // bundle's path.
   CFURLRef bundleURL = CFURLCreateWithFileSystemPath(
     kCFAllocatorDefault, bundlePathCFS, kCFURLPOSIXPathStyle, true);
 
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 62af48f..0af9983 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -5565,6 +5565,13 @@
   // compile features and options.
   tgt->CopyUsageEffects(&bmiConsumer, config);
 
+  auto const& preprocessorCompileOptions =
+    this->GetCxxModuleUsageEffects(config).GetPreprocessorCompileOptions();
+  for (auto it = preprocessorCompileOptions.rbegin();
+       it != preprocessorCompileOptions.rend(); ++it) {
+    tgt->InsertCompileOption(*it, true);
+  }
+
   // Copy properties which don't effect consumer compatibility
   tgt->CopyCxxModulesEntries(model);
 
diff --git a/Source/cmList.cxx b/Source/cmList.cxx
index aa5be7a..c920418 100644
--- a/Source/cmList.cxx
+++ b/Source/cmList.cxx
@@ -856,7 +856,7 @@
   void Initialize(TransformSelector* /*selector*/,
                   std::vector<std::string> const& /*args*/) override
   {
-    // This overload must not be used for APPLY — it lacks cmMakefile context.
+    // This overload must not be used for APPLY - it lacks cmMakefile context.
     throw transform_error(
       "sub-command TRANSFORM, action APPLY requires cmMakefile context.");
   }
diff --git a/Source/cmSbomBuilder.h b/Source/cmSbomBuilder.h
index f092e3f..0a29699 100644
--- a/Source/cmSbomBuilder.h
+++ b/Source/cmSbomBuilder.h
@@ -88,7 +88,7 @@
    *  install leaves consult cmGlobalGenerator::FindInstallSbomInfo. */
   virtual SbomInfo FindSbomInfoFor(cmGeneratorTarget const* target) const = 0;
 
-  /** The set of targets the SBOM directly describes — derived from the
+  /** The set of targets the SBOM directly describes - derived from the
    *  associated export sets. */
   std::set<cmGeneratorTarget const*> CollectTargets() const;
 
diff --git a/Source/cmString.hxx b/Source/cmString.hxx
index f7dcb2b..16881ac 100644
--- a/Source/cmString.hxx
+++ b/Source/cmString.hxx
@@ -16,6 +16,8 @@
 #include <cm/string_view>
 #include <cmext/string_view>
 
+#include <cm3p/rapidhash.h>
+
 namespace cm {
 
 class String;
@@ -961,8 +963,8 @@
 
   result_type operator()(argument_type const& s) const noexcept
   {
-    result_type const h(std::hash<cm::string_view>{}(s.view()));
-    return h;
+    cm::string_view const v = s.view();
+    return static_cast<result_type>(rapidhash(v.data(), v.size()));
   }
 };
 }
diff --git a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
index 6660eaa..2076ab8 100644
--- a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
@@ -9,8 +9,6 @@
 
 set(RunCMake-check-file check.cmake)
 
-include("${RunCMake_SOURCE_DIR}/validate_schema.cmake")
-
 function(reset_cmake_presets_directory name)
   set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/${name}")
   file(REMOVE_RECURSE "${RunCMake_TEST_SOURCE_DIR}")
@@ -130,7 +128,9 @@
 # Test CMakePresets.json errors
 set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
 run_cmake_presets(NoCMakePresets)
+set(CMakePresets_SCHEMA_EXPECTED_RESULT 3)
 run_cmake_presets(Comment)
+run_cmake_presets(JSONParseError)
 set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
 run_cmake_presets(NoCommentValid)
 run_cmake_presets(CommentValid)
@@ -142,7 +142,6 @@
 run_cmake_presets(GraphvizValid)
 set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
 run_cmake_presets(GraphvizValidOldSchema)
-run_cmake_presets(JSONParseError)
 run_cmake_presets(InvalidRoot)
 run_cmake_presets(NoVersion)
 run_cmake_presets(InvalidVersion)
diff --git a/Tests/RunCMake/CMakePresets/check.cmake b/Tests/RunCMake/CMakePresets/check.cmake
index 03f96a9..aff071d 100644
--- a/Tests/RunCMake/CMakePresets/check.cmake
+++ b/Tests/RunCMake/CMakePresets/check.cmake
@@ -1,22 +1,40 @@
-if(Python_EXECUTABLE AND CMake_TEST_JSON_SCHEMA)
-  if(NOT CMakePresets_SCHEMA_EXPECTED_RESULT)
-    set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
-  endif()
-  if(EXISTS "${RunCMake_TEST_SOURCE_DIR}/CMakePresets.json")
-    validate_schema("${RunCMake_TEST_SOURCE_DIR}/CMakePresets.json" "${CMakePresets_SCHEMA_EXPECTED_RESULT}")
-  endif()
-
-  if(NOT CMakeUserPresets_SCHEMA_EXPECTED_RESULT)
-    set(CMakeUserPresets_SCHEMA_EXPECTED_RESULT 0)
-  endif()
-  if(EXISTS "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json")
-    validate_schema("${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json" "${CMakeUserPresets_SCHEMA_EXPECTED_RESULT}")
-  endif()
-
-  if(NOT CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS)
-    set(CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS "${_CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS}")
-  endif()
-  foreach(_f _r IN ZIP_LISTS _CMakePresets_EXTRA_FILES_OUT CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS)
-    validate_schema("${_f}" "${_r}")
-  endforeach()
+if(NOT (Python_EXECUTABLE AND CMake_TEST_JSON_SCHEMA))
+  return()
 endif()
+
+include("${RunCMake_SOURCE_DIR}/../validate_json_schema.cmake")
+
+if(NOT CMakePresets_SCHEMA_EXPECTED_RESULT)
+  set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
+endif()
+
+set(CMakePresets_JSON_SCHEMA "${RunCMake_SOURCE_DIR}/../../../Help/manual/presets/schema.json")
+
+if(EXISTS "${RunCMake_TEST_SOURCE_DIR}/CMakePresets.json")
+  validate_json_schema(
+    "${CMakePresets_JSON_SCHEMA}"
+    "${RunCMake_TEST_SOURCE_DIR}/CMakePresets.json"
+    EXPECTED_RESULT "${CMakePresets_SCHEMA_EXPECTED_RESULT}"
+  )
+endif()
+
+if(NOT CMakeUserPresets_SCHEMA_EXPECTED_RESULT)
+  set(CMakeUserPresets_SCHEMA_EXPECTED_RESULT 0)
+endif()
+if(EXISTS "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json")
+  validate_json_schema(
+    "${CMakePresets_JSON_SCHEMA}"
+    "${RunCMake_TEST_SOURCE_DIR}/CMakeUserPresets.json"
+    EXPECTED_RESULT "${CMakeUserPresets_SCHEMA_EXPECTED_RESULT}"
+  )
+endif()
+
+if(NOT CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS)
+  set(CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS "${_CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS}")
+endif()
+foreach(_f _r IN ZIP_LISTS _CMakePresets_EXTRA_FILES_OUT CMakePresets_EXTRA_FILES_SCHEMA_EXPECTED_RESULTS)
+  validate_json_schema(
+    "${CMakePresets_JSON_SCHEMA}" "${_f}"
+    EXPECTED_RESULT "${_r}"
+  )
+endforeach()
diff --git a/Tests/RunCMake/CMakePresets/validate_schema.cmake b/Tests/RunCMake/CMakePresets/validate_schema.cmake
deleted file mode 100644
index 8b4f0b6..0000000
--- a/Tests/RunCMake/CMakePresets/validate_schema.cmake
+++ /dev/null
@@ -1,17 +0,0 @@
-function(validate_schema file expected_result)
-  if (NOT CMakePresets_VALIDATE_SCRIPT_PATH)
-    set(CMakePresets_VALIDATE_SCRIPT_PATH "${RunCMake_SOURCE_DIR}/validate_schema.py")
-  endif()
-
-  execute_process(
-    COMMAND "${Python_EXECUTABLE}" "${CMakePresets_VALIDATE_SCRIPT_PATH}" "${file}"
-    RESULT_VARIABLE _result
-    ERROR_VARIABLE _error
-    )
-  if(NOT _result STREQUAL expected_result)
-    string(REPLACE "\n" "\n  " _error_p "${_error}")
-    string(APPEND RunCMake_TEST_FAILED "Expected result of validating ${file}: ${expected_result}\nActual result: ${_result}\nError:\n  ${_error_p}")
-  endif()
-
-  set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
-endfunction()
diff --git a/Tests/RunCMake/CMakePresets/validate_schema.py b/Tests/RunCMake/CMakePresets/validate_schema.py
deleted file mode 100644
index 2409095..0000000
--- a/Tests/RunCMake/CMakePresets/validate_schema.py
+++ /dev/null
@@ -1,20 +0,0 @@
-import json
-import jsonschema
-import os.path
-import sys
-
-
-with open(sys.argv[1], "r", encoding="utf-8-sig") as f:
-    contents = json.load(f)
-
-schema_file = os.path.join(
-        os.path.dirname(__file__),
-        "..", "..", "..", "Help", "manual", "presets", "schema.json")
-with open(schema_file, "r", encoding="utf-8") as f:
-    schema = json.load(f)
-
-try:
-    jsonschema.validate(contents, schema)
-except (jsonschema.ValidationError, jsonschema.SchemaError) as e:
-    sys.stderr.write(e.message)
-    sys.exit(1)
diff --git a/Tests/RunCMake/CMakePresetsBuild/check.cmake b/Tests/RunCMake/CMakePresetsBuild/check.cmake
index e79c4f1..88fe122 100644
--- a/Tests/RunCMake/CMakePresetsBuild/check.cmake
+++ b/Tests/RunCMake/CMakePresetsBuild/check.cmake
@@ -1,3 +1 @@
-set(CMakePresets_VALIDATE_SCRIPT_PATH "${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.py")
-include("${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.cmake")
 include("${RunCMake_SOURCE_DIR}/../CMakePresets/check.cmake")
diff --git a/Tests/RunCMake/CMakePresetsPackage/check.cmake b/Tests/RunCMake/CMakePresetsPackage/check.cmake
index e79c4f1..88fe122 100644
--- a/Tests/RunCMake/CMakePresetsPackage/check.cmake
+++ b/Tests/RunCMake/CMakePresetsPackage/check.cmake
@@ -1,3 +1 @@
-set(CMakePresets_VALIDATE_SCRIPT_PATH "${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.py")
-include("${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.cmake")
 include("${RunCMake_SOURCE_DIR}/../CMakePresets/check.cmake")
diff --git a/Tests/RunCMake/CMakePresetsTest/check.cmake b/Tests/RunCMake/CMakePresetsTest/check.cmake
index e79c4f1..88fe122 100644
--- a/Tests/RunCMake/CMakePresetsTest/check.cmake
+++ b/Tests/RunCMake/CMakePresetsTest/check.cmake
@@ -1,3 +1 @@
-set(CMakePresets_VALIDATE_SCRIPT_PATH "${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.py")
-include("${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.cmake")
 include("${RunCMake_SOURCE_DIR}/../CMakePresets/check.cmake")
diff --git a/Tests/RunCMake/CMakePresetsWorkflow/check.cmake b/Tests/RunCMake/CMakePresetsWorkflow/check.cmake
index e79c4f1..88fe122 100644
--- a/Tests/RunCMake/CMakePresetsWorkflow/check.cmake
+++ b/Tests/RunCMake/CMakePresetsWorkflow/check.cmake
@@ -1,3 +1 @@
-set(CMakePresets_VALIDATE_SCRIPT_PATH "${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.py")
-include("${RunCMake_SOURCE_DIR}/../CMakePresets/validate_schema.cmake")
 include("${RunCMake_SOURCE_DIR}/../CMakePresets/check.cmake")
diff --git a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
index 829cdd8..ed407b8 100644
--- a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
@@ -512,18 +512,9 @@
   file(WRITE "${json_file}" "${actual_stdout}")
   set(actual_stdout "" PARENT_SCOPE)
 
-  if(CMake_TEST_JSON_SCHEMA)
-    execute_process(
-      COMMAND ${Python_EXECUTABLE} "${RunCMake_SOURCE_DIR}/show-only_json_validate_schema.py" "${json_file}"
-      RESULT_VARIABLE result
-      OUTPUT_VARIABLE output
-      ERROR_VARIABLE output
-    )
-    if(NOT result STREQUAL 0)
-      string(REPLACE "\n" "\n  " output "${output}")
-      string(APPEND RunCMake_TEST_FAILED "Failed to validate version ${v} JSON schema for file: ${file}\nOutput:\n${output}\n")
-    endif()
-  endif()
+  include("${RunCMake_SOURCE_DIR}/../validate_json_schema.cmake")
+  set(schema_file "${RunCMake_SOURCE_DIR}/../../../Help/manual/ctest/show-only-schema.json")
+  validate_json_schema("${schema_file}" "${json_file}")
 
   execute_process(
     COMMAND ${Python_EXECUTABLE} "${RunCMake_SOURCE_DIR}/show-only_json-v${v}_check.py" "${json_file}"
diff --git a/Tests/RunCMake/CTestCommandLine/show-only_json_validate_schema.py b/Tests/RunCMake/CTestCommandLine/show-only_json_validate_schema.py
deleted file mode 100644
index e0a8347..0000000
--- a/Tests/RunCMake/CTestCommandLine/show-only_json_validate_schema.py
+++ /dev/null
@@ -1,16 +0,0 @@
-import json
-import jsonschema
-import os.path
-import sys
-
-
-with open(sys.argv[1], "r", encoding="utf-8-sig") as f:
-    contents = json.load(f)
-
-schema_file = os.path.join(
-    os.path.dirname(__file__),
-    "..", "..", "..", "Help", "manual", "ctest", "show-only-schema.json")
-with open(schema_file, "r", encoding="utf-8") as f:
-    schema = json.load(f)
-
-jsonschema.validate(contents, schema)
diff --git a/Tests/RunCMake/CXXModulesCompile/RunCMakeTest.cmake b/Tests/RunCMake/CXXModulesCompile/RunCMakeTest.cmake
index d37cdbe..becb546 100644
--- a/Tests/RunCMake/CXXModulesCompile/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CXXModulesCompile/RunCMakeTest.cmake
@@ -335,6 +335,7 @@
 
 # Tests which install BMIs
 if ("export_bmi" IN_LIST CMake_TEST_MODULE_COMPILATION)
+  run_cxx_module_test(exp-nested-dirs-build)
   run_cxx_module_test(exp-iface-no-props-build)
   run_cxx_module_test(exp-iface-build)
   run_cxx_module_test(exp-incdirs-build)
diff --git a/Tests/RunCMake/CXXModulesCompile/exp-nested-dirs-build/CMakeLists.txt b/Tests/RunCMake/CXXModulesCompile/exp-nested-dirs-build/CMakeLists.txt
new file mode 100644
index 0000000..12d1474
--- /dev/null
+++ b/Tests/RunCMake/CXXModulesCompile/exp-nested-dirs-build/CMakeLists.txt
@@ -0,0 +1,50 @@
+cmake_minimum_required(VERSION 3.24...3.28)
+project(cxx_modules_nested_dirs CXX)
+
+include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
+
+add_library(export_nested_dirs STATIC)
+target_sources(export_nested_dirs
+  PUBLIC
+    FILE_SET modules TYPE CXX_MODULES
+      BASE_DIRS
+        "${CMAKE_CURRENT_SOURCE_DIR}"
+      FILES
+        nested/alpha.cxx
+        nested/sub/beta.cxx
+  )
+target_compile_features(export_nested_dirs PUBLIC cxx_std_20)
+
+install(TARGETS export_nested_dirs
+  EXPORT CXXModules
+  FILE_SET modules DESTINATION "lib/cxx/miu")
+export(EXPORT CXXModules
+  NAMESPACE CXXModules::
+  FILE "${CMAKE_CURRENT_BINARY_DIR}/export_nested_dirs-targets.cmake"
+  CXX_MODULES_DIRECTORY "export_nested_dirs-cxx-modules")
+export(PACKAGE_INFO export_nested_dirs_cps
+  EXPORT CXXModules
+  CXX_MODULES_DIRECTORY "export_nested_dirs-cxx-modules-cps")
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_nested_dirs-config.cmake"
+  "include(\"\${CMAKE_CURRENT_LIST_DIR}/export_nested_dirs-targets.cmake\")
+set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
+")
+
+set(generator
+  -G "${CMAKE_GENERATOR}")
+if (CMAKE_GENERATOR_TOOLSET)
+  list(APPEND generator
+    -T "${CMAKE_GENERATOR_TOOLSET}")
+endif ()
+if (CMAKE_GENERATOR_PLATFORM)
+  list(APPEND generator
+    -A "${CMAKE_GENERATOR_PLATFORM}")
+endif ()
+
+add_test(NAME export_nested_dirs_build
+  COMMAND
+    "${CMAKE_COMMAND}"
+    "-DCMAKE_PREFIX_PATH=${CMAKE_CURRENT_BINARY_DIR}"
+    ${generator}
+    -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
+    -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModulesCompile/exp-nested-dirs-build/nested/alpha.cxx b/Tests/RunCMake/CXXModulesCompile/exp-nested-dirs-build/nested/alpha.cxx
new file mode 100644
index 0000000..d5c20c0
--- /dev/null
+++ b/Tests/RunCMake/CXXModulesCompile/exp-nested-dirs-build/nested/alpha.cxx
@@ -0,0 +1,6 @@
+export module nested_alpha;
+
+export int from_alpha()
+{
+  return 1;
+}
diff --git a/Tests/RunCMake/CXXModulesCompile/exp-nested-dirs-build/nested/sub/beta.cxx b/Tests/RunCMake/CXXModulesCompile/exp-nested-dirs-build/nested/sub/beta.cxx
new file mode 100644
index 0000000..fea3c24
--- /dev/null
+++ b/Tests/RunCMake/CXXModulesCompile/exp-nested-dirs-build/nested/sub/beta.cxx
@@ -0,0 +1,6 @@
+export module nested_sub_beta;
+
+export int from_beta()
+{
+  return 2;
+}
diff --git a/Tests/RunCMake/CXXModulesCompile/exp-nested-dirs-build/test/CMakeLists.txt b/Tests/RunCMake/CXXModulesCompile/exp-nested-dirs-build/test/CMakeLists.txt
new file mode 100644
index 0000000..47d693e
--- /dev/null
+++ b/Tests/RunCMake/CXXModulesCompile/exp-nested-dirs-build/test/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 3.28)
+project(cxx_modules_library NONE)
+
+find_package(export_nested_dirs REQUIRED)
+find_package(export_nested_dirs_cps REQUIRED)
diff --git a/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-all-multi.json b/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-all-multi.json
index 1136806..e835f6a 100644
--- a/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-all-multi.json
+++ b/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-all-multi.json
@@ -185,7 +185,7 @@
         }
       ],
       "visible-sets": [
-        "CXXModules__export_build_database@synth_1@<CONFIG>"
+        "CXXModules__export_build_database@synth_0@<CONFIG>"
       ]
     },
     {
@@ -251,7 +251,7 @@
         }
       ],
       "visible-sets": [
-        "CXXModules__export_build_database@synth_1@<CONFIG_OTHER>"
+        "CXXModules__export_build_database@synth_0@<CONFIG_OTHER>"
       ]
     },
     {
@@ -275,8 +275,10 @@
             "-Dfrom_cmake_cxx_flags",
             "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
             "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
             "-Dtarget_public_option",
+            "-Dtarget_interface_option",
             "-Ddep_interface_option",
             "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/.d\"",
             "REGEX:<BMI_ONLY_FLAG>",
@@ -299,8 +301,10 @@
             "-Dfrom_cmake_cxx_flags",
             "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
             "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
             "-Dtarget_public_option",
+            "-Dtarget_interface_option",
             "-Ddep_interface_option"
           ],
           "local-arguments": [
@@ -318,8 +322,10 @@
             "-Dfrom_cmake_cxx_flags",
             "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
             "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
             "-Dtarget_public_option",
+            "-Dtarget_interface_option",
             "-Ddep_interface_option"
           ],
           "private": false,
@@ -354,8 +360,10 @@
             "-Dfrom_cmake_cxx_flags",
             "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
             "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
             "-Dtarget_public_option",
+            "-Dtarget_interface_option",
             "-Ddep_interface_option",
             "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_OTHER_DIR>/.d\"",
             "REGEX:<BMI_ONLY_FLAG>",
@@ -378,172 +386,6 @@
             "-Dfrom_cmake_cxx_flags",
             "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
             "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "private": false,
-          "provides": {
-            "importable": "<IGNORE>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    },
-    {
-      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
-      "name": "CXXModules__export_build_database@synth_1@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Dtarget_interface_option",
-            "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_1.dir<CONFIG_DIR>/.d\"",
-            "REGEX:<BMI_ONLY_FLAG>",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_1.dir<CONFIG_DIR>/",
-            "REGEX:-[cv]",
-            "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Dtarget_interface_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Dtarget_interface_option",
-            "-Ddep_interface_option"
-          ],
-          "private": false,
-          "provides": {
-            "importable": "<IGNORE>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    },
-    {
-      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
-      "name": "CXXModules__export_build_database@synth_1@<CONFIG_OTHER>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Dtarget_interface_option",
-            "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_1.dir<CONFIG_OTHER_DIR>/.d\"",
-            "REGEX:<BMI_ONLY_FLAG>",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_1.dir<CONFIG_OTHER_DIR>/",
-            "REGEX:-[cv]",
-            "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
             "-Dfrom_compile_options",
             "-Dtarget_private_option",
             "-Dtarget_public_option",
diff --git a/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-all.json b/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-all.json
index 83cef79..1f50bfa 100644
--- a/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-all.json
+++ b/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-all.json
@@ -125,7 +125,7 @@
         }
       ],
       "visible-sets": [
-        "CXXModules__export_build_database@synth_1@<CONFIG>"
+        "CXXModules__export_build_database@synth_0@<CONFIG>"
       ]
     },
     {
@@ -149,93 +149,14 @@
             "-Dfrom_cmake_cxx_flags",
             "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
             "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/.d\"",
-            "REGEX:<BMI_ONLY_FLAG>",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/",
-            "REGEX:-[cv]",
-            "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "private": false,
-          "provides": {
-            "importable": "<IGNORE>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    },
-    {
-      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
-      "name": "CXXModules__export_build_database@synth_1@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
             "-Dfrom_compile_options",
             "-Dtarget_private_option",
             "-Dtarget_public_option",
             "-Dtarget_interface_option",
             "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_1.dir<CONFIG_DIR>/.d\"",
+            "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/.d\"",
             "REGEX:<BMI_ONLY_FLAG>",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_1.dir<CONFIG_DIR>/",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/",
             "REGEX:-[cv]",
             "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
           ],
diff --git a/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-config.json b/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-config.json
index 83cef79..1f50bfa 100644
--- a/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-config.json
+++ b/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-config.json
@@ -125,7 +125,7 @@
         }
       ],
       "visible-sets": [
-        "CXXModules__export_build_database@synth_1@<CONFIG>"
+        "CXXModules__export_build_database@synth_0@<CONFIG>"
       ]
     },
     {
@@ -149,93 +149,14 @@
             "-Dfrom_cmake_cxx_flags",
             "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
             "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/.d\"",
-            "REGEX:<BMI_ONLY_FLAG>",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/",
-            "REGEX:-[cv]",
-            "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "private": false,
-          "provides": {
-            "importable": "<IGNORE>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    },
-    {
-      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
-      "name": "CXXModules__export_build_database@synth_1@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
             "-Dfrom_compile_options",
             "-Dtarget_private_option",
             "-Dtarget_public_option",
             "-Dtarget_interface_option",
             "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_1.dir<CONFIG_DIR>/.d\"",
+            "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/.d\"",
             "REGEX:<BMI_ONLY_FLAG>",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_1.dir<CONFIG_DIR>/",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/",
             "REGEX:-[cv]",
             "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
           ],
diff --git a/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-cxx-config.json b/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-cxx-config.json
index 83cef79..1f50bfa 100644
--- a/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-cxx-config.json
+++ b/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-cxx-config.json
@@ -125,7 +125,7 @@
         }
       ],
       "visible-sets": [
-        "CXXModules__export_build_database@synth_1@<CONFIG>"
+        "CXXModules__export_build_database@synth_0@<CONFIG>"
       ]
     },
     {
@@ -149,93 +149,14 @@
             "-Dfrom_cmake_cxx_flags",
             "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
             "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/.d\"",
-            "REGEX:<BMI_ONLY_FLAG>",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/",
-            "REGEX:-[cv]",
-            "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "private": false,
-          "provides": {
-            "importable": "<IGNORE>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    },
-    {
-      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
-      "name": "CXXModules__export_build_database@synth_1@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
             "-Dfrom_compile_options",
             "-Dtarget_private_option",
             "-Dtarget_public_option",
             "-Dtarget_interface_option",
             "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_1.dir<CONFIG_DIR>/.d\"",
+            "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/.d\"",
             "REGEX:<BMI_ONLY_FLAG>",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_1.dir<CONFIG_DIR>/",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/",
             "REGEX:-[cv]",
             "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
           ],
diff --git a/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-cxx-multi.json b/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-cxx-multi.json
index 1136806..e835f6a 100644
--- a/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-cxx-multi.json
+++ b/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-cxx-multi.json
@@ -185,7 +185,7 @@
         }
       ],
       "visible-sets": [
-        "CXXModules__export_build_database@synth_1@<CONFIG>"
+        "CXXModules__export_build_database@synth_0@<CONFIG>"
       ]
     },
     {
@@ -251,7 +251,7 @@
         }
       ],
       "visible-sets": [
-        "CXXModules__export_build_database@synth_1@<CONFIG_OTHER>"
+        "CXXModules__export_build_database@synth_0@<CONFIG_OTHER>"
       ]
     },
     {
@@ -275,8 +275,10 @@
             "-Dfrom_cmake_cxx_flags",
             "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
             "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
             "-Dtarget_public_option",
+            "-Dtarget_interface_option",
             "-Ddep_interface_option",
             "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/.d\"",
             "REGEX:<BMI_ONLY_FLAG>",
@@ -299,8 +301,10 @@
             "-Dfrom_cmake_cxx_flags",
             "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
             "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
             "-Dtarget_public_option",
+            "-Dtarget_interface_option",
             "-Ddep_interface_option"
           ],
           "local-arguments": [
@@ -318,8 +322,10 @@
             "-Dfrom_cmake_cxx_flags",
             "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
             "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
             "-Dtarget_public_option",
+            "-Dtarget_interface_option",
             "-Ddep_interface_option"
           ],
           "private": false,
@@ -354,8 +360,10 @@
             "-Dfrom_cmake_cxx_flags",
             "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
             "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
+            "-Dfrom_compile_options",
+            "-Dtarget_private_option",
             "-Dtarget_public_option",
+            "-Dtarget_interface_option",
             "-Ddep_interface_option",
             "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_OTHER_DIR>/.d\"",
             "REGEX:<BMI_ONLY_FLAG>",
@@ -378,172 +386,6 @@
             "-Dfrom_cmake_cxx_flags",
             "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
             "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "private": false,
-          "provides": {
-            "importable": "<IGNORE>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    },
-    {
-      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
-      "name": "CXXModules__export_build_database@synth_1@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Dtarget_interface_option",
-            "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_1.dir<CONFIG_DIR>/.d\"",
-            "REGEX:<BMI_ONLY_FLAG>",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_1.dir<CONFIG_DIR>/",
-            "REGEX:-[cv]",
-            "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Dtarget_interface_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Dtarget_interface_option",
-            "-Ddep_interface_option"
-          ],
-          "private": false,
-          "provides": {
-            "importable": "<IGNORE>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    },
-    {
-      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
-      "name": "CXXModules__export_build_database@synth_1@<CONFIG_OTHER>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Dtarget_interface_option",
-            "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_1.dir<CONFIG_OTHER_DIR>/.d\"",
-            "REGEX:<BMI_ONLY_FLAG>",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_1.dir<CONFIG_OTHER_DIR>/",
-            "REGEX:-[cv]",
-            "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
             "-Dfrom_compile_options",
             "-Dtarget_private_option",
             "-Dtarget_public_option",
diff --git a/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-cxx.json b/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-cxx.json
index 83cef79..1f50bfa 100644
--- a/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-cxx.json
+++ b/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-cxx.json
@@ -125,7 +125,7 @@
         }
       ],
       "visible-sets": [
-        "CXXModules__export_build_database@synth_1@<CONFIG>"
+        "CXXModules__export_build_database@synth_0@<CONFIG>"
       ]
     },
     {
@@ -149,93 +149,14 @@
             "-Dfrom_cmake_cxx_flags",
             "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
             "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/.d\"",
-            "REGEX:<BMI_ONLY_FLAG>",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/",
-            "REGEX:-[cv]",
-            "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "private": false,
-          "provides": {
-            "importable": "<IGNORE>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    },
-    {
-      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
-      "name": "CXXModules__export_build_database@synth_1@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_interface_define",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_private_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_public_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/exp-builddb/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
             "-Dfrom_compile_options",
             "-Dtarget_private_option",
             "-Dtarget_public_option",
             "-Dtarget_interface_option",
             "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_1.dir<CONFIG_DIR>/.d\"",
+            "PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/.d\"",
             "REGEX:<BMI_ONLY_FLAG>",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_1.dir<CONFIG_DIR>/",
+            "PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_0.dir<CONFIG_DIR>/",
             "REGEX:-[cv]",
             "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
           ],
diff --git a/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-matching-target.json b/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-matching-target.json
index 6154715..e6d2629 100644
--- a/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-matching-target.json
+++ b/Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-matching-target.json
@@ -65,7 +65,7 @@
         }
       ],
       "visible-sets": [
-        "CXXModules__export_build_database@synth_1@<CONFIG>"
+        "CXXModules__export_build_database@synth_0@<CONFIG>"
       ]
     }
   ]
diff --git a/Tests/RunCMake/CXXModulesCompile/mixed-bmi-compatibility-build-check.cmake b/Tests/RunCMake/CXXModulesCompile/mixed-bmi-compatibility-build-check.cmake
index 810364d..8728c7a 100644
--- a/Tests/RunCMake/CXXModulesCompile/mixed-bmi-compatibility-build-check.cmake
+++ b/Tests/RunCMake/CXXModulesCompile/mixed-bmi-compatibility-build-check.cmake
@@ -1,8 +1,8 @@
-# Verify the build system reused the owning target BMI when compatible and
-# generated a synthetic target BMI only for the incompatible importer.
-set(expected_consumers consumer20 consumer23)
-set(linked_dir_keys "")
-set(linked_dir_names "")
+# Verify the build system reused the owning target BMI when compatible,
+# generated a shared synthetic target BMI for the incompatible importers,
+# and ignored preprocessor-only compile options in the BMI compatibility hash.
+set(expected_consumers consumer20 consumer23 consumer23flag)
+set(shared_synth_target_name "")
 
 if (DEFINED RunCMake_TEST_CONFIG)
   set(config_dir "${RunCMake_TEST_CONFIG}")
@@ -36,9 +36,10 @@
     set(expected_linked_tgt_regex "^importable\.dir$")
     set(expected_linked_tgt_desc "owning target dir for 'importable'")
     set(expected_linked_tgt_has_bmi 0)
-  elseif (consumer STREQUAL "consumer23")
+  elseif (consumer STREQUAL "consumer23" OR
+          consumer STREQUAL "consumer23flag")
     set(expected_linked_tgt_regex "^importable@synth_[A-Za-z0-9_]+\.dir$")
-    set(expected_linked_tgt_desc "synthetic target dir for 'importable'")
+    set(expected_linked_tgt_desc "shared synthetic target dir for 'importable'")
     set(expected_linked_tgt_has_bmi 1)
   else ()
     list(APPEND RunCMake_TEST_FAILED
@@ -97,33 +98,15 @@
     endif ()
   endif ()
 
-  if (linked_tgt_name MATCHES "^importable@synth_[A-Za-z0-9_]+\.dir$")
-    # Record the consumers of each synthetic dir to verify uniqueness.
-    string(REGEX REPLACE "[^A-Za-z0-9_]" "_" linked_dir_key "${linked_tgt_name}")
-    set(linked_dir_consumers_var "linked_dir_consumers_${linked_dir_key}")
-    if (NOT DEFINED ${linked_dir_consumers_var})
-      list(APPEND linked_dir_keys "${linked_dir_key}")
-      list(APPEND linked_dir_names "${linked_tgt_name}")
+  if (consumer STREQUAL "consumer23" OR consumer STREQUAL "consumer23flag")
+    if (shared_synth_target_name STREQUAL "")
+      set(shared_synth_target_name "${linked_tgt_name}")
+    elseif (NOT linked_tgt_name STREQUAL shared_synth_target_name)
+      list(APPEND RunCMake_TEST_FAILED
+        "Expected consumer23 and consumer23flag to share one synthetic target dir, but found '${shared_synth_target_name}' and '${linked_tgt_name}'")
     endif ()
-
-    list(APPEND ${linked_dir_consumers_var} ${consumer})
   endif ()
 
 endforeach ()
 
-# Verify each synthetic target is consumed exactly once.
-foreach (linked_dir_key IN LISTS linked_dir_keys)
-  set(consumers "${linked_dir_consumers_${linked_dir_key}}")
-  list(LENGTH consumers linked_dir_consumer_count)
-
-  if (linked_dir_consumer_count GREATER 1)
-    list(FIND linked_dir_keys ${linked_dir_key} linked_dir_index)
-    list(GET linked_dir_names ${linked_dir_index} linked_tgt_name)
-
-    string(JOIN ", " linked_dir_consumers_joined ${consumers})
-    list(APPEND RunCMake_TEST_FAILED
-      "Expected per-compatibility synthetic BMI generation, but '${linked_tgt_name}' is linked to by multiple targets: ${linked_dir_consumers_joined}")
-  endif ()
-endforeach ()
-
 string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")
diff --git a/Tests/RunCMake/CXXModulesCompile/mixed-bmi-compatibility/CMakeLists.txt b/Tests/RunCMake/CXXModulesCompile/mixed-bmi-compatibility/CMakeLists.txt
index 4af50c8..794c0de 100644
--- a/Tests/RunCMake/CXXModulesCompile/mixed-bmi-compatibility/CMakeLists.txt
+++ b/Tests/RunCMake/CXXModulesCompile/mixed-bmi-compatibility/CMakeLists.txt
@@ -8,6 +8,7 @@
   PUBLIC FILE_SET CXX_MODULES FILES importable.cxx)
 
 target_compile_features(importable PUBLIC cxx_std_20)
+target_compile_options(importable PRIVATE "-DIMPORTABLE_PRIVATE_DEFINE=1")
 
 add_executable(consumer20 consumer20.cxx)
 target_compile_features(consumer20 PRIVATE cxx_std_20)
@@ -17,5 +18,11 @@
 target_compile_features(consumer23 PRIVATE cxx_std_23)
 target_link_libraries(consumer23 PRIVATE importable)
 
+add_executable(consumer23flag consumer23.cxx)
+target_compile_features(consumer23flag PRIVATE cxx_std_23)
+target_compile_options(consumer23flag PRIVATE "-DCONSUMER23FLAG_ONLY=1")
+target_link_libraries(consumer23flag PRIVATE importable)
+
 add_test(NAME consumer20 COMMAND consumer20)
 add_test(NAME consumer23 COMMAND consumer23)
+add_test(NAME consumer23flag COMMAND consumer23flag)
diff --git a/Tests/RunCMake/CXXModulesCompile/mixed-bmi-compatibility/importable.cxx b/Tests/RunCMake/CXXModulesCompile/mixed-bmi-compatibility/importable.cxx
index 607680a..f2a7908 100644
--- a/Tests/RunCMake/CXXModulesCompile/mixed-bmi-compatibility/importable.cxx
+++ b/Tests/RunCMake/CXXModulesCompile/mixed-bmi-compatibility/importable.cxx
@@ -1,5 +1,9 @@
 export module importable;
 
+#ifndef IMPORTABLE_PRIVATE_DEFINE
+#  error "missing private compile option required for BMI generation"
+#endif
+
 export int from_import()
 {
   return 0;
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index 2c587d4..9dd39dc 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -14,16 +14,10 @@
     set(actual_stdout "" PARENT_SCOPE)
   endif()
 
-  execute_process(
-    COMMAND ${Python_EXECUTABLE} "${RunCMake_SOURCE_DIR}/version_json_validate_schema.py" "${json_file}"
-    RESULT_VARIABLE result
-    OUTPUT_VARIABLE output
-    ERROR_VARIABLE output
-  )
-  if(NOT result STREQUAL 0)
-    string(REPLACE "\n" "\n  " output "${output}")
-    string(APPEND RunCMake_TEST_FAILED "Failed to validate version ${v} JSON schema for file: ${json_file}\nOutput:\n${output}\n")
-  endif()
+  include("${RunCMake_SOURCE_DIR}/../validate_json_schema.cmake")
+  set(schema_file "${RunCMake_SOURCE_DIR}/../../../Help/manual/cmake/version-schema.json")
+  validate_json_schema("${schema_file}" "${json_file}")
+
   return(PROPAGATE RunCMake_TEST_FAILED)
 endfunction()
 
diff --git a/Tests/RunCMake/CommandLine/version_json_validate_schema.py b/Tests/RunCMake/CommandLine/version_json_validate_schema.py
deleted file mode 100644
index 53c4bf9..0000000
--- a/Tests/RunCMake/CommandLine/version_json_validate_schema.py
+++ /dev/null
@@ -1,16 +0,0 @@
-import json
-import jsonschema
-import os.path
-import sys
-
-
-with open(sys.argv[1], "r", encoding="utf-8-sig") as f:
-    contents = json.load(f)
-
-schema_file = os.path.join(
-    os.path.dirname(__file__),
-    "..", "..", "..", "Help", "manual", "cmake", "version-schema.json")
-with open(schema_file, "r", encoding="utf-8") as f:
-    schema = json.load(f)
-
-jsonschema.validate(contents, schema)
diff --git a/Tests/RunCMake/ExportPackageInfo/PrivateLinkDependency-check.cmake b/Tests/RunCMake/ExportPackageInfo/PrivateLinkDependency-check.cmake
new file mode 100644
index 0000000..9b6ef52
--- /dev/null
+++ b/Tests/RunCMake/ExportPackageInfo/PrivateLinkDependency-check.cmake
@@ -0,0 +1,15 @@
+include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
+
+set(out_dir "${RunCMake_BINARY_DIR}/PrivateLinkDependency-build")
+
+file(READ "${out_dir}/cps/mylib/mylib.cps" content)
+
+# Private link dependency must appear in package requires
+expect_array("${content}" 1 "requires" "libdep" "components")
+expect_value("${content}" "libdep" "requires" "libdep" "components" 0)
+
+# And in per-config dyld_requires
+expect_array("${content}" 1
+  "components" "mylib" "configurations" "generic" "dyld_requires")
+expect_value("${content}" "libdep:libdep"
+  "components" "mylib" "configurations" "generic" "dyld_requires" 0)
diff --git a/Tests/RunCMake/ExportPackageInfo/PrivateLinkDependency.cmake b/Tests/RunCMake/ExportPackageInfo/PrivateLinkDependency.cmake
new file mode 100644
index 0000000..cb81e84
--- /dev/null
+++ b/Tests/RunCMake/ExportPackageInfo/PrivateLinkDependency.cmake
@@ -0,0 +1,20 @@
+project(PrivateLinkDependency CXX)
+
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+  set(CMAKE_CONFIGURATION_TYPES "generic" CACHE STRING "" FORCE)
+else()
+  set(CMAKE_BUILD_TYPE "generic" CACHE STRING "" FORCE)
+endif()
+
+find_package(
+  libdep REQUIRED CONFIG
+  NO_DEFAULT_PATH
+  PATHS ${CMAKE_CURRENT_LIST_DIR}
+)
+
+add_library(mylib SHARED foo.cxx)
+target_link_libraries(mylib PRIVATE libdep::libdep)
+
+install(TARGETS mylib EXPORT mylib DESTINATION .)
+export(PACKAGE_INFO mylib EXPORT mylib)
diff --git a/Tests/RunCMake/ExportPackageInfo/RunCMakeTest.cmake b/Tests/RunCMake/ExportPackageInfo/RunCMakeTest.cmake
index e2582cf..16242ca 100644
--- a/Tests/RunCMake/ExportPackageInfo/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/RunCMakeTest.cmake
@@ -29,6 +29,7 @@
 run_cmake(LowerCaseFile)
 run_cmake(Requirements)
 run_cmake(LinkDependentLibraries)
+run_cmake(PrivateLinkDependency)
 run_cmake(ExportSymbolicComponent)
 run_cmake(TargetTypes)
 run_cmake(DependsMultiple)
diff --git a/Tests/RunCMake/ExportPackageInfo/cps/libdep/libdep.cps b/Tests/RunCMake/ExportPackageInfo/cps/libdep/libdep.cps
new file mode 100644
index 0000000..7e9feac
--- /dev/null
+++ b/Tests/RunCMake/ExportPackageInfo/cps/libdep/libdep.cps
@@ -0,0 +1,12 @@
+{
+  "components" :
+  {
+    "libdep" :
+    {
+      "type" : "dylib"
+    }
+  },
+  "cps_path" : "@prefix@/cps/libdep",
+  "cps_version" : "0.14.1",
+  "name" : "libdep"
+}
diff --git a/Tests/RunCMake/ExportPackageInfo/cps/libdep/libdep@generic.cps b/Tests/RunCMake/ExportPackageInfo/cps/libdep/libdep@generic.cps
new file mode 100644
index 0000000..5e529ee
--- /dev/null
+++ b/Tests/RunCMake/ExportPackageInfo/cps/libdep/libdep@generic.cps
@@ -0,0 +1,12 @@
+{
+  "components" :
+  {
+    "libdep" :
+    {
+      "link_location" : "@prefix@/libdep.lib",
+      "location" : "@prefix@/libdep.dll"
+    }
+  },
+  "configuration" : "generic",
+  "name" : "libdep"
+}
diff --git a/Tests/RunCMake/FileAPI/RunCMakeTest.cmake b/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
index eda669c..e9fbf25 100644
--- a/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
+++ b/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
@@ -2,31 +2,7 @@
 
 cmake_policy(SET CMP0140 NEW)
 
-# Arguments after the first are the files to validate against the schema
-function(validate_fileapi_schema schema)
-  if(NOT ARGN)
-    # No files to validate against the schema
-    return()
-  endif()
-  list(JOIN ARGN "\n" file_list)
-  set(file_list_file ${RunCMake_TEST_BINARY_DIR}/check_file_list.txt)
-  file(WRITE "${file_list_file}" "${file_list}")
-  execute_process(
-    COMMAND ${Python_EXECUTABLE}
-      "${RunCMake_SOURCE_DIR}/fileapi_validate_schema.py"
-        "${file_list_file}"
-        "${schema}"
-    RESULT_VARIABLE result
-    OUTPUT_VARIABLE output
-    ERROR_VARIABLE output
-  )
-  if(NOT result STREQUAL 0)
-    string(REPLACE "\n" "\n  " output "${output}")
-    string(APPEND RunCMake_TEST_FAILED
-      "Failed to validate files against JSON schema: ${schema}\nOutput:\n${output}\n")
-  endif()
-  return(PROPAGATE RunCMake_TEST_FAILED)
-endfunction()
+include("${RunCMake_SOURCE_DIR}/../validate_json_schema.cmake")
 
 # Function called in *-check.cmake scripts to check api files.
 function(check_api expect)
@@ -73,9 +49,13 @@
       endif()
     endforeach()
     foreach(schema_type IN LISTS schema_types)
-      validate_fileapi_schema(
-        ${schema_dir}/schema_${schema_type}.json
-        ${schema_type_${schema_type}}
+      if("${schema_type_${schema_type}}" STREQUAL "")
+        # No files to validate against the schema
+        continue()
+      endif()
+      validate_json_schema(
+        "${schema_dir}/schema_${schema_type}.json"
+        "${schema_type_${schema_type}}"
       )
     endforeach()
   endif()
@@ -95,9 +75,9 @@
     REPLACE "^(.+)$" "${prefix}-\\1/query.json"
     OUTPUT_VARIABLE query_json_files
   )
-  validate_fileapi_schema(
-    ${schema_dir}/schema_stateful_query.json
-    ${query_json_files}
+  validate_json_schema(
+    "${schema_dir}/schema_stateful_query.json"
+    "${query_json_files}"
   )
   return(PROPAGATE RunCMake_TEST_FAILED)
 endfunction()
diff --git a/Tests/RunCMake/FileAPI/fileapi_validate_schema.py b/Tests/RunCMake/FileAPI/fileapi_validate_schema.py
deleted file mode 100644
index 8156a46..0000000
--- a/Tests/RunCMake/FileAPI/fileapi_validate_schema.py
+++ /dev/null
@@ -1,23 +0,0 @@
-import json
-import jsonschema
-import sys
-
-
-# First argument is a file containing the list of files to check
-with open(sys.argv[1], "r", encoding="utf-8") as file_list:
-    files_to_check = [line.strip() for line in file_list if line.strip()]
-
-# Second argument is the schema file
-with open(sys.argv[2], "r", encoding="utf-8-sig") as f:
-    schema = json.load(f)
-
-# Check each file against the schema
-for file_path in files_to_check:
-    try:
-        with open(file_path, "r", encoding="utf-8-sig") as f:
-            contents = json.load(f)
-        # The following raises an exception if validation fails
-        jsonschema.validate(contents, schema)
-    except Exception as e:
-        print(f"Failed to validate file {file_path}: {e}")
-        raise
diff --git a/Tests/RunCMake/InstallPackageInfo/PrivateLinkDependency-check.cmake b/Tests/RunCMake/InstallPackageInfo/PrivateLinkDependency-check.cmake
new file mode 100644
index 0000000..a074f0a
--- /dev/null
+++ b/Tests/RunCMake/InstallPackageInfo/PrivateLinkDependency-check.cmake
@@ -0,0 +1,14 @@
+include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
+
+set(out_dir "${RunCMake_BINARY_DIR}/PrivateLinkDependency-build/CMakeFiles/Export/510c5684a4a8a792eadfb55bc9744983")
+
+file(READ "${out_dir}/mylib.cps" content)
+
+# Private link dependency must appear in package requires
+expect_array("${content}" 1 "requires" "libdep" "components")
+expect_value("${content}" "libdep" "requires" "libdep" "components" 0)
+
+# And in per-config dyld_requires
+file(READ "${out_dir}/mylib@generic.cps" content)
+expect_array("${content}" 1 "components" "mylib" "dyld_requires")
+expect_value("${content}" "libdep:libdep" "components" "mylib" "dyld_requires" 0)
diff --git a/Tests/RunCMake/InstallPackageInfo/PrivateLinkDependency.cmake b/Tests/RunCMake/InstallPackageInfo/PrivateLinkDependency.cmake
new file mode 100644
index 0000000..c8626ef
--- /dev/null
+++ b/Tests/RunCMake/InstallPackageInfo/PrivateLinkDependency.cmake
@@ -0,0 +1,20 @@
+project(PrivateLinkDependency CXX)
+
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+  set(CMAKE_CONFIGURATION_TYPES "generic" CACHE STRING "" FORCE)
+else()
+  set(CMAKE_BUILD_TYPE "generic" CACHE STRING "" FORCE)
+endif()
+
+find_package(
+  libdep REQUIRED CONFIG
+  NO_DEFAULT_PATH
+  PATHS ${CMAKE_CURRENT_LIST_DIR}
+)
+
+add_library(mylib SHARED foo.cxx)
+target_link_libraries(mylib PRIVATE libdep::libdep)
+
+install(TARGETS mylib EXPORT mylib DESTINATION .)
+install(PACKAGE_INFO mylib DESTINATION cps EXPORT mylib)
diff --git a/Tests/RunCMake/InstallPackageInfo/RunCMakeTest.cmake b/Tests/RunCMake/InstallPackageInfo/RunCMakeTest.cmake
index 56ee883..c25c629 100644
--- a/Tests/RunCMake/InstallPackageInfo/RunCMakeTest.cmake
+++ b/Tests/RunCMake/InstallPackageInfo/RunCMakeTest.cmake
@@ -38,6 +38,7 @@
 run_cmake(MinimalVersion)
 run_cmake(LowerCaseFile)
 run_cmake(Requirements)
+run_cmake(PrivateLinkDependency)
 run_cmake(TargetTypes)
 run_cmake(DependsMultiple)
 run_cmake(DependsMultipleNotInstalled)
diff --git a/Tests/RunCMake/InstallPackageInfo/cps/libdep/libdep.cps b/Tests/RunCMake/InstallPackageInfo/cps/libdep/libdep.cps
new file mode 100644
index 0000000..7e9feac
--- /dev/null
+++ b/Tests/RunCMake/InstallPackageInfo/cps/libdep/libdep.cps
@@ -0,0 +1,12 @@
+{
+  "components" :
+  {
+    "libdep" :
+    {
+      "type" : "dylib"
+    }
+  },
+  "cps_path" : "@prefix@/cps/libdep",
+  "cps_version" : "0.14.1",
+  "name" : "libdep"
+}
diff --git a/Tests/RunCMake/InstallPackageInfo/cps/libdep/libdep@generic.cps b/Tests/RunCMake/InstallPackageInfo/cps/libdep/libdep@generic.cps
new file mode 100644
index 0000000..5e529ee
--- /dev/null
+++ b/Tests/RunCMake/InstallPackageInfo/cps/libdep/libdep@generic.cps
@@ -0,0 +1,12 @@
+{
+  "components" :
+  {
+    "libdep" :
+    {
+      "link_location" : "@prefix@/libdep.lib",
+      "location" : "@prefix@/libdep.dll"
+    }
+  },
+  "configuration" : "generic",
+  "name" : "libdep"
+}
diff --git a/Tests/RunCMake/Instrumentation/check-query-dir.cmake b/Tests/RunCMake/Instrumentation/check-query-dir.cmake
index b320479..38bbfbb 100644
--- a/Tests/RunCMake/Instrumentation/check-query-dir.cmake
+++ b/Tests/RunCMake/Instrumentation/check-query-dir.cmake
@@ -1,13 +1,14 @@
 include(${CMAKE_CURRENT_LIST_DIR}/verify-snippet.cmake)
 include(${CMAKE_CURRENT_LIST_DIR}/json.cmake)
-include(${CMAKE_CURRENT_LIST_DIR}/validate_schema.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/../validate_json_schema.cmake)
+
+set(schema_file "${CMAKE_CURRENT_LIST_DIR}/../../../Help/manual/instrumentation/query-v1-schema.json")
 
 file(GLOB_RECURSE queries LIST_DIRECTORIES false ${v1}/query/*)
 foreach(query ${queries})
-  validate_schema(
-    "${query}"
-    "${CMAKE_CURRENT_LIST_DIR}/../../../Help/manual/instrumentation/query-v1-schema.json"
-    "${schema_validate_result}"
+  validate_json_schema(
+    "${schema_file}" "${query}"
+    EXPECTED_RESULT "${schema_validate_result}"
   )
   if (RunCMake_TEST_FAILED)
     add_error("${RunCMake_TEST_FAILED}")
diff --git a/Tests/RunCMake/Instrumentation/hook.cmake b/Tests/RunCMake/Instrumentation/hook.cmake
index c456f20..89f2bbb 100644
--- a/Tests/RunCMake/Instrumentation/hook.cmake
+++ b/Tests/RunCMake/Instrumentation/hook.cmake
@@ -1,7 +1,7 @@
 cmake_minimum_required(VERSION 3.30)
 
 include(${CMAKE_CURRENT_LIST_DIR}/json.cmake)
-include(${CMAKE_CURRENT_LIST_DIR}/validate_schema.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/../validate_json_schema.cmake)
 include(${CMAKE_CURRENT_LIST_DIR}/verify-snippet.cmake)
 include(${CMAKE_CURRENT_LIST_DIR}/verify-trace.cmake)
 
@@ -53,12 +53,8 @@
   return(PROPAGATE ERROR_MESSAGE)
 endfunction()
 
-validate_schema(
-  "${index}"
-  "${CMAKE_CURRENT_LIST_DIR}/../../../Help/manual/instrumentation/index-v1-schema.json"
-  # We expect to always generate valid index files.
-  0
-)
+set(index_schema "${CMAKE_CURRENT_LIST_DIR}/../../../Help/manual/instrumentation/index-v1-schema.json")
+validate_json_schema("${index_schema}" "${index}")
 if (RunCMake_TEST_FAILED)
   add_error("${RunCMake_TEST_FAILED}")
   unset(RunCMake_TEST_FAILED)
diff --git a/Tests/RunCMake/Instrumentation/validate_schema.cmake b/Tests/RunCMake/Instrumentation/validate_schema.cmake
deleted file mode 100644
index 6fc49b7..0000000
--- a/Tests/RunCMake/Instrumentation/validate_schema.cmake
+++ /dev/null
@@ -1,15 +0,0 @@
-function(validate_schema json_file schema_file expected_result)
-  if (Python_EXECUTABLE AND CMake_TEST_JSON_SCHEMA)
-    execute_process(
-      COMMAND ${Python_EXECUTABLE} "${CMAKE_CURRENT_LIST_DIR}/validate_schema.py" "${json_file}" "${schema_file}"
-      RESULT_VARIABLE result
-      OUTPUT_VARIABLE output
-      ERROR_VARIABLE output
-    )
-    if(NOT result MATCHES ${expected_result})
-      string(REPLACE "\n" "\n  " output "${output}")
-      string(APPEND RunCMake_TEST_FAILED "Failed to validate version JSON schema for file: ${json_file}\nOutput:\n${output}\nResult: ${result}\nExpected: ${expected_result}")
-    endif()
-    return(PROPAGATE RunCMake_TEST_FAILED)
-  endif()
-endfunction()
diff --git a/Tests/RunCMake/Instrumentation/validate_schema.py b/Tests/RunCMake/Instrumentation/validate_schema.py
deleted file mode 100644
index ffcb2a5..0000000
--- a/Tests/RunCMake/Instrumentation/validate_schema.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import json
-import jsonschema
-import sys
-
-with open(sys.argv[1], "r", encoding="utf-8-sig") as f:
-    contents = json.load(f)
-
-with open(sys.argv[2], "r", encoding="utf-8") as f:
-    schema = json.load(f)
-
-try:
-    jsonschema.validate(contents, schema)
-except jsonschema.ValidationError as e:
-    print(e)
-    sys.exit(1)
diff --git a/Tests/RunCMake/Instrumentation/verify-snippet.cmake b/Tests/RunCMake/Instrumentation/verify-snippet.cmake
index 839fda1..fe89acb 100644
--- a/Tests/RunCMake/Instrumentation/verify-snippet.cmake
+++ b/Tests/RunCMake/Instrumentation/verify-snippet.cmake
@@ -2,7 +2,7 @@
 include_guard()
 
 include(${CMAKE_CURRENT_LIST_DIR}/json.cmake)
-include(${CMAKE_CURRENT_LIST_DIR}/validate_schema.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/../validate_json_schema.cmake)
 
 function(snippet_has_fields snippet contents)
   get_filename_component(filename "${snippet}" NAME)
@@ -111,12 +111,8 @@
     json_error("${snippet}" "Role \"${role}\" doesn't match snippet filename")
   endif()
 
-  validate_schema(
-    "${snippet}"
-    "${CMAKE_CURRENT_LIST_DIR}/../../../Help/manual/instrumentation/snippet-v1-schema.json"
-    # We expect to always generate valid snippet files.
-    0
-  )
+  set(snippet_schema "${CMAKE_CURRENT_LIST_DIR}/../../../Help/manual/instrumentation/snippet-v1-schema.json")
+  validate_json_schema("${snippet_schema}" "${snippet}")
   if (RunCMake_TEST_FAILED)
     add_error("${RunCMake_TEST_FAILED}")
   endif()
diff --git a/Tests/RunCMake/validate_json_schema.cmake b/Tests/RunCMake/validate_json_schema.cmake
new file mode 100644
index 0000000..6c3a393
--- /dev/null
+++ b/Tests/RunCMake/validate_json_schema.cmake
@@ -0,0 +1,35 @@
+cmake_policy(SET CMP0140 NEW)
+
+function(validate_json_schema schema_file input_files)
+  if (NOT(Python_EXECUTABLE AND CMake_TEST_JSON_SCHEMA))
+    return()
+  endif()
+
+  cmake_parse_arguments(ARG_VS "" "EXPECTED_RESULT" "" ${ARGN})
+
+  if(NOT ARG_VS_EXPECTED_RESULT)
+    set(ARG_VS_EXPECTED_RESULT 0)
+  endif()
+
+  set(_validate_py "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/validate_json_schema.py")
+  cmake_path(SET _schema NORMALIZE "${schema_file}")
+  set(_inputs)
+  foreach(_input IN LISTS input_files)
+    cmake_path(SET _input NORMALIZE "${_input}")
+    list(APPEND _inputs "${_input}")
+  endforeach()
+
+  execute_process(
+    COMMAND
+      "${Python_EXECUTABLE}" "${_validate_py}" "${_schema}"
+      "--input-files" ${_inputs}
+      # Include "--verbose" here for local debugging as needed.
+    RESULT_VARIABLE result
+    ERROR_VARIABLE error
+  )
+  if(NOT result MATCHES "${ARG_VS_EXPECTED_RESULT}")
+    string(REPLACE "\n" "\n  " error "${error}")
+    string(APPEND RunCMake_TEST_FAILED "Failed to validate version JSON schema for file: ${json_file}\nOutput:\n${error}\nResult: ${result}\nExpected: ${ARG_VS_EXPECTED_RESULT}")
+  endif()
+  return(PROPAGATE RunCMake_TEST_FAILED)
+endfunction()
diff --git a/Tests/RunCMake/validate_json_schema.py b/Tests/RunCMake/validate_json_schema.py
new file mode 100644
index 0000000..7cbad65
--- /dev/null
+++ b/Tests/RunCMake/validate_json_schema.py
@@ -0,0 +1,54 @@
+import argparse
+import json
+import pathlib
+import sys
+
+import jsonschema
+
+
+def main(argv=None) -> int:
+    parser = argparse.ArgumentParser(description="Validate CMake JSON schemas")
+    parser.add_argument(
+        "schema",
+        type=pathlib.Path,
+        help="the path to the schema file",
+    )
+    parser.add_argument(
+        "--input-files",
+        nargs="+",
+        type=pathlib.Path,
+        help="the path to an input file to validate",
+    )
+    parser.add_argument(
+        "-v",
+        "--verbose",
+        action="store_true",
+        help="enable verbose output",
+    )
+    args = parser.parse_args(argv)
+
+    with open(args.schema, "r", encoding="utf-8") as f:
+        schema = json.load(f)
+
+    for file in args.input_files:
+        try:
+            with open(file, "r", encoding="utf-8-sig") as f:
+                contents = json.load(f)
+            jsonschema.validate(contents, schema)
+        except jsonschema.ValidationError as e:
+            message = str(e) if args.verbose else str(e.message)
+            print(f"Failed to validate file {file}: {message}", file=sys.stderr)
+            return 1
+        except jsonschema.SchemaError as e:
+            message = str(e) if args.verbose else str(e.message)
+            print(f"Failed to validate schema: {message}", file=sys.stderr)
+            return 2
+        except Exception as e:
+            print(f"Unknown exception: {e}", file=sys.stderr)
+            return 3
+
+    return 0
+
+
+if __name__ == "__main__":
+    sys.exit(main(sys.argv[1:]))
diff --git a/Utilities/Scripts/update-rapidhash.bash b/Utilities/Scripts/update-rapidhash.bash
new file mode 100755
index 0000000..59a4a3a
--- /dev/null
+++ b/Utilities/Scripts/update-rapidhash.bash
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+shopt -s dotglob
+
+readonly name="rapidhash"
+readonly ownership="rapidhash upstream <kwrobot@kitware.com>"
+readonly subtree="Utilities/cmrapidhash"
+readonly repo="https://github.com/Nicoshev/rapidhash.git"
+readonly tag="rapidhash_v3"
+readonly shortlog=false
+readonly exact_tree_match=false
+readonly paths="
+  LICENSE
+  rapidhash.h
+"
+
+extract_source () {
+    git_archive
+    pushd "${extractdir}/${name}-reduced"
+    echo "* -whitespace" > .gitattributes
+    fromdos rapidhash.h
+    chmod a-x rapidhash.h
+    popd
+}
+
+. "${BASH_SOURCE%/*}/update-third-party.bash"
diff --git a/Utilities/cm3p/rapidhash.h b/Utilities/cm3p/rapidhash.h
new file mode 100644
index 0000000..99356d4
--- /dev/null
+++ b/Utilities/cm3p/rapidhash.h
@@ -0,0 +1,6 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#pragma once
+
+/* Use the rapidhash library bundled with CMake.  */
+#include <cmrapidhash/rapidhash.h> // IWYU pragma: export
diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt
index 625193b..428d9b5 100644
--- a/Utilities/cmcurl/CMakeLists.txt
+++ b/Utilities/cmcurl/CMakeLists.txt
@@ -88,7 +88,6 @@
 set(ENABLE_UNICODE ON)
 set(ENABLE_UNIX_SOCKETS OFF CACHE INTERNAL "No curl Unix domain sockets support")
 set(HAVE_ATOMIC 0)
-set(HAVE_BORINGSSL 0) # we do not need this info
 set(HAVE_RECV 1)
 set(HAVE_SEND 1)
 set(HAVE_STDATOMIC_H 0)
diff --git a/Utilities/cmrapidhash/.gitattributes b/Utilities/cmrapidhash/.gitattributes
new file mode 100644
index 0000000..562b12e
--- /dev/null
+++ b/Utilities/cmrapidhash/.gitattributes
@@ -0,0 +1 @@
+* -whitespace
diff --git a/Utilities/cmrapidhash/CMakeLists.txt b/Utilities/cmrapidhash/CMakeLists.txt
new file mode 100644
index 0000000..4c12831
--- /dev/null
+++ b/Utilities/cmrapidhash/CMakeLists.txt
@@ -0,0 +1,6 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+# rapidhash is a header-only library, so there is no library target to build.
+
+install(FILES LICENSE DESTINATION ${CMake_INSTALL_DOC_DIR}/cmrapidhash)
diff --git a/Utilities/cmrapidhash/LICENSE b/Utilities/cmrapidhash/LICENSE
new file mode 100644
index 0000000..67fe15f
--- /dev/null
+++ b/Utilities/cmrapidhash/LICENSE
@@ -0,0 +1,19 @@
+Copyright 2025 Nicolas De Carli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Utilities/cmrapidhash/rapidhash.h b/Utilities/cmrapidhash/rapidhash.h
new file mode 100644
index 0000000..b71c4e5
--- /dev/null
+++ b/Utilities/cmrapidhash/rapidhash.h
@@ -0,0 +1,574 @@
+/*
+ * rapidhash V3 - Very fast, high quality, platform-independent hashing algorithm.
+ *
+ * Based on 'wyhash', by Wang Yi <godspeed_china@yeah.net>
+ * 
+ * Copyright (C) 2025 Nicolas De Carli
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * You can contact the author at:
+ *   - rapidhash source repository: https://github.com/Nicoshev/rapidhash
+ */
+
+/*
+ *  Includes.
+ */
+ #include <stdint.h>
+ #include <string.h>
+ #if defined(_MSC_VER)
+ # include <intrin.h>
+ # if defined(_M_X64) && !defined(_M_ARM64EC)
+ #   pragma intrinsic(_umul128)
+ # endif
+ #endif
+ 
+ /*
+  *  C/C++ macros.
+  */
+ 
+ #ifdef _MSC_VER
+ # define RAPIDHASH_ALWAYS_INLINE __forceinline
+ #elif defined(__GNUC__)
+ # define RAPIDHASH_ALWAYS_INLINE inline __attribute__((__always_inline__))
+ #else
+ # define RAPIDHASH_ALWAYS_INLINE inline
+ #endif
+ 
+ #ifdef __cplusplus
+ # define RAPIDHASH_NOEXCEPT noexcept
+ # define RAPIDHASH_CONSTEXPR constexpr
+ # ifndef RAPIDHASH_INLINE
+ #   define RAPIDHASH_INLINE RAPIDHASH_ALWAYS_INLINE
+ # endif
+ # if __cplusplus >= 201402L && ((defined(__GNUC__) && __GNUC__ > 5) || defined(__INTEL_COMPILER) || defined(__clang__))
+ #   define RAPIDHASH_INLINE_CONSTEXPR RAPIDHASH_ALWAYS_INLINE constexpr
+ # else
+ #   define RAPIDHASH_INLINE_CONSTEXPR RAPIDHASH_ALWAYS_INLINE
+ # endif
+ #else
+ # define RAPIDHASH_NOEXCEPT
+ # define RAPIDHASH_CONSTEXPR static const
+ # ifndef RAPIDHASH_INLINE
+ #   define RAPIDHASH_INLINE static RAPIDHASH_ALWAYS_INLINE
+ # endif
+ # define RAPIDHASH_INLINE_CONSTEXPR RAPIDHASH_INLINE
+ #endif
+
+ /*
+  *  Unrolled macro.
+  *  Improves large input speed, but increases code size and worsens small input speed.
+  *
+  *  RAPIDHASH_COMPACT: Normal behavior.
+  *  RAPIDHASH_UNROLLED: 
+  *
+  */
+  #ifndef RAPIDHASH_UNROLLED
+  # define RAPIDHASH_COMPACT
+  #elif defined(RAPIDHASH_COMPACT)
+  # error "cannot define RAPIDHASH_COMPACT and RAPIDHASH_UNROLLED simultaneously."
+  #endif
+ 
+ /*
+  *  Protection macro, alters behaviour of rapid_mum multiplication function.
+  *
+  *  RAPIDHASH_FAST: Normal behavior, max speed.
+  *  RAPIDHASH_PROTECTED: Extra protection against entropy loss.
+  */
+ #ifndef RAPIDHASH_PROTECTED
+ # define RAPIDHASH_FAST
+ #elif defined(RAPIDHASH_FAST)
+ # error "cannot define RAPIDHASH_PROTECTED and RAPIDHASH_FAST simultaneously."
+ #endif
+ 
+ /*
+  *  Likely and unlikely macros.
+  */
+ #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__)
+ # define _likely_(x)  __builtin_expect(x,1)
+ # define _unlikely_(x)  __builtin_expect(x,0)
+ #else
+ # define _likely_(x) (x)
+ # define _unlikely_(x) (x)
+ #endif
+ 
+ /*
+  *  Endianness macros.
+  */
+ #ifndef RAPIDHASH_LITTLE_ENDIAN
+ # if defined(_WIN32) || defined(__LITTLE_ENDIAN__) || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+ #   define RAPIDHASH_LITTLE_ENDIAN
+ # elif defined(__BIG_ENDIAN__) || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+ #   define RAPIDHASH_BIG_ENDIAN
+ # else
+ #   warning "could not determine endianness! Falling back to little endian."
+ #   define RAPIDHASH_LITTLE_ENDIAN
+ # endif
+ #endif
+ 
+ /*
+  *  Default secret parameters.
+  */
+   RAPIDHASH_CONSTEXPR uint64_t rapid_secret[8] = {
+     0x2d358dccaa6c78a5ull,
+     0x8bb84b93962eacc9ull,
+     0x4b33a62ed433d4a3ull,
+     0x4d5a2da51de1aa47ull,
+     0xa0761d6478bd642full,
+     0xe7037ed1a0b428dbull,
+     0x90ed1765281c388cull,
+     0xaaaaaaaaaaaaaaaaull};
+ 
+ /*
+  *  64*64 -> 128bit multiply function.
+  *
+  *  @param A  Address of 64-bit number.
+  *  @param B  Address of 64-bit number.
+  *
+  *  Calculates 128-bit C = *A * *B.
+  *
+  *  When RAPIDHASH_FAST is defined:
+  *  Overwrites A contents with C's low 64 bits.
+  *  Overwrites B contents with C's high 64 bits.
+  *
+  *  When RAPIDHASH_PROTECTED is defined:
+  *  Xors and overwrites A contents with C's low 64 bits.
+  *  Xors and overwrites B contents with C's high 64 bits.
+  */
+ RAPIDHASH_INLINE_CONSTEXPR void rapid_mum(uint64_t *A, uint64_t *B) RAPIDHASH_NOEXCEPT {
+ #if defined(__SIZEOF_INT128__)
+   __uint128_t r=*A; r*=*B;
+   #ifdef RAPIDHASH_PROTECTED
+   *A^=(uint64_t)r; *B^=(uint64_t)(r>>64);
+   #else
+   *A=(uint64_t)r; *B=(uint64_t)(r>>64);
+   #endif
+ #elif defined(_MSC_VER) && (defined(_WIN64) || defined(_M_HYBRID_CHPE_ARM64))
+   #if defined(_M_X64)
+     #ifdef RAPIDHASH_PROTECTED
+     uint64_t a, b;
+     a=_umul128(*A,*B,&b);
+     *A^=a;  *B^=b;
+     #else
+     *A=_umul128(*A,*B,B);
+     #endif
+   #else
+     #ifdef RAPIDHASH_PROTECTED
+     uint64_t a, b;
+     b = __umulh(*A, *B);
+     a = *A * *B;
+     *A^=a;  *B^=b;
+     #else
+     uint64_t c = __umulh(*A, *B);
+     *A = *A * *B;
+     *B = c;
+     #endif
+   #endif
+ #else
+   uint64_t ha=*A>>32, hb=*B>>32, la=(uint32_t)*A, lb=(uint32_t)*B;
+   uint64_t rh=ha*hb, rm0=ha*lb, rm1=hb*la, rl=la*lb, t=rl+(rm0<<32), c=t<rl;
+   uint64_t lo=t+(rm1<<32); 
+   c+=lo<t; 
+   uint64_t hi=rh+(rm0>>32)+(rm1>>32)+c;
+   #ifdef RAPIDHASH_PROTECTED
+   *A^=lo;  *B^=hi;
+   #else
+   *A=lo;  *B=hi;
+   #endif
+ #endif
+ }
+ 
+ /*
+  *  Multiply and xor mix function.
+  *
+  *  @param A  64-bit number.
+  *  @param B  64-bit number.
+  *
+  *  Calculates 128-bit C = A * B.
+  *  Returns 64-bit xor between high and low 64 bits of C.
+  */
+  RAPIDHASH_INLINE_CONSTEXPR uint64_t rapid_mix(uint64_t A, uint64_t B) RAPIDHASH_NOEXCEPT { rapid_mum(&A,&B); return A^B; }
+ 
+ /*
+  *  Read functions.
+  */
+ #ifdef RAPIDHASH_LITTLE_ENDIAN
+ RAPIDHASH_INLINE uint64_t rapid_read64(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint64_t v; memcpy(&v, p, sizeof(uint64_t)); return v;}
+ RAPIDHASH_INLINE uint64_t rapid_read32(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint32_t v; memcpy(&v, p, sizeof(uint32_t)); return v;}
+ #elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__)
+ RAPIDHASH_INLINE uint64_t rapid_read64(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint64_t v; memcpy(&v, p, sizeof(uint64_t)); return __builtin_bswap64(v);}
+ RAPIDHASH_INLINE uint64_t rapid_read32(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint32_t v; memcpy(&v, p, sizeof(uint32_t)); return __builtin_bswap32(v);}
+ #elif defined(_MSC_VER)
+ RAPIDHASH_INLINE uint64_t rapid_read64(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint64_t v; memcpy(&v, p, sizeof(uint64_t)); return _byteswap_uint64(v);}
+ RAPIDHASH_INLINE uint64_t rapid_read32(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint32_t v; memcpy(&v, p, sizeof(uint32_t)); return _byteswap_ulong(v);}
+ #else
+ RAPIDHASH_INLINE uint64_t rapid_read64(const uint8_t *p) RAPIDHASH_NOEXCEPT {
+   uint64_t v; memcpy(&v, p, 8);
+   return (((v >> 56) & 0xff)| ((v >> 40) & 0xff00)| ((v >> 24) & 0xff0000)| ((v >>  8) & 0xff000000)| ((v <<  8) & 0xff00000000)| ((v << 24) & 0xff0000000000)| ((v << 40) & 0xff000000000000)| ((v << 56) & 0xff00000000000000));
+ }
+ RAPIDHASH_INLINE uint64_t rapid_read32(const uint8_t *p) RAPIDHASH_NOEXCEPT {
+   uint32_t v; memcpy(&v, p, 4);
+   return (((v >> 24) & 0xff)| ((v >>  8) & 0xff00)| ((v <<  8) & 0xff0000)| ((v << 24) & 0xff000000));
+ }
+ #endif
+ 
+ /*
+  *  rapidhash main function.
+  *
+  *  @param key     Buffer to be hashed.
+  *  @param len     @key length, in bytes.
+  *  @param seed    64-bit seed used to alter the hash result predictably.
+  *  @param secret  Triplet of 64-bit secrets used to alter hash result predictably.
+  *
+  *  Returns a 64-bit hash.
+  */
+RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_internal(const void *key, size_t len, uint64_t seed, const uint64_t* secret) RAPIDHASH_NOEXCEPT {
+  const uint8_t *p=(const uint8_t *)key;
+  seed ^= rapid_mix(seed ^ secret[2], secret[1]);
+  uint64_t a=0, b=0;
+  size_t i = len;
+  if (_likely_(len <= 16)) {
+    if (len >= 4) {
+      seed ^= len;
+      if (len >= 8) {
+        const uint8_t* plast = p + len - 8;
+        a = rapid_read64(p);
+        b = rapid_read64(plast);
+      } else {
+        const uint8_t* plast = p + len - 4;
+        a = rapid_read32(p);
+        b = rapid_read32(plast);
+      }
+    } else if (len > 0) {
+      a = (((uint64_t)p[0])<<45)|p[len-1];
+      b = p[len>>1];
+    } else
+      a = b = 0;
+  } else {
+    uint64_t see1 = seed, see2 = seed;
+    uint64_t see3 = seed, see4 = seed;
+    uint64_t see5 = seed, see6 = seed;
+#ifdef RAPIDHASH_COMPACT
+    if (i > 112) {
+      do {
+        seed = rapid_mix(rapid_read64(p) ^ secret[0], rapid_read64(p + 8) ^ seed);
+        see1 = rapid_mix(rapid_read64(p + 16) ^ secret[1], rapid_read64(p + 24) ^ see1);
+        see2 = rapid_mix(rapid_read64(p + 32) ^ secret[2], rapid_read64(p + 40) ^ see2);
+        see3 = rapid_mix(rapid_read64(p + 48) ^ secret[3], rapid_read64(p + 56) ^ see3);
+        see4 = rapid_mix(rapid_read64(p + 64) ^ secret[4], rapid_read64(p + 72) ^ see4);
+        see5 = rapid_mix(rapid_read64(p + 80) ^ secret[5], rapid_read64(p + 88) ^ see5);
+        see6 = rapid_mix(rapid_read64(p + 96) ^ secret[6], rapid_read64(p + 104) ^ see6);
+        p += 112;
+        i -= 112;
+      } while(i > 112);
+      seed ^= see1;
+      see2 ^= see3;
+      see4 ^= see5;
+      seed ^= see6;
+      see2 ^= see4;
+      seed ^= see2;
+    }
+#else 
+    if (i > 224) {
+      do {
+          seed = rapid_mix(rapid_read64(p) ^ secret[0], rapid_read64(p + 8) ^ seed);
+          see1 = rapid_mix(rapid_read64(p + 16) ^ secret[1], rapid_read64(p + 24) ^ see1);
+          see2 = rapid_mix(rapid_read64(p + 32) ^ secret[2], rapid_read64(p + 40) ^ see2);
+          see3 = rapid_mix(rapid_read64(p + 48) ^ secret[3], rapid_read64(p + 56) ^ see3);
+          see4 = rapid_mix(rapid_read64(p + 64) ^ secret[4], rapid_read64(p + 72) ^ see4);
+          see5 = rapid_mix(rapid_read64(p + 80) ^ secret[5], rapid_read64(p + 88) ^ see5);
+          see6 = rapid_mix(rapid_read64(p + 96) ^ secret[6], rapid_read64(p + 104) ^ see6);
+          seed = rapid_mix(rapid_read64(p + 112) ^ secret[0], rapid_read64(p + 120) ^ seed);
+          see1 = rapid_mix(rapid_read64(p + 128) ^ secret[1], rapid_read64(p + 136) ^ see1);
+          see2 = rapid_mix(rapid_read64(p + 144) ^ secret[2], rapid_read64(p + 152) ^ see2);
+          see3 = rapid_mix(rapid_read64(p + 160) ^ secret[3], rapid_read64(p + 168) ^ see3);
+          see4 = rapid_mix(rapid_read64(p + 176) ^ secret[4], rapid_read64(p + 184) ^ see4);
+          see5 = rapid_mix(rapid_read64(p + 192) ^ secret[5], rapid_read64(p + 200) ^ see5);
+          see6 = rapid_mix(rapid_read64(p + 208) ^ secret[6], rapid_read64(p + 216) ^ see6);
+          p += 224;
+          i -= 224;
+      } while (i > 224);
+    }
+    if (i > 112) {
+      seed = rapid_mix(rapid_read64(p) ^ secret[0], rapid_read64(p + 8) ^ seed);
+      see1 = rapid_mix(rapid_read64(p + 16) ^ secret[1], rapid_read64(p + 24) ^ see1);
+      see2 = rapid_mix(rapid_read64(p + 32) ^ secret[2], rapid_read64(p + 40) ^ see2);
+      see3 = rapid_mix(rapid_read64(p + 48) ^ secret[3], rapid_read64(p + 56) ^ see3);
+      see4 = rapid_mix(rapid_read64(p + 64) ^ secret[4], rapid_read64(p + 72) ^ see4);
+      see5 = rapid_mix(rapid_read64(p + 80) ^ secret[5], rapid_read64(p + 88) ^ see5);
+      see6 = rapid_mix(rapid_read64(p + 96) ^ secret[6], rapid_read64(p + 104) ^ see6);
+      p += 112;
+      i -= 112;
+    }
+    seed ^= see1;
+    see2 ^= see3;
+    see4 ^= see5;
+    seed ^= see6;
+    see2 ^= see4;
+    seed ^= see2;
+#endif
+    if (i > 16) {
+      seed = rapid_mix(rapid_read64(p) ^ secret[2], rapid_read64(p + 8) ^ seed);
+      if (i > 32) {
+          seed = rapid_mix(rapid_read64(p + 16) ^ secret[2], rapid_read64(p + 24) ^ seed);
+          if (i > 48) {
+              seed = rapid_mix(rapid_read64(p + 32) ^ secret[1], rapid_read64(p + 40) ^ seed);
+              if (i > 64) {
+                  seed = rapid_mix(rapid_read64(p + 48) ^ secret[1], rapid_read64(p + 56) ^ seed);
+                  if (i > 80) {
+                      seed = rapid_mix(rapid_read64(p + 64) ^ secret[2], rapid_read64(p + 72) ^ seed);
+                      if (i > 96) {
+                          seed = rapid_mix(rapid_read64(p + 80) ^ secret[1], rapid_read64(p + 88) ^ seed);
+                      }
+                  }
+              }
+          }
+      }
+    }
+    a=rapid_read64(p+i-16) ^ i;  b=rapid_read64(p+i-8);
+  }
+  a ^= secret[1];
+  b ^= seed;
+  rapid_mum(&a, &b);
+  return rapid_mix(a ^ secret[7], b ^ secret[1] ^ i);
+}
+
+ /*
+  *  rapidhashMicro main function.
+  *
+  *  @param key     Buffer to be hashed.
+  *  @param len     @key length, in bytes.
+  *  @param seed    64-bit seed used to alter the hash result predictably.
+  *  @param secret  Triplet of 64-bit secrets used to alter hash result predictably.
+  *
+  *  Returns a 64-bit hash.
+  */
+  RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashMicro_internal(const void *key, size_t len, uint64_t seed, const uint64_t* secret) RAPIDHASH_NOEXCEPT {
+    const uint8_t *p=(const uint8_t *)key;
+    seed ^= rapid_mix(seed ^ secret[2], secret[1]);
+    uint64_t a=0, b=0;
+    size_t i = len;
+    if (_likely_(len <= 16)) {
+      if (len >= 4) {
+        seed ^= len;
+        if (len >= 8) {
+          const uint8_t* plast = p + len - 8;
+          a = rapid_read64(p);
+          b = rapid_read64(plast);
+        } else {
+          const uint8_t* plast = p + len - 4;
+          a = rapid_read32(p);
+          b = rapid_read32(plast);
+        }
+      } else if (len > 0) {
+        a = (((uint64_t)p[0])<<45)|p[len-1];
+        b = p[len>>1];
+      } else
+        a = b = 0;
+    } else {
+      if (i > 80) {
+        uint64_t see1 = seed, see2 = seed;
+        uint64_t see3 = seed, see4 = seed;
+        do {
+          seed = rapid_mix(rapid_read64(p) ^ secret[0], rapid_read64(p + 8) ^ seed);
+          see1 = rapid_mix(rapid_read64(p + 16) ^ secret[1], rapid_read64(p + 24) ^ see1);
+          see2 = rapid_mix(rapid_read64(p + 32) ^ secret[2], rapid_read64(p + 40) ^ see2);
+          see3 = rapid_mix(rapid_read64(p + 48) ^ secret[3], rapid_read64(p + 56) ^ see3);
+          see4 = rapid_mix(rapid_read64(p + 64) ^ secret[4], rapid_read64(p + 72) ^ see4);
+          p += 80;
+          i -= 80;
+        } while(i > 80);
+        seed ^= see1;
+        see2 ^= see3;
+        seed ^= see4;
+        seed ^= see2;
+      }
+      if (i > 16) {
+        seed = rapid_mix(rapid_read64(p) ^ secret[2], rapid_read64(p + 8) ^ seed);
+        if (i > 32) {
+            seed = rapid_mix(rapid_read64(p + 16) ^ secret[2], rapid_read64(p + 24) ^ seed);
+            if (i > 48) {
+                seed = rapid_mix(rapid_read64(p + 32) ^ secret[1], rapid_read64(p + 40) ^ seed);
+                if (i > 64) {
+                    seed = rapid_mix(rapid_read64(p + 48) ^ secret[1], rapid_read64(p + 56) ^ seed);
+                }
+            }
+        }
+      }
+      a=rapid_read64(p+i-16) ^ i;  b=rapid_read64(p+i-8);
+    }
+    a ^= secret[1];
+    b ^= seed;
+    rapid_mum(&a, &b);
+    return rapid_mix(a ^ secret[7], b ^ secret[1] ^ i);
+  }
+
+  /*
+  *  rapidhashNano main function.
+  *
+  *  @param key     Buffer to be hashed.
+  *  @param len     @key length, in bytes.
+  *  @param seed    64-bit seed used to alter the hash result predictably.
+  *  @param secret  Triplet of 64-bit secrets used to alter hash result predictably.
+  *
+  *  Returns a 64-bit hash.
+  */
+  RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashNano_internal(const void *key, size_t len, uint64_t seed, const uint64_t* secret) RAPIDHASH_NOEXCEPT {
+    const uint8_t *p=(const uint8_t *)key;
+    seed ^= rapid_mix(seed ^ secret[2], secret[1]);
+    uint64_t a=0, b=0;
+    size_t i = len;
+    if (_likely_(len <= 16)) {
+      if (len >= 4) {
+        seed ^= len;
+        if (len >= 8) {
+          const uint8_t* plast = p + len - 8;
+          a = rapid_read64(p);
+          b = rapid_read64(plast);
+        } else {
+          const uint8_t* plast = p + len - 4;
+          a = rapid_read32(p);
+          b = rapid_read32(plast);
+        }
+      } else if (len > 0) {
+        a = (((uint64_t)p[0])<<45)|p[len-1];
+        b = p[len>>1];
+      } else
+        a = b = 0;
+    } else {
+      if (i > 48) {
+        uint64_t see1 = seed, see2 = seed;
+        do {
+          seed = rapid_mix(rapid_read64(p) ^ secret[0], rapid_read64(p + 8) ^ seed);
+          see1 = rapid_mix(rapid_read64(p + 16) ^ secret[1], rapid_read64(p + 24) ^ see1);
+          see2 = rapid_mix(rapid_read64(p + 32) ^ secret[2], rapid_read64(p + 40) ^ see2);
+          p += 48;
+          i -= 48;
+        } while(i > 48);
+        seed ^= see1;
+        seed ^= see2;
+      }
+      if (i > 16) {
+        seed = rapid_mix(rapid_read64(p) ^ secret[2], rapid_read64(p + 8) ^ seed);
+        if (i > 32) {
+            seed = rapid_mix(rapid_read64(p + 16) ^ secret[2], rapid_read64(p + 24) ^ seed);
+        }
+      }
+      a=rapid_read64(p+i-16) ^ i;  b=rapid_read64(p+i-8);
+    }
+    a ^= secret[1];
+    b ^= seed;
+    rapid_mum(&a, &b);
+    return rapid_mix(a ^ secret[7], b ^ secret[1] ^ i);
+  }
+ 
+/*
+ *  rapidhash seeded hash function.
+ *
+ *  @param key     Buffer to be hashed.
+ *  @param len     @key length, in bytes.
+ *  @param seed    64-bit seed used to alter the hash result predictably.
+ *
+ *  Calls rapidhash_internal using provided parameters and default secrets.
+ *
+ *  Returns a 64-bit hash.
+ */
+RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_withSeed(const void *key, size_t len, uint64_t seed) RAPIDHASH_NOEXCEPT {
+  return rapidhash_internal(key, len, seed, rapid_secret);
+}
+ 
+/*
+ *  rapidhash general purpose hash function.
+ *
+ *  @param key     Buffer to be hashed.
+ *  @param len     @key length, in bytes.
+ *
+ *  Calls rapidhash_withSeed using provided parameters and the default seed.
+ *
+ *  Returns a 64-bit hash.
+ */
+RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash(const void *key, size_t len) RAPIDHASH_NOEXCEPT {
+  return rapidhash_withSeed(key, len, 0);
+}
+
+/*
+ *  rapidhashMicro seeded hash function.
+ *
+ *  Designed for HPC and server applications, where cache misses make a noticeable performance detriment.
+ *  Clang-18+ compiles it to ~140 instructions without stack usage, both on x86-64 and aarch64.
+ *  Faster for sizes up to 512 bytes, just 15%-20% slower for inputs above 1kb.
+ *
+ *  @param key     Buffer to be hashed.
+ *  @param len     @key length, in bytes.
+ *  @param seed    64-bit seed used to alter the hash result predictably.
+ *
+ *  Calls rapidhash_internal using provided parameters and default secrets.
+ *
+ *  Returns a 64-bit hash.
+ */
+ RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashMicro_withSeed(const void *key, size_t len, uint64_t seed) RAPIDHASH_NOEXCEPT {
+  return rapidhashMicro_internal(key, len, seed, rapid_secret);
+}
+ 
+/*
+ *  rapidhashMicro hash function.
+ *
+ *  @param key     Buffer to be hashed.
+ *  @param len     @key length, in bytes.
+ *
+ *  Calls rapidhash_withSeed using provided parameters and the default seed.
+ *
+ *  Returns a 64-bit hash.
+ */
+RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashMicro(const void *key, size_t len) RAPIDHASH_NOEXCEPT {
+  return rapidhashMicro_withSeed(key, len, 0);
+}
+
+/*
+ *  rapidhashNano seeded hash function.
+ *
+ *  @param key     Buffer to be hashed.
+ *  @param len     @key length, in bytes.
+ *  @param seed    64-bit seed used to alter the hash result predictably.
+ *
+ *  Calls rapidhash_internal using provided parameters and default secrets.
+ *
+ *  Returns a 64-bit hash.
+ */
+ RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashNano_withSeed(const void *key, size_t len, uint64_t seed) RAPIDHASH_NOEXCEPT {
+  return rapidhashNano_internal(key, len, seed, rapid_secret);
+}
+ 
+/*
+ *  rapidhashNano hash function.
+ *
+ *  Designed for Mobile and embedded applications, where keeping a small code size is a top priority.
+ *  Clang-18+ compiles it to less than 100 instructions without stack usage, both on x86-64 and aarch64.
+ *  The fastest for sizes up to 48 bytes, but may be considerably slower for larger inputs.
+ *
+ *  @param key     Buffer to be hashed.
+ *  @param len     @key length, in bytes.
+ *
+ *  Calls rapidhash_withSeed using provided parameters and the default seed.
+ *
+ *  Returns a 64-bit hash.
+ */
+RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashNano(const void *key, size_t len) RAPIDHASH_NOEXCEPT {
+  return rapidhashNano_withSeed(key, len, 0);
+}
diff --git a/Utilities/std/cm/bits/string_view.cxx b/Utilities/std/cm/bits/string_view.cxx
index 4a18e2f..d89e964 100644
--- a/Utilities/std/cm/bits/string_view.cxx
+++ b/Utilities/std/cm/bits/string_view.cxx
@@ -9,7 +9,7 @@
 #  include <ostream>
 #  include <stdexcept>
 
-#  include <cm3p/kwiml/int.h>
+#  include <cm3p/rapidhash.h>
 
 namespace cm {
 
@@ -282,15 +282,7 @@
 std::hash<cm::string_view>::result_type std::hash<cm::string_view>::operator()(
   argument_type const& s) const noexcept
 {
-  // FNV-1a hash.
-  static KWIML_INT_uint64_t const fnv_offset_basis = 0xcbf29ce484222325;
-  static KWIML_INT_uint64_t const fnv_prime = 0x100000001b3;
-  KWIML_INT_uint64_t h = fnv_offset_basis;
-  for (char const& c : s) {
-    h = h ^ KWIML_INT_uint64_t(KWIML_INT_uint8_t(c));
-    h = h * fnv_prime;
-  }
-  return result_type(h);
+  return result_type(rapidhash(s.data(), s.size()));
 }
 #else
 // Avoid empty translation unit.