Merge branch 'release-4.2' into release-4.3
diff --git a/.git-remote-files b/.git-remote-files
new file mode 100644
index 0000000..ec5762d
--- /dev/null
+++ b/.git-remote-files
@@ -0,0 +1,5 @@
+[file "update-common.sh" from "https://gitlab.kitware.com/utils/git-import-third-party.git"]
+commit = 8f83cbcdac0af41574abfb632dfbe2c403948803
+branch = master
+target = Utilities/Scripts/update-third-party.bash
+comment = Core third party import logic
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index fc49cb8..289c6c6 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -31,7 +31,9 @@
 #   - a "base image"
 #   - a build script
 #   - tags for the jobs
-#   - rules for when to run the job
+#   - the `.rules` block
+#     - see `.gitlab/rules.yml` for variables jobs may set to control when the
+#       job is executed
 #
 # Additionally, jobs may also contain:
 #
@@ -56,9 +58,10 @@
         - .cmake_prep_source_linux
         - .linux_x86_64_tags
         - .cmake_release_artifacts
-        - .run_only_for_package
+        - .rules
     variables:
         CMAKE_CI_ARTIFACTS_NAME: "artifacts-source"
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
 
 p:doc-package:
     extends:
@@ -66,12 +69,17 @@
         - .cmake_prep_doc_linux
         - .linux_x86_64_tags
         - .cmake_doc_artifacts
-        - .run_only_for_package
+        - .rules
+    variables:
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
 
 u:source-package:
     extends:
         - .rsync_upload_package
-        - .run_only_for_package
+        - .rules
+    variables:
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
     needs:
         - p:source-package
 
@@ -79,20 +87,29 @@
     extends:
         - .cmake_version_update_linux
         - .linux_x86_64_tags
-        - .run_version_update
+        - .rules
+    variables:
+        CMAKE_CI_JOB_UPDATES_VERSION: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
 
 # Documentation builds
 
 b:cmake.org-help:
     extends:
         - .cmake_org_help
-        - .run_cmake_org_help
+        - .rules
+    variables:
+        CMAKE_CI_JOB_UPDATES_WEBSITE_HELP: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
     needs: []
 
 u:cmake.org-help:
     extends:
         - .rsync_upload_help
-        - .run_cmake_org_help
+        - .rules
+    variables:
+        CMAKE_CI_JOB_UPDATES_WEBSITE_HELP: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
     needs:
         - b:cmake.org-help
 
@@ -102,7 +119,7 @@
     extends:
         - .cmake_spellcheck_linux
         - .linux_x86_64_tags
-        - .run_automatically
+        - .rules
 
 l:iwyu-debian13:
     extends:
@@ -110,7 +127,7 @@
         - .cmake_build_linux
         - .linux_x86_64_tags
         - .cmake_cdash_artifacts
-        - .run_automatically
+        - .rules
 
 l:tidy-fedora43:
     extends:
@@ -119,7 +136,7 @@
         - .cmake_tidy_artifacts
         - .linux_x86_64_tags
         - .cmake_cdash_artifacts
-        - .run_automatically
+        - .rules
 
 l:sphinx-fedora43:
     extends:
@@ -127,7 +144,7 @@
         - .cmake_build_linux
         - .cmake_sphinx_artifacts
         - .linux_x86_64_tags
-        - .run_automatically
+        - .rules
     variables:
         CMAKE_CI_JOB_CONTINUOUS: "true"
         CMAKE_CI_JOB_HELP: "true"
@@ -137,16 +154,23 @@
         - .fedora43_clang_analyzer
         - .cmake_build_linux
         - .linux_x86_64_tags
-        - .run_automatically
+        - .rules
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
 
+l:clang-fuzzing-fedora43:
+    extends:
+        - .fedora43_clang_fuzzing
+        - .cmake_build_linux
+        - .linux_x86_64_tags
+        - .rules
+
 l:clazy-fedora43:
     extends:
         - .fedora43_clazy
         - .cmake_build_linux
         - .linux_x86_64_tags
-        - .run_automatically
+        - .rules
 
 # Coverage builds
 
@@ -156,9 +180,10 @@
         - .cmake_build_linux
         - .cmake_build_artifacts
         - .linux_x86_64_tags
-        - .run_manually
+        - .rules
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 t:fedora43-gcc-gcov:
     extends:
@@ -166,7 +191,7 @@
         - .cmake_test_linux
         - .cmake_coverage_artifacts
         - .linux_x86_64_tags_x11
-        - .run_dependent
+        - .rules
     # Run coverage analysis even if the tests fail.
     allow_failure: true
     needs:
@@ -180,7 +205,7 @@
         - .cmake_coverage_linux
         - .cmake_cdash_artifacts
         - .linux_x86_64_tags
-        - .run_dependent
+        - .rules
     needs:
         - t:fedora43-gcc-gcov
     variables:
@@ -192,9 +217,11 @@
         - .cmake_build_linux
         - .cmake_build_artifacts
         - .linux_x86_64_tags
-        - .run_manually
+        - .rules
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 t:fedora43-bullseye-coverage:
     extends:
@@ -202,13 +229,14 @@
         - .cmake_test_linux
         - .cmake_coverage_artifacts
         - .linux_x86_64_tags_x11
-        - .run_dependent
+        - .rules
     # Run coverage analysis even if the tests fail.
     allow_failure: true
     needs:
         - b:fedora43-bullseye-coverage
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
 
 a:fedora43-bullseye-coverage:
     extends:
@@ -216,11 +244,12 @@
         - .cmake_coverage_linux
         - .cmake_cdash_artifacts
         - .linux_x86_64_tags
-        - .run_dependent
+        - .rules
     needs:
         - t:fedora43-bullseye-coverage
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
 
 # Linux builds
 
@@ -230,20 +259,22 @@
         - .cmake_build_linux_release
         - .cmake_release_artifacts
         - .linux_x86_64_tags
-        - .run_manually
+        - .rules
     variables:
         CMAKE_CI_ARTIFACTS_NAME: "artifacts-centos7-x86_64"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
-b:centos7-aarch64:
+b:centos8-aarch64:
     extends:
         - .linux_release_aarch64
         - .cmake_build_linux_release
         - .cmake_release_artifacts
         - .linux_aarch64_tags
-        - .run_manually
+        - .rules
     variables:
-        CMAKE_CI_ARTIFACTS_NAME: "artifacts-centos7-aarch64"
-        CMAKE_CI_NO_MR: "true"
+        CMAKE_CI_ARTIFACTS_NAME: "artifacts-centos8-aarch64"
+        CMAKE_CI_JOB_NO_MR: "true"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 t:debian13-ninja:
     extends:
@@ -251,7 +282,7 @@
         - .cmake_test_linux_release
         - .linux_x86_64_tags
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY_NINJA: "true"
@@ -262,17 +293,17 @@
         - .cmake_test_linux_release
         - .linux_aarch64_tags
         - .cmake_junit_artifacts
-        - .run_dependent
-        - .needs_centos7_aarch64
+        - .rules
+        - .needs_centos8_aarch64
     variables:
-        CMAKE_CI_NO_MR: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
 
 t:debian13-ninja-clang:
     extends:
         - .debian13_ninja_clang
         - .cmake_test_linux_release
         - .linux_x86_64_tags
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -282,7 +313,7 @@
         - .debian13_makefiles_clang
         - .cmake_test_linux_release
         - .linux_x86_64_tags
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -293,7 +324,7 @@
         - .cmake_test_linux_release
         - .linux_x86_64_tags
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -304,7 +335,7 @@
         - .debian13_hip_radeon
         - .cmake_test_linux_release
         - .linux_x86_64_tags_rocm5.7
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -314,7 +345,7 @@
         - .fedora43_hip_radeon
         - .cmake_test_linux_release
         - .linux_x86_64_tags_rocm6.2
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -324,7 +355,7 @@
         - .fedora43_makefiles_lfortran
         - .cmake_test_linux_release
         - .linux_x86_64_tags
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -334,17 +365,25 @@
         - .fedora43_ninja_lfortran
         - .cmake_test_linux_release
         - .linux_x86_64_tags
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
 
+t:fedora43-ninja-multi:
+    extends:
+        - .fedora43_ninja_multi
+        - .cmake_test_linux_release
+        - .linux_x86_64_tags
+        - .rules
+        - .needs_centos7_x86_64
+
 t:fedora43-ninja-clang:
     extends:
         - .fedora43_ninja_clang
         - .cmake_test_linux_release
         - .linux_x86_64_tags
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -354,7 +393,7 @@
         - .fedora43_ninja_multi_clang
         - .cmake_test_linux_release
         - .linux_x86_64_tags
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -364,7 +403,7 @@
         - .fedora43_makefiles_clang
         - .cmake_test_linux_release
         - .linux_x86_64_tags
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -374,7 +413,7 @@
         - .fedora43_makefiles
         - .cmake_test_linux_release
         - .linux_x86_64_v3_tags
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
 
 t:fedora43-makefiles-nospace:
@@ -383,7 +422,7 @@
         - .cmake_test_linux_release
         - .linux_x86_64_v3_tags
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake-ci"
@@ -395,17 +434,28 @@
         - .fedora43_fastbuild
         - .cmake_test_linux_release
         - .linux_x86_64_v3_tags
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
 
+t:fedora43-instrumentation:
+    extends:
+        - .fedora43_ninja_instrumentation
+        - .cmake_test_linux_release
+        - .linux_x86_64_tags
+        - .rules
+        - .needs_centos7_x86_64
+        - .cmake_junit_artifacts
+    variables:
+        CMAKE_CI_JOB_NIGHTLY: "true"
+
 t:nvhpc24.9-ninja:
     extends:
         - .nvhpc_ninja
         - .cmake_test_linux_release
         - .linux_x86_64_v3_tags_cuda_arch_52
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -415,7 +465,7 @@
         - .cuda9.2_nvidia
         - .cmake_test_linux_release
         - .linux_x86_64_tags_cuda_arch_30
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -426,7 +476,7 @@
         - .cmake_test_linux_release
         - .linux_x86_64_tags_cuda_arch_52
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -436,7 +486,7 @@
         - .cuda10.2_clang
         - .cmake_test_linux_release
         - .linux_x86_64_tags_cuda_arch_52
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -447,7 +497,7 @@
         - .cmake_test_linux_release
         - .linux_x86_64_tags_cuda_arch_52
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -457,7 +507,7 @@
         - .cuda11.6_clang
         - .cmake_test_linux_release
         - .linux_x86_64_tags_cuda_arch_52
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -467,7 +517,7 @@
         - .cuda11.8_minimal_nvidia
         - .cmake_test_linux_release
         - .linux_x86_64_tags_cuda_arch_52
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -477,7 +527,7 @@
         - .cuda11.8_splayed_nvidia
         - .cmake_test_linux_release
         - .linux_x86_64_tags_cuda_arch_52
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -488,7 +538,7 @@
         - .cmake_test_linux_release
         - .linux_x86_64_tags_cuda_arch_52
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -498,7 +548,7 @@
         - .cuda12.2_clang
         - .cmake_test_linux_release
         - .linux_x86_64_tags_cuda_arch_52
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -509,7 +559,7 @@
         - .cmake_test_linux_release
         - .linux_x86_64_tags_cuda_arch_52
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -520,7 +570,7 @@
         - .cmake_test_linux_release
         - .linux_x86_64_tags_cuda_arch_52
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -530,7 +580,7 @@
         - .cuda12.6_clang
         - .cmake_test_linux_release
         - .linux_x86_64_tags_cuda_arch_52
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -541,16 +591,28 @@
         - .cmake_test_linux_release
         - .linux_x86_64_tags_cuda_arch_75
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
 
+t:cuda13.0-aarch64-nvidia:
+    extends:
+        - .cuda13.0_aarch64_nvidia
+        - .cmake_test_linux_release
+        - .linux_aarch64_tags_cuda_arch_75
+        - .cmake_junit_artifacts
+        - .rules
+        - .needs_centos8_aarch64
+    variables:
+        CMAKE_CI_JOB_NIGHTLY: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
+
 t:cuda13.0-nvidia-fastbuild:
     extends:
         - .cuda13.0_nvidia_fastbuild
         - .cmake_test_linux_release
         - .linux_x86_64_tags_cuda_arch_75
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -560,7 +622,7 @@
         - .hip6.3_nvidia
         - .cmake_test_linux_release
         - .linux_x86_64_tags_cuda_arch_52
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -570,7 +632,7 @@
         - .hip6.3_radeon
         - .cmake_test_linux_release
         - .linux_x86_64_tags_rocm6.3
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -580,7 +642,7 @@
         - .gcc_cxx_modules_reloc_ninja
         - .cmake_test_linux_release
         - .linux_x86_64_tags
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -590,7 +652,7 @@
         - .gcc_cxx_modules_ninja
         - .cmake_test_linux_release
         - .linux_x86_64_tags
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -600,7 +662,7 @@
         - .gcc_cxx_modules_ninja_multi
         - .cmake_test_linux_release
         - .linux_x86_64_tags
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -611,7 +673,7 @@
         - .cmake_test_linux_release
         - .linux_x86_64_tags
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -622,9 +684,10 @@
         - .cmake_build_linux
         - .cmake_build_artifacts
         - .linux_x86_64_tags
-        - .run_manually
+        - .rules
     variables:
         CMAKE_CI_JOB_CONTINUOUS: "true"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 b:fedora43-makefiles-symlinked:
     extends:
@@ -632,45 +695,50 @@
         - .cmake_build_linux
         - .cmake_build_artifacts
         - .linux_x86_64_tags
-        - .run_manually
+        - .rules
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 b:debian13-makefiles-inplace:
     extends:
         - .debian13_makefiles_inplace
         - .cmake_build_linux_standalone
         - .linux_x86_64_tags
-        - .run_manually
+        - .rules
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 b:debian13-extdeps:
     extends:
         - .debian13_extdeps
         - .cmake_build_linux_standalone
         - .linux_x86_64_tags
-        - .run_manually
+        - .rules
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 b:debian13-aarch64-extdeps:
     extends:
         - .debian13_aarch64_extdeps
         - .cmake_build_linux_standalone
         - .linux_aarch64_tags
-        - .run_manually
+        - .rules
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 b:fedora43-extdeps:
     extends:
         - .fedora43_extdeps
         - .cmake_build_linux_standalone
         - .linux_x86_64_tags
-        - .run_manually
+        - .rules
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 t:fedora43-ninja:
     extends:
@@ -678,7 +746,7 @@
         - .cmake_test_linux
         - .linux_x86_64_tags_x11
         - .cmake_test_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - b:fedora43-ninja
     variables:
@@ -690,22 +758,12 @@
         - .cmake_test_linux
         - .linux_x86_64_tags_x11
         - .cmake_test_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - b:fedora43-makefiles-symlinked
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
 
-t:fedora43-ninja-multi:
-    extends:
-        - .fedora43_ninja_multi
-        - .cmake_test_linux_external
-        - .linux_x86_64_tags
-        - .cmake_junit_artifacts
-        - .run_dependent
-    needs:
-        - t:fedora43-ninja
-
 t:intel2016u2-makefiles:
     extends:
         - .cmake_test_linux_intelclassic_makefiles
@@ -937,6 +995,13 @@
         CMAKE_CI_BUILD_NAME: oneapi2025.2.0_makefiles
         CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2025.2.0-rocky9
 
+t:oneapi2025.3.0-makefiles:
+    extends:
+        - .cmake_test_linux_inteloneapi_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: oneapi2025.3.0_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2025.3.0-rocky9
+
 b:linux-x86_64-package:
     extends:
         - .linux_package
@@ -944,16 +1009,20 @@
         - .cmake_build_linux_release
         - .cmake_release_artifacts
         - .linux_x86_64_tags
-        - .run_only_for_package
+        - .rules
     needs:
         - p:doc-package
     variables:
         CMAKE_CI_ARTIFACTS_NAME: "artifacts-linux-x86_64"
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
 
 u:linux-x86_64-package:
     extends:
         - .rsync_upload_package
-        - .run_only_for_package
+        - .rules
+    variables:
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
     needs:
         - b:linux-x86_64-package
 
@@ -964,16 +1033,20 @@
         - .cmake_build_linux_release
         - .cmake_release_artifacts
         - .linux_aarch64_tags
-        - .run_only_for_package
+        - .rules
     needs:
         - p:doc-package
     variables:
         CMAKE_CI_ARTIFACTS_NAME: "artifacts-linux-aarch64"
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
 
 u:linux-aarch64-package:
     extends:
         - .rsync_upload_package
-        - .run_only_for_package
+        - .rules
+    variables:
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
     needs:
         - b:linux-aarch64-package
 
@@ -984,16 +1057,20 @@
         - .cmake_build_sunos_release
         - .cmake_release_artifacts
         - .linux_x86_64_tags
-        - .run_only_for_package
+        - .rules
     needs:
         - p:doc-package
     variables:
         CMAKE_CI_ARTIFACTS_NAME: "artifacts-sunos-x86_64"
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
 
 u:sunos-x86_64-package:
     extends:
         - .rsync_upload_package
-        - .run_only_for_package
+        - .rules
+    variables:
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
     needs:
         - b:sunos-x86_64-package
 
@@ -1004,16 +1081,20 @@
         - .cmake_build_sunos_release
         - .cmake_release_artifacts
         - .linux_x86_64_tags
-        - .run_only_for_package
+        - .rules
     needs:
         - p:doc-package
     variables:
         CMAKE_CI_ARTIFACTS_NAME: "artifacts-sunos-sparc64"
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
 
 u:sunos-sparc64-package:
     extends:
         - .rsync_upload_package
-        - .run_only_for_package
+        - .rules
+    variables:
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
     needs:
         - b:sunos-sparc64-package
 
@@ -1025,9 +1106,10 @@
         - .cmake_build_linux
         - .cmake_build_artifacts
         - .linux_x86_64_tags
-        - .run_manually
+        - .rules
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 t:fedora43-asan:
     extends:
@@ -1035,7 +1117,7 @@
         - .cmake_memcheck_linux
         - .linux_x86_64_tags
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - b:fedora43-asan
     variables:
@@ -1048,7 +1130,7 @@
         # Use a fast CPU so that timeouts are less of a concern.
         - .linux_x86_64_tags_fast_x11
         - .cmake_valgrind_artifacts
-        - .run_dependent
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
@@ -1062,9 +1144,10 @@
         - .cmake_build_macos
         - .cmake_build_artifacts
         - .macos_x86_64_tags
-        - .run_manually
+        - .rules
     variables:
-        CMAKE_CI_NO_MR: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 b:macos-arm64-ninja:
     extends:
@@ -1072,9 +1155,10 @@
         - .cmake_build_macos
         - .cmake_build_artifacts
         - .macos_arm64_tags
-        - .run_manually
+        - .rules
     variables:
         CMAKE_CI_JOB_CONTINUOUS: "true"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 b:macos-arm64-ninja-symlinked:
     extends:
@@ -1082,18 +1166,20 @@
         - .cmake_build_macos
         - .cmake_build_artifacts
         - .macos_arm64_tags
-        - .run_manually
+        - .rules
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 b:macos-arm64-pch:
     extends:
         - .macos_arm64_pch
         - .cmake_build_macos
         - .macos_arm64_tags
-        - .run_manually
+        - .rules
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 t:macos-x86_64-ninja:
     extends:
@@ -1101,11 +1187,11 @@
         - .cmake_test_macos
         - .cmake_test_artifacts
         - .macos_x86_64_tags
-        - .run_dependent
+        - .rules
     needs:
         - b:macos-x86_64-ninja
     variables:
-        CMAKE_CI_NO_MR: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
 
 t:macos-arm64-ninja:
     extends:
@@ -1113,7 +1199,7 @@
         - .cmake_test_macos
         - .cmake_test_artifacts
         - .macos_arm64_tags
-        - .run_dependent
+        - .rules
     needs:
         - b:macos-arm64-ninja
     variables:
@@ -1126,7 +1212,7 @@
         - .cmake_test_macos
         - .cmake_test_artifacts
         - .macos_arm64_tags
-        - .run_dependent
+        - .rules
     needs:
         - b:macos-arm64-ninja-symlinked
     variables:
@@ -1139,14 +1225,16 @@
         - .cmake_build_macos
         - .cmake_build_artifacts
         - .macos_x86_64_tags
-        - .run_manually
+        - .rules
+    variables:
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 t:macos-x86_64-makefiles:
     extends:
         - .macos_x86_64_makefiles
         - .cmake_test_macos
         - .macos_x86_64_tags
-        - .run_dependent
+        - .rules
     needs:
         - b:macos-x86_64-makefiles
 
@@ -1156,7 +1244,7 @@
         - .cmake_test_macos_external
         - .macos_arm64_tags_ext
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:macos-arm64-ninja
     variables:
@@ -1168,11 +1256,11 @@
         - .cmake_test_macos_external
         - .macos_x86_64_tags_ext
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:macos-x86_64-ninja
     variables:
-        CMAKE_CI_NO_MR: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
 
 t:macos-arm64-xcode:
     extends:
@@ -1180,7 +1268,7 @@
         - .cmake_test_macos_external
         - .macos_arm64_tags_ext
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:macos-arm64-ninja
 
@@ -1190,7 +1278,7 @@
         - .cmake_test_macos_external
         - .macos_arm64_tags_ext
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:macos-arm64-ninja
     variables:
@@ -1202,7 +1290,7 @@
         - .cmake_test_macos_external
         - .macos_arm64_tags_ext
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:macos-arm64-ninja
     variables:
@@ -1214,11 +1302,11 @@
         - .cmake_test_macos_external
         - .macos_x86_64_tags_ext
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:macos-x86_64-ninja
     variables:
-        CMAKE_CI_NO_MR: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
 
 t:macos-arm64-xcode-ub:
     extends:
@@ -1226,7 +1314,7 @@
         - .cmake_test_macos_external
         - .macos_arm64_tags_ext
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:macos-arm64-ninja
     variables:
@@ -1238,18 +1326,34 @@
         - .cmake_build_macos
         - .cmake_release_artifacts
         - .macos_arm64_tags_package
-        - .run_only_for_package
+        - .rules
     needs:
         - p:doc-package
     variables:
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
+
+k:macos-package:
+    extends:
+        - .macos_sign
+        - .cmake_sign_macos
+        - .cmake_release_artifacts
+        - .macos_sign_tags
+        - .rules
+    needs:
+        - b:macos-package
+    variables:
         CMAKE_CI_ARTIFACTS_NAME: "artifacts-macos-universal"
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
 
 u:macos-package:
     extends:
         - .rsync_upload_package
-        - .run_only_for_package
+        - .rules
+    variables:
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
     needs:
-        - b:macos-package
+        - k:macos-package
 
 b:macos10.10-package:
     extends:
@@ -1257,18 +1361,34 @@
         - .cmake_build_macos
         - .cmake_release_artifacts
         - .macos_arm64_tags_package
-        - .run_only_for_package
+        - .rules
     needs:
         - p:doc-package
     variables:
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
+
+k:macos10.10-package:
+    extends:
+        - .macos_sign
+        - .cmake_sign_macos
+        - .cmake_release_artifacts
+        - .macos_sign_tags
+        - .rules
+    needs:
+        - b:macos10.10-package
+    variables:
         CMAKE_CI_ARTIFACTS_NAME: "artifacts-macos10.10-universal"
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
 
 u:macos10.10-package:
     extends:
         - .rsync_upload_package
-        - .run_only_for_package
+        - .rules
+    variables:
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
     needs:
-        - b:macos10.10-package
+        - k:macos10.10-package
 
 # Windows x86_64 jobs
 
@@ -1278,18 +1398,20 @@
         - .cmake_build_windows
         - .cmake_build_artifacts
         - .windows_x86_64_tags_nonconcurrent_vs2026
-        - .run_manually
+        - .rules
     variables:
         CMAKE_CI_JOB_CONTINUOUS: "true"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 b:windows-vs2026-x64-pch:
     extends:
         - .windows_vs2026_x64_pch
         - .cmake_build_windows
         - .windows_x86_64_tags_nonconcurrent_vs2026
-        - .run_manually
+        - .rules
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 t:windows-vs2026-x64-ninja:
     extends:
@@ -1297,7 +1419,7 @@
         - .cmake_test_windows
         - .windows_x86_64_tags_nonconcurrent_vs2026
         - .cmake_test_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - b:windows-vs2026-x64-ninja
     variables:
@@ -1310,7 +1432,7 @@
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent_vs2026
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
@@ -1321,7 +1443,7 @@
         - .windows_vs2026_x64
         - .cmake_test_windows_external
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
 
@@ -1354,7 +1476,7 @@
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent_vs2022_android
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
@@ -1366,7 +1488,7 @@
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent_vs2019_android
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
@@ -1378,7 +1500,7 @@
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent_vs2026
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
@@ -1390,7 +1512,7 @@
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent_vs2026
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
@@ -1402,7 +1524,7 @@
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent_vs2026
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
@@ -1414,7 +1536,7 @@
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
@@ -1426,62 +1548,62 @@
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
 
-t:windows-clang19.1-cl-ninja:
+t:windows-clang21.1-cl-ninja:
     extends:
         - .windows_clang_ninja
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent_vs2022_msvc14.44
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
-        CMAKE_CI_BUILD_NAME: windows_clang19.1_cl_ninja
+        CMAKE_CI_BUILD_NAME: windows_clang21.1_cl_ninja
         CMAKE_CI_JOB_NIGHTLY: "true"
 
-t:windows-clang19.1-cl-nmake:
+t:windows-clang21.1-cl-nmake:
     extends:
         - .windows_clang_nmake
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent_vs2022_msvc14.44
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
-        CMAKE_CI_BUILD_NAME: windows_clang19.1_cl_nmake
+        CMAKE_CI_BUILD_NAME: windows_clang21.1_cl_nmake
         CMAKE_CI_JOB_NIGHTLY: "true"
 
-t:windows-clang19.1-gnu-ninja:
+t:windows-clang21.1-gnu-ninja:
     extends:
         - .windows_clang_ninja
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent_vs2022_msvc14.44
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
-        CMAKE_CI_BUILD_NAME: windows_clang19.1_gnu_ninja
+        CMAKE_CI_BUILD_NAME: windows_clang21.1_gnu_ninja
         CMAKE_CI_JOB_NIGHTLY: "true"
 
-t:windows-clang19.1-gnu-nmake:
+t:windows-clang21.1-gnu-nmake:
     extends:
         - .windows_clang_nmake
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent_vs2022_msvc14.44
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
-        CMAKE_CI_BUILD_NAME: windows_clang19.1_gnu_nmake
+        CMAKE_CI_BUILD_NAME: windows_clang21.1_gnu_nmake
         CMAKE_CI_JOB_NIGHTLY: "true"
 
 t:windows-intel2021.9-ninja:
@@ -1490,7 +1612,7 @@
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent_vs2022_msvc14.43
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
@@ -1503,7 +1625,7 @@
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent_vs2022_msvc14.44
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
@@ -1516,7 +1638,7 @@
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
@@ -1528,7 +1650,7 @@
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
@@ -1540,7 +1662,7 @@
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
@@ -1552,7 +1674,7 @@
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
@@ -1564,7 +1686,7 @@
         - .cmake_test_windows_external
         - .windows_x86_64_tags_concurrent
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-vs2026-x64-ninja
     variables:
@@ -1578,9 +1700,10 @@
         - .cmake_build_windows
         - .cmake_build_artifacts
         - .windows_arm64_tags_nonconcurrent_vs2026
-        - .run_manually
+        - .rules
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
+        CMAKE_CI_JOB_RUN_MANUALLY: "true"
 
 t:windows-arm64-vs2026-ninja:
     extends:
@@ -1588,7 +1711,7 @@
         - .cmake_test_windows
         - .windows_arm64_tags_nonconcurrent_vs2026
         - .cmake_test_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - b:windows-arm64-vs2026-ninja
     variables:
@@ -1600,7 +1723,7 @@
         - .cmake_test_windows_external
         - .windows_arm64_tags_concurrent_vs2026
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-arm64-vs2026-ninja
     variables:
@@ -1612,7 +1735,7 @@
         - .cmake_test_windows_external
         - .windows_arm64_tags_concurrent_vs2022
         - .cmake_junit_artifacts
-        - .run_dependent
+        - .rules
     needs:
         - t:windows-arm64-vs2026-ninja
     variables:
@@ -1625,12 +1748,13 @@
         - .windows_x86_64_package
         - .cmake_build_windows
         - .cmake_build_package_artifacts
-        - .windows_x86_64_tags_nonconcurrent_vs2022_msvc14.44
-        - .run_only_for_package
+        - .windows_x86_64_tags_nonconcurrent_vs2026
+        - .rules
     needs:
         - p:doc-package
     variables:
         CMAKE_CI_ARTIFACTS_NAME: "artifacts-windows-x86_64-build"
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
 
 k:windows-x86_64-package:
     extends:
@@ -1638,16 +1762,20 @@
         - .cmake_package_windows
         - .cmake_release_artifacts
         - .windows_x86_64_tags_nonconcurrent_sign
-        - .run_only_for_package
+        - .rules
     needs:
         - b:windows-x86_64-package
     variables:
         CMAKE_CI_ARTIFACTS_NAME: "artifacts-windows-x86_64"
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
 
 u:windows-x86_64-package:
     extends:
         - .rsync_upload_package
-        - .run_only_for_package
+        - .rules
+    variables:
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
     needs:
         - k:windows-x86_64-package
 
@@ -1656,12 +1784,13 @@
         - .windows_i386_package
         - .cmake_build_windows
         - .cmake_build_package_artifacts
-        - .windows_x86_64_tags_nonconcurrent_vs2022_msvc14.44
-        - .run_only_for_package
+        - .windows_x86_64_tags_nonconcurrent_vs2026
+        - .rules
     needs:
         - p:doc-package
     variables:
         CMAKE_CI_ARTIFACTS_NAME: "artifacts-windows-i386-build"
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
 
 k:windows-i386-package:
     extends:
@@ -1669,16 +1798,20 @@
         - .cmake_package_windows
         - .cmake_release_artifacts
         - .windows_x86_64_tags_nonconcurrent_sign
-        - .run_only_for_package
+        - .rules
     needs:
         - b:windows-i386-package
     variables:
         CMAKE_CI_ARTIFACTS_NAME: "artifacts-windows-i386"
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
 
 u:windows-i386-package:
     extends:
         - .rsync_upload_package
-        - .run_only_for_package
+        - .rules
+    variables:
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
     needs:
         - k:windows-i386-package
 
@@ -1688,11 +1821,12 @@
         - .cmake_build_windows
         - .cmake_build_package_artifacts
         - .windows_x86_64_tags_nonconcurrent_vs2026_arm64
-        - .run_only_for_package
+        - .rules
     needs:
         - p:doc-package
     variables:
         CMAKE_CI_ARTIFACTS_NAME: "artifacts-windows-arm64-build"
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
 
 k:windows-arm64-package:
     extends:
@@ -1700,15 +1834,19 @@
         - .cmake_package_windows
         - .cmake_release_artifacts
         - .windows_x86_64_tags_nonconcurrent_sign
-        - .run_only_for_package
+        - .rules
     needs:
         - b:windows-arm64-package
     variables:
         CMAKE_CI_ARTIFACTS_NAME: "artifacts-windows-arm64"
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
 
 u:windows-arm64-package:
     extends:
         - .rsync_upload_package
-        - .run_only_for_package
+        - .rules
+    variables:
+        CMAKE_CI_JOB_PACKAGE_ONLY: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
     needs:
         - k:windows-arm64-package
diff --git a/.gitlab/.gitignore b/.gitlab/.gitignore
index e8f9c98..91e677b 100644
--- a/.gitlab/.gitignore
+++ b/.gitlab/.gitignore
@@ -1,5 +1,6 @@
 # Ignore files known to be downloaded by CI jobs.
-/5.15.1-0-202009071110*
+/6.9.3-0-202509261208*
+/6.9.3-0-202509261207*
 /appimagetool
 /bcc*
 /cmake*
@@ -11,7 +12,6 @@
 /innosetup
 /jom
 /llvm*
-/MacOS*
 /mingw
 /msvc*
 /ninja*
diff --git a/.gitlab/artifacts.yml b/.gitlab/artifacts.yml
index e33cdc8..af7fbac 100644
--- a/.gitlab/artifacts.yml
+++ b/.gitlab/artifacts.yml
@@ -122,8 +122,6 @@
             # Any source packages made.
             - ${CMAKE_CI_BUILD_DIR}/cmake-*.tar.gz
             - ${CMAKE_CI_BUILD_DIR}/cmake-*.zip
-            # Any unsigned packages made.
-            - ${CMAKE_CI_BUILD_DIR}/unsigned/cmake-*
         reports:
             annotations:
                 - ${CMAKE_CI_BUILD_DIR}/annotations.json
diff --git a/.gitlab/ci/clang.ps1 b/.gitlab/ci/clang.ps1
index 61361b1..327fe3b 100644
--- a/.gitlab/ci/clang.ps1
+++ b/.gitlab/ci/clang.ps1
@@ -1,10 +1,10 @@
 $erroractionpreference = "stop"
 
-if ("$env:CMAKE_CI_BUILD_NAME".Contains("clang19.1")) {
-    # LLVM/Clang 19.1.0
-    # https://github.com/llvm/llvm-project/releases/tag/llvmorg-19.1.0
-    $filename = "llvm-19.1.0-win-x86_64-1"
-    $sha256sum = "C1F974511A6FA2DC5B4892996C064A55BF81D7F244514F8AB5A453110ADEC0EC"
+if ("$env:CMAKE_CI_BUILD_NAME".Contains("clang21.1")) {
+    # LLVM/Clang 21.1.8
+    # https://github.com/llvm/llvm-project/releases/tag/llvmorg-21.1.8
+    $filename = "llvm-21.1.8-win-x86_64-1"
+    $sha256sum = "3DB0063A6E434C694799CDD70052F27F08A758F1FF4B4C04D9910AD4198F6064"
 } else {
     throw ('unknown CMAKE_CI_BUILD_NAME: ' + "$env:CMAKE_CI_BUILD_NAME")
 }
diff --git a/.gitlab/ci/configure_cuda13.0_aarch64_nvidia.cmake b/.gitlab/ci/configure_cuda13.0_aarch64_nvidia.cmake
new file mode 100644
index 0000000..71aafcf
--- /dev/null
+++ b/.gitlab/ci/configure_cuda13.0_aarch64_nvidia.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_LIST_DIR}/configure_cuda13.0_nvidia_common.cmake")
diff --git a/.gitlab/ci/configure_debian13_aarch64_ninja.cmake b/.gitlab/ci/configure_debian13_aarch64_ninja.cmake
index b533822..90fb7d9 100644
--- a/.gitlab/ci/configure_debian13_aarch64_ninja.cmake
+++ b/.gitlab/ci/configure_debian13_aarch64_ninja.cmake
@@ -1,5 +1,5 @@
 set(CMake_TEST_C_STANDARDS "90;99;11;17;23" CACHE STRING "")
-set(CMake_TEST_CXX_STANDARDS "98;11;14;17;20;23" CACHE STRING "")
+set(CMake_TEST_CXX_STANDARDS "98;11;14;17;20;23;26" CACHE STRING "")
 
 set(blas_lapack_cases
   All
diff --git a/.gitlab/ci/configure_debian13_makefiles_clang.cmake b/.gitlab/ci/configure_debian13_makefiles_clang.cmake
index c0cf7b5..f928ecc 100644
--- a/.gitlab/ci/configure_debian13_makefiles_clang.cmake
+++ b/.gitlab/ci/configure_debian13_makefiles_clang.cmake
@@ -1,5 +1,5 @@
 set(CMake_TEST_C_STANDARDS "90;99;11;17;23" CACHE STRING "")
-set(CMake_TEST_CXX_STANDARDS "98;11;14;17;20;23" CACHE STRING "")
+set(CMake_TEST_CXX_STANDARDS "98;11;14;17;20;23;26" CACHE STRING "")
 
 if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
   set(CMake_TEST_IAR_TOOLCHAINS "/opt/iarsystems" CACHE PATH "")
diff --git a/.gitlab/ci/configure_debian13_ninja_common.cmake b/.gitlab/ci/configure_debian13_ninja_common.cmake
index b638f75..8b1bf14 100644
--- a/.gitlab/ci/configure_debian13_ninja_common.cmake
+++ b/.gitlab/ci/configure_debian13_ninja_common.cmake
@@ -1,5 +1,5 @@
 set(CMake_TEST_C_STANDARDS "90;99;11;17;23" CACHE STRING "")
-set(CMake_TEST_CXX_STANDARDS "98;11;14;17;20;23" CACHE STRING "")
+set(CMake_TEST_CXX_STANDARDS "98;11;14;17;20;23;26" CACHE STRING "")
 
 set(CMake_TEST_CTestUpdate_BZR "ON" CACHE BOOL "")
 set(CMake_TEST_CTestUpdate_CVS "ON" CACHE BOOL "")
diff --git a/.gitlab/ci/configure_fedora43_bullseye_coverage.cmake b/.gitlab/ci/configure_fedora43_bullseye_coverage.cmake
index f9dabd8..5b35c57 100644
--- a/.gitlab/ci/configure_fedora43_bullseye_coverage.cmake
+++ b/.gitlab/ci/configure_fedora43_bullseye_coverage.cmake
@@ -12,7 +12,7 @@
 set(ENV{KWSYS_TEST_PROCESS_1_COUNT} 11)
 
 set(CMake_TEST_GUI "ON" CACHE BOOL "")
-set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly,build_database" CACHE STRING "")
+set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly,build_database,import_std23" CACHE STRING "")
 set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
 set(CMake_TEST_TLS_VERIFY_URL_BAD "https://badtls-expired.kitware.com" CACHE STRING "")
 set(CMake_TEST_TLS_VERSION "1.3" CACHE STRING "")
diff --git a/.gitlab/ci/configure_fedora43_clang_fuzzing.cmake b/.gitlab/ci/configure_fedora43_clang_fuzzing.cmake
new file mode 100644
index 0000000..48a4b7b
--- /dev/null
+++ b/.gitlab/ci/configure_fedora43_clang_fuzzing.cmake
@@ -0,0 +1,3 @@
+set(CMake_BUILD_FUZZING ON CACHE BOOL "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")
diff --git a/.gitlab/ci/configure_fedora43_gcc_gcov.cmake b/.gitlab/ci/configure_fedora43_gcc_gcov.cmake
index 0b0f46d..b2eb3ac 100644
--- a/.gitlab/ci/configure_fedora43_gcc_gcov.cmake
+++ b/.gitlab/ci/configure_fedora43_gcc_gcov.cmake
@@ -1,5 +1,5 @@
 set(CMake_TEST_GUI "ON" CACHE BOOL "")
-set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly,build_database" CACHE STRING "")
+set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly,build_database,import_std23" CACHE STRING "")
 set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
 set(CMake_TEST_TLS_VERIFY_URL_BAD "https://badtls-expired.kitware.com" CACHE STRING "")
 set(CMake_TEST_TLS_VERSION "1.3" CACHE STRING "")
diff --git a/.gitlab/ci/configure_fedora43_makefiles.cmake b/.gitlab/ci/configure_fedora43_makefiles.cmake
index e84dcbd..3ddf236 100644
--- a/.gitlab/ci/configure_fedora43_makefiles.cmake
+++ b/.gitlab/ci/configure_fedora43_makefiles.cmake
@@ -6,6 +6,7 @@
 set(CMake_TEST_CTestUpdate_HG "ON" CACHE BOOL "")
 set(CMake_TEST_CTestUpdate_SVN "ON" CACHE BOOL "")
 if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
+  set(CMake_TEST_BIN2C_LARGE_FILE "ON" CACHE BOOL "")
   set(CMake_TEST_CTestUpdate_P4 "ON" CACHE BOOL "")
 endif()
 
@@ -107,6 +108,7 @@
 if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
   set(CMake_TEST_ISPC "ON" CACHE STRING "")
 endif()
+set(CMake_TEST_LOCALE_CHARSET "ISO-8859-1" CACHE STRING "")
 set(CMake_TEST_Qt5 "ON" CACHE BOOL "")
 set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
 set(CMake_TEST_TLS_VERIFY_URL_BAD "https://badtls-expired.kitware.com" CACHE STRING "")
diff --git a/.gitlab/ci/configure_fedora43_ninja.cmake b/.gitlab/ci/configure_fedora43_ninja.cmake
index 43cfbba..0371ebc 100644
--- a/.gitlab/ci/configure_fedora43_ninja.cmake
+++ b/.gitlab/ci/configure_fedora43_ninja.cmake
@@ -4,7 +4,9 @@
   set(CMake_TEST_CPACK_APPIMAGE_RUNTIME_FILE "$ENV{CI_PROJECT_DIR}/.gitlab/appimagetool/lib/appimagetool/runtime" CACHE FILEPATH "")
   set(CMake_TEST_ISPC "ON" CACHE STRING "")
 endif()
-set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly,build_database" CACHE STRING "")
+set(CMake_TEST_LOCALE_CHARSET "UTF-8" CACHE STRING "")
+set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly,build_database,import_std23" CACHE STRING "")
+set(CMake_TEST_Rust "ON" CACHE STRING "")
 set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
 set(CMake_TEST_TLS_VERIFY_URL_BAD "https://badtls-expired.kitware.com" CACHE STRING "")
 set(CMake_TEST_TLS_VERSION "1.3" CACHE STRING "")
diff --git a/.gitlab/ci/configure_fedora43_ninja_instrumentation.cmake b/.gitlab/ci/configure_fedora43_ninja_instrumentation.cmake
new file mode 100644
index 0000000..daf845f
--- /dev/null
+++ b/.gitlab/ci/configure_fedora43_ninja_instrumentation.cmake
@@ -0,0 +1,3 @@
+set(CMake_ENABLE_INSTRUMENTATION "ON" CACHE BOOL "")
+set(CMake_TEST_GUI "OFF" CACHE BOOL "")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora43_ninja.cmake")
diff --git a/.gitlab/ci/configure_fedora43_ninja_multi.cmake b/.gitlab/ci/configure_fedora43_ninja_multi.cmake
index b4d9a70..a99b5d1 100644
--- a/.gitlab/ci/configure_fedora43_ninja_multi.cmake
+++ b/.gitlab/ci/configure_fedora43_ninja_multi.cmake
@@ -1,6 +1,7 @@
 if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
   set(CMake_TEST_ISPC "ON" CACHE STRING "")
 endif()
-set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly,build_database" CACHE STRING "")
+set(CMake_TEST_MODULE_COMPILATION "named,compile_commands,collation,partitions,internal_partitions,export_bmi,install_bmi,shared,bmionly,build_database,import_std23" CACHE STRING "")
+set(CMake_TEST_Rust "ON" CACHE STRING "")
 
 include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_macos_arm64_ninja.cmake b/.gitlab/ci/configure_macos_arm64_ninja.cmake
index eb319c9..c1924fe 100644
--- a/.gitlab/ci/configure_macos_arm64_ninja.cmake
+++ b/.gitlab/ci/configure_macos_arm64_ninja.cmake
@@ -1,11 +1,12 @@
 set(CMake_TEST_C_STANDARDS "90;99;11;17;23" CACHE STRING "")
-set(CMake_TEST_CXX_STANDARDS "98;11;14;17;20;23" CACHE STRING "")
+set(CMake_TEST_CXX_STANDARDS "98;11;14;17;20;23;26" CACHE STRING "")
 
 set(CMake_TEST_FindOpenAL "ON" CACHE BOOL "")
 set(CMake_TEST_FindOpenMP "ON" CACHE BOOL "")
 set(CMake_TEST_FindOpenMP_C "ON" CACHE BOOL "")
 set(CMake_TEST_FindOpenMP_CXX "ON" CACHE BOOL "")
 set(CMake_TEST_GUI "ON" CACHE BOOL "")
+set(CMake_TEST_LOCALE_CHARSET "UTF-8" CACHE STRING "")
 set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
 set(CMake_TEST_TLS_VERIFY_URL_BAD "https://badtls-expired.kitware.com" CACHE STRING "")
 set(CMake_TEST_TLS_VERSION "1.2" CACHE STRING "")
diff --git a/.gitlab/ci/configure_macos_package.cmake b/.gitlab/ci/configure_macos_package.cmake
index cdc8fd2..9a86aeb 100644
--- a/.gitlab/ci/configure_macos_package.cmake
+++ b/.gitlab/ci/configure_macos_package.cmake
@@ -1,5 +1,6 @@
 set(CPACK_SYSTEM_NAME "macos-universal" CACHE STRING "")
 set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "")
+set(CMake_GUI_OSX_DEPLOYMENT_TARGET "12" CACHE STRING "")
 set(CMAKE_C_STANDARD "11" CACHE STRING "")
 set(CMAKE_CXX_STANDARD "17" CACHE STRING "")
 
diff --git a/.gitlab/ci/configure_macos_package_common.cmake b/.gitlab/ci/configure_macos_package_common.cmake
index 2ac7ad6..05206bd 100644
--- a/.gitlab/ci/configure_macos_package_common.cmake
+++ b/.gitlab/ci/configure_macos_package_common.cmake
@@ -11,7 +11,6 @@
 set(BUILD_QtDialog "TRUE" CACHE BOOL "")
 set(CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL "3" CACHE STRING "")
 set(CMake_INSTALL_DEPENDENCIES "ON" CACHE BOOL "")
-set(CMAKE_SKIP_RPATH "TRUE" CACHE BOOL "")
 set(CMake_TEST_BOOTSTRAP OFF CACHE BOOL "")
 set(CMake_TEST_NO_FindPackageModeMakefileTest "TRUE" CACHE BOOL "")
 
diff --git a/.gitlab/ci/configure_macos_x86_64_ninja.cmake b/.gitlab/ci/configure_macos_x86_64_ninja.cmake
index 9de043e..1af144f 100644
--- a/.gitlab/ci/configure_macos_x86_64_ninja.cmake
+++ b/.gitlab/ci/configure_macos_x86_64_ninja.cmake
@@ -1,5 +1,5 @@
 set(CMake_TEST_C_STANDARDS "90;99;11;17;23" CACHE STRING "")
-set(CMake_TEST_CXX_STANDARDS "98;11;14;17;20;23" CACHE STRING "")
+set(CMake_TEST_CXX_STANDARDS "98;11;14;17;20;23;26" CACHE STRING "")
 
 set(CMake_TEST_FindOpenAL "ON" CACHE BOOL "")
 set(CMake_TEST_FindOpenMP "ON" CACHE BOOL "")
@@ -9,6 +9,7 @@
 if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
   set(CMake_TEST_ISPC "ON" CACHE STRING "")
 endif()
+set(CMake_TEST_LOCALE_CHARSET "UTF-8" CACHE STRING "")
 set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
 set(CMake_TEST_TLS_VERIFY_URL_BAD "https://badtls-expired.kitware.com" CACHE STRING "")
 set(CMake_TEST_TLS_VERSION "1.2" CACHE STRING "")
diff --git a/.gitlab/ci/configure_windows_arm64_package.cmake b/.gitlab/ci/configure_windows_arm64_package.cmake
index f3ce853..de88acd 100644
--- a/.gitlab/ci/configure_windows_arm64_package.cmake
+++ b/.gitlab/ci/configure_windows_arm64_package.cmake
@@ -4,7 +4,7 @@
 # Tell WiX to package for this architecture.
 set(CPACK_WIX_ARCHITECTURE "arm64" CACHE STRING "")
 
-# Use APIs from at most Windows 7
+# Use APIs from at most Windows 10
 set(CMAKE_C_FLAGS "-D_WIN32_WINNT=0x0A00 -DNTDDI_VERSION=0x0A000008" CACHE STRING "")
 set(CMAKE_CXX_FLAGS "-GR -EHsc -D_WIN32_WINNT=0x0A00 -DNTDDI_VERSION=0x0A000008" CACHE STRING "")
 set(CMAKE_EXE_LINKER_FLAGS "-machine:arm64 -subsystem:console,6.02" CACHE STRING "")
diff --git a/.gitlab/ci/configure_windows_common.cmake b/.gitlab/ci/configure_windows_common.cmake
index 7467cfd..1246885 100644
--- a/.gitlab/ci/configure_windows_common.cmake
+++ b/.gitlab/ci/configure_windows_common.cmake
@@ -2,6 +2,7 @@
 set(BUILD_CursesDialog ON CACHE BOOL "")
 set(CMAKE_PREFIX_PATH "$ENV{CI_PROJECT_DIR}/.gitlab/qt" CACHE STRING "")
 set(CMake_TEST_Java OFF CACHE BOOL "")
+set(CMake_TEST_LOCALE_CHARSET "UTF-8" CACHE STRING "")
 set(Python_FIND_REGISTRY NEVER CACHE STRING "")
 
 include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")
diff --git a/.gitlab/ci/configure_windows_i386_package.cmake b/.gitlab/ci/configure_windows_i386_package.cmake
index c80ebcc..650a898 100644
--- a/.gitlab/ci/configure_windows_i386_package.cmake
+++ b/.gitlab/ci/configure_windows_i386_package.cmake
@@ -4,10 +4,12 @@
 # Tell WiX to package for this architecture.
 set(CPACK_WIX_ARCHITECTURE "x86" CACHE STRING "")
 
-# Use APIs from at most Windows 7
-set(CMAKE_C_FLAGS "-D_WIN32_WINNT=0x601 -DNTDDI_VERSION=0x06010000" CACHE STRING "")
-set(CMAKE_CXX_FLAGS "-GR -EHsc -D_WIN32_WINNT=0x601 -DNTDDI_VERSION=0x06010000" CACHE STRING "")
-set(CMAKE_EXE_LINKER_FLAGS "-machine:x86 -subsystem:console,6.01" CACHE STRING "")
+# Use APIs from at most Windows 10
+set(CMAKE_C_FLAGS "-D_WIN32_WINNT=0x0A00 -DNTDDI_VERSION=0x0A000000" CACHE STRING "")
+set(CMAKE_CXX_FLAGS "-GR -EHsc -D_WIN32_WINNT=0x0A00 -DNTDDI_VERSION=0x0A000000" CACHE STRING "")
+set(CMAKE_EXE_LINKER_FLAGS "-machine:x86 -subsystem:console,6.02" CACHE STRING "")
 
-include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_package_common_x86.cmake")
+set(qt "$ENV{CI_PROJECT_DIR}/.gitlab/qt")
+set(CMAKE_PREFIX_PATH "${qt}" CACHE STRING "")
+
 include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_package_common.cmake")
diff --git a/.gitlab/ci/configure_windows_package_common_x86.cmake b/.gitlab/ci/configure_windows_package_common_x86.cmake
deleted file mode 100644
index a8b5928..0000000
--- a/.gitlab/ci/configure_windows_package_common_x86.cmake
+++ /dev/null
@@ -1,13 +0,0 @@
-set(qt "$ENV{CI_PROJECT_DIR}/.gitlab/qt")
-set(CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES
-  ${qt}/plugins/platforms/qwindows.lib
-  ${qt}/plugins/styles/qwindowsvistastyle.lib
-  ${qt}/lib/Qt5EventDispatcherSupport.lib
-  ${qt}/lib/Qt5FontDatabaseSupport.lib
-  ${qt}/lib/Qt5ThemeSupport.lib
-  ${qt}/lib/qtfreetype.lib
-  ${qt}/lib/qtlibpng.lib
-  imm32.lib
-  wtsapi32.lib
-  CACHE STRING "")
-set(CMAKE_PREFIX_PATH "${qt}" CACHE STRING "")
diff --git a/.gitlab/ci/configure_windows_vs2019_x64_ninja.cmake b/.gitlab/ci/configure_windows_vs2019_x64_ninja.cmake
deleted file mode 100644
index c078f90..0000000
--- a/.gitlab/ci/configure_windows_vs2019_x64_ninja.cmake
+++ /dev/null
@@ -1 +0,0 @@
-include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_vs_common_ninja.cmake")
diff --git a/.gitlab/ci/configure_windows_vs2026_x64_ninja.cmake b/.gitlab/ci/configure_windows_vs2026_x64_ninja.cmake
index 2771e3f..ad0af0b 100644
--- a/.gitlab/ci/configure_windows_vs2026_x64_ninja.cmake
+++ b/.gitlab/ci/configure_windows_vs2026_x64_ninja.cmake
@@ -2,6 +2,7 @@
 set(CMake_TEST_CXX_STANDARDS "98;11;14;17;20;23" CACHE STRING "")
 
 if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
+  set(CMake_TEST_BIN2C_LARGE_FILE "ON" CACHE BOOL "")
   set(CMake_TEST_CPACK_INNOSETUP "ON" CACHE STRING "")
   set(CMake_TEST_CPACK_NUGET "ON" CACHE STRING "")
   set(CMake_TEST_IAR_TOOLCHAINS "$ENV{CI_PROJECT_DIR}/.gitlab/iar" CACHE PATH "")
diff --git a/.gitlab/ci/configure_windows_x86_64_package.cmake b/.gitlab/ci/configure_windows_x86_64_package.cmake
index 051e3fc..b61e199 100644
--- a/.gitlab/ci/configure_windows_x86_64_package.cmake
+++ b/.gitlab/ci/configure_windows_x86_64_package.cmake
@@ -4,10 +4,12 @@
 # Tell WiX to package for this architecture.
 set(CPACK_WIX_ARCHITECTURE "x64" CACHE STRING "")
 
-# Use APIs from at most Windows 7
-set(CMAKE_C_FLAGS "-D_WIN32_WINNT=0x601 -DNTDDI_VERSION=0x06010000" CACHE STRING "")
-set(CMAKE_CXX_FLAGS "-GR -EHsc -D_WIN32_WINNT=0x601 -DNTDDI_VERSION=0x06010000" CACHE STRING "")
-set(CMAKE_EXE_LINKER_FLAGS "-machine:x64 -subsystem:console,6.01" CACHE STRING "")
+# Use APIs from at most Windows 10
+set(CMAKE_C_FLAGS "-D_WIN32_WINNT=0x0A00 -DNTDDI_VERSION=0x0A000000" CACHE STRING "")
+set(CMAKE_CXX_FLAGS "-GR -EHsc -D_WIN32_WINNT=0x0A00 -DNTDDI_VERSION=0x0A000000" CACHE STRING "")
+set(CMAKE_EXE_LINKER_FLAGS "-machine:x64 -subsystem:console,6.02" CACHE STRING "")
 
-include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_package_common_x86.cmake")
+set(qt "$ENV{CI_PROJECT_DIR}/.gitlab/qt")
+set(CMAKE_PREFIX_PATH "${qt}" CACHE STRING "")
+
 include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_package_common.cmake")
diff --git a/.gitlab/ci/ctest_exclusions.cmake b/.gitlab/ci/ctest_exclusions.cmake
index 30f796b..e04dea3 100644
--- a/.gitlab/ci/ctest_exclusions.cmake
+++ b/.gitlab/ci/ctest_exclusions.cmake
@@ -34,6 +34,7 @@
     "^RunCMake.Autogen_Qt6_1$"
     "^RunCMake.GoogleTest$"
     "^RunCMake.CXXModules$"
+    "^RunCMake.CXXModulesCompile$"
     "^RunCMake.CommandLine$"
 
     # Too spurious under Valgrind.
@@ -41,6 +42,13 @@
     )
 endif()
 
+if ("$ENV{CMAKE_CONFIGURATION}" MATCHES "^macos_x86_64_")
+  list(APPEND test_exclusions
+    # FIXME(#27376): CMakeGUI's simpleConfigure:fail case hangs.
+    "^CMakeGUI$"
+    )
+endif()
+
 string(REPLACE ";" "|" test_exclusions "${test_exclusions}")
 if (test_exclusions)
   set(test_exclusions "(${test_exclusions})")
diff --git a/.gitlab/ci/ctest_memcheck_prep.cmake b/.gitlab/ci/ctest_memcheck_prep.cmake
index 1d9d12c..9b4c2f5 100644
--- a/.gitlab/ci/ctest_memcheck_prep.cmake
+++ b/.gitlab/ci/ctest_memcheck_prep.cmake
@@ -29,7 +29,7 @@
     sample_script
     */Tests/CTestTest2/kwsysBin/*
     */Tests/CTestTestCrash/Crash
-    *QtAutogen
+    */Tests/Qt*Autogen/*
     # Ignore ISPC files which may contain unimplemented instructions.
     */build/Tests/ISPC/TryCompile/ISPCTryCompile
     # Ignore anything CI downloads.
diff --git a/.gitlab/ci/docker/cuda13.0-aarch64/Dockerfile b/.gitlab/ci/docker/cuda13.0-aarch64/Dockerfile
new file mode 100644
index 0000000..1dc4131
--- /dev/null
+++ b/.gitlab/ci/docker/cuda13.0-aarch64/Dockerfile
@@ -0,0 +1,32 @@
+# syntax=docker/dockerfile:1
+
+ARG BASE_IMAGE=kitware/nvidia-cuda:13.0.1-devel-ubuntu24.04
+
+FROM ${BASE_IMAGE} AS apt-config
+ADD https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/sbsa/cuda-keyring_1.1-1_all.deb /root/
+RUN --mount=type=tmpfs,target=/var/log \
+    dpkg -i /root/cuda-keyring_1.1-1_all.deb \
+ && rm /root/cuda-keyring_1.1-1_all.deb /etc/apt/sources.list.d/cuda.list
+
+FROM apt-config AS apt-cache
+# Populate APT cache w/ the fresh metadata and prefetch packages.
+# Use an empty `docker-clean` file to "hide" the image-provided
+# file to disallow removing packages after `apt-get` operations.
+RUN --mount=type=tmpfs,target=/var/log \
+    --mount=type=bind,source=docker-clean,target=/etc/apt/apt.conf.d/docker-clean \
+    --mount=type=bind,source=deps_packages.lst,target=/root/deps_packages.lst \
+    apt-get update \
+ && apt-get --download-only -y install $(grep -h '^[^#]\+$' /root/*.lst)
+
+FROM apt-config
+MAINTAINER Brad King <brad.king@kitware.com>
+
+RUN --mount=type=bind,source=install_deps.sh,target=/root/install_deps.sh \
+    --mount=type=bind,source=deps_packages.lst,target=/root/deps_packages.lst \
+    --mount=type=bind,source=dpkg-exclude,target=/etc/dpkg/dpkg.cfg.d/exclude \
+    --mount=type=bind,source=docker-clean,target=/etc/apt/apt.conf.d/docker-clean \
+    --mount=type=cache,from=apt-cache,source=/var/lib/apt/lists,target=/var/lib/apt/lists \
+    --mount=type=cache,from=apt-cache,source=/var/cache/apt,target=/var/cache/apt,sharing=private \
+    --mount=type=tmpfs,target=/var/log \
+    --mount=type=tmpfs,target=/tmp \
+    sh /root/install_deps.sh
diff --git a/.gitlab/ci/docker/cuda13.0-aarch64/deps_packages.lst b/.gitlab/ci/docker/cuda13.0-aarch64/deps_packages.lst
new file mode 100644
index 0000000..4637272
--- /dev/null
+++ b/.gitlab/ci/docker/cuda13.0-aarch64/deps_packages.lst
@@ -0,0 +1,11 @@
+# Host tools
+curl
+git
+unzip
+
+# Compilers
+g++
+
+# CUDA Dependencies
+ocl-icd-opencl-dev
+opencl-headers
diff --git a/.gitlab/ci/docker/cuda13.0/docker-clean b/.gitlab/ci/docker/cuda13.0-aarch64/docker-clean
similarity index 100%
rename from .gitlab/ci/docker/cuda13.0/docker-clean
rename to .gitlab/ci/docker/cuda13.0-aarch64/docker-clean
diff --git a/.gitlab/ci/docker/cuda13.0/dpkg-exclude b/.gitlab/ci/docker/cuda13.0-aarch64/dpkg-exclude
similarity index 100%
rename from .gitlab/ci/docker/cuda13.0/dpkg-exclude
rename to .gitlab/ci/docker/cuda13.0-aarch64/dpkg-exclude
diff --git a/.gitlab/ci/docker/cuda13.0/install_deps.sh b/.gitlab/ci/docker/cuda13.0-aarch64/install_deps.sh
similarity index 100%
rename from .gitlab/ci/docker/cuda13.0/install_deps.sh
rename to .gitlab/ci/docker/cuda13.0-aarch64/install_deps.sh
diff --git a/.gitlab/ci/docker/cuda13.0/Dockerfile b/.gitlab/ci/docker/cuda13.0-x86_64/Dockerfile
similarity index 100%
rename from .gitlab/ci/docker/cuda13.0/Dockerfile
rename to .gitlab/ci/docker/cuda13.0-x86_64/Dockerfile
diff --git a/.gitlab/ci/docker/cuda13.0/deps_packages.lst b/.gitlab/ci/docker/cuda13.0-x86_64/deps_packages.lst
similarity index 100%
rename from .gitlab/ci/docker/cuda13.0/deps_packages.lst
rename to .gitlab/ci/docker/cuda13.0-x86_64/deps_packages.lst
diff --git a/.gitlab/ci/docker/cuda13.0/docker-clean b/.gitlab/ci/docker/cuda13.0-x86_64/docker-clean
similarity index 100%
copy from .gitlab/ci/docker/cuda13.0/docker-clean
copy to .gitlab/ci/docker/cuda13.0-x86_64/docker-clean
diff --git a/.gitlab/ci/docker/cuda13.0/dpkg-exclude b/.gitlab/ci/docker/cuda13.0-x86_64/dpkg-exclude
similarity index 100%
copy from .gitlab/ci/docker/cuda13.0/dpkg-exclude
copy to .gitlab/ci/docker/cuda13.0-x86_64/dpkg-exclude
diff --git a/.gitlab/ci/docker/cuda13.0/install_deps.sh b/.gitlab/ci/docker/cuda13.0-x86_64/install_deps.sh
similarity index 100%
copy from .gitlab/ci/docker/cuda13.0/install_deps.sh
copy to .gitlab/ci/docker/cuda13.0-x86_64/install_deps.sh
diff --git a/.gitlab/ci/docker/debian13-aarch64/Dockerfile b/.gitlab/ci/docker/debian13-aarch64/Dockerfile
index 4793a96..5a7f2fb 100644
--- a/.gitlab/ci/docker/debian13-aarch64/Dockerfile
+++ b/.gitlab/ci/docker/debian13-aarch64/Dockerfile
@@ -3,7 +3,7 @@
 ARG BASE_IMAGE=arm64v8/debian:13
 
 FROM ${BASE_IMAGE} AS cuda-keyring
-ADD https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/sbsa/cuda-keyring_1.1-1_all.deb /root/
+ADD https://developer.download.nvidia.com/compute/cuda/repos/debian13/sbsa/cuda-keyring_1.1-1_all.deb /root/
 RUN --mount=type=tmpfs,target=/var/log \
     apt-get update \
  && apt-get -y install ca-certificates \
diff --git a/.gitlab/ci/docker/debian13-aarch64/deps_packages.lst b/.gitlab/ci/docker/debian13-aarch64/deps_packages.lst
index 0b76622..2e13e5b 100644
--- a/.gitlab/ci/docker/debian13-aarch64/deps_packages.lst
+++ b/.gitlab/ci/docker/debian13-aarch64/deps_packages.lst
@@ -1,3 +1,5 @@
+locales
+
 # Install build requirements.
 libssl-dev
 
diff --git a/.gitlab/ci/docker/debian13-aarch64/install_deps.sh b/.gitlab/ci/docker/debian13-aarch64/install_deps.sh
index d1c8aed..25b59aa 100755
--- a/.gitlab/ci/docker/debian13-aarch64/install_deps.sh
+++ b/.gitlab/ci/docker/debian13-aarch64/install_deps.sh
@@ -3,3 +3,7 @@
 set -e
 
 apt-get install -y $(grep '^[^#]\+$' /root/deps_packages.lst)
+
+# Add locales.
+sed -i -E '/^# en_US[ .](ISO-8859-1|UTF-8)( |$)/ s/^# //' /etc/locale.gen
+dpkg-reconfigure --frontend=noninteractive locales
diff --git a/.gitlab/ci/docker/debian13-x86_64/Dockerfile b/.gitlab/ci/docker/debian13-x86_64/Dockerfile
index 3c40e52..defa93f 100644
--- a/.gitlab/ci/docker/debian13-x86_64/Dockerfile
+++ b/.gitlab/ci/docker/debian13-x86_64/Dockerfile
@@ -16,7 +16,7 @@
 
 
 FROM ${BASE_IMAGE} AS iwyu-build
-LABEL maintainer="Ben Boeckel <ben.boeckel@kitware.com>"
+LABEL maintainer="Brad King <brad.king@kitware.com>"
 
 RUN --mount=type=bind,source=install_iwyu.sh,target=/root/install_iwyu.sh \
     --mount=type=bind,source=iwyu_packages.lst,target=/root/iwyu_packages.lst \
@@ -29,7 +29,7 @@
 
 
 FROM ${BASE_IMAGE} AS rvm-build
-LABEL maintainer="Ben Boeckel <ben.boeckel@kitware.com>"
+LABEL maintainer="Brad King <brad.king@kitware.com>"
 
 RUN --mount=type=bind,source=install_rvm.sh,target=/root/install_rvm.sh \
     --mount=type=bind,source=rvm_packages.lst,target=/root/rvm_packages.lst \
@@ -42,7 +42,7 @@
 
 
 FROM ${BASE_IMAGE}
-LABEL maintainer="Ben Boeckel <ben.boeckel@kitware.com>"
+LABEL maintainer="Brad King <brad.king@kitware.com>"
 
 ENV RBENV_ROOT=/opt/rbenv
 
diff --git a/.gitlab/ci/docker/debian13-x86_64/deps_packages.lst b/.gitlab/ci/docker/debian13-x86_64/deps_packages.lst
index b1b792c..339053d 100644
--- a/.gitlab/ci/docker/debian13-x86_64/deps_packages.lst
+++ b/.gitlab/ci/docker/debian13-x86_64/deps_packages.lst
@@ -1,3 +1,5 @@
+locales
+
 # Install build requirements.
 libssl-dev
 
diff --git a/.gitlab/ci/docker/debian13-x86_64/install_deps.sh b/.gitlab/ci/docker/debian13-x86_64/install_deps.sh
index 1493f1e..c916159 100755
--- a/.gitlab/ci/docker/debian13-x86_64/install_deps.sh
+++ b/.gitlab/ci/docker/debian13-x86_64/install_deps.sh
@@ -4,6 +4,10 @@
 
 apt-get install -y $(grep '^[^#]\+$' /root/deps_packages.lst)
 
+# Add locales.
+sed -i -E '/^# en_US[ .](ISO-8859-1|UTF-8)( |$)/ s/^# //' /etc/locale.gen
+dpkg-reconfigure --frontend=noninteractive locales
+
 curl -L -O https://github.com/IronLanguages/ironpython3/releases/download/v3.4.0/ironpython_3.4.0.deb
 echo '7dcd10b7a0ec0342bd7e20eebb597a96bb15267eb797d59358a3b1cfaa3e1adc  ironpython_3.4.0.deb' > ironpython.sha256sum
 sha256sum --check ironpython.sha256sum
diff --git a/.gitlab/ci/docker/fedora43/Dockerfile b/.gitlab/ci/docker/fedora43/Dockerfile
index 57c70b5..86ee3b8 100644
--- a/.gitlab/ci/docker/fedora43/Dockerfile
+++ b/.gitlab/ci/docker/fedora43/Dockerfile
@@ -16,7 +16,7 @@
 
 
 FROM ${BASE_IMAGE} AS rust-build-env
-LABEL maintainer="Ben Boeckel <ben.boeckel@kitware.com>"
+LABEL maintainer="Brad King <brad.king@kitware.com>"
 # Pre-install prerequisites to build Rust projects.
 RUN --mount=type=bind,source=dnf.conf,target=/etc/dnf/dnf.conf \
     --mount=type=bind,source=rust_packages.lst,target=/root/rust_packages.lst \
@@ -27,7 +27,7 @@
 
 
 FROM rust-build-env AS rust-build
-LABEL maintainer="Ben Boeckel <ben.boeckel@kitware.com>"
+LABEL maintainer="Brad King <brad.king@kitware.com>"
 # Build the needed Rust packages.
 # https://doc.rust-lang.org/cargo/guide/cargo-home.html?highlight=.cargo#caching-the-cargo-home-in-ci
 RUN --mount=type=bind,source=build_rust.sh,target=/root/build_rust.sh \
@@ -38,7 +38,7 @@
 
 
 FROM ${BASE_IMAGE} AS rvm-build-env
-LABEL maintainer="Ben Boeckel <ben.boeckel@kitware.com>"
+LABEL maintainer="Brad King <brad.king@kitware.com>"
 # Pre-install prerequisites for RVM.
 RUN --mount=type=bind,source=dnf.conf,target=/etc/dnf/dnf.conf \
     --mount=type=bind,source=rvm_packages.lst,target=/root/rvm_packages.lst \
@@ -49,7 +49,7 @@
 
 
 FROM rvm-build-env AS rvm-build
-LABEL maintainer="Ben Boeckel <ben.boeckel@kitware.com>"
+LABEL maintainer="Brad King <brad.king@kitware.com>"
 # Build Ruby with RVM.
 RUN --mount=type=bind,source=build_rvm.sh,target=/root/build_rvm.sh \
     --mount=type=cache,target=/usr/local/rvm/archives \
@@ -108,7 +108,7 @@
 
 
 FROM ${BASE_IMAGE}
-LABEL maintainer="Ben Boeckel <ben.boeckel@kitware.com>"
+LABEL maintainer="Brad King <brad.king@kitware.com>"
 
 ENV RBENV_ROOT=/opt/rbenv
 
diff --git a/.gitlab/ci/docker/fedora43/build_rust.sh b/.gitlab/ci/docker/fedora43/build_rust.sh
index 5dcea8f..5ab91f7 100755
--- a/.gitlab/ci/docker/fedora43/build_rust.sh
+++ b/.gitlab/ci/docker/fedora43/build_rust.sh
@@ -2,7 +2,7 @@
 
 set -e
 
-typos_version=1.38.1
+typos_version=1.44.0
 cargo install --root /usr/local --version "$typos_version" typos-cli
 
 strip /usr/local/bin/typos
diff --git a/.gitlab/ci/docker/fedora43/deps_packages.lst b/.gitlab/ci/docker/fedora43/deps_packages.lst
index 7873533..143c296 100644
--- a/.gitlab/ci/docker/fedora43/deps_packages.lst
+++ b/.gitlab/ci/docker/fedora43/deps_packages.lst
@@ -1,3 +1,5 @@
+glibc-locale-source
+
 # Install build requirements.
 ncurses-devel
 openssl-devel
@@ -16,6 +18,7 @@
 lfortran
 llvm-devel
 make
+rust
 
 # Install optional external build dependencies.
 bzip2-devel
diff --git a/.gitlab/ci/docker/fedora43/install_deps.sh b/.gitlab/ci/docker/fedora43/install_deps.sh
index 6ee3a3d..cc3480a 100755
--- a/.gitlab/ci/docker/fedora43/install_deps.sh
+++ b/.gitlab/ci/docker/fedora43/install_deps.sh
@@ -4,6 +4,10 @@
 
 dnf install -y $(grep '^[^#]\+$' /root/deps_packages.lst)
 
+# Add locales.
+localedef --no-archive --inputfile=en_US --charmap=ISO-8859-1 en_US.ISO-8859-1
+localedef --no-archive --inputfile=en_US --charmap=UTF-8 en_US.UTF-8
+
 # Remove tests for Python packages
 for v in 3.14; do
     find /usr/lib64/python${v}/site-packages -type d -a -name tests -exec rm -rf {} +
diff --git a/.gitlab/ci/download_qt.cmake b/.gitlab/ci/download_qt.cmake
index 0c0d3d1..759365e 100644
--- a/.gitlab/ci/download_qt.cmake
+++ b/.gitlab/ci/download_qt.cmake
@@ -1,75 +1,49 @@
 cmake_minimum_required(VERSION 3.29)
 
-# Input variables.
-set(qt_version_major "5")
-set(qt_version_minor "15")
-set(qt_version_patch "1")
-
-# Combined version variables.
-set(qt_version "${qt_version_major}.${qt_version_minor}.${qt_version_patch}")
-set(qt_version_nodot "${qt_version_major}${qt_version_minor}${qt_version_patch}")
+set(qt_tar_workdir ".gitlab")
 
 # Files needed to download.
 set(qt_files)
 if ("$ENV{CMAKE_CONFIGURATION}" MATCHES "windows.*package")
-  set(qt_url_root "https://cmake.org/files/dependencies")
+  set(qt_url_root "https://cmake.org/files/dependencies/qt")
   set(qt_url_path "")
   if ("$ENV{CMAKE_CONFIGURATION}" MATCHES "windows_x86_64_package")
-    list(APPEND qt_files "qt-5.15.10-win-x86_64-msvc_v142-1.zip")
-    set(qt_subdir "qt-5.15.10-win-x86_64-msvc_v142-1")
+    list(APPEND qt_files "qt-6.10.1-win-x86_64-msvc_v145-1.zip")
+    set(qt_subdir "qt-6.10.1-win-x86_64-msvc_v145-1")
   elseif ("$ENV{CMAKE_CONFIGURATION}" MATCHES "windows_i386_package")
-    list(APPEND qt_files "qt-5.15.10-win-i386-msvc_v142-1.zip")
-    set(qt_subdir "qt-5.15.10-win-i386-msvc_v142-1")
+    list(APPEND qt_files "qt-6.10.1-win-i386-msvc_v145-1.zip")
+    set(qt_subdir "qt-6.10.1-win-i386-msvc_v145-1")
   elseif ("$ENV{CMAKE_CONFIGURATION}" MATCHES "windows_arm64_package")
-    list(APPEND qt_files "qt-6.3.0-win-arm64-msvc_v143-1.zip")
-    set(qt_subdir "qt-6.3.0-win-arm64-msvc_v143-1")
-    list(APPEND qt_files "qt-6.3.0-win-x86_64-msvc_v143-1.zip")
-    set(qt_host_subdir "qt-6.3.0-win-x86_64-msvc_v143-1")
+    list(APPEND qt_files "qt-6.10.1-win-arm64-msvc_v145-1.zip")
+    set(qt_subdir "qt-6.10.1-win-arm64-msvc_v145-1")
+    list(APPEND qt_files "qt-6.10.1-win-x86_64-msvc_v145-1.zip")
+    set(qt_host_subdir "qt-6.10.1-win-x86_64-msvc_v145-1")
   else ()
     message(FATAL_ERROR "Unknown arch to use for Qt")
   endif()
 elseif ("$ENV{CMAKE_CONFIGURATION}" MATCHES "windows")
-  # Determine the ABI to fetch for Qt.
-  if ("$ENV{CMAKE_CONFIGURATION}" MATCHES "vs2015")
-    set(qt_platform "windows_x86")
-    set(msvc_year "2015")
-    set(qt_abi "win64_msvc${msvc_year}_64")
-  elseif ("$ENV{CMAKE_CONFIGURATION}" MATCHES "vs2017" OR
-          "$ENV{CMAKE_CONFIGURATION}" MATCHES "vs2019" OR
-          "$ENV{CMAKE_CONFIGURATION}" MATCHES "vs2022" OR
-          "$ENV{CMAKE_CONFIGURATION}" MATCHES "vs2026")
-    set(qt_platform "windows_x86")
-    set(msvc_year "2019")
-    set(qt_abi "win64_msvc${msvc_year}_64")
-  else ()
-    message(FATAL_ERROR "Unknown ABI to use for Qt")
-  endif ()
-
-  set(qt_build_stamp "202009071110")
-
-  set(qt_file_name_prefix "${qt_version}-0-${qt_build_stamp}")
-
-  foreach (qt_component IN ITEMS qtbase qtwinextras)
-    list(APPEND qt_files
-      "${qt_file_name_prefix}${qt_component}-Windows-Windows_10-MSVC${msvc_year}-Windows-Windows_10-X86_64.7z")
-  endforeach ()
-
-  set(qt_subdir "${qt_version}/msvc${msvc_year}_64")
-
   # This URL is only visible inside of Kitware's network.
   # Please use your own Qt Account to obtain these files.
   set(qt_url_root "https://paraview.org/files/dependencies/internal/qt")
-  set(qt_url_path "${qt_platform}/desktop/qt5_${qt_version_nodot}/qt.qt5.${qt_version_nodot}.${qt_abi}")
+  set(qt_url_path "windows_x86/desktop/qt6_693/qt6_693/qt.qt6.693.win64_msvc2022_64")
+  list(APPEND qt_files "6.9.3-0-202509261208qtbase-Windows-Windows_11_23H2-MSVC2022-Windows-Windows_11_23H2-X86_64.7z")
+  set(qt_subdir "qt-extract")
+  set(qt_tar_workdir ".gitlab/${qt_subdir}")
 elseif ("$ENV{CMAKE_CONFIGURATION}" MATCHES "macos")
   if ("$ENV{CMAKE_CONFIGURATION}" MATCHES "macos10.10_package")
+    set(qt_url_root "https://cmake.org/files/dependencies/qt")
+    set(qt_url_path "")
     list(APPEND qt_files "qt-5.9.9-macosx10.10-x86_64-arm64.tar.xz")
     set(qt_subdir "qt-5.9.9-macosx10.10-x86_64-arm64")
   else ()
-    list(APPEND qt_files "qt-5.15.2-macosx10.13-x86_64-arm64.tar.xz")
-    set(qt_subdir "qt-5.15.2-macosx10.13-x86_64-arm64")
+    # This URL is only visible inside of Kitware's network.
+    # Please use your own Qt Account to obtain these files.
+    set(qt_url_root "https://www.paraview.org/files/dependencies/internal/qt")
+    set(qt_url_path "mac_x64/desktop/qt6_693/qt6_693/qt.qt6.693.clang_64")
+    list(APPEND qt_files "6.9.3-0-202509261207qtbase-MacOS-MacOS_15-Clang-MacOS-MacOS_15-X86_64-ARM64.7z")
+    set(qt_subdir "qt-extract")
+    set(qt_tar_workdir ".gitlab/${qt_subdir}")
   endif()
-  set(qt_url_root "https://cmake.org/files/dependencies")
-  set(qt_url_path "")
 else()
   message(FATAL_ERROR "Unknown OS to use for Qt")
 endif ()
@@ -110,12 +84,13 @@
   endif ()
 
   # Extract the file.
+  file(MAKE_DIRECTORY "${qt_tar_workdir}")
   execute_process(
     COMMAND
       "${CMAKE_COMMAND}"
       -E tar
-      xf "${qt_file}"
-    WORKING_DIRECTORY ".gitlab"
+      xf "${CMAKE_CURRENT_SOURCE_DIR}/.gitlab/${qt_file}"
+    WORKING_DIRECTORY "${qt_tar_workdir}"
     RESULT_VARIABLE res
     ERROR_VARIABLE err
     ERROR_STRIP_TRAILING_WHITESPACE)
@@ -126,29 +101,6 @@
   file(REMOVE "${qt_file}")
 endforeach ()
 
-# The Windows tarballs have some unfortunate permissions in them that prevent
-# deletion when `git clean -ffdx` tries to clean up the directory.
-if (qt_platform STREQUAL "windows_x86")
-  # Fix permissions.
-  file(TO_NATIVE_PATH ".gitlab/${qt_subdir}/*.*" native_qt_dir)
-  execute_process(
-    # Remove any read-only flags that aren't affected by `icacls`.
-    COMMAND
-      attrib
-      -r # Remove readonly flag
-      "${native_qt_dir}"
-      /d # Treat as a directory
-      /s # Recursive
-      /l # Don't dereference symlinks
-    RESULT_VARIABLE res
-    ERROR_VARIABLE err
-    ERROR_STRIP_TRAILING_WHITESPACE)
-  if (res)
-    message(FATAL_ERROR
-      "Failed to fix remove read-only flags in ${qt_file}: ${err}")
-  endif ()
-endif ()
-
 # Move to a predictable prefix.
 file(RENAME
   ".gitlab/${qt_subdir}"
diff --git a/.gitlab/ci/download_qt_hashes.cmake b/.gitlab/ci/download_qt_hashes.cmake
index 1b9cf14..ea3220a 100644
--- a/.gitlab/ci/download_qt_hashes.cmake
+++ b/.gitlab/ci/download_qt_hashes.cmake
@@ -2,20 +2,11 @@
 #
 #   sha256sum $files | awk '{ print "set(\"" $2 "_hash\" " $1 ")" }' >> $thisfile
 
-set("5.15.1-0-202009071110qtbase-Windows-Windows_10-MSVC2019-Windows-Windows_10-X86_64.7z_hash" a5635124a135f383d9fb92bf628b018cff9f781addfd388926a367cda5b7cd38)
-set("5.15.1-0-202009071110qtwinextras-Windows-Windows_10-MSVC2019-Windows-Windows_10-X86_64.7z_hash" 908947855b5d7a854886746365ac29e9296b5d64d4e18089641a6988167807d3)
-
-set("5.15.1-0-202009071110qtbase-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z_hash" 5d0d2e71e3b00cf88ac4c616b4b314a7e73871f325512821f53c464cdfee961f)
-set("5.15.1-0-202009071110qtwinextras-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z_hash" 803e0234169464babb5305dedc21382e90c3266c6f9414ff0cff04be578681e1)
-
-set("5.15.1-0-202009071110qtbase-MacOS-MacOS_10_13-Clang-MacOS-MacOS_10_13-X86_64.7z_hash" df2813ce7c6cb4287abd7956cd1cb9d08312e4ac1208b6cb57af4df11b8ebba1)
-
 set("qt-5.9.9-macosx10.10-x86_64-arm64.tar.xz_hash" d4449771afa0bc6a809c14f1e6d939e7732494cf059503ae451e2bfe8fc60cc1)
-set("qt-5.15.2-macosx10.13-x86_64-arm64.tar.xz_hash" 7b9463a01c8beeee5bf8d01c70deff2d08561cd20aaf6f7a2f41cf8b68ce8a6b)
+set("6.9.3-0-202509261207qtbase-MacOS-MacOS_15-Clang-MacOS-MacOS_15-X86_64-ARM64.7z_hash" 805144e619b7c7b0e9c985d929e1f290241d88b884218db3ad7d56bd579d6b4a)
 
-set("qt-5.15.10-win-i386-msvc_v142-1.zip_hash" c158cebc054d3f4f09733772a8a04789e2884912d45782e8c0c5e6a0b2773e92)
-set("qt-5.15.10-win-x86_64-msvc_v142-1.zip_hash" d55c017aef359f6aa8c592b18ba13cc120c749417b55671548970690126cd139)
+set("6.9.3-0-202509261208qtbase-Windows-Windows_11_23H2-MSVC2022-Windows-Windows_11_23H2-X86_64.7z_hash" 94f8a097d3078661943446c9ecfee3fb4375d9b992a91a1a2d1856379c749d8d)
 
-set("qt-6.3.0-win-arm64-msvc_v143-1.zip_hash" f794c035fd4ff9f04468e1787a60d93d7496119c0060c3173a76d24a6b551b14)
-set("qt-6.3.0-win-i386-msvc_v143-1.zip_hash" 972bc707f78d11b44f360643ca4d0c898e761f7add43b96117d958c70d84a443)
-set("qt-6.3.0-win-x86_64-msvc_v143-1.zip_hash" 4fb0aaebe184f40392f1bb246469dca591bfdfb8f915e19f921476222473ac90)
+set("qt-6.10.1-win-arm64-msvc_v145-1.zip_hash" 59e150883f31c0e31a2890f06b6e434ad44505dba876fda4a7c0994c9b0bdfe1)
+set("qt-6.10.1-win-i386-msvc_v145-1.zip_hash" 09100628aecb7cdde07040d7437c09830ed8c17720960b10339b114cb4bbf18b)
+set("qt-6.10.1-win-x86_64-msvc_v145-1.zip_hash" 931f2354c715b30bc0ac35028f9d778aa552aa8a66580fc73c6a32384c5fa042)
diff --git a/.gitlab/ci/env.sh b/.gitlab/ci/env.sh
index de5cf6f..8b66654 100644
--- a/.gitlab/ci/env.sh
+++ b/.gitlab/ci/env.sh
@@ -19,10 +19,21 @@
   test "$(git -C "$CI_PROJECT_DIR/work/cmake" rev-parse HEAD)" = "$(git -C "$CI_PROJECT_DIR" rev-parse HEAD)"
 fi
 
+# Default to a UTF-8 locale.  The per-job environment may override it.
+locales="$(locale -a 2>/dev/null)"
+if echo "$locales" | grep -qE '^C\.(UTF-8|utf8)$'; then
+  export LANG=C.UTF-8
+elif echo "$locales" | grep -qE '^en_US\.(UTF-8|utf8)$'; then
+  export LANG=en_US.UTF-8
+fi
+
 if test -r ".gitlab/ci/env_${CMAKE_CONFIGURATION}.sh"; then
   source ".gitlab/ci/env_${CMAKE_CONFIGURATION}.sh"
 fi
 
+# Report the selected locale.
+echo "locale: $(locale | grep '^LANG=') with $(locale -k charmap)"
+
 case "$(uname -s)-$(uname -m)" in
     Linux-*)
         # Remove superuser tools from PATH.
diff --git a/.gitlab/ci/env_fedora43_clang_fuzzing.sh b/.gitlab/ci/env_fedora43_clang_fuzzing.sh
new file mode 100644
index 0000000..729fb37
--- /dev/null
+++ b/.gitlab/ci/env_fedora43_clang_fuzzing.sh
@@ -0,0 +1,5 @@
+export CC=/usr/bin/clang
+export CXX=/usr/bin/clang++
+
+export CFLAGS=-fsanitize=fuzzer-no-link,address
+export CXXFLAGS=-fsanitize=fuzzer-no-link,address
diff --git a/.gitlab/ci/env_fedora43_makefiles.sh b/.gitlab/ci/env_fedora43_makefiles.sh
index 217ff30..f02e487 100644
--- a/.gitlab/ci/env_fedora43_makefiles.sh
+++ b/.gitlab/ci/env_fedora43_makefiles.sh
@@ -1,3 +1,6 @@
 if test "$CMAKE_CI_NIGHTLY" = "true"; then
   source .gitlab/ci/ispc-env.sh
 fi
+
+# Test in a Latin-1 locale.
+export LANG=en_US.ISO-8859-1
diff --git a/.gitlab/ci/env_fedora43_ninja.sh b/.gitlab/ci/env_fedora43_ninja.sh
index a2b941b..0ef4bce 100644
--- a/.gitlab/ci/env_fedora43_ninja.sh
+++ b/.gitlab/ci/env_fedora43_ninja.sh
@@ -2,3 +2,6 @@
   source .gitlab/ci/appimagetool-env.sh
   source .gitlab/ci/ispc-env.sh
 fi
+
+# Test in a UTF-8 locale.
+export LANG=en_US.UTF-8
diff --git a/.gitlab/ci/env_fedora43_ninja_instrumentation.sh b/.gitlab/ci/env_fedora43_ninja_instrumentation.sh
new file mode 100644
index 0000000..cc89d0b
--- /dev/null
+++ b/.gitlab/ci/env_fedora43_ninja_instrumentation.sh
@@ -0,0 +1 @@
+source .gitlab/ci/env_fedora43_ninja.sh
diff --git a/.gitlab/ci/env_macos_package.sh b/.gitlab/ci/env_macos_package.sh
deleted file mode 100644
index e810f63..0000000
--- a/.gitlab/ci/env_macos_package.sh
+++ /dev/null
@@ -1 +0,0 @@
-. .gitlab/ci/macos-env.sh
diff --git a/.gitlab/ci/iar-env.sh b/.gitlab/ci/iar-env.sh
index 39a5580..67d9d54 100644
--- a/.gitlab/ci/iar-env.sh
+++ b/.gitlab/ci/iar-env.sh
@@ -1,9 +1,9 @@
 files='
-bxarm-9.70.1.deb
-bxavr-8.10.2.deb
-bxrh850-3.10.2.deb
-bxriscv-3.40.1.deb
-bxrl78-5.20.1.deb
+bxarm-9.70.2.deb
+bxavr-8.10.3.deb
+bxrh850-3.20.1.deb
+bxriscv-3.40.2.deb
+bxrl78-5.20.2.deb
 bxrx-5.20.1.deb
 '
 for f in $files; do
@@ -12,11 +12,11 @@
 done
 
 echo '
-3b16748e560ab8fa3ffe6d6807186ac706134c78bc9db911112ab3ee67c7b997  bxarm-9.70.1.deb
-4a1065291952a23a8bfbbaa4eb36ca49b0af8653b8faab34ce955d9d48d64506  bxavr-8.10.2.deb
-b14085a0f21750c58168125d3cece2e3fcbd4c6495c652b5e65b6637bac0ac31  bxrh850-3.10.2.deb
-2e7de58a3aad43ef4199b811edd4dae9c4bff633376393f12fcb77ca27aba831  bxriscv-3.40.1.deb
-6a2b6163dd971635715f49cb072c853e5de55d2b0089f319a6a9f6db540af4bd  bxrl78-5.20.1.deb
+0a90ec54f097ebc24f7e12aa665b22cdaa78ea0a59792814392dce510d9fece1  bxarm-9.70.2.deb
+4fc428eee8617d365c526d67f9a30ed0873cbb916160a35ab7b50b4de0628dc0  bxavr-8.10.3.deb
+48b85860fc226aa8284b21ba3a49bfe018b12d61b5d0ab184e90840836583521  bxrh850-3.20.1.deb
+e701a208d4fac3fe52f685b785c1983383de48d556a77c5921f649d983c7339f  bxriscv-3.40.2.deb
+eb672e903d11f45adb591cf4a56e45187fe979c05e1c21d30ba7c1f6d95ea648  bxrl78-5.20.2.deb
 059667a53b6683b1b09b7842d71e784c04bc2376734421c3a628acdbc6bef9e3  bxrx-5.20.1.deb
 ' > bxdebs.sha256sum
 sha256sum --check bxdebs.sha256sum
diff --git a/.gitlab/ci/iar.ps1 b/.gitlab/ci/iar.ps1
index 4c1093d..d0f41b9 100644
--- a/.gitlab/ci/iar.ps1
+++ b/.gitlab/ci/iar.ps1
@@ -7,12 +7,12 @@
 $iar_dir = New-Item -Force -ItemType Directory -Path "$outdir\iar"
 
 $files = @{
-    "bxarm-9.70.1.13552-1.zip" = "866792FA6881C28610558E87EE02A45752CC06E7550FB57682720CDC300DA0B7"
-    "BXAVR-8102-1.zip"         = "862EFD23531854506070D5647F9B32197B80E5A727304BFBD8E386A3DAADF093"
-    "BXRH850-3102-1.zip"       = "8D1D009A0D138C7CA8431316123CB85CE1B41319A68B997F90D2E338CD469C7F"
-    "BXRISCV-3401-1.zip"       = "633F9BF64429923B0C478FB8ED0C47B3A67BC9B23DD9A2851DE66AC70DA64E06"
-    "bxrl78-5.20.1.2826-1.zip" = "71E981EC18C5BC031A356D89C4D6579DF0B0EF9EB34AB3B46A48DA3F3737C2D4"
-    "bxrx-5.20.1.6541-1.zip"   = "C000B333618A253482DCCB8F06CB902F6D9D0B7D554B863175D316004FBFFC82"
+    "bxarm-9.70.2.18199-1.zip"  = "47F91EB1829754440ED57B112D068345F1662309748AD5F1F8A6F6DA7362A54E"
+    "BXAVR-8103-1.zip"          = "53DA32EC4CF0CD0A2D4B81EF2CB5B8AF4D48B14A65661CB112394C634F897C8C"
+    "bxrh850-3.20.1.2142-1.zip" = "21EBFC9B61F5B25DF91F6578C6311AABC5BEB9FC9A71CDC54B85727149079ACF"
+    "BXRISCV-3402-1.zip"        = "6A694D111DED058944F55545F7E64E5B67DEC3E28B30B4436BEF6C0080C90F8D"
+    "bxrl78-5.20.2.2949-1.zip"  = "81ED60CFB7A8528490C1CBFCB22894E56B0A32A401F2F79ADFEA1D626EE7AF34"
+    "bxrx-5.20.1.6541-1.zip"    = "C000B333618A253482DCCB8F06CB902F6D9D0B7D554B863175D316004FBFFC82"
 }
 
 foreach ($f in $files.GetEnumerator()) {
diff --git a/.gitlab/ci/macos-env.sh b/.gitlab/ci/macos-env.sh
deleted file mode 100644
index 1b8ad8e..0000000
--- a/.gitlab/ci/macos-env.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-.gitlab/ci/macos.sh
-export SDKROOT="$PWD/.gitlab/MacOSX.sdk"
diff --git a/.gitlab/ci/macos.sh b/.gitlab/ci/macos.sh
deleted file mode 100755
index 7e947a2..0000000
--- a/.gitlab/ci/macos.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/sh
-
-set -e
-
-# This URL is only visible inside of Kitware's network.
-baseurl="https://cmake.org/files/dependencies/internal/macos"
-
-case "$(uname -s)-$(uname -m)" in
-    Darwin-*)
-        shatool="shasum -a 256"
-        sha256sum="427612880d6c40bcef2b0ecb39d92b057ee7a43ec3552fbd4449859991eb1cc6"
-        tarball="MacOSX15.5.sdk.tar.bz2"
-        ;;
-    *)
-        echo "Unrecognized platform $(uname -s)-$(uname -m)"
-        exit 1
-        ;;
-esac
-readonly shatool
-readonly sha256sum
-
-cd .gitlab
-
-echo "$sha256sum  $tarball" > macos.sha256sum
-curl -OL "$baseurl/$tarball"
-$shatool --check macos.sha256sum
-tar xjf "$tarball"
-rm "$tarball" macos.sha256sum
diff --git a/.gitlab/ci/package_macos.sh b/.gitlab/ci/package_macos.sh
index 7625c5d..21f5138 100644
--- a/.gitlab/ci/package_macos.sh
+++ b/.gitlab/ci/package_macos.sh
@@ -1,12 +1,2 @@
 cd build
-cpack -G TGZ
 cpack -G DragNDrop
-
-case "$CMAKE_CI_PACKAGE" in
-    dev)
-        ;;
-    *)
-        mkdir -p unsigned
-        mv cmake-*-macos*-universal.* unsigned/
-        ;;
-esac
diff --git a/.gitlab/ci/package_macos_sign.sh b/.gitlab/ci/package_macos_sign.sh
new file mode 100644
index 0000000..7ae21d7
--- /dev/null
+++ b/.gitlab/ci/package_macos_sign.sh
@@ -0,0 +1 @@
+Utilities/Release/macos/sign-notarize.bash -- build/cmake-*-macos*-universal.dmg
diff --git a/.gitlab/ci/repackage/iar.ps1 b/.gitlab/ci/repackage/iar.ps1
index eb140cd..01f0c79 100644
--- a/.gitlab/ci/repackage/iar.ps1
+++ b/.gitlab/ci/repackage/iar.ps1
@@ -21,14 +21,25 @@
 $exclude = @(
   "arm/config/debugger"
   "arm/config/flashloader"
+  "arm/doc"
   "arm/drivers"
   "arm/src"
+  "avr/doc"
+  "avr/src/cstat"
+  "avr/src/lib"
+  "avr/src/lib_tiny"
+  "avr/src/linker"
   "riscv/config/debugger"
   "riscv/config/flashloader"
+  "riscv/doc"
   "riscv/drivers"
   "riscv/src"
+  "rh850/config/debugger"
+  "rh850/doc"
+  "rh850/src"
   "rl78/config/debugger"
-  "rl78/config/flashloader"
+  "rl78/config/renesas"
+  "rl78/doc"
   "rl78/drivers"
   "rl78/src"
   "rx/config/debugger"
diff --git a/.gitlab/ci/repackage/macos.sh b/.gitlab/ci/repackage/macos.sh
deleted file mode 100755
index 3499001..0000000
--- a/.gitlab/ci/repackage/macos.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-
-sdkPath="$(xcrun --show-sdk-path)"
-sdkVers="$(xcrun --show-sdk-version)"
-
-tar cjf "MacOSX${sdkVers}.sdk.tar.bz2" -C "${sdkPath%/*}" --no-fflags "MacOSX.sdk"
diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml
index 2317e5f..7ec2288 100644
--- a/.gitlab/os-linux.yml
+++ b/.gitlab/os-linux.yml
@@ -11,7 +11,7 @@
         GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
 
 .linux_release_x86_64:
-    image: "kitware/cmake:build-linux-x86_64-deps-2023-08-16@sha256:aa0ebdbd90a51cc83d31f393c5c48ec4599a28f7ccdc288558522c6265b24fae"
+    image: "kitware/cmake:build-linux-x86_64-deps-2026-01-13@sha256:eae18d032e8d7be3caa97d2e5754ae2b7196d7a3d375b7b4d1ba9034f1229317"
 
     variables:
         GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
@@ -19,11 +19,10 @@
         CMAKE_ARCH: x86_64
 
 .linux_release_aarch64:
-    image: "kitware/cmake:build-linux-aarch64-deps-2020-12-21@sha256:0bd7dfe4e45593b04e39cd21e44011034610cfd376900558c5ef959bb1af15af"
+    image: "kitware/cmake:build-linux-aarch64-deps-2026-01-13@sha256:7373fe775ea571a3113251b3e8b5857ef321f6e9b5dfa5963f6e44d062349244"
 
     variables:
         GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
-        LAUNCHER: "scl enable devtoolset-7 --"
         CMAKE_ARCH: aarch64
 
 .linux_package:
@@ -52,14 +51,14 @@
     needs:
         - b:centos7-x86_64
 
-.needs_centos7_aarch64:
+.needs_centos8_aarch64:
     needs:
-        - b:centos7-aarch64
+        - b:centos8-aarch64
 
 ### Debian
 
 .debian13:
-    image: "kitware/cmake:ci-debian13-x86_64-2025-11-11"
+    image: "kitware/cmake:ci-debian13-x86_64-2026-02-08"
 
     variables:
         GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
@@ -74,7 +73,7 @@
         CMAKE_CI_NO_INSTALL: 1
 
 .debian13_aarch64:
-    image: "kitware/cmake:ci-debian13-aarch64-2025-11-11"
+    image: "kitware/cmake:ci-debian13-aarch64-2026-02-08"
 
     variables:
         GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
@@ -83,7 +82,7 @@
 ### Fedora
 
 .fedora43:
-    image: "kitware/cmake:ci-fedora43-x86_64-2025-11-06"
+    image: "kitware/cmake:ci-fedora43-x86_64-2026-02-08"
 
     variables:
         GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci/long file name for testing purposes"
@@ -142,6 +141,14 @@
         CTEST_NO_WARNINGS_ALLOWED: 1
         CMAKE_CI_NO_INSTALL: 1
 
+.fedora43_clang_fuzzing:
+    extends: .fedora43
+
+    variables:
+        CMAKE_CONFIGURATION: fedora43_clang_fuzzing
+        CTEST_NO_WARNINGS_ALLOWED: 1
+        CMAKE_CI_NO_INSTALL: 1
+
 .fedora43_clazy:
     extends: .fedora43
 
@@ -236,14 +243,6 @@
         CMAKE_CI_BUILD_TYPE: Release
         CTEST_NO_WARNINGS_ALLOWED: 1
 
-.fedora43_ninja_multi:
-    extends: .fedora43
-
-    variables:
-        CMAKE_CONFIGURATION: fedora43_ninja_multi
-        CTEST_NO_WARNINGS_ALLOWED: 1
-        CMAKE_GENERATOR: "Ninja Multi-Config"
-
 .fedora43_makefiles:
     extends: .fedora43
 
@@ -270,6 +269,14 @@
         CTEST_NO_WARNINGS_ALLOWED: 1
         CMAKE_GENERATOR: "FASTBuild"
 
+.fedora43_ninja_instrumentation:
+    extends: .fedora43
+
+    variables:
+        CMAKE_CONFIGURATION: fedora43_ninja_instrumentation
+        CTEST_NO_WARNINGS_ALLOWED: 1
+        CMAKE_GENERATOR: "Ninja"
+
 ### Clang Compiler
 
 .debian13_makefiles_clang:
@@ -311,6 +318,13 @@
         CMAKE_CONFIGURATION: fedora43_ninja_lfortran
         CTEST_LABELS: "Fortran"
 
+.fedora43_ninja_multi:
+    extends: .fedora43
+
+    variables:
+        CMAKE_CONFIGURATION: fedora43_ninja_multi
+        CMAKE_GENERATOR: "Ninja Multi-Config"
+
 .fedora43_ninja_clang:
     extends: .fedora43
 
@@ -354,7 +368,6 @@
     variables:
         CMAKE_CONFIGURATION: fedora43_asan
 
-
 .fedora43_ninja_valgrind:
     extends:
         - .fedora43
@@ -533,6 +546,18 @@
         CTEST_NO_WARNINGS_ALLOWED: 1
         CMAKE_GENERATOR: "FASTBuild"
 
+.cuda13.0_aarch64:
+    extends: .cuda
+    image: "kitware/cmake:ci-cuda13.0-aarch64-2025-10-31"
+    variables:
+        CMAKE_ARCH: aarch64
+
+.cuda13.0_aarch64_nvidia:
+    extends: .cuda13.0_aarch64
+    variables:
+        CMAKE_CONFIGURATION: cuda13.0_aarch64_nvidia
+        CTEST_NO_WARNINGS_ALLOWED: 1
+
 ### HIP builds
 
 .hip6.3:
@@ -572,6 +597,7 @@
     variables:
         CMAKE_CONFIGURATION: hip6.3_nvidia
         CTEST_LABELS: "HIP"
+        CMAKE_CUDA_ARCHITECTURES_NATIVE_CLAMP: 1
 
 ### C++ modules
 
@@ -709,6 +735,13 @@
         - docker
         - linux-aarch64
 
+.linux_aarch64_tags_cuda_arch_75:
+    tags:
+        - cmake
+        - cuda-arch-75
+        - docker
+        - linux-aarch64
+
 ## Linux-specific scripts
 
 .before_script_linux: &before_script_linux
@@ -866,36 +899,23 @@
 
     interruptible: true
 
-.cmake_test_linux_external:
-    stage: test-ext
-
-    script:
-        - *before_script_linux
-        - .gitlab/ci/sccache.sh
-        - sccache --start-server
-        - sccache --show-stats
-        - "$LAUNCHER build/install/bin/ctest --output-on-failure -V -S .gitlab/ci/ctest_standalone.cmake"
-        - sccache --show-stats
-
-    interruptible: true
-
 .cmake_test_linux_intelclassic_makefiles:
     extends:
         - .intelclassic_makefiles
         - .cmake_test_linux_release
         - .linux_x86_64_tags
-        - .run_manually
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
-        CMAKE_CI_NO_MR: "true"
+        CMAKE_CI_JOB_NO_MR: "true"
 
 .cmake_test_linux_inteloneapi_makefiles:
     extends:
         - .inteloneapi_makefiles
         - .cmake_test_linux_release
         - .linux_x86_64_tags
-        - .run_manually
+        - .rules
         - .needs_centos7_x86_64
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
diff --git a/.gitlab/os-macos.yml b/.gitlab/os-macos.yml
index 99c0bb0..7b13dee 100644
--- a/.gitlab/os-macos.yml
+++ b/.gitlab/os-macos.yml
@@ -92,6 +92,11 @@
         CTEST_NO_WARNINGS_ALLOWED: 1
         CMAKE_CI_NO_INSTALL: 1
 
+.macos_sign:
+    variables:
+        GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
+        CMAKE_CONFIGURATION: macos_sign
+
 ### External testing
 
 .macos_x86_64_xcode:
@@ -100,7 +105,7 @@
     variables:
         CMAKE_CONFIGURATION: macos_x86_64_xcode
         CMAKE_GENERATOR: Xcode
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .macos_arm64_xcode:
     extends: .macos_arm64
@@ -108,7 +113,7 @@
     variables:
         CMAKE_CONFIGURATION: macos_arm64_xcode
         CMAKE_GENERATOR: Xcode
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .macos_arm64_xcode_symlinked:
     extends: .macos_arm64
@@ -116,7 +121,7 @@
     variables:
         CMAKE_CONFIGURATION: macos_arm64_xcode_symlinked
         CMAKE_GENERATOR: Xcode
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
         CMAKE_CI_IN_SYMLINK_TREE: 1
         CMAKE_CI_BUILD_DIR: "real_work/work/build"
 
@@ -126,7 +131,7 @@
     variables:
         CMAKE_CONFIGURATION: macos_arm64_xcode_ub
         CMAKE_GENERATOR: Xcode
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .macos_arm64_ninja_multi:
     extends: .macos_arm64
@@ -134,14 +139,14 @@
     variables:
         CMAKE_CONFIGURATION: macos_arm64_ninja_multi
         CMAKE_GENERATOR: "Ninja Multi-Config"
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .macos_x86_64_ninja_ub:
     extends: .macos_x86_64
 
     variables:
         CMAKE_CONFIGURATION: macos_x86_64_ninja_ub
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .macos_arm64_fastbuild:
     extends: .macos_arm64
@@ -149,7 +154,7 @@
     variables:
         CMAKE_CONFIGURATION: macos_arm64_fastbuild
         CMAKE_GENERATOR: FASTBuild
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 ## Tags
 
@@ -194,6 +199,13 @@
         - nonconcurrent
         - finder
 
+.macos_sign_tags:
+    tags:
+        - cmake # Since this is a bare runner, pin to a project.
+        - shell
+        - sign-macos-v1
+        - nonconcurrent
+
 ## macOS-specific scripts
 
 .before_script_macos: &before_script_macos
@@ -245,3 +257,12 @@
         - sccache --show-stats
 
     interruptible: true
+
+.cmake_sign_macos:
+    stage: package
+    environment:
+        name: sign-macos
+    script:
+        - source .gitlab/ci/env.sh
+        - source .gitlab/ci/package_macos_sign.sh
+    interruptible: true
diff --git a/.gitlab/os-windows.yml b/.gitlab/os-windows.yml
index 1fed177..55bc515 100644
--- a/.gitlab/os-windows.yml
+++ b/.gitlab/os-windows.yml
@@ -41,12 +41,6 @@
         VCVARSPLATFORM: "x64"
         VCVARSVERSION: "14.44.35207"
 
-.windows_vcvarsall_vs2022_x86_msvc14.44:
-    variables:
-        VCVARSALL: "${VS170COMNTOOLS}\\..\\..\\VC\\Auxiliary\\Build\\vcvarsall.bat"
-        VCVARSPLATFORM: "x86"
-        VCVARSVERSION: "14.44.35207"
-
 .windows_vcvarsall_vs2026_x64:
     variables:
         VCVARSALL: "${VS180COMNTOOLS}\\..\\..\\VC\\Auxiliary\\Build\\vcvarsall.bat"
@@ -105,7 +99,7 @@
 .windows_x86_64_package:
     extends:
         - .windows_package
-        - .windows_vcvarsall_vs2022_x64_msvc14.44
+        - .windows_vcvarsall_vs2026_x64
 
     variables:
         CMAKE_CONFIGURATION: windows_x86_64_package
@@ -113,7 +107,7 @@
 .windows_i386_package:
     extends:
         - .windows_package
-        - .windows_vcvarsall_vs2022_x86_msvc14.44
+        - .windows_vcvarsall_vs2026_x86
 
     variables:
         CMAKE_CONFIGURATION: windows_i386_package
@@ -136,7 +130,7 @@
         CMAKE_GENERATOR: "Visual Studio 18 2026"
         CMAKE_GENERATOR_PLATFORM: "x64"
         CMAKE_GENERATOR_TOOLSET: "v145,version=14.50.35717"
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .windows_vs2022_x64:
     extends: .windows
@@ -146,7 +140,7 @@
         CMAKE_GENERATOR: "Visual Studio 17 2022"
         CMAKE_GENERATOR_PLATFORM: "x64"
         CMAKE_GENERATOR_TOOLSET: "v143,version=14.44.35207"
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .windows_vs2019_x64:
     extends: .windows
@@ -156,7 +150,7 @@
         CMAKE_GENERATOR: "Visual Studio 16 2019"
         CMAKE_GENERATOR_PLATFORM: "x64"
         CMAKE_GENERATOR_TOOLSET: "v142,version=14.29.30133"
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .windows_borland:
     extends: .windows
@@ -164,7 +158,7 @@
     variables:
         CMAKE_GENERATOR: "Borland Makefiles"
         CMAKE_CI_BUILD_TYPE: Release
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .windows_borland5.5:
     extends: .windows_borland
@@ -184,14 +178,14 @@
     variables:
         CMAKE_GENERATOR: "Ninja"
         CMAKE_CI_BUILD_TYPE: Release
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .windows_ninja_multi:
     extends: .windows
 
     variables:
         CMAKE_GENERATOR: "Ninja Multi-Config"
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .windows_nmake:
     extends: .windows
@@ -199,7 +193,7 @@
     variables:
         CMAKE_GENERATOR: "NMake Makefiles"
         CMAKE_CI_BUILD_TYPE: Release
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .windows_jom:
     extends: .windows
@@ -207,7 +201,7 @@
     variables:
         CMAKE_GENERATOR: "NMake Makefiles JOM"
         CMAKE_CI_BUILD_TYPE: Release
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .windows_fastbuild:
     extends: .windows
@@ -215,7 +209,7 @@
     variables:
         CMAKE_GENERATOR: "FASTBuild"
         CMAKE_CI_BUILD_TYPE: Release
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .windows_vs2026_x64_nmake:
     extends:
@@ -295,7 +289,7 @@
         GIT_CLONE_PATH: "$CI_BUILDS_DIR\\cmake-ci-ext\\$CI_CONCURRENT_ID"
         CMAKE_GENERATOR: "Watcom WMake"
         CMAKE_CI_BUILD_TYPE: Release
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .windows_openwatcom1.9:
     extends: .windows_openwatcom
@@ -309,7 +303,7 @@
     variables:
         CMAKE_GENERATOR: "Ninja"
         CMAKE_CI_BUILD_TYPE: Release
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .windows_orangec6.73.1:
     extends: .windows_orangec
@@ -325,7 +319,7 @@
         CMAKE_GENERATOR: "Visual Studio 18 2026"
         CMAKE_GENERATOR_PLATFORM: "ARM64"
         CMAKE_GENERATOR_TOOLSET: "v145,version=14.50.35717"
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .windows_arm64_vs2022:
     extends: .windows
@@ -335,7 +329,7 @@
         CMAKE_GENERATOR: "Visual Studio 17 2022"
         CMAKE_GENERATOR_PLATFORM: "ARM64"
         CMAKE_GENERATOR_TOOLSET: "v143,version=14.44.35207"
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .mingw_osdn_io:
     extends: .windows
@@ -344,7 +338,7 @@
         # Place MinGW environment in a path without spaces.
         GIT_CLONE_PATH: "$CI_BUILDS_DIR\\cmake-ci-ext\\$CI_CONCURRENT_ID"
         CMAKE_CI_BUILD_TYPE: Debug
-        CMAKE_CI_NIGHTLY_IGNORE_DEPS: "true"
+        CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS: "true"
 
 .mingw_osdn_io_mingw_makefiles:
     extends: .mingw_osdn_io
@@ -407,15 +401,6 @@
         - msvc-14.50
         - concurrent
 
-.windows_x86_64_tags_nonconcurrent_vs2022_msvc14.44:
-    tags:
-        - cmake # Since this is a bare runner, pin to a project.
-        - windows-x86_64
-        - shell
-        - vs2022
-        - msvc-14.44
-        - nonconcurrent
-
 .windows_x86_64_tags_concurrent_vs2022_msvc14.44:
     tags:
         - cmake # Since this is a bare runner, pin to a project.
diff --git a/.gitlab/rules.yml b/.gitlab/rules.yml
index efb7290..b0ac9a6 100644
--- a/.gitlab/rules.yml
+++ b/.gitlab/rules.yml
@@ -1,117 +1,218 @@
 # Rules for where jobs can run
 
-.run_manually:
-    rules:
-        - if: '$CMAKE_CI_PACKAGE != null || $CMAKE_CI_VERSION_UPDATE != null'
-          when: never
-        - if: '($CMAKE_CI_NIGHTLY == "true" && $CMAKE_CI_JOB_NIGHTLY == "false")'
-          when: never
-        - if: '$CMAKE_CI_NIGHTLY == "true"'
-          when: on_success
-        - if: '$CMAKE_CI_JOB_NIGHTLY == "true"'
-          when: never
-        - if: '$CMAKE_CI_PROJECT_CONTINUOUS_BRANCH != null && $CI_COMMIT_BRANCH != null && $CMAKE_CI_PROJECT_CONTINUOUS_BRANCH == $CI_COMMIT_BRANCH && $CMAKE_CI_JOB_CONTINUOUS == "true"'
-          when: delayed
-          start_in: 5 minutes
-        - if: '($CMAKE_CI_NO_MR == "true" && $CI_MERGE_REQUEST_ID)'
-          when: never
-        - if: '$CI_MERGE_REQUEST_ID'
-          when: manual
-        - if: '$CI_PROJECT_PATH == "cmake/cmake" && $CI_PIPELINE_SOURCE == "schedule"'
-          when: on_success
-        - if: '$CI_PROJECT_PATH == "cmake/cmake"'
-          when: manual
-        - when: never
+###
+## Job variables:
+##   CMAKE_CI_JOB_UPDATES_VERSION
+##     Set to "true" if the job performs a task that occurs with version
+##     updates.
+##   CMAKE_CI_JOB_UPDATES_WEBSITE_HELP
+##     Set to "true" if the job performs tasks to update website help.
+##   CMAKE_CI_JOB_NO_MR
+##     Set to "true" if the job should never run for merge requests.
+##     These jobs require secrets that MR pipelines cannot provide
+##     (software license information, upload secrets, etc.).
+##   CMAKE_CI_JOB_PACKAGE_ONLY
+##     Set to "true" if the job handles packaging tasks. These jobs will only
+##     run during packaging pipelines.
+##   CMAKE_CI_JOB_NIGHTLY
+##     Set to "true" if the job should only run for nightly pipelines. Set to
+##     "false" to suppress the job for nightly pipelines.
+##   CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS
+##     Set to "true" if the job should run even if dependent jobs fail (e.g.,
+##     further testing of the same setup under a different generator. Should
+##     only be used on jobs with `needs` on other jobs.
+##   CMAKE_CI_JOB_RUN_MANUALLY
+##     Set to "true" if the job should be manually triggered in MRs.
+##     These jobs will also be delayed for branch update pipelines.
+## Pipeline variables:
+##   CMAKE_CI_VERSION_UPDATE
+##     Set to "true" if the pipeline should perform version update tasks.
+##     No other tasks are performed if set.
+##   CMAKE_CI_PACKAGE
+##     Set to either "dev" or `vX.Y` to construct a packaging pipeline. Also
+##     uploads constructed packages. May also run website help jobs. No other
+##     tasks are performed if set.
+##   CMAKE_CI_NIGHTLY
+##     Set to "true" to enable nightly-only jobs.
+## Project variables:
+##   CMAKE_CI_PROJECT_MAIN_BRANCH
+##     Set to the name of the main integration branch where development
+##     version documentation pipelines run.
+##   CMAKE_CI_PROJECT_CONTINUOUS_BRANCH
+##     Set to the name of the staging branch where continuous pipelines run.
+####
 
-.run_automatically:
-    rules:
-        - if: '$CMAKE_CI_PACKAGE != null || $CMAKE_CI_VERSION_UPDATE != null'
-          when: never
-        - if: '($CMAKE_CI_NIGHTLY == "true" && $CMAKE_CI_JOB_NIGHTLY == "false")'
-          when: never
-        - if: '$CMAKE_CI_NIGHTLY == "true"'
-          when: on_success
-        - if: '$CMAKE_CI_JOB_NIGHTLY == "true"'
-          when: never
-        - if: '$CMAKE_CI_PROJECT_CONTINUOUS_BRANCH != null && $CI_COMMIT_BRANCH != null && $CMAKE_CI_PROJECT_CONTINUOUS_BRANCH == $CI_COMMIT_BRANCH && $CMAKE_CI_JOB_CONTINUOUS == "true"'
-          when: on_success
-        - if: '($CMAKE_CI_NO_MR == "true" && $CI_MERGE_REQUEST_ID)'
-          when: never
-        - if: '$CI_MERGE_REQUEST_ID'
-          when: on_success
-        - if: '$CI_PROJECT_PATH == "cmake/cmake" && $CI_PIPELINE_SOURCE == "schedule"'
-          when: on_success
-        - if: '$CI_PROJECT_PATH == "cmake/cmake"'
-          when: delayed
-          start_in: 5 minutes
-        - when: never
+variables:
+    CMAKE_CI_PIPELINE_NAME: 'Branch "$CI_COMMIT_REF_NAME"'
 
-.run_dependent:
+# When to even consider running a pipeline.
+workflow:
+    name: "$CMAKE_CI_PIPELINE_NAME"
     rules:
-        - if: '$CMAKE_CI_PACKAGE != null || $CMAKE_CI_VERSION_UPDATE != null'
-          when: never
-        - if: '($CMAKE_CI_NIGHTLY == "true" && $CMAKE_CI_JOB_NIGHTLY == "false")'
-          when: never
-        - if: '($CMAKE_CI_NIGHTLY == "true" && $CMAKE_CI_NIGHTLY_IGNORE_DEPS == "true")'
+        # Run for merge requests.
+        - if: '$CI_MERGE_REQUEST_ID'
           when: always
-        - if: '$CMAKE_CI_NIGHTLY == "true"'
-          when: on_success
-        - if: '$CMAKE_CI_JOB_NIGHTLY == "true"'
+          auto_cancel:
+              # Cancel all pipeline jobs if a new commit comes in on the branch/tag.
+              on_new_commit: interruptible
+          variables:
+              CMAKE_CI_PIPELINE_NAME: 'Merge request !$CI_MERGE_REQUEST_IID'
+        # If this is not a MR, do not run for other projects.
+        - if: '$CI_PROJECT_PATH != "cmake/cmake" && $CMAKE_CI_PROJECT_CONTINUOUS_BRANCH == null && $CMAKE_CI_PROJECT_MAIN_BRANCH == null'
           when: never
-        - if: '$CMAKE_CI_PROJECT_CONTINUOUS_BRANCH != null && $CI_COMMIT_BRANCH != null && $CMAKE_CI_PROJECT_CONTINUOUS_BRANCH == $CI_COMMIT_BRANCH && $CMAKE_CI_JOB_CONTINUOUS == "true"'
-          when: on_success
-        - if: '($CMAKE_CI_NO_MR == "true" && $CI_MERGE_REQUEST_ID)'
-          when: never
-        - if: '$CI_MERGE_REQUEST_ID'
-          when: on_success
-        - if: '$CI_PROJECT_PATH == "cmake/cmake"'
-          when: on_success
+        # Run for schedules.
+        - if: '$CI_PIPELINE_SOURCE == "schedule"'
+          when: always
+          auto_cancel:
+              # Never cancel scheduled pipelines because of new commits.
+              on_new_commit: none
+          variables:
+              CMAKE_CI_PIPELINE_NAME: 'Schedule "$CI_PIPELINE_SCHEDULE_DESCRIPTION"'
+        # Run for development documentation.
+        - if: '$CMAKE_CI_PROJECT_MAIN_BRANCH != null && $CI_COMMIT_BRANCH != null && $CMAKE_CI_PROJECT_MAIN_BRANCH == $CI_COMMIT_BRANCH'
+          when: always
+          variables:
+              CMAKE_CI_PIPELINE_NAME: 'Development documentation on branch "$CI_COMMIT_REF_NAME"'
+        # Run for continuous testing of staging branch.
+        - if: '$CMAKE_CI_PROJECT_CONTINUOUS_BRANCH != null && $CI_COMMIT_BRANCH != null && $CMAKE_CI_PROJECT_CONTINUOUS_BRANCH == $CI_COMMIT_BRANCH'
+          when: always
+          variables:
+              CMAKE_CI_PIPELINE_NAME: 'Continuous branch "$CI_COMMIT_REF_NAME"'
+        # Run for protected branches.
+        - if: '$CI_COMMIT_REF_PROTECTED == "true"'
+          when: always
+          auto_cancel:
+              # Cancel all pipeline jobs if a new commit comes in on the branch.
+              on_new_commit: interruptible
+          variables:
+              CMAKE_CI_PIPELINE_NAME: 'Protected branch "$CI_COMMIT_REF_NAME"'
+        # Run for tags.
+        - if: '$CI_COMMIT_TAG'
+          when: always
+          variables:
+              CMAKE_CI_PIPELINE_NAME: 'Tag "$CI_COMMIT_TAG"'
+        # Skip pipelines in all other cases.
         - when: never
 
-.run_only_for_package:
+.rules:
     rules:
-        - if: '$CMAKE_CI_PACKAGE == "dev" && $CI_JOB_STAGE != "upload"'
+        ### Version update pipelines.
+        # Version update pipelines run version update jobs automatically.
+        - if: '$CMAKE_CI_VERSION_UPDATE == "true" && $CMAKE_CI_JOB_UPDATES_VERSION == "true"'
           when: on_success
-        - if: '$CMAKE_CI_PACKAGE == "dev" && $CI_JOB_STAGE == "upload"'
-          variables:
-              RSYNC_DESTINATION: "kitware@cmake.org:dev/"
-          when: on_success
-        - if: '$CMAKE_CI_PACKAGE != null && $CI_JOB_STAGE == "prep"'
-          when: manual
-        - if: '$CMAKE_CI_PACKAGE != null && $CI_JOB_STAGE != "upload"'
-          when: on_success
-        - if: '$CMAKE_CI_PACKAGE != null && $CI_JOB_STAGE == "upload" && $CMAKE_CI_PACKAGE_URL != null'
-          variables:
-              RSYNC_DESTINATION: "$CMAKE_CI_PACKAGE_URL"
-          when: on_success
-        - when: never
-
-.run_cmake_org_help:
-    rules:
+        # Version update pipelines run no other jobs.
         - if: '$CMAKE_CI_VERSION_UPDATE != null'
           when: never
-        - if: '$CMAKE_CI_PACKAGE =~ /v[0-9]+\.[0-9]+/'
+        # Version update jobs do not run in any other situations.
+        - if: '$CMAKE_CI_JOB_UPDATES_VERSION == "true"'
+          when: never
+
+        ### Website help update jobs run in a variety of pipeline kinds.
+        # Packaging pipelines upload release version documentation to the website upon request.
+        - if: '$CMAKE_CI_PACKAGE =~ /v[0-9]+\.[0-9]+/ && $CMAKE_CI_JOB_UPDATES_WEBSITE_HELP == "true"'
           variables:
               RSYNC_DESTINATION: "kitware@cmake.org:$CMAKE_CI_PACKAGE/"
               CMAKE_CI_SPHINX_QTHELP: "ON"
               CMAKE_CI_VERSION_NO_GIT: "ON"
           when: manual
-        - if: '$CMAKE_CI_PROJECT_MAIN_BRANCH != null && $CI_COMMIT_BRANCH != null && $CMAKE_CI_PROJECT_MAIN_BRANCH == $CI_COMMIT_BRANCH'
+        # Development documentation pipelines upload documentation to the website automatically.
+        - if: '$CMAKE_CI_PROJECT_MAIN_BRANCH != null && $CI_COMMIT_BRANCH != null && $CMAKE_CI_PROJECT_MAIN_BRANCH == $CI_COMMIT_BRANCH && $CMAKE_CI_JOB_UPDATES_WEBSITE_HELP == "true"'
           variables:
               RSYNC_DESTINATION: "kitware@cmake.org:git-master/"
               CMAKE_CI_SPHINX_QTHELP: "OFF"
               CMAKE_CI_VERSION_NO_GIT: "OFF"
           when: on_success
-        - if: '$CMAKE_CI_PROJECT_CONTINUOUS_BRANCH != null && $CI_COMMIT_BRANCH != null && $CMAKE_CI_PROJECT_CONTINUOUS_BRANCH == $CI_COMMIT_BRANCH'
+        # Continuous pipelines upload staging branch documentation to the website automatically.
+        - if: '$CMAKE_CI_PROJECT_CONTINUOUS_BRANCH != null && $CI_COMMIT_BRANCH != null && $CMAKE_CI_PROJECT_CONTINUOUS_BRANCH == $CI_COMMIT_BRANCH && $CMAKE_CI_JOB_UPDATES_WEBSITE_HELP == "true"'
           variables:
               RSYNC_DESTINATION: "kitware@cmake.org:git-stage/"
               CMAKE_CI_SPHINX_QTHELP: "OFF"
               CMAKE_CI_VERSION_NO_GIT: "OFF"
           when: on_success
-        - when: never
+        # Website help update jobs do not run in any other situations.
+        - if: '$CMAKE_CI_JOB_UPDATES_WEBSITE_HELP == "true"'
+          when: never
 
-.run_version_update:
-    rules:
-        - if: '$CMAKE_CI_VERSION_UPDATE != null'
+        ### Packaging pipelines.
+        # Packaging pipelines build development version packages automatically.
+        - if: '$CMAKE_CI_PACKAGE == "dev" && $CMAKE_CI_JOB_PACKAGE_ONLY == "true" && $CI_JOB_STAGE != "upload"'
           when: on_success
-        - when: never
+        # Packaging pipelines upload development version packages to the website automatically.
+        - if: '$CMAKE_CI_PACKAGE == "dev" && $CMAKE_CI_JOB_PACKAGE_ONLY == "true" && $CI_JOB_STAGE == "upload"'
+          variables:
+              RSYNC_DESTINATION: "kitware@cmake.org:dev/"
+          when: on_success
+        # Packaging pipelines build release version packages upon request.
+        - if: '$CMAKE_CI_PACKAGE != null && $CMAKE_CI_JOB_PACKAGE_ONLY == "true" && $CI_JOB_STAGE == "prep"'
+          when: manual
+        - if: '$CMAKE_CI_PACKAGE != null && $CMAKE_CI_JOB_PACKAGE_ONLY == "true" && $CI_JOB_STAGE != "upload"'
+          when: on_success
+        # Packaging pipelines upload release version packages to a staging area.
+        - if: '$CMAKE_CI_PACKAGE != null && $CMAKE_CI_JOB_PACKAGE_ONLY == "true" && $CI_JOB_STAGE == "upload" && $CMAKE_CI_PACKAGE_URL != null'
+          variables:
+              RSYNC_DESTINATION: "$CMAKE_CI_PACKAGE_URL"
+          when: on_success
+        # Packaging pipelines run no other jobs.
+        - if: '$CMAKE_CI_PACKAGE != null'
+          when: never
+        # Package-only jobs do not run in any other situations.
+        - if: '$CMAKE_CI_JOB_PACKAGE_ONLY == "true"'
+          when: never
+
+        ### Development documentation pipelines.
+        # Development documentation pipelines run no other jobs.
+        - if: '$CMAKE_CI_PROJECT_MAIN_BRANCH != null && $CI_COMMIT_BRANCH != null && $CMAKE_CI_PROJECT_MAIN_BRANCH == $CI_COMMIT_BRANCH'
+          when: never
+
+        ### Continuous pipelines.
+        # Continuous pipelines run manual jobs automatically after 5 minutes.
+        - if: '$CMAKE_CI_PROJECT_CONTINUOUS_BRANCH != null && $CI_COMMIT_BRANCH != null && $CMAKE_CI_PROJECT_CONTINUOUS_BRANCH == $CI_COMMIT_BRANCH && $CMAKE_CI_JOB_CONTINUOUS == "true" && $CMAKE_CI_JOB_RUN_MANUALLY == "true"'
+          when: delayed
+          start_in: 5 minutes
+        # Continuous pipelines run other jobs automatically.
+        - if: '$CMAKE_CI_PROJECT_CONTINUOUS_BRANCH != null && $CI_COMMIT_BRANCH != null && $CMAKE_CI_PROJECT_CONTINUOUS_BRANCH == $CI_COMMIT_BRANCH && $CMAKE_CI_JOB_CONTINUOUS == "true"'
+          when: on_success
+        # Continuous pipelines run no other jobs.
+        - if: '$CMAKE_CI_PROJECT_CONTINUOUS_BRANCH != null && $CI_COMMIT_BRANCH != null && $CMAKE_CI_PROJECT_CONTINUOUS_BRANCH == $CI_COMMIT_BRANCH'
+          when: never
+
+        ### Nightly pipelines.
+        # Nightly pipelines do not run jobs that are explicitly excluded.
+        - if: '$CMAKE_CI_NIGHTLY == "true" && $CMAKE_CI_JOB_NIGHTLY == "false"'
+          when: never
+        # Nightly pipelines always run jobs that ignore their dependencies.
+        - if: '$CMAKE_CI_NIGHTLY == "true" && $CMAKE_CI_JOB_NIGHTLY_IGNORE_DEPS == "true"'
+          when: always
+        # Nightly pipelines run all other jobs automatically when ready.
+        - if: '$CMAKE_CI_NIGHTLY == "true"'
+          when: on_success
+        # Nightly-only jobs do not run in any other situations.
+        - if: '$CMAKE_CI_JOB_NIGHTLY == "true"'
+          when: never
+
+        ### Merge request pipelines.
+        # Merge request pipelines do not run jobs that are explicitly excluded.
+        - if: '$CI_MERGE_REQUEST_ID && $CMAKE_CI_JOB_NO_MR == "true"'
+          when: never
+        # Merge request pipelines run manual jobs upon request.
+        - if: '$CI_MERGE_REQUEST_ID && $CMAKE_CI_JOB_RUN_MANUALLY == "true"'
+          when: manual
+        # Merge request pipelines run other jobs automatically when ready.
+        - if: '$CI_MERGE_REQUEST_ID'
+          when: on_success
+
+        ### Scheduled pipelines.
+        # Scheduled pipelines run all jobs automatically when ready.
+        - if: '$CI_PIPELINE_SOURCE == "schedule"'
+          when: on_success
+
+        ### Other pipelines.
+        # Other pipelines run manual jobs upon request.
+        - if: '$CMAKE_CI_JOB_RUN_MANUALLY == "true"'
+          when: manual
+        # Other pipelines run jobs in the `build` stage automatically after 5 minutes.
+        - if: '$CI_JOB_STAGE == "build"'
+          when: delayed
+          start_in: 5 minutes
+        # Other pipelines run other jobs automatically when ready.
+        - when: on_success
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 1f9477c..64acb89 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -62,8 +62,11 @@
                   | define_property/define_property-INITIALIZE_FROM_VARIABLE-invalid_[12]-result\.txt
                   | FindMatlab/MatlabTest2-stderr\.txt
                   | string/UTF-(16|32)LE\.txt
-                  | Syntax/BOM-UTF-(16|32)-LE.cmake
-                  | Syntax/CommandEOF\.cmake
+                  | Syntax/(
+                        OneCharacter
+                      | (Broken-)?BOM-UTF-(16|32)-[BL]E
+                      | CommandEOF
+                      )\.cmake
                   | VS10Project/shader2?\.hlsl
                   )
               | SourceGroups/README\.txt
@@ -81,7 +84,7 @@
         pass_filenames: false
 
   - repo: https://github.com/sphinx-contrib/sphinx-lint
-    rev: v1.0.1
+    rev: v1.0.2
     hooks:
       - id: sphinx-lint
         # NOTE Looks like `bad-dedent` gives too many false-positives.
@@ -110,7 +113,7 @@
 
     # NOTE See BUG https://github.com/crate-ci/typos/issues/390
   - repo: https://github.com/adhtruong/mirrors-typos
-    rev: v1.39.0
+    rev: v1.44.0
     hooks:
       - id: typos
         # NOTE Override hook's default args to prevent automatic
diff --git a/.typos.toml b/.typos.toml
index db890af..0db7ca8 100644
--- a/.typos.toml
+++ b/.typos.toml
@@ -42,6 +42,8 @@
 Spectre = "Spectre"
 # Identifier used in source code (`GlobalTargetInfo`)
 gti = "gti"
+# StrCpy in NSIS input.
+Cpy = "Cpy"
 
 [files]
 ignore-hidden = false
diff --git a/Auxiliary/CMakeLists.txt b/Auxiliary/CMakeLists.txt
index c0aebef..ff6d308 100644
--- a/Auxiliary/CMakeLists.txt
+++ b/Auxiliary/CMakeLists.txt
@@ -1,16 +1,16 @@
 # Install Vim files to a typical system integration directory.
 # Packagers can set CMake_INSTALL_VIMFILES_DIR to control this.
 if(NOT CMake_INSTALL_VIMFILES_DIR)
-  set(CMake_INSTALL_VIMFILES_DIR ${CMAKE_XDGDATA_DIR}/vim/vimfiles)
+  set(CMake_INSTALL_VIMFILES_DIR ${CMake_INSTALL_XDGDATA_DIR}/vim/vimfiles)
 endif()
 install(DIRECTORY vim/indent vim/syntax DESTINATION ${CMake_INSTALL_VIMFILES_DIR})
 
 # Install Emacs files to a typical system integration directory.
 # Packagers can set CMake_INSTALL_EMACS_DIR to control this.
 if(NOT CMake_INSTALL_EMACS_DIR)
-  set(CMake_INSTALL_EMACS_DIR ${CMAKE_XDGDATA_DIR}/emacs/site-lisp)
+  set(CMake_INSTALL_EMACS_DIR ${CMake_INSTALL_XDGDATA_DIR}/emacs/site-lisp)
 endif()
 install(FILES cmake-mode.el DESTINATION ${CMake_INSTALL_EMACS_DIR})
 
-install(FILES cmake.m4 DESTINATION ${CMAKE_XDGDATA_DIR}/aclocal)
+install(FILES cmake.m4 DESTINATION ${CMake_INSTALL_XDGDATA_DIR}/aclocal)
 add_subdirectory (bash-completion)
diff --git a/Auxiliary/bash-completion/CMakeLists.txt b/Auxiliary/bash-completion/CMakeLists.txt
index 93b6ffd..2c9e448 100644
--- a/Auxiliary/bash-completion/CMakeLists.txt
+++ b/Auxiliary/bash-completion/CMakeLists.txt
@@ -15,7 +15,7 @@
     set(CMake_INSTALL_BASH_COMP_DIR "${CMAKE_BASH_COMP_DIR}")
   else()
     # Default.
-    set(CMake_INSTALL_BASH_COMP_DIR ${CMAKE_XDGDATA_DIR}/bash-completion/completions)
+    set(CMake_INSTALL_BASH_COMP_DIR ${CMake_INSTALL_XDGDATA_DIR}/bash-completion/completions)
   endif()
 endif()
 install(FILES cmake cpack ctest DESTINATION ${CMake_INSTALL_BASH_COMP_DIR})
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim
index adcfed4..280dd9b 100644
--- a/Auxiliary/vim/syntax/cmake.vim
+++ b/Auxiliary/vim/syntax/cmake.vim
@@ -3539,7 +3539,6 @@
             \ APPENDIX
             \ AUTO
             \ CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_DEPENDENCIES
-            \ CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO
             \ CMAKE_MAP_IMPORTED_CONFIG_
             \ COMPAT_VERSION
             \ CONFIG
@@ -3835,7 +3834,6 @@
             \ BYPASS_PROVIDER
             \ CATEGORY
             \ CMAKE_DISABLE_FIND_PACKAGE_
-            \ CMAKE_EXPERIMENTAL_FIND_CPS_PACKAGES
             \ CMAKE_FIND_ROOT_PATH_BOTH
             \ CMAKE_FIND_USE_
             \ CMAKE_REQUIRE_FIND_PACKAGE_
@@ -4149,7 +4147,6 @@
             \ BUILD_TYPE
             \ BUNDLE_EXECUTABLE
             \ CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_DEPENDENCIES
-            \ CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO
             \ CMAKE_INSTALL_BINDIR
             \ CMAKE_INSTALL_DATADIR
             \ CMAKE_INSTALL_DATAROOTDIR
@@ -4417,7 +4414,6 @@
             \ ASM_MASM
             \ ASM_NASM
             \ ATT
-            \ CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO
             \ CMAKE_PROJECT_
             \ COMPAT_VERSION
             \ CPS
diff --git a/CMakeCPack.cmake b/CMakeCPack.cmake
index f38fe6d..b0e5848 100644
--- a/CMakeCPack.cmake
+++ b/CMakeCPack.cmake
@@ -177,7 +177,7 @@
     endif()
   endif()
   install(FILES "${CMake_SOURCE_DIR}/Source/QtIFW/cmake.org.html"
-    DESTINATION "${CMAKE_DOC_DIR}"
+    DESTINATION "${CMake_INSTALL_DOC_DIR}"
   )
 endif()
 
@@ -220,7 +220,7 @@
 set(CPACK_PACKAGE_CONTACT "cmake+development@discourse.cmake.org")
 
 if(UNIX)
-  set(CPACK_STRIP_FILES "${CMAKE_BIN_DIR}/ccmake;${CMAKE_BIN_DIR}/cmake;${CMAKE_BIN_DIR}/cpack;${CMAKE_BIN_DIR}/ctest")
+  set(CPACK_STRIP_FILES "${CMake_INSTALL_BIN_DIR}/ccmake;${CMake_INSTALL_BIN_DIR}/cmake;${CMake_INSTALL_BIN_DIR}/cpack;${CMake_INSTALL_BIN_DIR}/ctest")
   set(CPACK_SOURCE_STRIP_FILES "")
   set(CPACK_PACKAGE_EXECUTABLES "ccmake" "CMake")
 endif()
diff --git a/CMakeCPackOptions.cmake.in b/CMakeCPackOptions.cmake.in
index 65f266e..fe7cab2 100644
--- a/CMakeCPackOptions.cmake.in
+++ b/CMakeCPackOptions.cmake.in
@@ -13,7 +13,7 @@
   set(CPACK_PACKAGE_ICON "@CMake_SOURCE_DIR@/Utilities/Release\\CMakeInstall.bmp")
   # tell cpack to create links to the doc files
   set(CPACK_NSIS_MENU_LINKS
-    "@CMAKE_DOC_DIR@/html/index.html" "CMake Documentation"
+    "@CMake_INSTALL_DOC_DIR@/html/index.html" "CMake Documentation"
     "https://cmake.org" "CMake Web Site"
     )
   # Use the icon from cmake-gui for add-remove programs
@@ -241,7 +241,7 @@
     "@CMake_SOURCE_DIR@/Utilities/Release/CMakeLogo.ico"
   )
 
-  set_property(INSTALL "@CMAKE_DOC_DIR@/html/index.html" PROPERTY
+  set_property(INSTALL "@CMake_INSTALL_DOC_DIR@/html/index.html" PROPERTY
     CPACK_START_MENU_SHORTCUTS "CMake Documentation"
   )
 
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f26b228..8252775 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,7 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file LICENSE.rst or https://cmake.org/licensing for details.
 
-cmake_minimum_required(VERSION 3.13...4.0 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.13...4.1 FATAL_ERROR)
 set(CMAKE_USER_MAKE_RULES_OVERRIDE_C ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideC.cmake)
 set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideCXX.cmake)
 
@@ -111,12 +111,32 @@
     # Avoid messaging about curl-only dependencies.
     list(REMOVE_ITEM UTILITIES NGHTTP2)
   endif()
+
+  set(DEPS_SYSTEM "")
+  set(DEPS_BUNDLED "")
   foreach(util IN LISTS UTILITIES ITEMS KWIML)
     if(CMAKE_USE_SYSTEM_${util})
-      message(STATUS "Using system-installed ${util}")
+      string(APPEND DEPS_SYSTEM " ${util}")
+    else()
+      string(APPEND DEPS_BUNDLED " ${util}")
     endif()
   endforeach()
 
+  # OpenSSL is not included in the UTILITIES list,
+  # but it is a system dependency, if used
+  if(CMAKE_USE_OPENSSL)
+    string(APPEND DEPS_SYSTEM " OPENSSL")
+  endif()
+
+  if(DEPS_SYSTEM)
+    message(STATUS "Using system-installed:${DEPS_SYSTEM}")
+  endif()
+  if(DEPS_BUNDLED)
+    message(STATUS "Using bundled:${DEPS_BUNDLED}")
+  endif()
+  unset(DEPS_SYSTEM)
+  unset(DEPS_BUNDLED)
+
   # Inform utility library header wrappers whether to use system versions.
   configure_file(Utilities/cmThirdParty.h.in Utilities/cmThirdParty.h @ONLY)
 endif()
@@ -167,6 +187,14 @@
   if(NOT CMake_HAVE_CXX_UNIQUE_PTR)
     message(FATAL_ERROR "The C++ compiler does not support C++11 (e.g. std::unique_ptr).")
   endif()
+
+  if(CMake_ENABLE_INSTRUMENTATION)
+    cmake_instrumentation(
+        API_VERSION 1
+        DATA_VERSION 1
+        OPTIONS cdashSubmit cdashVerbose trace
+    )
+  endif()
 endif()
 
 # Inform STL library header wrappers whether to use system versions.
@@ -211,6 +239,9 @@
 
 option(CMake_BUILD_PCH "Compile CMake with precompiled headers" OFF)
 
+option(CMake_BUILD_FUZZING "Build fuzz testing targets" OFF)
+mark_as_advanced(CMake_BUILD_FUZZING)
+
 # Check whether to build support for the debugger mode.
 if(NOT CMake_TEST_EXTERNAL_CMAKE)
   if(NOT DEFINED CMake_ENABLE_DEBUGGER)
@@ -443,19 +474,6 @@
   # build the utilities
   include(CMakeBuildUtilities)
 
-  if(BUILD_QtDialog)
-    if(APPLE)
-      set(CMAKE_BUNDLE_VERSION
-        "${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}.${CMake_VERSION_PATCH}")
-      set(CMAKE_BUNDLE_LOCATION "${CMAKE_INSTALL_PREFIX}")
-      # make sure CMAKE_INSTALL_PREFIX ends in /
-      if(NOT CMAKE_INSTALL_PREFIX MATCHES "/$")
-        string(APPEND CMAKE_INSTALL_PREFIX "/")
-      endif()
-      string(APPEND CMAKE_INSTALL_PREFIX "CMake.app/Contents")
-    endif()
-  endif()
-
   if(UNIX)
     # Install executables with the RPATH set for libraries outside the build tree.
     # This is also suitable for binaries in the build tree.  Avoid re-link on install.
@@ -541,12 +559,12 @@
   install(FILES
     "${CMake_LICENSE_FILE}"
     "${CMake_SOURCE_DIR}/CONTRIBUTORS.rst"
-    DESTINATION ${CMAKE_DOC_DIR})
+    DESTINATION ${CMake_INSTALL_DOC_DIR})
 
   # Install script directories.
   install(
     DIRECTORY Help Modules Templates
-    DESTINATION ${CMAKE_DATA_DIR}
+    DESTINATION ${CMake_INSTALL_DATA_DIR}
     FILE_PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
     DIRECTORY_PERMISSIONS OWNER_READ OWNER_EXECUTE OWNER_WRITE
                           GROUP_READ GROUP_EXECUTE
diff --git a/CMakeLogo.gif b/CMakeLogo.gif
deleted file mode 100644
index 8426402..0000000
--- a/CMakeLogo.gif
+++ /dev/null
Binary files differ
diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst
index 76cd4ba..d4d030e 100644
--- a/CONTRIBUTORS.rst
+++ b/CONTRIBUTORS.rst
@@ -3,84 +3,85 @@
 
 The following individuals and institutions are among the contributors:
 
-* `Aaron C. Meadows <mailto:cmake@shadowguarddev.com>`_
-* `Adriaan de Groot <mailto:groot@kde.org>`_
-* `Aleksey Avdeev <mailto:solo@altlinux.ru>`_
-* `Alexander Neundorf <mailto:neundorf@kde.org>`_
-* `Alexander Smorkalov <mailto:alexander.smorkalov@itseez.com>`_
-* `Alexey Sokolov <mailto:sokolov@google.com>`_
-* `Alex Merry <mailto:alex.merry@kde.org>`_
-* `Alex Turbov <mailto:i.zaufi@gmail.com>`_
-* `Andreas Pakulat <mailto:apaku@gmx.de>`_
-* `Andreas Schneider <mailto:asn@cryptomilk.org>`_
-* `André Rigland Brodtkorb <mailto:Andre.Brodtkorb@ifi.uio.no>`_
+* `Aaron C. Meadows <mailto:cmake@shadowguarddev.com>`__
+* `Adriaan de Groot <mailto:groot@kde.org>`__
+* `Aleksey Avdeev <mailto:solo@altlinux.ru>`__
+* `Alexander Neundorf <mailto:neundorf@kde.org>`__
+* `Alexander Smorkalov <mailto:alexander.smorkalov@itseez.com>`__
+* `Alexey Sokolov <mailto:sokolov@google.com>`__
+* `Alex Merry <mailto:alex.merry@kde.org>`__
+* `Alex Turbov <mailto:i.zaufi@gmail.com>`__
+* `Andreas Pakulat <mailto:apaku@gmx.de>`__
+* `Andreas Schneider <mailto:asn@cryptomilk.org>`__
+* `André Rigland Brodtkorb <mailto:Andre.Brodtkorb@ifi.uio.no>`__
 * Axel Huebl, Helmholtz-Zentrum Dresden - Rossendorf
 * Benjamin Eikel
-* `Bjoern Ricks <mailto:bjoern.ricks@gmail.com>`_
-* `Brad Hards <mailto:bradh@kde.org>`_
+* `Bjoern Ricks <mailto:bjoern.ricks@gmail.com>`__
+* `Brad Hards <mailto:bradh@kde.org>`__
 * Christopher Harvey
-* `Christoph Grüninger <mailto:foss@grueninger.de>`_
-* `Clement Creusot <mailto:creusot@cs.york.ac.uk>`_
-* `Daniel Blezek <mailto:blezek@gmail.com>`_
-* `Daniel Pfeifer <mailto:daniel@pfeifer-mail.de>`_
-* `Dawid Wróbel <mailto:me@dawidwrobel.com>`_
-* `Enrico Scholz <mailto:enrico.scholz@informatik.tu-chemnitz.de>`_
-* `Eran Ifrah <mailto:eran.ifrah@gmail.com>`_
+* `Christoph Grüninger <mailto:foss@grueninger.de>`__
+* `Clement Creusot <mailto:creusot@cs.york.ac.uk>`__
+* `Daniel Blezek <mailto:blezek@gmail.com>`__
+* `Daniel Pfeifer <mailto:daniel@pfeifer-mail.de>`__
+* `Dawid Wróbel <mailto:me@dawidwrobel.com>`__
+* `Enrico Scholz <mailto:enrico.scholz@informatik.tu-chemnitz.de>`__
+* `Eran Ifrah <mailto:eran.ifrah@gmail.com>`__
 * Esben Mose Hansen, Ange Optimization ApS
-* `Geoffrey Viola <mailto:geoffrey.viola@asirobots.com>`_
-* `Google Inc <https://www.google.com/>`_
+* `Geoffrey Viola <mailto:geoffrey.viola@asirobots.com>`__
+* `Georg Brandl <mailto:georg@python.org>`__
+* `Google Inc <https://www.google.com/>`__
 * Gregor Jasny
-* `Helio Chissini de Castro <mailto:helio@kde.org>`_
-* `Ilya Lavrenov <mailto:ilya.lavrenov@itseez.com>`_
-* `Insight Software Consortium <https://insightsoftwareconsortium.org/>`_
-* `Intel Corporation <https://www.intel.com/>`_
+* `Helio Chissini de Castro <mailto:helio@kde.org>`__
+* `Ilya Lavrenov <mailto:ilya.lavrenov@itseez.com>`__
+* `Insight Software Consortium <https://insightsoftwareconsortium.org/>`__
+* `Intel Corporation <https://www.intel.com/>`__
 * Jan Woetzel
-* `Jordan Williams <mailto:jordan@jwillikers.com>`_
+* `Jordan Williams <mailto:jordan@jwillikers.com>`__
 * Julien Schueller
-* `Kelly Thompson <mailto:kgt@lanl.gov>`_
-* `Konstantin Podsvirov <mailto:konstantin@podsvirov.su>`_
-* `Laurent Montel <mailto:montel@kde.org>`_
-* `Mario Bensi <mailto:mbensi@ipsquad.net>`_
-* `Martin Gräßlin <mailto:mgraesslin@kde.org>`_
-* `Mathieu Malaterre <mailto:mathieu.malaterre@gmail.com>`_
+* `Kelly Thompson <mailto:kgt@lanl.gov>`__
+* `Konstantin Podsvirov <mailto:konstantin@podsvirov.su>`__
+* `Laurent Montel <mailto:montel@kde.org>`__
+* `Mario Bensi <mailto:mbensi@ipsquad.net>`__
+* `Martin Gräßlin <mailto:mgraesslin@kde.org>`__
+* `Mathieu Malaterre <mailto:mathieu.malaterre@gmail.com>`__
 * Matthaeus G. Chajdas
-* `Matthias Kretz <mailto:kretz@kde.org>`_
-* `Matthias Maennich <mailto:matthias@maennich.net>`_
-* `Michael Hirsch, Ph.D. <https://www.scivision.dev/>`_
+* `Matthias Kretz <mailto:kretz@kde.org>`__
+* `Matthias Maennich <mailto:matthias@maennich.net>`__
+* `Michael Hirsch, Ph.D. <https://www.scivision.dev/>`__
 * Michael Stürmer
 * Miguel A. Figueroa-Villanueva
-* `Mike Durso <mailto:rbprogrammer@gmail.com>`_
+* `Mike Durso <mailto:rbprogrammer@gmail.com>`__
 * Mike Jackson
-* `Mike McQuaid <mailto:mike@mikemcquaid.com>`_
-* `Nicolas Bock <mailto:nicolasbock@gmail.com>`_
-* `Nicolas Despres <mailto:nicolas.despres@gmail.com>`_
-* `Nikita Krupen'ko <mailto:krnekit@gmail.com>`_
-* `NVIDIA Corporation <https://www.nvidia.com/>`_
-* `OpenGamma Ltd. <https://opengamma.com/>`_
-* `Patrick Stotko <mailto:stotko@cs.uni-bonn.de>`_
-* `Per Øyvind Karlsen <mailto:peroyvind@mandriva.org>`_
-* `Peter Collingbourne <mailto:peter@pcc.me.uk>`_
-* `Petr Gotthard <mailto:gotthard@honeywell.com>`_
-* `Philip Lowman <mailto:philip@yhbt.com>`_
-* `Philippe Proulx <mailto:pproulx@efficios.com>`_
+* `Mike McQuaid <mailto:mike@mikemcquaid.com>`__
+* `Nicolas Bock <mailto:nicolasbock@gmail.com>`__
+* `Nicolas Despres <mailto:nicolas.despres@gmail.com>`__
+* `Nikita Krupen'ko <mailto:krnekit@gmail.com>`__
+* `NVIDIA Corporation <https://www.nvidia.com/>`__
+* `OpenGamma Ltd. <https://opengamma.com/>`__
+* `Patrick Stotko <mailto:stotko@cs.uni-bonn.de>`__
+* `Per Øyvind Karlsen <mailto:peroyvind@mandriva.org>`__
+* `Peter Collingbourne <mailto:peter@pcc.me.uk>`__
+* `Petr Gotthard <mailto:gotthard@honeywell.com>`__
+* `Philip Lowman <mailto:philip@yhbt.com>`__
+* `Philippe Proulx <mailto:pproulx@efficios.com>`__
 * Raffi Enficiaud, Max Planck Society
 * Raumfeld
-* `Roger Leigh <mailto:rleigh@codelibre.net>`_
-* `Rolf Eike Beer <mailto:eike@sf-mail.de>`_
-* `Roman Donchenko <mailto:roman.donchenko@itseez.com>`_
-* `Roman Kharitonov <mailto:roman.kharitonov@itseez.com>`_
+* `Roger Leigh <mailto:rleigh@codelibre.net>`__
+* `Rolf Eike Beer <mailto:eike@sf-mail.de>`__
+* `Roman Donchenko <mailto:roman.donchenko@itseez.com>`__
+* `Roman Kharitonov <mailto:roman.kharitonov@itseez.com>`__
 * Ruslan Baratov
-* `Sebastian Holtermann <mailto:sebholt@xwmw.org>`_
-* `Stephen Kelly <mailto:steveire@gmail.com>`_
-* `Sylvain Joubert <mailto:joubert.sy@gmail.com>`_
-* `The Qt Company Ltd. <https://www.qt.io/>`_
-* `Thomas Sondergaard <mailto:ts@medical-insight.com>`_
-* `Tobias Hunger <mailto:tobias.hunger@qt.io>`_
-* `Todd Gamblin <mailto:tgamblin@llnl.gov>`_
+* `Sebastian Holtermann <mailto:sebholt@xwmw.org>`__
+* `Stephen Kelly <mailto:steveire@gmail.com>`__
+* `Sylvain Joubert <mailto:joubert.sy@gmail.com>`__
+* `The Qt Company Ltd. <https://www.qt.io/>`__
+* `Thomas Sondergaard <mailto:ts@medical-insight.com>`__
+* `Tobias Hunger <mailto:tobias.hunger@qt.io>`__
+* `Todd Gamblin <mailto:tgamblin@llnl.gov>`__
 * Tristan Carel
-* `University of Dundee <https://www.dundee.ac.uk/>`_
+* `University of Dundee <https://www.dundee.ac.uk/>`__
 * Vadim Zhukov
-* `Will Dicharry <mailto:wdicharry@stellarscience.com>`_
+* `Will Dicharry <mailto:wdicharry@stellarscience.com>`__
 
 See version control history for details of individual contributions.
 
diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst
index 8d66752..cb18bcc 100644
--- a/Help/command/add_custom_command.rst
+++ b/Help/command/add_custom_command.rst
@@ -3,479 +3,494 @@
 
 Add a custom build rule to the generated build system.
 
-There are two main signatures for ``add_custom_command``.
+Synopsis
+^^^^^^^^
 
-.. _`add_custom_command(OUTPUT)`:
+.. parsed-literal::
+  `Generating Files`_
+    add_custom_command(`OUTPUT`_ <output1> [<output2> ...]
+                       COMMAND <command1> [ARGS] [<args1>...]
+                       [...])
+
+  `Build Events`_
+    add_custom_command(`TARGET`_ <target>
+                       PRE_BUILD | PRE_LINK | POST_BUILD
+                       [...])
 
 Generating Files
 ^^^^^^^^^^^^^^^^
 
-The first signature is for adding a custom command to produce an output:
+.. signature::
+  add_custom_command(OUTPUT <output1> [<output2> ...]
+                     COMMAND <command1> [ARGS] [<args1>...]
+                     [...])
 
-.. code-block:: cmake
+  Add a custom command to produce an output:
 
-  add_custom_command(OUTPUT output1 [output2 ...]
-                     COMMAND command1 [ARGS] [args1...]
-                     [COMMAND command2 [ARGS] [args2...] ...]
-                     [MAIN_DEPENDENCY depend]
-                     [DEPENDS [depends...]]
-                     [BYPRODUCTS [files...]]
-                     [IMPLICIT_DEPENDS <lang1> depend1
-                                      [<lang2> depend2] ...]
-                     [WORKING_DIRECTORY dir]
-                     [COMMENT comment]
-                     [DEPFILE depfile]
-                     [JOB_POOL job_pool]
-                     [JOB_SERVER_AWARE <bool>]
-                     [VERBATIM] [APPEND] [USES_TERMINAL]
-                     [CODEGEN]
-                     [COMMAND_EXPAND_LISTS]
-                     [DEPENDS_EXPLICIT_ONLY])
+  .. code-block:: cmake
 
-This defines a command to generate specified ``OUTPUT`` file(s).
-A target created in the same directory (``CMakeLists.txt`` file)
-that specifies any output of the custom command as a source file
-is given a rule to generate the file using the command at build time.
+    add_custom_command(OUTPUT <output1> [<output2> ...]
+                       COMMAND <command1> [ARGS] [<args1>...]
+                       [COMMAND <command2> [ARGS] [<args2>...]] ...
+                       [MAIN_DEPENDENCY depend]
+                       [DEPENDS <depends>...]
+                       [BYPRODUCTS <files>...]
+                       [IMPLICIT_DEPENDS <lang1> <depend1>
+                                        [<lang2> <depend2>] ...]
+                       [WORKING_DIRECTORY <dir>]
+                       [COMMENT <comment>]
+                       [DEPFILE <depfile>]
+                       [JOB_POOL <job_pool>]
+                       [JOB_SERVER_AWARE <bool>]
+                       [VERBATIM] [APPEND] [USES_TERMINAL]
+                       [CODEGEN]
+                       [COMMAND_EXPAND_LISTS]
+                       [DEPENDS_EXPLICIT_ONLY])
 
-Do not list the output in more than one independent target that
-may build in parallel or the instances of the rule may conflict.
-Instead, use the :command:`add_custom_target` command to drive the
-command and make the other targets depend on that one.  See the
-`Example: Generating Files for Multiple Targets`_ below.
+  This defines a command to generate specified ``OUTPUT`` file(s).
+  A target created in the same directory (``CMakeLists.txt`` file)
+  that specifies any output of the custom command as a source file
+  is given a rule to generate the file using the command at build time.
 
-The options are:
+  Do not list the output in more than one independent target that
+  may build in parallel or the instances of the rule may conflict.
+  Instead, use the :command:`add_custom_target` command to drive the
+  command and make the other targets depend on that one.  See the
+  `Example: Generating Files for Multiple Targets`_ below.
 
-``APPEND``
-  Append the ``COMMAND`` and ``DEPENDS`` option values to the custom
-  command for the first output specified.  There must have already
-  been a previous call to this command with the same output.
+  The options are:
 
-  If the previous call specified the output via a generator expression,
-  the output specified by the current call must match in at least one
-  configuration after evaluating generator expressions.  In this case,
-  the appended commands and dependencies apply to all configurations.
+  ``APPEND``
+    Append the ``COMMAND`` and ``DEPENDS`` option values to the custom
+    command for the first output specified.  There must have already
+    been a previous call to this command with the same output.
 
-  The ``COMMENT``, ``MAIN_DEPENDENCY``, and ``WORKING_DIRECTORY``
-  options are currently ignored when ``APPEND`` is given, but may be
-  used in the future.
+    If the previous call specified the output via a generator expression,
+    the output specified by the current call must match in at least one
+    configuration after evaluating generator expressions.  In this case,
+    the appended commands and dependencies apply to all configurations.
 
-``BYPRODUCTS``
-  .. versionadded:: 3.2
+    The ``COMMENT``, ``MAIN_DEPENDENCY``, and ``WORKING_DIRECTORY``
+    options are currently ignored when ``APPEND`` is given, but may be
+    used in the future.
 
-  Specify the files the command is expected to produce but whose
-  modification time may or may not be newer than the dependencies.
-  If a byproduct name is a relative path it will be interpreted
-  relative to the build tree directory corresponding to the
-  current source directory.
-  Each byproduct file will be marked with the :prop_sf:`GENERATED`
-  source file property automatically.
+  ``BYPRODUCTS``
+    .. versionadded:: 3.2
 
-  *See policy* :policy:`CMP0058` *for the motivation behind this feature.*
+    Specify the files the command is expected to produce but whose
+    modification time may or may not be newer than the dependencies.
+    If a byproduct name is a relative path it will be interpreted
+    relative to the build tree directory corresponding to the
+    current source directory.
+    Each byproduct file will be marked with the :prop_sf:`GENERATED`
+    source file property automatically.
 
-  Explicit specification of byproducts is supported by the
-  :generator:`Ninja` generator to tell the ``ninja`` build tool
-  how to regenerate byproducts when they are missing.  It is
-  also useful when other build rules (e.g. custom commands)
-  depend on the byproducts.  Ninja requires a build rule for any
-  generated file on which another rule depends even if there are
-  order-only dependencies to ensure the byproducts will be
-  available before their dependents build.
+    *See policy* :policy:`CMP0058` *for the motivation behind this feature.*
 
-  The :ref:`Makefile Generators` will remove ``BYPRODUCTS`` and other
-  :prop_sf:`GENERATED` files during ``make clean``.
+    Explicit specification of byproducts is supported by the
+    :generator:`Ninja` generator to tell the ``ninja`` build tool
+    how to regenerate byproducts when they are missing.  It is
+    also useful when other build rules (e.g. custom commands)
+    depend on the byproducts.  Ninja requires a build rule for any
+    generated file on which another rule depends even if there are
+    order-only dependencies to ensure the byproducts will be
+    available before their dependents build.
 
-  This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
-  All byproducts must be set in the first call to
-  ``add_custom_command(OUTPUT...)`` for the output files.
+    The :ref:`Makefile Generators` will remove ``BYPRODUCTS`` and other
+    :prop_sf:`GENERATED` files during ``make clean``.
 
-  .. versionadded:: 3.20
-    Arguments to ``BYPRODUCTS`` may use a restricted set of
+    This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+    All byproducts must be set in the first call to
+    ``add_custom_command(OUTPUT...)`` for the output files.
+
+    .. versionadded:: 3.20
+      Arguments to ``BYPRODUCTS`` may use a restricted set of
+      :manual:`generator expressions <cmake-generator-expressions(7)>`.
+      :ref:`Target-dependent expressions <Target-Dependent Expressions>`
+      are not permitted.
+
+    .. versionchanged:: 3.28
+      In targets using :ref:`file sets`, custom command byproducts are now
+      considered private unless they are listed in a non-private file set.
+      See policy :policy:`CMP0154`.
+
+  ``COMMAND``
+    Specify the command-line(s) to execute at build time.
+    At least one ``COMMAND`` would normally be given, but certain patterns
+    may omit it, such as adding commands in separate calls using ``APPEND``.
+
+    If more than one ``COMMAND`` is specified, they will be executed in order,
+    but *not* necessarily composed into a stateful shell or batch script.
+    To run a full script, use the :command:`configure_file` command or the
+    :command:`file(GENERATE)` command to create it, and then specify
+    a ``COMMAND`` to launch it.
+
+    The optional ``ARGS`` argument is for backward compatibility and
+    will be ignored.
+
+    If ``COMMAND`` specifies an executable target name (created by the
+    :command:`add_executable` command), it will automatically be replaced
+    by the location of the executable created at build time if either of
+    the following is true:
+
+    * The target is not being cross-compiled (i.e. the
+      :variable:`CMAKE_CROSSCOMPILING` variable is not set to true).
+    * .. versionadded:: 3.6
+        The target is being cross-compiled and an emulator is provided (i.e.
+        its :prop_tgt:`CROSSCOMPILING_EMULATOR` target property is set).
+        In this case, the contents of :prop_tgt:`CROSSCOMPILING_EMULATOR` will be
+        prepended to the command before the location of the target executable.
+
+    If neither of the above conditions are met, it is assumed that the
+    command name is a program to be found on the ``PATH`` at build time.
+
+    Arguments to ``COMMAND`` may use
     :manual:`generator expressions <cmake-generator-expressions(7)>`.
-    :ref:`Target-dependent expressions <Target-Dependent Expressions>`
-    are not permitted.
+    Use the :genex:`TARGET_FILE` generator expression to refer to the location
+    of a target later in the command line (i.e. as a command argument rather
+    than as the command to execute).
 
-  .. versionchanged:: 3.28
-    In targets using :ref:`file sets`, custom command byproducts are now
-    considered private unless they are listed in a non-private file set.
-    See policy :policy:`CMP0154`.
+    Whenever one of the following target based generator expressions are used as
+    a command to execute or is mentioned in a command argument, a target-level
+    dependency will be added automatically so that the mentioned target will be
+    built before any target using this custom command
+    (see policy :policy:`CMP0112`).
 
-``COMMAND``
-  Specify the command-line(s) to execute at build time.
-  At least one ``COMMAND`` would normally be given, but certain patterns
-  may omit it, such as adding commands in separate calls using ``APPEND``.
+    * ``TARGET_FILE``
+    * ``TARGET_LINKER_FILE``
+    * ``TARGET_SONAME_FILE``
+    * ``TARGET_PDB_FILE``
 
-  If more than one ``COMMAND`` is specified, they will be executed in order,
-  but *not* necessarily composed into a stateful shell or batch script.
-  To run a full script, use the :command:`configure_file` command or the
-  :command:`file(GENERATE)` command to create it, and then specify
-  a ``COMMAND`` to launch it.
+    This target-level dependency does NOT add a file-level dependency that would
+    cause the custom command to re-run whenever the executable is recompiled.
+    List target names with the ``DEPENDS`` option to add such file-level
+    dependencies.
 
-  The optional ``ARGS`` argument is for backward compatibility and
-  will be ignored.
+  ``COMMENT``
+    Display the given message before the commands are executed at
+    build time.  This will be ignored if ``APPEND`` is given, although a future
+    version may use it.
 
-  If ``COMMAND`` specifies an executable target name (created by the
-  :command:`add_executable` command), it will automatically be replaced
-  by the location of the executable created at build time if either of
-  the following is true:
+    .. versionadded:: 3.26
+      Arguments to ``COMMENT`` may use
+      :manual:`generator expressions <cmake-generator-expressions(7)>`.
 
-  * The target is not being cross-compiled (i.e. the
-    :variable:`CMAKE_CROSSCOMPILING` variable is not set to true).
-  * .. versionadded:: 3.6
-      The target is being cross-compiled and an emulator is provided (i.e.
-      its :prop_tgt:`CROSSCOMPILING_EMULATOR` target property is set).
-      In this case, the contents of :prop_tgt:`CROSSCOMPILING_EMULATOR` will be
-      prepended to the command before the location of the target executable.
+  ``DEPENDS``
+    Specify files on which the command depends.  Each argument is converted
+    to a dependency as follows:
 
-  If neither of the above conditions are met, it is assumed that the
-  command name is a program to be found on the ``PATH`` at build time.
+    1. If the argument is the name of a target (created by the
+       :command:`add_custom_target`, :command:`add_executable`, or
+       :command:`add_library` command) a target-level dependency is
+       created to make sure the target is built before any target
+       using this custom command.  Additionally, if the target is an
+       executable or library, a file-level dependency is created to
+       cause the custom command to re-run whenever the target is
+       recompiled.
 
-  Arguments to ``COMMAND`` may use
-  :manual:`generator expressions <cmake-generator-expressions(7)>`.
-  Use the :genex:`TARGET_FILE` generator expression to refer to the location
-  of a target later in the command line (i.e. as a command argument rather
-  than as the command to execute).
+    2. If the argument is an absolute path, a file-level dependency
+       is created on that path.
 
-  Whenever one of the following target based generator expressions are used as
-  a command to execute or is mentioned in a command argument, a target-level
-  dependency will be added automatically so that the mentioned target will be
-  built before any target using this custom command
-  (see policy :policy:`CMP0112`).
+    3. If the argument is the name of a source file that has been
+       added to a target or on which a source file property has been set,
+       a file-level dependency is created on that source file.
 
-  * ``TARGET_FILE``
-  * ``TARGET_LINKER_FILE``
-  * ``TARGET_SONAME_FILE``
-  * ``TARGET_PDB_FILE``
+    4. If the argument is a relative path and it exists in the current
+       source directory, a file-level dependency is created on that
+       file in the current source directory.
 
-  This target-level dependency does NOT add a file-level dependency that would
-  cause the custom command to re-run whenever the executable is recompiled.
-  List target names with the ``DEPENDS`` option to add such file-level
-  dependencies.
+    5. Otherwise, a file-level dependency is created on that path relative
+       to the current binary directory.
 
-``COMMENT``
-  Display the given message before the commands are executed at
-  build time.  This will be ignored if ``APPEND`` is given, although a future
-  version may use it.
+    If any dependency is an ``OUTPUT`` of another custom command in the same
+    directory (``CMakeLists.txt`` file), CMake automatically brings the other
+    custom command into the target in which this command is built.
 
-  .. versionadded:: 3.26
-    Arguments to ``COMMENT`` may use
-    :manual:`generator expressions <cmake-generator-expressions(7)>`.
+    .. versionadded:: 3.16
+      A target-level dependency is added if any dependency is listed as
+      ``BYPRODUCTS`` of a target or any of its build events in the same
+      directory to ensure the byproducts will be available.
 
-``DEPENDS``
-  Specify files on which the command depends.  Each argument is converted
-  to a dependency as follows:
+    If ``DEPENDS`` is not specified, the command will run whenever
+    the ``OUTPUT`` is missing; if the command does not actually
+    create the ``OUTPUT``, the rule will always run.
 
-  1. If the argument is the name of a target (created by the
-     :command:`add_custom_target`, :command:`add_executable`, or
-     :command:`add_library` command) a target-level dependency is
-     created to make sure the target is built before any target
-     using this custom command.  Additionally, if the target is an
-     executable or library, a file-level dependency is created to
-     cause the custom command to re-run whenever the target is
-     recompiled.
+    .. versionadded:: 3.1
+      Arguments to ``DEPENDS`` may use
+      :manual:`generator expressions <cmake-generator-expressions(7)>`.
 
-  2. If the argument is an absolute path, a file-level dependency
-     is created on that path.
+  ``COMMAND_EXPAND_LISTS``
+    .. versionadded:: 3.8
 
-  3. If the argument is the name of a source file that has been
-     added to a target or on which a source file property has been set,
-     a file-level dependency is created on that source file.
+    Lists in ``COMMAND`` arguments will be expanded, including those
+    created with
+    :manual:`generator expressions <cmake-generator-expressions(7)>`,
+    allowing ``COMMAND`` arguments such as
+    ``${CC} "-I$<JOIN:$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>,;-I>" foo.cc``
+    to be properly expanded.
 
-  4. If the argument is a relative path and it exists in the current
-     source directory, a file-level dependency is created on that
-     file in the current source directory.
+    This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+    If the appended commands need this option to be set, it must be set on the
+    first call to ``add_custom_command(OUTPUT...)`` for the output files.
 
-  5. Otherwise, a file-level dependency is created on that path relative
-     to the current binary directory.
+  ``CODEGEN``
+    .. versionadded:: 3.31
 
-  If any dependency is an ``OUTPUT`` of another custom command in the same
-  directory (``CMakeLists.txt`` file), CMake automatically brings the other
-  custom command into the target in which this command is built.
+    Adds the custom command to a global ``codegen`` target that can be
+    used to execute the custom command while avoiding the majority of the
+    build graph.
 
-  .. versionadded:: 3.16
-    A target-level dependency is added if any dependency is listed as
-    ``BYPRODUCTS`` of a target or any of its build events in the same
-    directory to ensure the byproducts will be available.
+    This option is supported only by :ref:`Ninja Generators` and
+    :ref:`Makefile Generators`, and is ignored by other generators.
+    Furthermore, this option is allowed only if policy :policy:`CMP0171`
+    is set to ``NEW``.
 
-  If ``DEPENDS`` is not specified, the command will run whenever
-  the ``OUTPUT`` is missing; if the command does not actually
-  create the ``OUTPUT``, the rule will always run.
+    This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+    It can only be set on the first call to ``add_custom_command(OUTPUT...)``
+    for the output files.
 
-  .. versionadded:: 3.1
-    Arguments to ``DEPENDS`` may use
-    :manual:`generator expressions <cmake-generator-expressions(7)>`.
-
-``COMMAND_EXPAND_LISTS``
-  .. versionadded:: 3.8
-
-  Lists in ``COMMAND`` arguments will be expanded, including those
-  created with
-  :manual:`generator expressions <cmake-generator-expressions(7)>`,
-  allowing ``COMMAND`` arguments such as
-  ``${CC} "-I$<JOIN:$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>,;-I>" foo.cc``
-  to be properly expanded.
-
-  This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
-  If the appended commands need this option to be set, it must be set on the
-  first call to ``add_custom_command(OUTPUT...)`` for the output files.
-
-``CODEGEN``
-  .. versionadded:: 3.31
-
-  Adds the custom command to a global ``codegen`` target that can be
-  used to execute the custom command while avoiding the majority of the
-  build graph.
-
-  This option is supported only by :ref:`Ninja Generators` and
-  :ref:`Makefile Generators`, and is ignored by other generators.
-  Furthermore, this option is allowed only if policy :policy:`CMP0171`
-  is set to ``NEW``.
-
-  This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
-  It can only be set on the first call to ``add_custom_command(OUTPUT...)``
-  for the output files.
-
-``IMPLICIT_DEPENDS``
-  Request scanning of implicit dependencies of an input file.
-  The language given specifies the programming language whose
-  corresponding dependency scanner should be used.
-  Currently only ``C`` and ``CXX`` language scanners are supported.
-  The language has to be specified for every file in the
-  ``IMPLICIT_DEPENDS`` list.  Dependencies discovered from the
-  scanning are added to those of the custom command at build time.
-  Note that the ``IMPLICIT_DEPENDS`` option is currently supported
-  only for Makefile generators and will be ignored by other generators.
-
-  .. note::
-
-    This option cannot be specified at the same time as ``DEPFILE`` option.
-
-``JOB_POOL``
-  .. versionadded:: 3.15
-
-  Specify a :prop_gbl:`pool <JOB_POOLS>` for the :generator:`Ninja`
-  generator. Incompatible with ``USES_TERMINAL``, which implies
-  the ``console`` pool.
-  Using a pool that is not defined by :prop_gbl:`JOB_POOLS` causes
-  an error by ninja at build time.
-
-  This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
-  Job pools can only be specified in the first call to
-  ``add_custom_command(OUTPUT...)`` for the output files.
-
-``JOB_SERVER_AWARE``
-  .. versionadded:: 3.28
-
-  Specify that the command is GNU Make job server aware.
-
-  For the :generator:`Unix Makefiles`, :generator:`MSYS Makefiles`, and
-  :generator:`MinGW Makefiles` generators this will add the ``+`` prefix to the
-  recipe line. See the `GNU Make Documentation`_ for more information.
-
-  This option is silently ignored by other generators.
-
-  This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
-  Job server awareness can only be specified in the first call to
-  ``add_custom_command(OUTPUT...)`` for the output files.
-
-.. _`GNU Make Documentation`: https://www.gnu.org/software/make/manual/html_node/MAKE-Variable.html
-
-``MAIN_DEPENDENCY``
-  Specify the primary input source file to the command.  This is
-  treated just like any value given to the ``DEPENDS`` option
-  but also suggests to :ref:`Visual Studio Generators` where to hang
-  the custom command. Each source file may have at most one command
-  specifying it as its main dependency. A compile command (i.e. for a
-  library or an executable) counts as an implicit main dependency which
-  gets silently overwritten by a custom command specification.
-
-  This option is currently ignored if ``APPEND`` is given, but a future
-  version may use it.
-
-``OUTPUT``
-  Specify the output files the command is expected to produce.
-  Each output file will be marked with the :prop_sf:`GENERATED`
-  source file property automatically.
-  If the output of the custom command is not actually created
-  as a file on disk it should be marked with the :prop_sf:`SYMBOLIC`
-  source file property.
-
-  If an output file name is a relative path, its absolute path is
-  determined by interpreting it relative to:
-
-  1. the build directory corresponding to the current source directory
-     (:variable:`CMAKE_CURRENT_BINARY_DIR`), or
-
-  2. the current source directory (:variable:`CMAKE_CURRENT_SOURCE_DIR`).
-
-  The path in the build directory is preferred unless the path in the
-  source tree is mentioned as an absolute source file path elsewhere
-  in the current directory.
-
-  The output file path may not contain ``<`` or ``>`` characters.
-
-  .. versionadded:: 3.20
-    Arguments to ``OUTPUT`` may use a restricted set of
-    :manual:`generator expressions <cmake-generator-expressions(7)>`.
-    :ref:`Target-dependent expressions <Target-Dependent Expressions>`
-    are not permitted.
-
-  .. versionchanged:: 3.28
-    In targets using :ref:`file sets`, custom command outputs are now
-    considered private unless they are listed in a non-private file set.
-    See policy :policy:`CMP0154`.
-
-  .. versionchanged:: 3.30
-    The output file path may now use ``#`` characters, except
-    when using the :generator:`Borland Makefiles` generator.
-
-``USES_TERMINAL``
-  .. versionadded:: 3.2
-
-  The command will be given direct access to the terminal if possible.
-  With the :generator:`Ninja` generator, this places the command in
-  the ``console`` :prop_gbl:`pool <JOB_POOLS>`.
-
-  This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
-  If the appended commands need access to the terminal, it must be set on
-  the first call to ``add_custom_command(OUTPUT...)`` for the output files.
-
-``VERBATIM``
-  All arguments to the commands will be escaped properly for the
-  build tool so that the invoked command receives each argument
-  unchanged.  Note that one level of escapes is still used by the
-  CMake language processor before add_custom_command even sees the
-  arguments.  Use of ``VERBATIM`` is recommended as it enables
-  correct behavior.  When ``VERBATIM`` is not given the behavior
-  is platform specific because there is no protection of
-  tool-specific special characters.
-
-  This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
-  If the appended commands need to be treated as ``VERBATIM``, it must be set
-  on the first call to ``add_custom_command(OUTPUT...)`` for the output files.
-
-``WORKING_DIRECTORY``
-  Execute the command with the given current working directory.
-  If it is a relative path, it will be interpreted relative to the
-  build tree directory corresponding to the current source directory.
-  If not specified, set to :variable:`CMAKE_CURRENT_BINARY_DIR`.
-
-  This option is currently ignored if ``APPEND`` is given, but a future
-  version may use it.
-
-  .. versionadded:: 3.13
-    Arguments to ``WORKING_DIRECTORY`` may use
-    :manual:`generator expressions <cmake-generator-expressions(7)>`.
-
-``DEPFILE``
-  .. versionadded:: 3.7
-
-  Specify a depfile which holds dependencies for the custom command. It is
-  usually emitted by the custom command itself.  This keyword may only be used
-  if the generator supports it, as detailed below.
-
-  The expected format, compatible with what is generated by ``gcc`` with the
-  option ``-M``, is independent of the generator or platform.
-
-  The formal syntax, as specified using
-  `BNF <https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form>`_ notation with
-  the regular extensions, is the following:
-
-  .. raw:: latex
-
-    \begin{small}
-
-  .. productionlist:: depfile
-    depfile: `rule`*
-    rule: `targets` (':' (`separator` `dependencies`?)?)? `eol`
-    targets: `target` (`separator` `target`)* `separator`*
-    target: `pathname`
-    dependencies: `dependency` (`separator` `dependency`)* `separator`*
-    dependency: `pathname`
-    separator: (`space` | `line_continue`)+
-    line_continue: '\' `eol`
-    space: ' ' | '\t'
-    pathname: `character`+
-    character: `std_character` | `dollar` | `hash` | `whitespace`
-    std_character: <any character except '$', '#' or ' '>
-    dollar: '$$'
-    hash: '\#'
-    whitespace: '\ '
-    eol: '\r'? '\n'
-
-  .. raw:: latex
-
-    \end{small}
-
-  .. note::
-
-    As part of ``pathname``, any slash and backslash is interpreted as
-    a directory separator.
-
-  .. versionadded:: 3.7
-    The :generator:`Ninja` generator supports ``DEPFILE`` since the keyword
-    was first added.
-
-  .. versionadded:: 3.17
-    Added the :generator:`Ninja Multi-Config` generator, which included
-    support for the ``DEPFILE`` keyword.
-
-  .. versionadded:: 3.20
-    Added support for :ref:`Makefile Generators`.
+  ``IMPLICIT_DEPENDS``
+    Request scanning of implicit dependencies of an input file.
+    The language given specifies the programming language whose
+    corresponding dependency scanner should be used.
+    Currently only ``C`` and ``CXX`` language scanners are supported.
+    The language has to be specified for every file in the
+    ``IMPLICIT_DEPENDS`` list.  Dependencies discovered from the
+    scanning are added to those of the custom command at build time.
+    Note that the ``IMPLICIT_DEPENDS`` option is currently supported
+    only for Makefile generators and will be ignored by other generators.
 
     .. note::
 
-      ``DEPFILE`` cannot be specified at the same time as the
-      ``IMPLICIT_DEPENDS`` option for :ref:`Makefile Generators`.
+      This option cannot be specified at the same time as ``DEPFILE`` option.
 
-  .. versionadded:: 3.21
-    Added support for :ref:`Visual Studio Generators` with VS 2012 and above,
-    and for the :generator:`Xcode` generator.  Support for
-    :manual:`generator expressions <cmake-generator-expressions(7)>` was also
-    added.
+  ``JOB_POOL``
+    .. versionadded:: 3.15
 
-  .. versionadded:: 3.29
-    The :ref:`Ninja Generators` will now incorporate the dependencies into its
-    "deps log" database if the file is not listed in ``OUTPUTS`` or
-    ``BYPRODUCTS``.
+    Specify a :prop_gbl:`pool <JOB_POOLS>` for the :generator:`Ninja`
+    generator. Incompatible with ``USES_TERMINAL``, which implies
+    the ``console`` pool.
+    Using a pool that is not defined by :prop_gbl:`JOB_POOLS` causes
+    an error by ninja at build time.
 
-  Using ``DEPFILE`` with generators other than those listed above is an error.
+    This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+    Job pools can only be specified in the first call to
+    ``add_custom_command(OUTPUT...)`` for the output files.
 
-  If the ``DEPFILE`` argument is relative, it should be relative to
-  :variable:`CMAKE_CURRENT_BINARY_DIR`, and any relative paths inside the
-  ``DEPFILE`` should also be relative to :variable:`CMAKE_CURRENT_BINARY_DIR`.
-  See policy :policy:`CMP0116`, which is always ``NEW`` for
-  :ref:`Makefile Generators`, :ref:`Visual Studio Generators`,
-  and the :generator:`Xcode` generator.
+  ``JOB_SERVER_AWARE``
+    .. versionadded:: 3.28
 
-  This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
-  Depfiles can only be set on the first call to
-  ``add_custom_command(OUTPUT...)`` for the output files.
+    Specify that the command is GNU Make job server aware.
 
-``DEPENDS_EXPLICIT_ONLY``
+    For the :generator:`Unix Makefiles`, :generator:`MSYS Makefiles`, and
+    :generator:`MinGW Makefiles` generators this will add the ``+`` prefix to the
+    recipe line. See the `GNU Make Documentation`_ for more information.
 
-  .. versionadded:: 3.27
+    This option is silently ignored by other generators.
 
-  Indicates that the command's ``DEPENDS`` argument represents all files
-  required by the command and implicit dependencies are not required.
+    This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+    Job server awareness can only be specified in the first call to
+    ``add_custom_command(OUTPUT...)`` for the output files.
 
-  Without this option, if any target uses the output of the custom command,
-  CMake will consider that target's dependencies as implicit dependencies for
-  the custom command in case this custom command requires files implicitly
-  created by those targets.
+  .. _`GNU Make Documentation`: https://www.gnu.org/software/make/manual/html_node/MAKE-Variable.html
 
-  This option can be enabled on all custom commands by setting
-  :variable:`CMAKE_ADD_CUSTOM_COMMAND_DEPENDS_EXPLICIT_ONLY` to ``ON``.
+  ``MAIN_DEPENDENCY``
+    Specify the primary input source file to the command.  This is
+    treated just like any value given to the ``DEPENDS`` option
+    but also suggests to :ref:`Visual Studio Generators` where to hang
+    the custom command. Each source file may have at most one command
+    specifying it as its main dependency. A compile command (i.e. for a
+    library or an executable) counts as an implicit main dependency which
+    gets silently overwritten by a custom command specification.
 
-  This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
-  It can only be set on the first call to ``add_custom_command(OUTPUT...)``
-  for the output files.
+    This option is currently ignored if ``APPEND`` is given, but a future
+    version may use it.
 
-  Only the :ref:`Ninja Generators` actually use this information to remove
-  unnecessary implicit dependencies.
+  ``OUTPUT``
+    Specify the output files the command is expected to produce.
+    Each output file will be marked with the :prop_sf:`GENERATED`
+    source file property automatically.
+    If the output of the custom command is not actually created
+    as a file on disk it should be marked with the :prop_sf:`SYMBOLIC`
+    source file property.
 
-  See also the :prop_tgt:`OPTIMIZE_DEPENDENCIES` target property, which may
-  provide another way for reducing the impact of target dependencies in some
-  scenarios.
+    If an output file name is a relative path, its absolute path is
+    determined by interpreting it relative to:
+
+    1. the build directory corresponding to the current source directory
+       (:variable:`CMAKE_CURRENT_BINARY_DIR`), or
+
+    2. the current source directory (:variable:`CMAKE_CURRENT_SOURCE_DIR`).
+
+    The path in the build directory is preferred unless the path in the
+    source tree is mentioned as an absolute source file path elsewhere
+    in the current directory.
+
+    The output file path may not contain ``<`` or ``>`` characters.
+
+    .. versionadded:: 3.20
+      Arguments to ``OUTPUT`` may use a restricted set of
+      :manual:`generator expressions <cmake-generator-expressions(7)>`.
+      :ref:`Target-dependent expressions <Target-Dependent Expressions>`
+      are not permitted.
+
+    .. versionchanged:: 3.28
+      In targets using :ref:`file sets`, custom command outputs are now
+      considered private unless they are listed in a non-private file set.
+      See policy :policy:`CMP0154`.
+
+    .. versionchanged:: 3.30
+      The output file path may now use ``#`` characters, except
+      when using the :generator:`Borland Makefiles` generator.
+
+  ``USES_TERMINAL``
+    .. versionadded:: 3.2
+
+    The command will be given direct access to the terminal if possible.
+    With the :generator:`Ninja` generator, this places the command in
+    the ``console`` :prop_gbl:`pool <JOB_POOLS>`.
+
+    This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+    If the appended commands need access to the terminal, it must be set on
+    the first call to ``add_custom_command(OUTPUT...)`` for the output files.
+
+  ``VERBATIM``
+    All arguments to the commands will be escaped properly for the
+    build tool so that the invoked command receives each argument
+    unchanged.  Note that one level of escapes is still used by the
+    CMake language processor before add_custom_command even sees the
+    arguments.  Use of ``VERBATIM`` is recommended as it enables
+    correct behavior.  When ``VERBATIM`` is not given the behavior
+    is platform specific because there is no protection of
+    tool-specific special characters.
+
+    This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+    If the appended commands need to be treated as ``VERBATIM``, it must be set
+    on the first call to ``add_custom_command(OUTPUT...)`` for the output files.
+
+  ``WORKING_DIRECTORY``
+    Execute the command with the given current working directory.
+    If it is a relative path, it will be interpreted relative to the
+    build tree directory corresponding to the current source directory.
+    If not specified, set to :variable:`CMAKE_CURRENT_BINARY_DIR`.
+
+    This option is currently ignored if ``APPEND`` is given, but a future
+    version may use it.
+
+    .. versionadded:: 3.13
+      Arguments to ``WORKING_DIRECTORY`` may use
+      :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+  ``DEPFILE``
+    .. versionadded:: 3.7
+
+    Specify a depfile which holds dependencies for the custom command. It is
+    usually emitted by the custom command itself.  This keyword may only be used
+    if the generator supports it, as detailed below.
+
+    The expected format, compatible with what is generated by ``gcc`` with the
+    option ``-M``, is independent of the generator or platform.
+
+    The formal syntax, as specified using
+    `BNF <https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form>`_ notation with
+    the regular extensions, is the following:
+
+    .. raw:: latex
+
+      \begin{small}
+
+    .. productionlist:: depfile
+      depfile: `rule`*
+      rule: `targets` (':' (`separator` `dependencies`?)?)? `eol`
+      targets: `target` (`separator` `target`)* `separator`*
+      target: `pathname`
+      dependencies: `dependency` (`separator` `dependency`)* `separator`*
+      dependency: `pathname`
+      separator: (`space` | `line_continue`)+
+      line_continue: '\' `eol`
+      space: ' ' | '\t'
+      pathname: `character`+
+      character: `std_character` | `dollar` | `hash` | `whitespace`
+      std_character: <any character except '$', '#' or ' '>
+      dollar: '$$'
+      hash: '\#'
+      whitespace: '\ '
+      eol: '\r'? '\n'
+
+    .. raw:: latex
+
+      \end{small}
+
+    .. note::
+
+      As part of ``pathname``, any slash and backslash is interpreted as
+      a directory separator.
+
+    .. versionadded:: 3.7
+      The :generator:`Ninja` generator supports ``DEPFILE`` since the keyword
+      was first added.
+
+    .. versionadded:: 3.17
+      Added the :generator:`Ninja Multi-Config` generator, which included
+      support for the ``DEPFILE`` keyword.
+
+    .. versionadded:: 3.20
+      Added support for :ref:`Makefile Generators`.
+
+      .. note::
+
+        ``DEPFILE`` cannot be specified at the same time as the
+        ``IMPLICIT_DEPENDS`` option for :ref:`Makefile Generators`.
+
+    .. versionadded:: 3.21
+      Added support for :ref:`Visual Studio Generators` with VS 2012 and above,
+      and for the :generator:`Xcode` generator.  Support for
+      :manual:`generator expressions <cmake-generator-expressions(7)>` was also
+      added.
+
+    .. versionadded:: 3.29
+      The :ref:`Ninja Generators` will now incorporate the dependencies into its
+      "deps log" database if the file is not listed in ``OUTPUTS`` or
+      ``BYPRODUCTS``.
+
+    Using ``DEPFILE`` with generators other than those listed above is an error.
+
+    If the ``DEPFILE`` argument is relative, it should be relative to
+    :variable:`CMAKE_CURRENT_BINARY_DIR`, and any relative paths inside the
+    ``DEPFILE`` should also be relative to :variable:`CMAKE_CURRENT_BINARY_DIR`.
+    See policy :policy:`CMP0116`, which is always ``NEW`` for
+    :ref:`Makefile Generators`, :ref:`Visual Studio Generators`,
+    and the :generator:`Xcode` generator.
+
+    This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+    Depfiles can only be set on the first call to
+    ``add_custom_command(OUTPUT...)`` for the output files.
+
+  ``DEPENDS_EXPLICIT_ONLY``
+
+    .. versionadded:: 3.27
+
+    Indicates that the command's ``DEPENDS`` argument represents all files
+    required by the command and implicit dependencies are not required.
+
+    Without this option, if any target uses the output of the custom command,
+    CMake will consider that target's dependencies as implicit dependencies for
+    the custom command in case this custom command requires files implicitly
+    created by those targets.
+
+    This option can be enabled on all custom commands by setting
+    :variable:`CMAKE_ADD_CUSTOM_COMMAND_DEPENDS_EXPLICIT_ONLY` to ``ON``.
+
+    This keyword cannot be used with ``APPEND`` (see policy :policy:`CMP0175`).
+    It can only be set on the first call to ``add_custom_command(OUTPUT...)``
+    for the output files.
+
+    Only the :ref:`Ninja Generators` actually use this information to remove
+    unnecessary implicit dependencies.
+
+    See also the :prop_tgt:`OPTIMIZE_DEPENDENCIES` target property, which may
+    provide another way for reducing the impact of target dependencies in some
+    scenarios.
 
 Examples: Generating Files
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -578,58 +593,61 @@
 ``foo`` and ``bar``, will not build until after target ``generate_table_csv``
 is built.
 
-.. _`add_custom_command(TARGET)`:
-
 Build Events
 ^^^^^^^^^^^^
 
-The second signature adds a custom command to a target such as a
-library or executable.  This is useful for performing an operation
-before or after building the target.  The command becomes part of the
-target and will only execute when the target itself is built.  If the
-target is already built, the command will not execute.
-
-.. code-block:: cmake
-
+.. signature::
   add_custom_command(TARGET <target>
                      PRE_BUILD | PRE_LINK | POST_BUILD
-                     COMMAND command1 [ARGS] [args1...]
-                     [COMMAND command2 [ARGS] [args2...] ...]
-                     [BYPRODUCTS [files...]]
-                     [WORKING_DIRECTORY dir]
-                     [COMMENT comment]
-                     [VERBATIM]
-                     [COMMAND_EXPAND_LISTS]
-                     [USES_TERMINAL])
+                     [...])
 
-This defines a new command that will be associated with building the
-specified ``<target>``.  The ``<target>`` must be defined in the current
-directory; targets defined in other directories may not be specified.
+  Add a build event to a target such as a
+  library or executable.  This is useful for performing an operation
+  before or after building the target.  The command becomes part of the
+  target and will only execute when the target itself is built.  If the
+  target is already built, the command will not execute.
 
-When the command will happen is determined by which
-of the following is specified:
+  .. code-block:: cmake
 
-``PRE_BUILD``
-  This option has unique behavior for the :ref:`Visual Studio Generators`.
-  When using one of the Visual Studio generators, the command will run before
-  any other rules are executed within the target.  With all other generators,
-  this option behaves the same as ``PRE_LINK`` instead.  Because of this,
-  it is recommended to avoid using ``PRE_BUILD`` except when it is known that
-  a Visual Studio generator is being used.
-``PRE_LINK``
-  Run after sources have been compiled but before linking the binary
-  or running the librarian or archiver tool of a static library.
-  This is not defined for targets created by the
-  :command:`add_custom_target` command.
-``POST_BUILD``
-  Run after all other rules within the target have been executed.
+    add_custom_command(TARGET <target>
+                       PRE_BUILD | PRE_LINK | POST_BUILD
+                       COMMAND <command1> [ARGS] [<args1>...]
+                       [COMMAND <command2> [ARGS] [<args2>...]] ...
+                       [BYPRODUCTS <files>...]
+                       [WORKING_DIRECTORY <dir>]
+                       [COMMENT <comment>]
+                       [VERBATIM]
+                       [COMMAND_EXPAND_LISTS]
+                       [USES_TERMINAL])
 
-Projects should always specify one of the above three keywords when using
-the ``TARGET`` form.  See policy :policy:`CMP0175`.
+  This defines a new command that will be associated with building the
+  specified ``<target>``.  The ``<target>`` must be defined in the current
+  directory; targets defined in other directories may not be specified.
 
-All other keywords shown in the signature above have the same meaning as they
-do for the :command:`add_custom_command(OUTPUT)` form of the command.
-At least one ``COMMAND`` must be given, see policy :policy:`CMP0175`.
+  When the command will happen is determined by which
+  of the following is specified:
+
+  ``PRE_BUILD``
+    This option has unique behavior for the :ref:`Visual Studio Generators`.
+    When using one of the Visual Studio generators, the command will run before
+    any other rules are executed within the target.  With all other generators,
+    this option behaves the same as ``PRE_LINK`` instead.  Because of this,
+    it is recommended to avoid using ``PRE_BUILD`` except when it is known that
+    a Visual Studio generator is being used.
+  ``PRE_LINK``
+    Run after sources have been compiled but before linking the binary
+    or running the librarian or archiver tool of a static library.
+    This is not defined for targets created by the
+    :command:`add_custom_target` command.
+  ``POST_BUILD``
+    Run after all other rules within the target have been executed.
+
+  Projects should always specify one of the above three keywords when using
+  the ``TARGET`` form.  See policy :policy:`CMP0175`.
+
+  All other keywords shown in the signature above have the same meaning as they
+  do for the :command:`add_custom_command(OUTPUT)` form of the command.
+  At least one ``COMMAND`` must be given, see policy :policy:`CMP0175`.
 
 .. note::
   Because generator expressions can be used in custom commands,
diff --git a/Help/command/add_custom_target.rst b/Help/command/add_custom_target.rst
index 83fe6b4..fd38729 100644
--- a/Help/command/add_custom_target.rst
+++ b/Help/command/add_custom_target.rst
@@ -5,17 +5,17 @@
 
 .. code-block:: cmake
 
-  add_custom_target(Name [ALL] [command1 [args1...]]
-                    [COMMAND command2 [args2...] ...]
-                    [DEPENDS depend depend depend ...]
-                    [BYPRODUCTS [files...]]
-                    [WORKING_DIRECTORY dir]
-                    [COMMENT comment]
-                    [JOB_POOL job_pool]
+  add_custom_target(Name [ALL] [command1 [<args1>...]]
+                    [COMMAND command2 [<args2>...]] ...
+                    [DEPENDS <depend>...]
+                    [BYPRODUCTS <file>...]
+                    [WORKING_DIRECTORY <dir>]
+                    [COMMENT <comment>]
+                    [JOB_POOL <job_pool>]
                     [JOB_SERVER_AWARE <bool>]
                     [VERBATIM] [USES_TERMINAL]
                     [COMMAND_EXPAND_LISTS]
-                    [SOURCES src1 [src2...]])
+                    [SOURCES <source>...])
 
 Adds a target with the given name that executes the given commands.
 The target has no output file and is *always considered out of date*
diff --git a/Help/command/add_link_options.rst b/Help/command/add_link_options.rst
index 419ee56..462fee9 100644
--- a/Help/command/add_link_options.rst
+++ b/Help/command/add_link_options.rst
@@ -42,3 +42,8 @@
 * :variable:`CMAKE_<LANG>_FLAGS` and :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>`
   add language-wide flags passed to all invocations of the compiler.
   This includes invocations that drive compiling and those that drive linking.
+
+* .. versionadded:: 4.3
+    :variable:`CMAKE_<LANG>_LINK_FLAGS` and
+    :variable:`CMAKE_<LANG>_LINK_FLAGS_<CONFIG>` add language-wide flags passed
+    to all invocations of the compiler which drive linking.
diff --git a/Help/command/cmake_host_system_information.rst b/Help/command/cmake_host_system_information.rst
index 4e72749..35360c2 100644
--- a/Help/command/cmake_host_system_information.rst
+++ b/Help/command/cmake_host_system_information.rst
@@ -9,17 +9,18 @@
 .. parsed-literal::
 
   `Query host system specific information`_
-    cmake_host_system_information(RESULT <variable> QUERY <key> ...)
+    cmake_host_system_information(RESULT <variable> `QUERY`_ <key> ...)
 
-  `Query Windows registry`_
-    cmake_host_system_information(RESULT <variable> QUERY WINDOWS_REGISTRY <key> ...)
+  `Query the Windows registry`_
+    cmake_host_system_information(RESULT <variable> `QUERY WINDOWS_REGISTRY`_ <key> ...)
 
 Query host system specific information
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-.. code-block:: cmake
-
+.. signature::
   cmake_host_system_information(RESULT <variable> QUERY <key> ...)
+  :target:
+    QUERY
 
 Queries system information of the host system on which cmake runs.
 One or more ``<key>`` can be provided to select the information to be
@@ -111,6 +112,16 @@
 
   One if processor has serial number
 
+``HAS_APIC``
+  .. versionadded:: 4.3
+
+  One if processor supports APIC
+
+``HAS_L1_CACHE``
+  .. versionadded:: 4.3
+
+  One if processor has L1 cache
+
 ``PROCESSOR_SERIAL_NUMBER``
   .. versionadded:: 3.10
 
@@ -126,6 +137,17 @@
 
   Human readable full processor description
 
+``LOCALE_CHARSET``
+  .. versionadded:: 4.3
+
+  The locale's character set, if known, otherwise empty.
+
+  This is the :ref:`encoding <CMake Language Encoding>` expected
+  in :manual:`cmake-language(7)` files and scripts:
+
+  * On Windows, this is always ``UTF-8``.
+  * On UNIX and macOS, this is based on the current locale.
+
 ``OS_NAME``
   .. versionadded:: 3.10
 
@@ -161,6 +183,46 @@
   environment that sets the ``MSYSTEM`` environment variable, this
   is its installation prefix.  Otherwise, this is the empty string.
 
+``FAMILY_ID``
+  .. versionadded:: 4.3
+
+  The processor family name
+
+``MODEL_ID``
+  .. versionadded:: 4.3
+
+  The processor model ID
+
+``MODEL_NAME``
+  .. versionadded:: 4.3
+
+  The processor model name
+
+``PROCESSOR_APIC_ID``
+  .. versionadded:: 4.3
+
+  The processor APIC ID
+
+``PROCESSOR_CACHE_SIZE``
+  .. versionadded:: 4.3
+
+  The processor L1 cache size
+
+``PROCESSOR_CLOCK_FREQUENCY``
+  .. versionadded:: 4.3
+
+  The processor clock frequency
+
+``VENDOR_ID``
+  .. versionadded:: 4.3
+
+  The processor vendor ID
+
+``VENDOR_STRING``
+  .. versionadded:: 4.3
+
+  The processor vendor string
+
 ``DISTRIB_INFO``
   .. versionadded:: 3.22
 
@@ -290,20 +352,19 @@
 .. _man 5 os-release: https://www.freedesktop.org/software/systemd/man/latest/os-release.html
 .. _various distribution-specific files: http://linuxmafia.com/faq/Admin/release-files.html
 
-.. _Query Windows registry:
-
-Query Windows registry
-^^^^^^^^^^^^^^^^^^^^^^
+Query the Windows registry
+^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 .. versionadded:: 3.24
 
-.. code-block:: cmake
-
+.. signature::
   cmake_host_system_information(RESULT <variable>
                                 QUERY WINDOWS_REGISTRY <key> [VALUE_NAMES|SUBKEYS|VALUE <name>]
                                 [VIEW (64|32|64_32|32_64|HOST|TARGET|BOTH)]
                                 [SEPARATOR <separator>]
                                 [ERROR_VARIABLE <result>])
+  :target:
+    QUERY WINDOWS_REGISTRY
 
 Performs query operations on local computer registry subkey. Returns a list of
 subkeys or value names that are located under the specified subkey in the
diff --git a/Help/command/cmake_instrumentation.rst b/Help/command/cmake_instrumentation.rst
index 0d2cd50..4e2aa43 100644
--- a/Help/command/cmake_instrumentation.rst
+++ b/Help/command/cmake_instrumentation.rst
@@ -1,12 +1,7 @@
 cmake_instrumentation
 ---------------------
 
-.. versionadded:: 4.0
-
-.. note::
-
-   This command is only available when experimental support for instrumentation
-   has been enabled by the ``CMAKE_EXPERIMENTAL_INSTRUMENTATION`` gate.
+.. versionadded:: 4.3
 
 Enables interacting with the
 :manual:`CMake Instrumentation API <cmake-instrumentation(7)>`.
diff --git a/Help/command/cmake_minimum_required.rst b/Help/command/cmake_minimum_required.rst
index 98861f9..1eaba0c 100644
--- a/Help/command/cmake_minimum_required.rst
+++ b/Help/command/cmake_minimum_required.rst
@@ -22,8 +22,8 @@
 ``<min>`` version and sets the `Policy Version`_.
 If the running version of CMake is older than 3.12, the extra ``...``
 dots will be seen as version component separators, resulting in the
-``...<max>`` part being ignored and preserving the pre-3.12 behavior
-of basing policies on ``<min>``.
+``...<policy_max>`` part being ignored and preserving the pre-3.12
+behavior of basing policies on ``<min>``.
 
 This command will set the value of the
 :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` variable to ``<min>``.
@@ -53,11 +53,12 @@
 Policy Version
 ^^^^^^^^^^^^^^
 
-``cmake_minimum_required(VERSION <min>[...<max>])`` implicitly invokes
+``cmake_minimum_required(VERSION <min>[...<policy_max>])`` implicitly
+invokes
 
 .. code-block:: cmake
 
-  cmake_policy(VERSION <min>[...<max>])
+  cmake_policy(VERSION <min>[...<policy_max>])
 
 .. include:: include/POLICY_VERSION.rst
 
diff --git a/Help/command/cmake_path.rst b/Help/command/cmake_path.rst
index 3fc3b7c..5fb0ef1 100644
--- a/Help/command/cmake_path.rst
+++ b/Help/command/cmake_path.rst
@@ -169,6 +169,7 @@
 be empty.  A ``relative-part`` refers to the full path with any ``root-path``
 removed.
 
+.. _Creating a Path Variable:
 
 Creating A Path Variable
 ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -193,6 +194,16 @@
 keyword.  All other sub-commands store the result in a mandatory ``<out-var>``
 variable.
 
+.. note::
+
+  The ``cmake_path`` command can be used directly with variables provided by
+  CMake representing paths (e.g., :variable:`CMAKE_SOURCE_DIR`). However, since
+  the command can modify these variables, and many of them have undefined
+  behavior when modified, they should never be specified as an ``<out-var>``,
+  and only as the ``<path-var>`` when a separate ``<out-var>`` is specified.
+  See :manual:`cmake-variables(7)` for the list of CMake variables and
+  identifiers reserved by CMake.
+
 .. _Normalization:
 
 Normalization
@@ -395,7 +406,7 @@
 Query
 ^^^^^
 
-Each of the `cmake_path(GET) <GET_>`_ subcommands has a corresponding
+Each of the :cref:`GET` subcommands has a corresponding
 ``HAS_...`` subcommand which can be used to discover whether a particular path
 component is present.  See `Path Structure And Terminology`_ for the
 meaning of each path component.
@@ -500,7 +511,7 @@
   cmake_path(SET <path-var> [NORMALIZE] <input>)
 
   Assigns the ``<input>`` path to ``<path-var>``.  If ``<input>`` is a native
-  path, it is converted into a cmake-style path with forward-slashes
+  path, it is converted into a CMake-style path with forward-slashes
   (``/``). On Windows, the long filename marker is taken into account.
 
   When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
@@ -550,12 +561,16 @@
 
     append <input> omitting any root-name to <path>
 
+  See :ref:`Creating a Path Variable` for details on the output variable.
+
 .. signature::
   cmake_path(APPEND_STRING <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
 
   Appends all the ``<input>`` arguments to the ``<path-var>`` without adding any
   ``directory-separator``.
 
+  See :ref:`Creating a Path Variable` for details on the output variable.
+
 .. signature::
   cmake_path(REMOVE_FILENAME <path-var> [OUTPUT_VARIABLE <out-var>])
 
@@ -563,8 +578,8 @@
   :cref:`GET ... FILENAME`) from ``<path-var>``.  After removal, any trailing
   ``directory-separator`` is left alone, if present.
 
-  If ``OUTPUT_VARIABLE`` is not given, then after this function returns,
-  :cref:`HAS_FILENAME` returns false for ``<path-var>``.
+  :cref:`HAS_FILENAME` will return false for the result, whether stored in
+  ``<out-var>`` or ``<path-var>``.
 
   For example:
 
@@ -583,6 +598,8 @@
     First path is "/a/"
     Second path is "/a/"
 
+  See :ref:`Creating a Path Variable` for details on the output variable.
+
 .. signature::
   cmake_path(REPLACE_FILENAME <path-var> <input> [OUTPUT_VARIABLE <out-var>])
 
@@ -599,12 +616,16 @@
       cmake_path(APPEND path "${input}")
     endif()
 
+  See :ref:`Creating a Path Variable` for details on the output variable.
+
 .. signature::
   cmake_path(REMOVE_EXTENSION <path-var> [LAST_ONLY]
                                          [OUTPUT_VARIABLE <out-var>])
 
   Removes the :ref:`extension <EXTENSION_DEF>`, if any, from ``<path-var>``.
 
+  See :ref:`Creating a Path Variable` for details on the output variable.
+
 .. signature::
   cmake_path(REPLACE_EXTENSION <path-var> [LAST_ONLY] <input>
                                [OUTPUT_VARIABLE <out-var>])
@@ -620,6 +641,8 @@
     endif()
     cmake_path(APPEND_STRING path "${input}")
 
+  See :ref:`Creating a Path Variable` for details on the output variable.
+
 
 .. _Path Generation:
 
@@ -632,6 +655,8 @@
   Normalizes ``<path-var>`` according the steps described in
   :ref:`Normalization`.
 
+  See :ref:`Creating a Path Variable` for details on the output variable.
+
 .. signature::
   cmake_path(RELATIVE_PATH <path-var> [BASE_DIRECTORY <input>]
                                       [OUTPUT_VARIABLE <out-var>])
@@ -645,6 +670,8 @@
   `std::filesystem::path::lexically_relative
   <https://en.cppreference.com/w/cpp/filesystem/path/lexically_normal>`_.
 
+  See :ref:`Creating a Path Variable` for details on the output variable.
+
 .. signature::
   cmake_path(ABSOLUTE_PATH <path-var> [BASE_DIRECTORY <input>] [NORMALIZE]
                                       [OUTPUT_VARIABLE <out-var>])
@@ -662,6 +689,8 @@
   with symbolic links resolved and leading tildes expanded, use the
   :command:`file(REAL_PATH)` command instead.
 
+  See :ref:`Creating a Path Variable` for details on the output variable.
+
 Native Conversion
 ^^^^^^^^^^^^^^^^^
 
@@ -671,12 +700,14 @@
 .. signature::
   cmake_path(NATIVE_PATH <path-var> [NORMALIZE] <out-var>)
 
-  Converts a cmake-style ``<path-var>`` into a native path with
+  Converts a CMake-style ``<path-var>`` into a native path with
   platform-specific slashes (``\`` on Windows hosts and ``/`` elsewhere).
 
   When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
   <Normalization>` before the conversion.
 
+  See :ref:`Creating a Path Variable` for details on the output variable.
+
 .. _CONVERT:
 
 .. signature::
@@ -684,17 +715,20 @@
   :target:
     CONVERT ... TO_CMAKE_PATH_LIST
 
-  Converts a native ``<input>`` path into a cmake-style path with forward
-  slashes (``/``).  On Windows hosts, the long filename marker is taken into
+  Converts a native ``<input>`` path into a CMake-style path with forward
+  slashes (``/``).
+
+  On Windows hosts, the long filename marker is taken into
   account.  The input can be a single path or a system search path like
-  ``$ENV{PATH}``.  A search path will be converted to a cmake-style list
-  separated by ``;`` characters (on non-Windows platforms, this essentially
-  means ``:`` separators are replaced with ``;``).  The result of the
-  conversion is stored in the ``<out-var>`` variable.
+  ``$ENV{PATH}``.  A search path will be converted to a
+  :ref:`semicolon-separated list <CMake Language Lists>` (on non-Windows
+  platforms, this essentially means ``:`` separators are replaced with ``;``).
 
   When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
   <Normalization>` before the conversion.
 
+  See :ref:`Creating a Path Variable` for details on the output variable.
+
   .. note::
     Unlike most other ``cmake_path()`` subcommands, the ``CONVERT`` subcommand
     takes a literal string as input, not the name of a variable.
@@ -704,16 +738,18 @@
   :target:
     CONVERT ... TO_NATIVE_PATH_LIST
 
-  Converts a cmake-style ``<input>`` path into a native path with
+  Converts a CMake-style ``<input>`` path into a native path with
   platform-specific slashes (``\`` on Windows hosts and ``/`` elsewhere).
-  The input can be a single path or a cmake-style list.  A list will be
-  converted into a native search path (``;``-separated on Windows,
-  ``:``-separated on other platforms).  The result of the conversion is
-  stored in the ``<out-var>`` variable.
+
+  The input can be a single path or a :ref:`semicolon-separated list
+  <CMake Language Lists>`.  A list will be converted into a native search path
+  (``;``-separated on Windows, ``:``-separated on other platforms).
 
   When the ``NORMALIZE`` option is specified, the path is :ref:`normalized
   <Normalization>` before the conversion.
 
+  See :ref:`Creating a Path Variable` for details on the output variable.
+
   .. note::
     Unlike most other ``cmake_path()`` subcommands, the ``CONVERT`` subcommand
     takes a literal string as input, not the name of a variable.
@@ -744,3 +780,5 @@
   ``p2`` that compare equal (:cref:`COMPARE ... EQUAL`), the hash value of
   ``p1`` is equal to the hash value of ``p2``.  The path is always
   :ref:`normalized <Normalization>` before the hash is computed.
+
+  See :ref:`Creating a Path Variable` for details on the output variable.
diff --git a/Help/command/cmake_policy.rst b/Help/command/cmake_policy.rst
index bbec8e6..5be074c 100644
--- a/Help/command/cmake_policy.rst
+++ b/Help/command/cmake_policy.rst
@@ -24,20 +24,21 @@
 behavior.  While setting policies individually is supported, we
 encourage projects to set policies based on CMake versions:
 
-.. signature:: cmake_policy(VERSION <min>[...<max>])
+.. signature:: cmake_policy(VERSION <min>[...<policy_max>])
   :target: VERSION
 
 .. versionadded:: 3.12
-  The optional ``<max>`` version.
+  The optional ``<policy_max>`` version.
 
-``<min>`` and the optional ``<max>`` are each CMake versions of the form
-``major.minor[.patch[.tweak]]``, and the ``...`` is literal.  The ``<min>``
-version must be at least ``2.4`` and at most the running version of CMake.
-The ``<max>`` version, if specified, must be at least the ``<min>`` version
-but may exceed the running version of CMake.  If the running version of
-CMake is older than 3.12, the extra ``...`` dots will be seen as version
-component separators, resulting in the ``...<max>`` part being ignored and
-preserving the pre-3.12 behavior of basing policies on ``<min>``.
+``<min>`` and the optional ``<policy_max>`` are each CMake versions of the
+form ``major.minor[.patch[.tweak]]``, and the ``...`` is literal.
+The ``<min>`` version must be at least ``2.4`` and at most the running
+version of CMake.  The ``<policy_max>`` version, if specified, must be at
+least the ``<min>`` version but may exceed the running version of CMake.
+If the running version of CMake is older than 3.12, the extra ``...``
+dots will be seen as version component separators, resulting in the
+``...<policy_max>`` part being ignored and preserving the pre-3.12 behavior
+of basing policies on ``<min>``.
 
 .. include:: include/POLICY_VERSION.rst
 
diff --git a/Help/command/configure_file.rst b/Help/command/configure_file.rst
index 546f9ce..956400c 100644
--- a/Help/command/configure_file.rst
+++ b/Help/command/configure_file.rst
@@ -193,7 +193,7 @@
 
 .. code-block:: cmake
 
-  target_include_directories(<target> [SYSTEM] <INTERFACE|PUBLIC|PRIVATE> "${CMAKE_CURRENT_BINARY_DIR}")
+  target_include_directories(<target> [SYSTEM] {INTERFACE|PUBLIC|PRIVATE} "${CMAKE_CURRENT_BINARY_DIR}")
 
 so that sources may include the header as ``#include <foo.h>``.
 
diff --git a/Help/command/define_property.rst b/Help/command/define_property.rst
index 3dccca9..8952f1f 100644
--- a/Help/command/define_property.rst
+++ b/Help/command/define_property.rst
@@ -8,8 +8,8 @@
   define_property(<GLOBAL | DIRECTORY | TARGET | SOURCE |
                    TEST | VARIABLE | CACHED_VARIABLE>
                    PROPERTY <name> [INHERITED]
-                   [BRIEF_DOCS <brief-doc> [docs...]]
-                   [FULL_DOCS <full-doc> [docs...]]
+                   [BRIEF_DOCS <brief-doc> [<docs>...]]
+                   [FULL_DOCS <full-doc> [<docs>...]]
                    [INITIALIZE_FROM_VARIABLE <variable>])
 
 Defines one property in a scope for use with the :command:`set_property` and
diff --git a/Help/command/enable_language.rst b/Help/command/enable_language.rst
index 1bffef6..7584e35 100644
--- a/Help/command/enable_language.rst
+++ b/Help/command/enable_language.rst
@@ -15,7 +15,8 @@
 
 The following restrictions apply to where ``enable_language()`` may be called:
 
-* It must be called in file scope, not in a function call.
+* It must be called in file scope, not in a :command:`function` call
+  nor inside a :command:`block()`.
 * It must not be called before the first call to :command:`project`.
   See policy :policy:`CMP0165`.
 * It must be called in the highest directory common to all targets
diff --git a/Help/command/enable_testing.rst b/Help/command/enable_testing.rst
index 7bae5c0..4a45aac 100644
--- a/Help/command/enable_testing.rst
+++ b/Help/command/enable_testing.rst
@@ -1,20 +1,51 @@
 enable_testing
 --------------
 
-Enable testing for current directory and below.
+Enables testing for the current directory and below:
 
 .. code-block:: cmake
 
   enable_testing()
 
-Enables testing for this directory and below.
-
-This command should be in the top-level source directory because
+This command should be invoked in the top-level source directory because
 :manual:`ctest(1)` expects to find a test file in the top-level
 build directory.
 
-This command is automatically invoked when the :module:`CTest`
+This command is also automatically invoked when the :module:`CTest`
 module is included, except if the :variable:`BUILD_TESTING`
 option is turned off.
 
-See also the :command:`add_test` command.
+The following restrictions apply to where ``enable_testing()`` may be called:
+
+* It must be called in file scope, not in a :command:`function` call nor inside
+  a :command:`block`.
+
+Examples
+^^^^^^^^
+
+In the following example, this command is conditionally called depending on how
+the project is used.  For instance, when the Example project is added via the
+:module:`FetchContent` module as a subdirectory of a parent project that defines
+its own tests, testing for the Example project is disabled.
+
+.. code-block:: cmake
+  :caption: ``CMakeLists.txt``
+
+  project(Example)
+
+  option(Example_ENABLE_TESTING "Enable testing" ${PROJECT_IS_TOP_LEVEL})
+
+  if(Example_ENABLE_TESTING)
+    enable_testing()
+  endif()
+
+  # ...
+
+  if(Example_ENABLE_TESTING)
+    add_test(...)
+  endif()
+
+See Also
+^^^^^^^^
+
+* The :command:`add_test` command.
diff --git a/Help/command/export.rst b/Help/command/export.rst
index 9673869..0ecdbd9 100644
--- a/Help/command/export.rst
+++ b/Help/command/export.rst
@@ -16,6 +16,8 @@
   export(`EXPORT`_ <export-name> [...])
   export(`PACKAGE`_ <PackageName>)
   export(`SETUP`_ <export-name> [...])
+  export(`PACKAGE_INFO`_ <package-name> [...])
+  export(`SBOM`_ <sbom-name> [...])
 
 Exporting Targets
 ^^^^^^^^^^^^^^^^^
@@ -130,9 +132,12 @@
 Exporting Targets to the |CPS|
 """"""""""""""""""""""""""""""
 
+.. signature::
+  export(PACKAGE_INFO <package-name> [...])
+
 .. code-block:: cmake
 
-  export(EXPORT <export-name> PACKAGE_INFO <package-name>
+  export(PACKAGE_INFO <package-name> EXPORT <export-name>
          [PROJECT <project-name>|NO_PROJECT_METADATA]
          [APPENDIX <appendix-name>]
          [LOWER_CASE_FILE]
@@ -144,12 +149,10 @@
          [LICENSE <license-string>]
          [DEFAULT_LICENSE <license-string>]
          [DESCRIPTION <description-string>]
-         [HOMEPAGE_URL <url-string>])
+         [HOMEPAGE_URL <url-string>]
+         [CXX_MODULES_DIRECTORY <directory>])
 
-.. versionadded:: 4.1
-.. note::
-
-  Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+.. versionadded:: 4.3
 
 Creates a file in the |CPS|_ that may be included by outside projects to import
 targets named by ``<target>...`` from the current project's build tree.  See
@@ -162,6 +165,34 @@
 
 See :command:`install(PACKAGE_INFO)` for a description of the other options.
 
+Exporting Software Bill of Materials (SBOM) Documents
+"""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+.. signature::
+  export(SBOM <sbom-name> [...])
+
+.. code-block:: cmake
+
+  export(SBOM <sbom-name> EXPORT <export-name>
+         [FORMAT <string>]
+         [PROJECT <project-name>|NO_PROJECT_METADATA]
+         [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
+         [LICENSE <license-string>]
+         [DESCRIPTION <description-string>]
+         [HOMEPAGE_URL <url-string>]
+         [PACKAGE_URL <url-string>])
+
+.. versionadded:: 4.3
+.. note::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_GENERATE_SBOM``.
+
+Generates a software bill of materials (SBOM) document describing the targets
+in the export ``<export-name>`` and their dependencies in the build tree
+
+See :command:`install(SBOM)` for details about the supported SBOM formats and a
+description of the other options.
+
 Exporting Packages
 ^^^^^^^^^^^^^^^^^^
 
diff --git a/Help/command/file.rst b/Help/command/file.rst
index 81f2a01..5bc7b3c 100644
--- a/Help/command/file.rst
+++ b/Help/command/file.rst
@@ -11,7 +11,8 @@
 
 .. note::
 
-  The sub-commands `RELATIVE_PATH`_, `TO_CMAKE_PATH`_, and `TO_NATIVE_PATH`_
+  The sub-commands :command:`file(RELATIVE_PATH)`,
+  :command:`file(TO_CMAKE_PATH)`, and :command:`file(TO_NATIVE_PATH)`
   have been superseded, respectively, by the sub-commands
   :command:`cmake_path(RELATIVE_PATH)`,
   :command:`cmake_path(CONVERT ... TO_CMAKE_PATH_LIST)`, and
@@ -605,7 +606,7 @@
 
   Create a link ``<linkname>`` that points to ``<original>``.
   It will be a hard link by default, but providing the ``SYMBOLIC`` option
-  results in a symbolic link instead.  Hard links require that ``original``
+  results in a symbolic link instead.  Hard links require that ``<original>``
   exists and is a file, not a directory.  If ``<linkname>`` already exists,
   it will be overwritten.
 
@@ -615,12 +616,17 @@
   emitted.
 
   Specifying ``COPY_ON_ERROR`` enables copying the file as a fallback if
-  creating the link fails.  If the source is a directory, the destination
-  directory will be created if it does not exist, but no files will be copied
-  the from source one.  It can be useful for handling situations such as
+  creating the link fails.  It can be useful for handling situations such as
   ``<original>`` and ``<linkname>`` being on different drives or mount points,
   which would make them unable to support a hard link.
 
+  .. versionchanged:: 4.3
+
+    If the source is a directory, CMake versions prior to 4.3 will create the
+    destination directory if it does not exist, but not copy any files.
+    With CMake 4.3 and above, the contents of the source directory will be
+    copied recursively to the destination.  See policy :policy:`CMP0205`.
+
 .. signature::
   file(CHMOD <files>... <directories>...
        [PERMISSIONS <permissions>...]
@@ -708,12 +714,12 @@
   file(TO_CMAKE_PATH "<path>" <variable>)
   file(TO_NATIVE_PATH "<path>" <variable>)
 
-  The ``TO_CMAKE_PATH`` mode converts a native ``<path>`` into a cmake-style
+  The ``TO_CMAKE_PATH`` mode converts a native ``<path>`` into a CMake-style
   path with forward-slashes (``/``).  The input can be a single path or a
   system search path like ``$ENV{PATH}``.  A search path will be converted
-  to a cmake-style list separated by ``;`` characters.
+  to a :ref:`semicolon-separated list <CMake Language Lists>`.
 
-  The ``TO_NATIVE_PATH`` mode converts a cmake-style ``<path>`` into a native
+  The ``TO_NATIVE_PATH`` mode converts a CMake-style ``<path>`` into a native
   path with platform-specific slashes (``\`` on Windows hosts and ``/``
   elsewhere).
 
@@ -914,6 +920,7 @@
     [COMPRESSION <compression>
     [COMPRESSION_LEVEL <compression-level>]]
     [MTIME <mtime>]
+    [THREADS <number>]
     [WORKING_DIRECTORY <dir>]
     [VERBOSE])
   :target: ARCHIVE_CREATE
@@ -932,17 +939,55 @@
     ``7zip``, ``gnutar``, ``pax``, ``paxr``, ``raw`` and ``zip``.
     If ``FORMAT`` is not given, the default format is ``paxr``.
 
+    The default compression method depends on the format:
+
+    * ``7zip`` uses ``LZMA`` compression
+    * ``zip`` uses ``Deflate`` compression
+    * others uses no compression by default
+
   ``COMPRESSION <compression>``
     Some archive formats allow the type of compression to be specified.
     The ``7zip`` and ``zip`` archive formats already imply a specific type of
     compression.  The other formats use no compression by default, but can be
     directed to do so with the ``COMPRESSION`` option.  Valid values for
-    ``<compression>`` are ``None``, ``BZip2``, ``GZip``, ``XZ``, and ``Zstd``.
+    ``<compression>`` are:
+
+    * ``None``
+    * ``BZip2``
+    * ``Deflate``
+
+      .. versionadded:: 4.3
+
+      This is an alias for ``GZip``.
+
+    * ``GZip``
+    * ``LZMA``
+
+      .. versionadded:: 4.3
+
+    * ``LZMA2``
+
+      .. versionadded:: 4.3
+
+      This is an alias for ``XZ``.
+
+    * ``PPMd``
+
+      .. versionadded:: 4.3
+
+      This compression method is only supported by the ``7zip`` archive format.
+
+    * ``XZ``
+    * ``Zstd``
 
     .. note::
       With ``FORMAT`` set to ``raw``, only one file will be compressed
       with the compression type specified by ``COMPRESSION``.
 
+    .. versionadded:: 4.3
+
+      The ``7zip`` and ``zip`` formats support changing the default compression.
+
   ``COMPRESSION_LEVEL <compression-level>``
     .. versionadded:: 3.19
 
@@ -951,13 +996,31 @@
     default being 0.  The ``COMPRESSION`` option must be present when
     ``COMPRESSION_LEVEL`` is given.
 
+    The value ``0`` is used to specify the default compression level.
+    It is selected automatically by the archive library backend and
+    not directly set by CMake itself. The default compression level
+    may vary between archive formats, platforms, etc.
+
     .. versionadded:: 3.26
       The ``<compression-level>`` of the ``Zstd`` algorithm can be set
       between 0-19.
 
+    .. versionadded:: 4.3
+      The ``<compression-level>`` can be specified for the ``7zip`` and ``zip``
+      formats too. The ``Zstd`` algorithm compression level can be set
+      between 0-19, except for ``zip`` format.
+
   ``MTIME <mtime>``
     Specify the modification time recorded in tarball entries.
 
+  ``THREADS <number>``
+    .. versionadded:: 4.3
+
+    Use the ``<number>`` threads to operate on the archive.
+
+    The number of available cores on the machine will be used if set to ``0``.
+    Note that not all compression modes support threading in all environments.
+
   ``WORKING_DIRECTORY <dir>``
     .. versionadded:: 3.31
 
@@ -1008,6 +1071,10 @@
   ``VERBOSE``
     Enable verbose output from the extraction operation.
 
+  .. versionchanged:: 4.3
+    Archive entries containing path traversal sequences (``..``), or
+    absolute paths, are rejected for security.
+
   .. note::
     The working directory for this subcommand is the ``DESTINATION`` directory
     (provided or computed) except when ``LIST_ONLY`` is specified. Therefore,
@@ -1121,6 +1188,8 @@
 
   The following arguments specify filters for including or excluding libraries
   to be resolved. See below for a full description of how they work.
+  Directory separators in file paths may be matched using forward
+  slashes unless policy :policy:`CMP0207` is not set to ``NEW``.
 
     ``PRE_INCLUDE_REGEXES <regexes>...``
       List of pre-include regexes through which to filter the names of
diff --git a/Help/command/find_file.rst b/Help/command/find_file.rst
index a1dc5f9..13aae97 100644
--- a/Help/command/find_file.rst
+++ b/Help/command/find_file.rst
@@ -2,7 +2,7 @@
 ---------
 
 .. |FIND_XXX| replace:: find_file
-.. |NAMES| replace:: NAMES name1 [name2 ...]
+.. |NAMES| replace:: NAMES <name>...
 .. |SEARCH_XXX| replace:: full path to a file
 .. |SEARCH_XXX_DESC| replace:: full path to a named file
 .. |prefix_XXX_SUBDIR| replace:: ``<prefix>/include``
diff --git a/Help/command/find_library.rst b/Help/command/find_library.rst
index b150818..54f7a8e 100644
--- a/Help/command/find_library.rst
+++ b/Help/command/find_library.rst
@@ -2,7 +2,7 @@
 ------------
 
 .. |FIND_XXX| replace:: find_library
-.. |NAMES| replace:: NAMES name1 [name2 ...] [NAMES_PER_DIR]
+.. |NAMES| replace:: NAMES <name>... [NAMES_PER_DIR]
 .. |SEARCH_XXX| replace:: library
 .. |SEARCH_XXX_DESC| replace:: library
 .. |prefix_XXX_SUBDIR| replace:: ``<prefix>/lib``
diff --git a/Help/command/find_package.rst b/Help/command/find_package.rst
index 97390f7..d757263 100644
--- a/Help/command/find_package.rst
+++ b/Help/command/find_package.rst
@@ -75,23 +75,25 @@
 .. _`Config mode`:
 
 **Config mode**
-  In this mode, CMake searches for a file called
-  ``<lowercasePackageName>-config.cmake`` or ``<PackageName>Config.cmake``.
-  It will also look for ``<lowercasePackageName>-config-version.cmake`` or
+  In this mode, CMake searches for a file matching any of:
+
+  * ``<PackageName>.cps``
+  * ``<lowercasePackageName>.cps``
+  * ``<lowercasePackageName>-config.cmake``
+  * ``<PackageName>Config.cmake``
+
+  If one of the latter two is found, CMake will also look respectively, for
+  ``<lowercasePackageName>-config-version.cmake`` or
   ``<PackageName>ConfigVersion.cmake`` if version details were specified
   (see :ref:`version selection` for an explanation of how these separate
-  version files are used).
+  version files are used).  The latter two options are CMake-script package
+  descriptions.  The first two are |CPS|_ (CPS) package descriptions, which
+  are more portable and include version information in the 'base' file.  Aside
+  from any explicitly noted exceptions, any references to "config files",
+  "config mode", "package configuration files", and so forth refer equally to
+  both CPS and CMake-script files.
 
   .. note::
-    If the experimental ``CMAKE_EXPERIMENTAL_FIND_CPS_PACKAGES`` is enabled,
-    files named ``<PackageName>.cps`` and ``<lowercasePackageName>.cps`` are
-    also considered.  These files provide package information according to the
-    |CPS|_ (CPS), which is more portable than CMake script.  Aside from any
-    explicitly noted exceptions, any references to "config files", "config
-    mode", "package configuration files", and so forth refer equally to both
-    CPS and CMake-script files.  This functionality is a work in progress, and
-    some features may be missing.
-
     Search is implemented in a manner that will tend to prefer |CPS| files
     over CMake-script config files in most cases.  Specifying ``CONFIGS``
     suppresses consideration of CPS files.
@@ -135,10 +137,10 @@
 
 .. code-block:: cmake
 
-  find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
-               [REQUIRED|OPTIONAL] [[COMPONENTS] [components...]]
-               [OPTIONAL_COMPONENTS components...]
-               [REGISTRY_VIEW  (64|32|64_32|32_64|HOST|TARGET|BOTH)]
+  find_package(<PackageName> [<version>] [EXACT] [QUIET] [MODULE]
+               [REQUIRED|OPTIONAL] [[COMPONENTS] <component>...]
+               [OPTIONAL_COMPONENTS <component>...]
+               [REGISTRY_VIEW {64|32|64_32|32_64|HOST|TARGET|BOTH}]
                [GLOBAL]
                [NO_POLICY_SCOPE]
                [BYPASS_PROVIDER]
@@ -209,7 +211,7 @@
 
 .. _FIND_PACKAGE_VERSION_FORMAT:
 
-The ``[version]`` argument requests a version with which the package found
+The ``<version>`` argument requests a version with which the package found
 should be compatible. There are two possible forms in which it may be
 specified:
 
@@ -234,10 +236,10 @@
 The ``EXACT`` option requests that the version be matched exactly. This option
 is incompatible with the specification of a version range.
 
-If no ``[version]`` and/or component list is given to a recursive invocation
+If no ``<version>`` and/or component list is given to a recursive invocation
 inside a find-module, the corresponding arguments are forwarded
 automatically from the outer call (including the ``EXACT`` flag for
-``[version]``).
+``<version>``).
 
 See the :command:`cmake_policy` command documentation for discussion
 of the ``NO_POLICY_SCOPE`` option.
@@ -273,18 +275,18 @@
 .. code-block:: cmake
 
   find_package(<PackageName> [version] [EXACT] [QUIET]
-               [REQUIRED|OPTIONAL] [[COMPONENTS] [components...]]
-               [OPTIONAL_COMPONENTS components...]
+               [REQUIRED|OPTIONAL] [[COMPONENTS] <component>...]
+               [OPTIONAL_COMPONENTS <component>...]
                [CONFIG|NO_MODULE]
                [GLOBAL]
                [NO_POLICY_SCOPE]
                [BYPASS_PROVIDER]
-               [NAMES name1 [name2 ...]]
-               [CONFIGS config1 [config2 ...]]
-               [HINTS path1 [path2 ...]]
-               [PATHS path1 [path2 ...]]
-               [REGISTRY_VIEW  (64|32|64_32|32_64|HOST|TARGET|BOTH)]
-               [PATH_SUFFIXES suffix1 [suffix2 ...]]
+               [NAMES <name>...]
+               [CONFIGS <config>...]
+               [HINTS <path>...]
+               [PATHS <path>...]
+               [REGISTRY_VIEW {64|32|64_32|32_64|HOST|TARGET|BOTH}]
+               [PATH_SUFFIXES <suffix>...]
                [NO_DEFAULT_PATH]
                [NO_PACKAGE_ROOT_PATH]
                [NO_CMAKE_PATH]
@@ -312,8 +314,14 @@
 also considered when determining whether to redirect the call to a package
 provided by :module:`FetchContent`.
 
-The command searches for a file called ``<PackageName>Config.cmake`` or
-``<lowercasePackageName>-config.cmake`` for each name specified.
+The command searches for a file whose name, for each package name specified,
+matches any of:
+
+* ``<PackageName>Config.cmake``
+* ``<lowercasePackageName>-config.cmake``
+* ``<PackageName>.cps``
+* ``<lowercasePackageName>.cps``
+
 A replacement set of possible configuration file names may be given
 using the ``CONFIGS`` option.  The :ref:`search procedure` is specified below.
 Once found, any :ref:`version constraint <version selection>` is checked,
@@ -324,9 +332,8 @@
 
 .. note::
 
-  If the experimental ``CMAKE_EXPERIMENTAL_FIND_CPS_PACKAGES`` is enabled,
-  files named ``<PackageName>.cps`` and ``<lowercasePackageName>.cps`` are
-  also considered, unless ``CONFIGS`` is given.
+  Because CPS files are not permitted to have names that do *not* match the
+  package name, specifying ``CONFIGS`` will suppress searcing for CPS files.
 
 All configuration files which have been considered by CMake while
 searching for the package with an appropriate version are stored in the
@@ -396,7 +403,7 @@
 
 .. [#p1] .. versionadded:: 3.25
 
-.. [#p2] .. versionadded:: 4.0
+.. [#p2] .. versionadded:: 4.3
 
 On systems supporting macOS :prop_tgt:`FRAMEWORK` and :prop_tgt:`BUNDLE`, the
 following directories are searched for Frameworks or Application Bundles
@@ -416,7 +423,7 @@
  ``<prefix>/<name>.app/Contents/Resources/CMake/``                 A
 =============================================================== ==========
 
-.. [#p3] .. versionadded:: 4.0
+.. [#p3] .. versionadded:: 4.3
 
 When searching the above paths, ``find_package`` will only look for ``.cps``
 files in search paths which contain ``/cps/``, and will only look for
@@ -683,7 +690,7 @@
   regardless of whether the :ref:`full <full signature>` or
   :ref:`basic <basic signature>` signature was given.
 
-When the ``[version]`` argument is given, Config mode will only find a
+When the ``<version>`` argument is given, Config mode will only find a
 version of the package that claims compatibility with the requested
 version (see :ref:`format specification <FIND_PACKAGE_VERSION_FORMAT>`).  If
 the ``EXACT`` option is given, only a version of the package claiming an exact
@@ -980,21 +987,12 @@
 In Module mode the loaded find module is responsible to honor the
 request detailed by these variables; see the find module for details.
 In Config mode ``find_package`` handles ``REQUIRED``, ``QUIET``, and
-``[version]`` options automatically but leaves it to the package
+``<version>`` options automatically but leaves it to the package
 configuration file to handle components in a way that makes sense
 for the package.  The package configuration file may set
 ``<PackageName>_FOUND`` to false to tell ``find_package`` that component
 requirements are not satisfied.
 
-.. _CPS: https://cps-org.github.io/cps/
-.. |CPS| replace:: Common Package Specification
-
-.. _cps-compat_version: https://cps-org.github.io/cps/schema.html#compat-version
-.. |cps-compat_version| replace:: ``compat_version``
-
-.. _cps-version_schema: https://cps-org.github.io/cps/schema.html#version-schema
-.. |cps-version_schema| replace:: ``version_schema``
-
 CPS Transitive Requirements
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -1028,3 +1026,12 @@
 targets.  Those targets must be named ``<PackageName>::<ComponentName>``, in
 conformance with CPS convention, or the check will consider the package not
 found.
+
+.. _CPS: https://cps-org.github.io/cps/
+.. |CPS| replace:: Common Package Specification
+
+.. _cps-compat_version: https://cps-org.github.io/cps/schema.html#compat-version
+.. |cps-compat_version| replace:: ``compat_version``
+
+.. _cps-version_schema: https://cps-org.github.io/cps/schema.html#version-schema
+.. |cps-version_schema| replace:: ``version_schema``
diff --git a/Help/command/find_path.rst b/Help/command/find_path.rst
index ab44e32..7ac9024 100644
--- a/Help/command/find_path.rst
+++ b/Help/command/find_path.rst
@@ -2,7 +2,7 @@
 ---------
 
 .. |FIND_XXX| replace:: find_path
-.. |NAMES| replace:: NAMES name1 [name2 ...]
+.. |NAMES| replace:: NAMES <name>...
 .. |SEARCH_XXX| replace:: file in a directory
 .. |SEARCH_XXX_DESC| replace:: directory containing the named file
 .. |prefix_XXX_SUBDIR| replace:: ``<prefix>/include``
diff --git a/Help/command/find_program.rst b/Help/command/find_program.rst
index bde5289..e314f9e 100644
--- a/Help/command/find_program.rst
+++ b/Help/command/find_program.rst
@@ -2,7 +2,7 @@
 ------------
 
 .. |FIND_XXX| replace:: find_program
-.. |NAMES| replace:: NAMES name1 [name2 ...] [NAMES_PER_DIR]
+.. |NAMES| replace:: NAMES <name>... [NAMES_PER_DIR]
 .. |SEARCH_XXX| replace:: program
 .. |SEARCH_XXX_DESC| replace:: program
 .. |prefix_XXX_SUBDIR| replace:: ``<prefix>/[s]bin``
diff --git a/Help/command/get_filename_component.rst b/Help/command/get_filename_component.rst
index 87ed6bc..2bdad98 100644
--- a/Help/command/get_filename_component.rst
+++ b/Help/command/get_filename_component.rst
@@ -10,9 +10,8 @@
 
 .. versionchanged:: 3.24
   The undocumented feature offering the capability to query the ``Windows``
-  registry is superseded by
-  :ref:`cmake_host_system_information(QUERY WINDOWS_REGISTRY)<Query Windows registry>`
-  command.
+  registry is superseded by the
+  :command:`cmake_host_system_information(QUERY WINDOWS_REGISTRY)` command.
 
 .. code-block:: cmake
 
diff --git a/Help/command/get_property.rst b/Help/command/get_property.rst
index 202bfd9..5ce9e83 100644
--- a/Help/command/get_property.rst
+++ b/Help/command/get_property.rst
@@ -6,16 +6,17 @@
 .. code-block:: cmake
 
   get_property(<variable>
-               <GLOBAL             |
-                DIRECTORY [<dir>]  |
-                TARGET    <target> |
+               <GLOBAL                                                  |
+                DIRECTORY [<dir>]                                       |
+                TARGET    <target>                                      |
+                FILE_SET  <file_set> TARGET <target>                    |
                 SOURCE    <source>
                           [DIRECTORY <dir> | TARGET_DIRECTORY <target>] |
-                INSTALL   <file>   |
+                INSTALL   <file>                                        |
                 TEST      <test>
-                          [DIRECTORY <dir>] |
-                CACHE     <entry>  |
-                VARIABLE           >
+                          [DIRECTORY <dir>]                             |
+                CACHE     <entry>                                       |
+                VARIABLE>
                PROPERTY <name>
                [SET | DEFINED | BRIEF_DOCS | FULL_DOCS])
 
@@ -42,6 +43,16 @@
   Scope must name one existing target.
   See also the :command:`get_target_property` command.
 
+``FILE_SET``
+  .. versionadded:: 4.3
+
+  Scope must name one existing file set.
+
+  The following option is required:
+
+  ``TARGET <target>``
+    The target to which the file set is attached.
+
 ``SOURCE``
   Scope must name one source file.  By default, the source file's property
   will be read from the current source directory's scope.
diff --git a/Help/command/include/DEPRECATED_POLICY_VERSIONS.rst b/Help/command/include/DEPRECATED_POLICY_VERSIONS.rst
index 1b9f0d4..dd4a104 100644
--- a/Help/command/include/DEPRECATED_POLICY_VERSIONS.rst
+++ b/Help/command/include/DEPRECATED_POLICY_VERSIONS.rst
@@ -3,7 +3,7 @@
   Compatibility with versions of CMake older than 3.5 is removed.
   Calls to :command:`cmake_minimum_required(VERSION)` or
   :command:`cmake_policy(VERSION)` that do not specify at least
-  3.5 as their policy version (optionally via ``...<max>``)
+  3.5 as their policy version (optionally via ``...<policy_max>``)
   will produce an error in CMake 4.0 and above.
 
 .. versionchanged:: 3.31
@@ -11,7 +11,7 @@
   Compatibility with versions of CMake older than 3.10 is deprecated.
   Calls to :command:`cmake_minimum_required(VERSION)` or
   :command:`cmake_policy(VERSION)` that do not specify at least
-  3.10 as their policy version (optionally via ``...<max>``)
+  3.10 as their policy version (optionally via ``...<policy_max>``)
   will produce a deprecation warning in CMake 3.31 and above.
 
 .. versionchanged:: 3.27
@@ -19,7 +19,7 @@
   Compatibility with versions of CMake older than 3.5 is deprecated.
   Calls to :command:`cmake_minimum_required(VERSION)` or
   :command:`cmake_policy(VERSION)` that do not specify at least
-  3.5 as their policy version (optionally via ``...<max>``)
+  3.5 as their policy version (optionally via ``...<policy_max>``)
   will produce a deprecation warning in CMake 3.27 and above.
 
 .. versionchanged:: 3.19
@@ -27,5 +27,5 @@
   Compatibility with versions of CMake older than 2.8.12 is deprecated.
   Calls to :command:`cmake_minimum_required(VERSION)` or
   :command:`cmake_policy(VERSION)` that do not specify at least
-  2.8.12 as their policy version (optionally via ``...<max>``)
+  2.8.12 as their policy version (optionally via ``...<policy_max>``)
   will produce a deprecation warning in CMake 3.19 and above.
diff --git a/Help/command/include/FIND_XXX.rst b/Help/command/include/FIND_XXX.rst
index 194b6f8..ce3ed64 100644
--- a/Help/command/include/FIND_XXX.rst
+++ b/Help/command/include/FIND_XXX.rst
@@ -2,7 +2,7 @@
 
 .. parsed-literal::
 
-   |FIND_XXX| (<VAR> name1 [path1 path2 ...])
+   |FIND_XXX| (<VAR> <name> [<path>...])
 
 The general signature is:
 
@@ -10,12 +10,12 @@
 
    |FIND_XXX| (
              <VAR>
-             name | |NAMES|
-             [HINTS [path | ENV var]...]
-             [PATHS [path | ENV var]...]
-             [REGISTRY_VIEW (64|32|64_32|32_64|HOST|TARGET|BOTH)]
-             [PATH_SUFFIXES suffix1 [suffix2 ...]]
-             [VALIDATOR function]
+             {<name> | |NAMES|}
+             [HINTS {<path> | ENV <var>}...]
+             [PATHS {<path> | ENV <var>}...]
+             [REGISTRY_VIEW {64|32|64_32|32_64|HOST|TARGET|BOTH}]
+             [PATH_SUFFIXES <suffix>...]
+             [VALIDATOR <function>]
              [DOC "cache documentation string"]
              [NO_CACHE]
              [REQUIRED|OPTIONAL]
diff --git a/Help/command/include/FIND_XXX_ORDER.rst b/Help/command/include/FIND_XXX_ORDER.rst
index bac2419..6dfae54 100644
--- a/Help/command/include/FIND_XXX_ORDER.rst
+++ b/Help/command/include/FIND_XXX_ORDER.rst
@@ -5,7 +5,7 @@
 
 .. parsed-literal::
 
-   |FIND_XXX| (|FIND_ARGS_XXX| PATHS paths... NO_DEFAULT_PATH)
+   |FIND_XXX| (|FIND_ARGS_XXX| PATHS <paths>... NO_DEFAULT_PATH)
    |FIND_XXX| (|FIND_ARGS_XXX|)
 
 Once one of the calls succeeds the result variable will be set
diff --git a/Help/command/include/POLICY_VERSION.rst b/Help/command/include/POLICY_VERSION.rst
index 424849d..c180dce 100644
--- a/Help/command/include/POLICY_VERSION.rst
+++ b/Help/command/include/POLICY_VERSION.rst
@@ -1,7 +1,7 @@
 This specifies that the current CMake code is written for the given range of
-CMake versions, ``<min>[...<max>]``. It sets the "policy version" to:
+CMake versions, ``<min>[...<policy_max>]``. It sets the "policy version" to:
 
-* the range's ``<max>`` version, if specified, or to
+* the range's ``<policy_max>`` version, if specified, or to
 * the ``<min>`` version, or to
 * the value of the :variable:`CMAKE_POLICY_VERSION_MINIMUM` variable
   if it is higher than the other two versions.
@@ -9,8 +9,12 @@
 The policy version effectively requests behavior preferred as of a given CMake
 version and tells newer CMake versions to warn about their new policies.
 All policies known to the running version of CMake and introduced
-in that version or earlier will be set to use ``NEW`` behavior.
+in the policy version or earlier will be set to use ``NEW`` behavior.
 All policies introduced in later versions will be unset (unless the
 :variable:`CMAKE_POLICY_DEFAULT_CMP<NNNN>` variable sets a default).
-This effectively requests behavior preferred as of a given CMake
-version and tells newer CMake versions to warn about their new policies.
+
+.. note::
+
+  ``...<policy_max>`` does *not* signify that later CMake versions are
+  forbidden.  It merely specifies the highest CMake version for which
+  the project or module has been actively updated and maintained.
diff --git a/Help/command/install.rst b/Help/command/install.rst
index f3c4d2f..f7fcb94 100644
--- a/Help/command/install.rst
+++ b/Help/command/install.rst
@@ -21,6 +21,7 @@
   install(`EXPORT`_ <export-name> [...])
   install(`PACKAGE_INFO`_ <package-name> [...])
   install(`RUNTIME_DEPENDENCY_SET`_ <set-name> [...])
+  install(`SBOM`_ <sbom-name> [...])
 
 Introduction
 ^^^^^^^^^^^^
@@ -497,7 +498,7 @@
              [CONFIGURATIONS <config>...]
              [COMPONENT <component>]
              [OPTIONAL] [EXCLUDE_FROM_ALL]
-            ] [...]
+            ]...
             )
 
   The ``IMPORTED_RUNTIME_ARTIFACTS`` form specifies rules for installing the
@@ -550,7 +551,7 @@
   programs that are not targets, such as shell scripts.  Use the ``TARGETS``
   form to install targets built within the project.
 
-  The list of ``files...`` given to ``FILES`` or ``PROGRAMS`` may use
+  The list of files given to ``FILES`` or ``PROGRAMS`` may use
   "generator expressions" with the syntax ``$<...>``.  See the
   :manual:`cmake-generator-expressions(7)` manual for available expressions.
   However, if any item begins in a generator expression it must evaluate
@@ -791,7 +792,7 @@
       Exclude the matched file or directory from installation.
 
     ``PERMISSIONS <permission>...``
-      Ovrerride the permissions setting for the matched file or directory.
+      Override the permissions setting for the matched file or directory.
 
     For example, the code
 
@@ -818,7 +819,7 @@
 
     install([[SCRIPT <file>] [CODE <code>]]
             [ALL_COMPONENTS | COMPONENT <component>]
-            [EXCLUDE_FROM_ALL] [...])
+            [EXCLUDE_FROM_ALL])
 
   The ``SCRIPT`` form will invoke the given CMake script files during
   installation.  If the script file name is a relative path it will be
@@ -974,12 +975,9 @@
 .. signature::
   install(PACKAGE_INFO <package-name> [...])
 
-  .. versionadded:: 3.31
-  .. note::
+  .. versionadded:: 4.3
 
-    Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
-
-  Installs a |CPS|_ file exporting targets for dependent projects:
+  Installs a |CPS|_ ("CPS") file exporting targets for dependent projects:
 
   .. code-block:: cmake
 
@@ -999,6 +997,7 @@
             [HOMEPAGE_URL <url-string>]
             [PERMISSIONS <permission>...]
             [CONFIGURATIONS <config>...]
+            [CXX_MODULES_DIRECTORY <directory>]
             [COMPONENT <component>]
             [EXCLUDE_FROM_ALL])
 
@@ -1105,6 +1104,20 @@
   use of ``LOWER_CASE_FILE`` should be consistent between the main package and
   any appendices.
 
+  .. note::
+    Because it is intended to be portable across multiple build tools, CPS
+    may not support all features that are allowed in CMake-script exports.  In
+    particular, support for generator expressions in interface properties is
+    limited at this time to configuration-dependent expressions.
+
+  .. note::
+    This is the recommended way to generate |CPS| package information for a
+    project.  For distributors whose users may require CPS package information
+    when making changes to the project's build files is not practical, the
+    :variable:`CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO` variable may be used to
+    generate ``.cps`` files from :command:`install(EXPORT)` calls.  Refer to
+    the variable's documentation for usage and caveats.
+
 .. signature::
   install(RUNTIME_DEPENDENCY_SET <set-name> [...])
 
@@ -1122,7 +1135,7 @@
              [COMPONENT <component>]
              [NAMELINK_COMPONENT <component>]
              [OPTIONAL] [EXCLUDE_FROM_ALL]
-            ] [...]
+            ]...
             [PRE_INCLUDE_REGEXES <regex>...]
             [PRE_EXCLUDE_REGEXES <regex>...]
             [POST_INCLUDE_REGEXES <regex>...]
@@ -1178,6 +1191,92 @@
   :command:`install_files`, and :command:`install_programs` commands
   is not defined.
 
+.. signature::
+  install(SBOM <sbom-name> [...])
+
+  .. versionadded:: 4.3
+  .. note::
+
+    Experimental. Gated by ``CMAKE_EXPERIMENTAL_GENERATE_SBOM``.
+
+  Installs a |SBOM| or "SBOM" which describes the project:
+
+  .. code-block:: cmake
+
+    install(SBOM <sbom-name> EXPORT <export-name>
+            [PROJECT <project-name>|NO_PROJECT_METADATA]
+            [DESTINATION <dir>]
+            [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
+            [LICENSE <license-string>]
+            [DESCRIPTION <description-string>]
+            [HOMEPAGE_URL <url-string>]
+            [PACKAGE_URL <url-string>]
+            [FORMAT <string>])
+
+  The ``SBOM`` form generates a |SBOM| or "SBOM" file for a given project
+  and installs it as part of the project installation.  A |SBOM| is a
+  machine-readable description of the project's targets, linked libraries,
+  and related metadata, such as versions and license information.  CMake
+  currently generates SBOM files using the |SPDX|_ 3.0 specification in
+  its JSON-LD representation, as selected by the ``FORMAT`` option, but
+  the interface is designed to allow additional SBOM formats or schema
+  versions to be supported in future CMake releases.
+
+  Target installations are associated with the export ``<export-name>``
+  using the ``EXPORT`` option of the :command:`install(TARGETS)` signature
+  documented above. If ``DESTINATION`` is not specified, a platform-specific
+  default is used.
+
+  Several options may be used to specify package metadata:
+
+  ``VERSION <version>``
+    The package version, specified as a series of non-negative  integer components,
+    i.e. <major>[.<minor>[.<patch>[.<tweak>]]].  See :command:`project(VERSION)` for
+    more information.
+
+  ``FORMAT <string>``
+    The format in which the SBOM should be exported, which must be an expression of
+    the form ``<format>[-<version>][+<representation>]``.  CMake currently supports
+    the JSON-LD serialization of |SPDX|_ v3.0.1 (``spdx`` or ``spdx-3.0.1+json``),
+    which is also the default if ``FORMAT`` is not specified.
+
+  ``HOMEPAGE_URL <url-string>``
+
+    An informational canonical home URL for the project.
+
+  ``PACKAGE_URL <url-string>``
+
+    An informational canonical package URL for the project.
+
+  ``LICENSE <license-string>``
+
+    A |SPDX|_ (SPDX) `License Expression`_ that describes the license(s) of the
+    project as a whole, including documentation, resources, or other materials
+    distributed with the project, in addition to software artifacts.  See the
+    SPDX `License List`_ for a list of commonly used licenses and their
+    identifiers.
+
+    The license of individual components is taken from the
+    :prop_tgt:`SPDX_LICENSE` property of their respective targets.
+
+  ``DESCRIPTION <description-string>``
+
+    An informational description of the project.  It is recommended that this
+    description is a relatively short string, usually no more than a few words.
+
+  By default, if the specified ``<sbom-name>`` matches the current CMake
+  :variable:`PROJECT_NAME`, sbom metadata will be inherited from the
+  project.  The ``PROJECT <project-name>`` option may be used to specify a
+  different project from which to inherit metadata.  If ``NO_PROJECT_METADATA``
+  is specified, automatic inheritance of sbom metadata will be disabled.
+  In any case, any metadata values specified in the ``install`` command will
+  take precedence.
+
+  Note that an SBOM file cannot be generated for targets with generator
+  expressions contained in their :prop_tgt:`LINK_LIBRARIES` or
+  :prop_tgt:`INTERFACE_LINK_LIBRARIES` properties, unless the generator
+  expressions are guarded by :genex:`LINK_ONLY`.
+
 Examples
 ^^^^^^^^
 
@@ -1309,3 +1408,5 @@
 
 .. _License Expression: https://spdx.github.io/spdx-spec/v3.0.1/annexes/spdx-license-expressions/
 .. _License List: https://spdx.org/licenses/
+
+.. |SBOM| replace:: Software Bill of Material
diff --git a/Help/command/macro.rst b/Help/command/macro.rst
index 978f7d6..3faa3db 100644
--- a/Help/command/macro.rst
+++ b/Help/command/macro.rst
@@ -55,9 +55,10 @@
 Arguments
 ^^^^^^^^^
 
-When a macro is invoked, the commands recorded in the macro are
-first modified by replacing formal parameters (``${arg1}``, ...)
-with the arguments passed, and then invoked as normal commands.
+When a macro is invoked, first all commands recorded in the macro are
+modified by replacing formal parameters (``${arg1}``, ...)
+with the arguments passed. Then all modified commands are invoked as
+normal commands.
 
 In addition to referencing the formal parameters you can reference the
 values ``${ARGC}`` which will be set to the number of arguments passed
diff --git a/Help/command/project.rst b/Help/command/project.rst
index a77e0b1..ad4f32e 100644
--- a/Help/command/project.rst
+++ b/Help/command/project.rst
@@ -89,10 +89,7 @@
     :variable:`CMAKE_PROJECT_VERSION`.
 
 ``COMPAT_VERSION <version>``
-  .. versionadded:: 4.1
-  .. note::
-
-    Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+  .. versionadded:: 4.3
 
   Optional; requires ``VERSION`` also be set.
 
@@ -101,17 +98,14 @@
   and sets the variables
 
   * :variable:`PROJECT_COMPAT_VERSION`,
-    :variable:`<PROJECT-NAME>_COMPAT_VERSION`
+    :variable:`<PROJECT-NAME>_COMPAT_VERSION`.
 
-    When the ``project()`` command is called from the top-level
-    ``CMakeLists.txt``, then the compatibility version is also stored in the
-    variable :variable:`CMAKE_PROJECT_COMPAT_VERSION`.
+  When the ``project()`` command is called from the top-level
+  ``CMakeLists.txt``, then the compatibility version is also stored in the
+  variable :variable:`CMAKE_PROJECT_COMPAT_VERSION`.
 
 ``SPDX_LICENSE <license-string>``
-  .. versionadded:: 4.2
-  .. note::
-
-    Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+  .. versionadded:: 4.3
 
   Optional.
   Sets the variables
diff --git a/Help/command/remove_definitions.rst b/Help/command/remove_definitions.rst
index faad16d..74730e5 100644
--- a/Help/command/remove_definitions.rst
+++ b/Help/command/remove_definitions.rst
@@ -1,11 +1,32 @@
 remove_definitions
 ------------------
 
-Remove -D define flags added by :command:`add_definitions`.
+Removes compile definitions added by :command:`add_compile_definitions`, or
+:command:`add_definitions`:
 
 .. code-block:: cmake
 
-  remove_definitions(-DFOO -DBAR ...)
+  remove_definitions([<definitions>...])
 
-Removes flags (added by :command:`add_definitions`) from the compiler
-command line for sources in the current directory and below.
+The arguments are:
+
+``<definitions>...``
+  Zero or more compile definitions.
+
+This command can be also used to remove any flags added by
+:command:`add_definitions`, but it is intended to remove preprocessor
+definitions passed with ``-D``, or ``/D``.
+
+Examples
+^^^^^^^^
+
+In the following example targets of the current directory scope will have
+only ``BAZ`` and ``QUUX`` compile definitions:
+
+.. code-block:: cmake
+
+  add_compile_definitions(FOO BAR BAZ -DQUUX)
+
+  # ...
+
+  remove_definitions(-DFOO -DBAR)
diff --git a/Help/command/set_property.rst b/Help/command/set_property.rst
index f14b63d..e560f18 100644
--- a/Help/command/set_property.rst
+++ b/Help/command/set_property.rst
@@ -5,18 +5,19 @@
 
 .. code-block:: cmake
 
-  set_property(<GLOBAL                      |
-                DIRECTORY [<dir>]           |
-                TARGET    [<target1> ...]   |
-                SOURCE    [<src1> ...]
+  set_property({GLOBAL                                    |
+                DIRECTORY [<dir>]                         |
+                TARGET    <target>...                     |
+                FILE_SET  <file_set>... TARGET <target>   |
+                SOURCE    <source>...
                           [DIRECTORY <dirs> ...]
-                          [TARGET_DIRECTORY <targets> ...] |
-                INSTALL   [<file1> ...]     |
-                TEST      [<test1> ...]
-                          [DIRECTORY <dir>] |
-                CACHE     [<entry1> ...]    >
+                          [TARGET_DIRECTORY <targets>...] |
+                INSTALL   <file>...                       |
+                TEST      <test>...
+                          [DIRECTORY <dir>]               |
+                CACHE     <entry>...}
                [APPEND] [APPEND_STRING]
-               PROPERTY <name> [<value1> ...])
+               PROPERTY <name> [<value>...])
 
 Sets one property on zero or more objects of a scope.
 
@@ -41,6 +42,16 @@
 
   :ref:`Alias Targets` do not support setting target properties.
 
+``FILE_SET``
+  .. versionadded:: 4.3
+
+  Scope may name zero or more existing file sets.
+
+  The following option is required:
+
+  ``TARGET <target>``
+    The target to which the file set is attached.
+
 ``SOURCE``
   Scope may name zero or more source files.  By default, source file properties
   are only visible to targets added in the same directory (``CMakeLists.txt``).
diff --git a/Help/command/source_group.rst b/Help/command/source_group.rst
index 83ae286..130beca 100644
--- a/Help/command/source_group.rst
+++ b/Help/command/source_group.rst
@@ -36,6 +36,10 @@
  ``<name>``.  Relative paths are interpreted with respect to the
  current source directory.
 
+ .. versionadded:: 4.3
+   Arguments to ``FILES`` may use
+   :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
 ``REGULAR_EXPRESSION``
  Any source file whose name matches the regular expression will
  be placed in group ``<name>``.
diff --git a/Help/command/string.rst b/Help/command/string.rst
index ae138e8..b7ed69a 100644
--- a/Help/command/string.rst
+++ b/Help/command/string.rst
@@ -46,7 +46,10 @@
 
   `JSON`_
     string(JSON <out-var> [ERROR_VARIABLE <error-var>]
-           {`GET <JSON-GET_>`__ | `TYPE <JSON-TYPE_>`__ | `LENGTH <JSON-LENGTH_>`__ | `REMOVE <JSON-REMOVE_>`__}
+           {`GET <JSON-GET_>`__ | `GET_RAW <JSON-GET-RAW_>`__ | `TYPE <JSON-TYPE_>`__ | `LENGTH <JSON-LENGTH_>`__}
+           <json-string> [<member|index> ...])
+    string(JSON <out-var> [ERROR_VARIABLE <error-var>]
+           `REMOVE <JSON-REMOVE_>`__
            <json-string> <member|index> [<member|index> ...])
     string(JSON <out-var> [ERROR_VARIABLE <error-var>]
            `MEMBER <JSON-MEMBER_>`__ <json-string>
@@ -56,6 +59,8 @@
            <member|index> [<member|index> ...] <value>)
     string(JSON <out-var> [ERROR_VARIABLE <error-var>]
            `EQUAL <JSON-EQUAL_>`__ <json-string1> <json-string2>)
+    string(JSON <out-var> [ERROR_VARIABLE <error-var>]
+           `STRING_ENCODE <STRING-ENCODE_>`__ <string>)
 
 Search and Replace
 ^^^^^^^^^^^^^^^^^^
@@ -549,7 +554,7 @@
 
 .. signature::
   string(JSON <out-var> [ERROR_VARIABLE <error-variable>]
-         GET <json-string> <member|index> [<member|index> ...])
+         GET <json-string> [<member|index> ...])
   :target: JSON-GET
 
   Get an element from ``<json-string>`` at the location given
@@ -561,7 +566,19 @@
 
 .. signature::
   string(JSON <out-var> [ERROR_VARIABLE <error-variable>]
-         TYPE <json-string> <member|index> [<member|index> ...])
+         GET_RAW <json-string> [<member|index> ...])
+  :target: JSON-GET-RAW
+
+  .. versionadded:: 4.3
+
+  Get an element from ``<json-string>`` at the location given
+  by the list of ``<member|index>`` arguments. Similar to
+  :cref:`GET <JSON-GET_>`, but does not convert number, string,
+  boolean, or null elements.
+
+.. signature::
+  string(JSON <out-var> [ERROR_VARIABLE <error-variable>]
+         TYPE <json-string> [<member|index> ...])
   :target: JSON-TYPE
 
   Get the type of an element in ``<json-string>`` at the location
@@ -619,3 +636,13 @@
   and ``<json-string2>`` should be valid JSON.  The ``<out-var>``
   will be set to a true value if the JSON objects are considered equal,
   or a false value otherwise.
+
+.. signature::
+  string(JSON <out-var> [ERROR_VARIABLE <error-var>]
+         STRING_ENCODE <string>)
+  :target: STRING-ENCODE
+
+  .. versionadded:: 4.3
+
+  Turn a raw string into a JSON string surrounded by quotes. Special characters
+  will be properly escaped inside the JSON string.
diff --git a/Help/command/target_compile_definitions.rst b/Help/command/target_compile_definitions.rst
index 61cfb19..cb2629e 100644
--- a/Help/command/target_compile_definitions.rst
+++ b/Help/command/target_compile_definitions.rst
@@ -6,8 +6,8 @@
 .. code-block:: cmake
 
   target_compile_definitions(<target>
-    <INTERFACE|PUBLIC|PRIVATE> [items1...]
-    [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
+    <INTERFACE|PUBLIC|PRIVATE> <definition>...
+    [<INTERFACE|PUBLIC|PRIVATE> <definition>... ...])
 
 Specifies compile definitions to use when compiling a given ``<target>``.  The
 named ``<target>`` must have been created by a command such as
diff --git a/Help/command/target_compile_features.rst b/Help/command/target_compile_features.rst
index 2d569e9..f63a56c 100644
--- a/Help/command/target_compile_features.rst
+++ b/Help/command/target_compile_features.rst
@@ -7,7 +7,9 @@
 
 .. code-block:: cmake
 
-  target_compile_features(<target> <PRIVATE|PUBLIC|INTERFACE> <feature> [...])
+  target_compile_features(<target>
+    {INTERFACE|PUBLIC|PRIVATE} <feature>...
+    [{INTERFACE|PUBLIC|PRIVATE} <feature>...]...)
 
 Specifies compiler features required when compiling a given target.  If the
 feature is not listed in the :variable:`CMAKE_C_COMPILE_FEATURES`,
diff --git a/Help/command/target_compile_options.rst b/Help/command/target_compile_options.rst
index 6fb86cd..a16e55b 100644
--- a/Help/command/target_compile_options.rst
+++ b/Help/command/target_compile_options.rst
@@ -6,8 +6,8 @@
 .. code-block:: cmake
 
   target_compile_options(<target> [BEFORE]
-    <INTERFACE|PUBLIC|PRIVATE> [items1...]
-    [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
+    {INTERFACE|PUBLIC|PRIVATE} <item>...
+    [{INTERFACE|PUBLIC|PRIVATE} <item>...]...)
 
 Adds options to the :prop_tgt:`COMPILE_OPTIONS` or
 :prop_tgt:`INTERFACE_COMPILE_OPTIONS` target properties. These options
diff --git a/Help/command/target_include_directories.rst b/Help/command/target_include_directories.rst
index 38bf581..59d0cd5 100644
--- a/Help/command/target_include_directories.rst
+++ b/Help/command/target_include_directories.rst
@@ -6,8 +6,8 @@
 .. code-block:: cmake
 
   target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
-    <INTERFACE|PUBLIC|PRIVATE> [items1...]
-    [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
+    {INTERFACE|PUBLIC|PRIVATE} <dir...
+    [{INTERFACE|PUBLIC|PRIVATE} <dir>...]...)
 
 Specifies include directories to use when compiling a given target.
 The named ``<target>`` must have been created by a command such
diff --git a/Help/command/target_link_directories.rst b/Help/command/target_link_directories.rst
index af7a506..91c1feb 100644
--- a/Help/command/target_link_directories.rst
+++ b/Help/command/target_link_directories.rst
@@ -8,8 +8,8 @@
 .. code-block:: cmake
 
   target_link_directories(<target> [BEFORE]
-    <INTERFACE|PUBLIC|PRIVATE> [items1...]
-    [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
+    {INTERFACE|PUBLIC|PRIVATE} <dir>...
+    [{INTERFACE|PUBLIC|PRIVATE} <dir>...]...)
 
 Specifies the paths in which the linker should search for libraries when
 linking a given target.  Each item can be an absolute or relative path,
diff --git a/Help/command/target_link_libraries.rst b/Help/command/target_link_libraries.rst
index a8ba92c..4d964f4 100644
--- a/Help/command/target_link_libraries.rst
+++ b/Help/command/target_link_libraries.rst
@@ -158,8 +158,8 @@
 .. code-block:: cmake
 
   target_link_libraries(<target>
-                        <PRIVATE|PUBLIC|INTERFACE> <item>...
-                       [<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
+    {INTERFACE|PUBLIC|PRIVATE} <item>...
+    [{INTERFACE|PUBLIC|PRIVATE} <item>...]...)
 
 The ``PUBLIC``, ``PRIVATE`` and ``INTERFACE``
 :ref:`scope <Target Command Scope>` keywords can be used to
diff --git a/Help/command/target_link_options.rst b/Help/command/target_link_options.rst
index cbbd720..9e55e9d 100644
--- a/Help/command/target_link_options.rst
+++ b/Help/command/target_link_options.rst
@@ -9,8 +9,8 @@
 .. code-block:: cmake
 
   target_link_options(<target> [BEFORE]
-    <INTERFACE|PUBLIC|PRIVATE> [items1...]
-    [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
+    {INTERFACE|PUBLIC|PRIVATE} <item>...
+    [{INTERFACE|PUBLIC|PRIVATE} <item>...]...)
 
 The named ``<target>`` must have been created by a command such as
 :command:`add_executable` or :command:`add_library` and must not be an
@@ -67,5 +67,10 @@
   add language-wide flags passed to all invocations of the compiler.
   This includes invocations that drive compiling and those that drive linking.
 
+* .. versionadded:: 4.3
+    :variable:`CMAKE_<LANG>_LINK_FLAGS` and
+    :variable:`CMAKE_<LANG>_LINK_FLAGS_<CONFIG>` add language-wide flags passed
+    to all invocations of the compiler which drive linking.
+
 * The :module:`CheckLinkerFlag` module to check whether a linker flag is
   supported by the compiler.
diff --git a/Help/command/target_precompile_headers.rst b/Help/command/target_precompile_headers.rst
index acd83a8..7089582 100644
--- a/Help/command/target_precompile_headers.rst
+++ b/Help/command/target_precompile_headers.rst
@@ -15,8 +15,8 @@
 .. code-block:: cmake
 
   target_precompile_headers(<target>
-    <INTERFACE|PUBLIC|PRIVATE> [header1...]
-    [<INTERFACE|PUBLIC|PRIVATE> [header2...] ...])
+    {INTERFACE|PUBLIC|PRIVATE} <header>...
+    [{INTERFACE|PUBLIC|PRIVATE} <header>...]...)
 
 The command adds header files to the :prop_tgt:`PRECOMPILE_HEADERS` and/or
 :prop_tgt:`INTERFACE_PRECOMPILE_HEADERS` target properties of ``<target>``.
diff --git a/Help/command/target_sources.rst b/Help/command/target_sources.rst
index 0d31f8c..5fa4ef1 100644
--- a/Help/command/target_sources.rst
+++ b/Help/command/target_sources.rst
@@ -8,8 +8,8 @@
 .. code-block:: cmake
 
   target_sources(<target>
-    <INTERFACE|PUBLIC|PRIVATE> [items1...]
-    [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
+    {INTERFACE|PUBLIC|PRIVATE} <source>...
+    [{INTERFACE|PUBLIC|PRIVATE} <source>...]...)
 
 Specifies sources to use when building a target and/or its dependents.
 The named ``<target>`` must have been created by a command such as
@@ -70,7 +70,7 @@
 .. code-block:: cmake
 
   target_sources(<target>
-    [<INTERFACE|PUBLIC|PRIVATE>
+    [{INTERFACE|PUBLIC|PRIVATE}
      [FILE_SET <set> [TYPE <type>] [BASE_DIRS <dirs>...] [FILES <files>...]]...
     ]...)
 
diff --git a/Help/command/try_compile.rst b/Help/command/try_compile.rst
index 181e850..dc6ec44 100644
--- a/Help/command/try_compile.rst
+++ b/Help/command/try_compile.rst
@@ -71,10 +71,10 @@
 
   try_compile(<compileResultVar>
               [SOURCES_TYPE <type>]
-              <SOURCES <srcfile...>                 |
+              {SOURCES <srcfile>...                 |
                SOURCE_FROM_CONTENT <name> <content> |
                SOURCE_FROM_VAR <name> <var>         |
-               SOURCE_FROM_FILE <name> <path>       >...
+               SOURCE_FROM_FILE <name> <path>       }...
               [LOG_DESCRIPTION <text>]
               [NO_CACHE]
               [NO_LOG]
@@ -130,7 +130,7 @@
 
 .. code-block:: cmake
 
-  try_compile(<compileResultVar> <bindir> <srcfile|SOURCES srcfile...>
+  try_compile(<compileResultVar> <bindir> {<srcfile>|SOURCES <srcfile>...}
               [CMAKE_FLAGS <flags>...]
               [COMPILE_DEFINITIONS <defs>...]
               [LINK_OPTIONS <options>...]
@@ -320,8 +320,12 @@
 
   * :variable:`CMAKE_CUDA_RUNTIME_LIBRARY`
   * :variable:`CMAKE_ENABLE_EXPORTS`
+  * :variable:`CMAKE_EXECUTABLE_ENABLE_EXPORTS`
+  * :variable:`CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS`
   * :variable:`CMAKE_EXE_LINKER_FLAGS`, unless using CMake versions
     prior to 4.0 without policy :policy:`CMP0056` set to ``NEW``
+  * :variable:`CMAKE_<LANG>_LINK_FLAGS`, unless using CMake versions
+    prior to 4.3 without policy :policy:`CMP0210` set to ``NEW``
   * :variable:`CMAKE_LINK_SEARCH_START_STATIC`
   * :variable:`CMAKE_LINK_SEARCH_END_STATIC`
   * :variable:`CMAKE_MSVC_RUNTIME_LIBRARY`
@@ -350,10 +354,7 @@
 * :policy:`CMP0157`
 * :policy:`CMP0181`
 * :policy:`CMP0184`
-
-.. versionadded:: 4.0
-  The current setting of :policy:`CMP0181` policy is propagated through to the
-  generated test project.
+* :policy:`CMP0210`
 
 Set variable :variable:`CMAKE_TRY_COMPILE_CONFIGURATION` to choose a build
 configuration:
@@ -423,6 +424,11 @@
   :variable:`CMAKE_MSVC_RUNTIME_CHECKS` to specify the enabled MSVC runtime
   checks.
 
+.. versionadded:: 4.3
+  If :policy:`CMP0210` is set to ``NEW``, :variable:`CMAKE_<LANG>_LINK_FLAGS`
+  and :variable:`CMAKE_<LANG>_LINK_FLAGS_<CONFIG>` are propagated into the
+  test project's build configuration.
+
 See Also
 ^^^^^^^^
 
diff --git a/Help/command/try_run.rst b/Help/command/try_run.rst
index 7973e1b..2cae17b 100644
--- a/Help/command/try_run.rst
+++ b/Help/command/try_run.rst
@@ -14,10 +14,10 @@
 
   try_run(<runResultVar> <compileResultVar>
           [SOURCES_TYPE <type>]
-          <SOURCES <srcfile...>                 |
+          {SOURCES <srcfile>...                 |
            SOURCE_FROM_CONTENT <name> <content> |
            SOURCE_FROM_VAR <name> <var>         |
-           SOURCE_FROM_FILE <name> <path>       >...
+           SOURCE_FROM_FILE <name> <path>       }...
           [LOG_DESCRIPTION <text>]
           [NO_CACHE]
           [NO_LOG]
@@ -63,7 +63,7 @@
 .. code-block:: cmake
 
   try_run(<runResultVar> <compileResultVar>
-          <bindir> <srcfile|SOURCES srcfile...>
+          <bindir> {<srcfile>|SOURCES <srcfile>...}
           [CMAKE_FLAGS <flags>...]
           [COMPILE_DEFINITIONS <defs>...]
           [LINK_OPTIONS <options>...]
diff --git a/Help/cpack_gen/archive.rst b/Help/cpack_gen/archive.rst
index 81da98b..21e67ce 100644
--- a/Help/cpack_gen/archive.rst
+++ b/Help/cpack_gen/archive.rst
@@ -4,29 +4,85 @@
 CPack generator for packaging files into an archive, which can have
 any of the following formats:
 
-- 7Z - 7zip - (``.7z``)
+- 7Z - 7zip - (``.7z``) - LZMA compressed
 
   .. versionadded:: 3.1
 
-- TAR (``.tar``)
+  This is an alias for ``7Z_LZMA``
+
+- 7Z_BZ2 - 7zip - (``.7z``) - BZip2 compressed
+
+  .. versionadded:: 4.3
+
+- 7Z_DEFLATE - 7zip - (``.7z``) - Deflate compressed
+
+  .. versionadded:: 4.3
+
+- 7Z_LZMA - 7zip - (``.7z``) - LZMA compressed
+
+  .. versionadded:: 4.3
+
+- 7Z_LZMA2 - 7zip - (``.7z``) - LZMA2 compressed
+
+  .. versionadded:: 4.3
+
+- 7Z_PPMD - 7zip - (``.7z``) - PPMd compressed
+
+  .. versionadded:: 4.3
+
+- 7Z_STORE - 7zip - (``.7z``) - no compression is used
+
+  .. versionadded:: 4.3
+
+- 7Z_ZSTD - 7zip - (``.7z``) - Zstandard compressed
+
+  .. versionadded:: 4.3
+
+- TAR (``.tar``) - no compression is used
 
   .. versionadded:: 4.0
 
-- TBZ2 (``.tar.bz2``)
+- TBZ2 (``.tar.bz2``) - BZip2 compressed
 
-- TGZ (``.tar.gz``)
+- TGZ (``.tar.gz``) - Deflate compressed
 
-- TXZ (``.tar.xz``)
+- TXZ (``.tar.xz``) - LZMA2 compressed
 
   .. versionadded:: 3.1
 
-- TZ (``.tar.Z``)
+- TZ (``.tar.Z``) - LZW compressed
 
-- TZST (``.tar.zst``)
+- TZST (``.tar.zst``) - Zstandard compressed
 
   .. versionadded:: 3.16
 
-- ZIP (``.zip``)
+- ZIP (``.zip``) - Deflate compressed
+
+  This is an alias for ``ZIP_DEFLATE``
+
+- ZIP_BZ2 (``.zip``) - BZip2 compressed
+
+  .. versionadded:: 4.3
+
+- ZIP_DEFLATE (``.zip``) - Deflate compressed
+
+  .. versionadded:: 4.3
+
+- ZIP_LZMA (``.zip``) - LZMA compressed
+
+  .. versionadded:: 4.3
+
+- ZIP_LZMA2 (``.zip``) - LZMA2 compressed
+
+  .. versionadded:: 4.3
+
+- ZIP_STORE (``.zip``) - no compression is used
+
+  .. versionadded:: 4.3
+
+- ZIP_ZSTD (``.zip``) - Zstandard compressed
+
+  .. versionadded:: 4.3
 
 When this generator is called from ``CPackSourceConfig.cmake`` (or through
 the ``package_source`` target), then the generated archive will contain all
@@ -100,6 +156,24 @@
   If enabled (``ON``) multiple packages are generated. By default a single package
   containing files of all components is generated.
 
+.. variable:: CPACK_ARCHIVE_UID
+
+  .. versionadded: 4.3
+
+  Set the UID of entries contained in the archive.
+  Specify ``-1`` to use the UID of the current user.
+
+  :Default: ``0`` (see policy :policy:`CMP0206`)
+
+.. variable:: CPACK_ARCHIVE_GID
+
+  .. versionadded: 4.3
+
+  Set the GID of entries contained in the archive.
+  Specify ``-1`` to use the GID of the current user.
+
+  :Default: ``0`` (see policy :policy:`CMP0206`)
+
 Variables used by CPack Archive generator
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -125,3 +199,21 @@
     Official CMake binaries available on ``cmake.org`` now ship
     with a ``liblzma`` that supports parallel compression.
     Older versions did not.
+
+.. variable:: CPACK_ARCHIVE_COMPRESSION_LEVEL
+
+  .. versionadded:: 4.3
+
+  The compression level to use when compressing the archive.
+
+  :Default: value of :variable:`CPACK_COMPRESSION_LEVEL`
+
+  The compression level should be between ``0`` and ``9``.
+
+  The compression level of the Zstandard-based algorithm can be set
+  between ``0`` and ``19``, except for the ``ZIP_ZSTD`` mode.
+
+  The value ``0`` is used to specify the default compression level.
+  It is selected automatically by the archive library backend and
+  not directly set by CMake itself. The default compression level
+  may vary between archive formats, platforms, etc.
diff --git a/Help/cpack_gen/deb.rst b/Help/cpack_gen/deb.rst
index ce7a3e8..d738804 100644
--- a/Help/cpack_gen/deb.rst
+++ b/Help/cpack_gen/deb.rst
@@ -293,19 +293,50 @@
     Lempel–Ziv–Markov chain algorithm
 
   ``xz``
-    XZ Utils compression
+    XZ Utils LZMA2 (Lempel–Ziv–Markov chain algorithm, version 2) compression
 
   ``bzip2``
     bzip2 Burrows–Wheeler algorithm
 
   ``gzip``
-    GNU Gzip compression
+    GNU Gzip Deflate compression
 
   ``zstd``
     .. versionadded:: 3.22
 
     Zstandard compression
 
+.. variable:: CPACK_DEBIAN_COMPRESSION_LEVEL
+
+ .. versionadded:: 4.3
+
+ The compression level used for creating the Debian package.
+
+ :Mandatory: No
+ :Default: value of :variable:`CPACK_COMPRESSION_LEVEL`
+
+ This variable allows fine-tuning of the compression ratio and speed for the
+ Debian package archive. It controls the numeric compression level passed to
+ the compressor defined by :variable:`CPACK_DEBIAN_COMPRESSION_TYPE`.
+ If ``CPACK_DEBIAN_COMPRESSION_LEVEL`` is not set, or is set to ``0``,
+ the default value will be used.
+
+ 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
+
+ Example usage:
+
+ .. code-block:: cmake
+
+   set(CPACK_DEBIAN_COMPRESSION_TYPE "xz")
+   set(CPACK_DEBIAN_COMPRESSION_LEVEL 9)
+
+   include(CPack)
 
 .. variable:: CPACK_DEBIAN_PACKAGE_PRIORITY
               CPACK_DEBIAN_<COMPONENT>_PACKAGE_PRIORITY
diff --git a/Help/cpack_gen/ifw.rst b/Help/cpack_gen/ifw.rst
index 9687281..e22aa91 100644
--- a/Help/cpack_gen/ifw.rst
+++ b/Help/cpack_gen/ifw.rst
@@ -469,7 +469,7 @@
 The ``DOWNLOADED`` option in the :command:`cpack_add_component` command
 specifies that a component is to be downloaded. Alternatively, the ``ALL``
 option in the :command:`cpack_configure_downloads` command specifies that
-``all`` components are to be be downloaded.
+``all`` components are to be downloaded.
 
 The :command:`cpack_ifw_add_repository` command and the
 :variable:`CPACK_IFW_DOWNLOAD_ALL` variable allow for more specific
diff --git a/Help/cpack_gen/rpm.rst b/Help/cpack_gen/rpm.rst
index 3583765..b25b822 100644
--- a/Help/cpack_gen/rpm.rst
+++ b/Help/cpack_gen/rpm.rst
@@ -255,13 +255,13 @@
     Lempel–Ziv–Markov chain algorithm
 
   ``xz``
-    XZ Utils compression
+    XZ Utils LZMA2 (Lempel–Ziv–Markov chain algorithm, version 2) compression
 
   ``bzip2``
     bzip2 Burrows–Wheeler algorithm
 
   ``gzip``
-    GNU Gzip compression
+    GNU Gzip Deflate compression
 
   ``zstd``
     .. versionadded:: 3.31
diff --git a/Help/cpack_gen/wix.rst b/Help/cpack_gen/wix.rst
index fce5c38..738ee7c 100644
--- a/Help/cpack_gen/wix.rst
+++ b/Help/cpack_gen/wix.rst
@@ -408,8 +408,9 @@
  In 32-bit builds the token will expand empty while in 64-bit builds
  it will expand to ``64``.
 
- When unset generated installers will default installing to
- ``ProgramFiles<64>Folder``.
+ When unset generated installers will install to
+ ``LocalAppDataFolder`` if :variable:`CPACK_WIX_INSTALL_SCOPE` is ``perUser``,
+ and to ``ProgramFiles<64>Folder`` otherwise.
 
 .. variable:: CPACK_WIX_ROOT
 
@@ -451,7 +452,7 @@
  .. versionadded:: 3.29
 
  This variable can be optionally set to specify the ``InstallScope``
- of the installer:
+ of the installer (see https://docs.firegiant.com/wix3/xsd/wix/package/):
 
  ``perMachine``
    Create an installer that installs for all users and requires
@@ -461,7 +462,20 @@
    This is the default.  See policy :policy:`CMP0172`.
 
  ``perUser``
-   Not yet supported. This is reserved for future use.
+   Create an installer that installs only for the current user
+   and does not require administrative privileges. Start menu entries created
+   by the installer are visible only to the current user.
+
+   To enable per-user installation, the installer has to generate some
+   additional registry entries to serve as "key paths" for installed
+   components (see https://learn.microsoft.com/en-us/windows/win32/msi/ice38).
+   These registry entries are created under ``HKEY_CURRENT_USER``, using the
+   path specified by the :variable:`CPACK_WIX_COMPONENT_KEYS_REGISTRY_PATH`
+   variable.
+
+   .. versionchanged:: 4.3
+
+     Before CMake 4.3, this value was reserved for future use and not supported.
 
  ``NONE``
    Create an installer without any ``InstallScope`` attribute.
@@ -477,16 +491,30 @@
      but the start menu entry and uninstaller registration are created only
      for the current user.
 
-   .. warning::
+ .. warning::
+   Installations performed by installers created with different
+   ``InstallScope`` values cannot be cleanly updated or replaced by each other.
+   For example, to transition a project's installers from ``NONE`` to
+   ``perMachine``, or from ``perMachine`` to ``perUser``, the latter installer
+   should be distributed with instructions to first manually uninstall
+   any older version.
 
-     An installation performed by an installer created without any
-     ``InstallScope`` cannot be cleanly updated or replaced by an
-     installer with an ``InstallScope``.  In order to transition
-     a project's installers from ``NONE`` to ``perMachine``, the
-     latter installer should be distributed with instructions to
-     first manually uninstall any older version.
+.. variable:: CPACK_WIX_COMPONENT_KEYS_REGISTRY_PATH
 
- See https://docs.firegiant.com/wix3/xsd/wix/package/
+ .. versionadded:: 4.3
+
+ This variable determines the registry path under ``HKEY_CURRENT_USER``
+ where the installer will create registry entries to serve as "key paths"
+ for components if :variable:`CPACK_WIX_INSTALL_SCOPE` is set to ``perUser``.
+
+ Use forward slashes (``/``) as path separators to avoid issues with escapes;
+ they will be converted to backslashes (``\``) by the WIX generator.
+
+ Default value is ``Software/<Vendor>/<PackageName>/Components``,
+ where ``<Vendor>`` is taken from :variable:`CPACK_PACKAGE_VENDOR`,
+ and ``<PackageName>`` is taken from :variable:`CPACK_PACKAGE_NAME`.
+
+ Example: ``Software/MyCompany/MyProduct/Components``
 
 .. variable:: CPACK_WIX_CAB_PER_COMPONENT
 
diff --git a/Help/dev/experimental.rst b/Help/dev/experimental.rst
index 0c0e618..3d52871 100644
--- a/Help/dev/experimental.rst
+++ b/Help/dev/experimental.rst
@@ -39,40 +39,25 @@
   using the ``CMAKE_EXPORT_FIND_PACKAGE_NAME`` variable and/or
 ``EXPORT_FIND_PACKAGE_NAME`` target property.
 
-Export |CPS| Package Information
-================================
+Export |CPS| Package Information for ``install(EXPORT)``
+========================================================
 
 In order to activate support for this experimental feature, set
 
-* variable ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO`` to
-* value ``b80be207-778e-46ba-8080-b23bba22639e``.
+* variable ``CMAKE_EXPERIMENTAL_MAPPED_PACKAGE_INFO`` to
+* value ``ababa1b5-7099-495f-a9cd-e22d38f274f2``.
 
-This UUID may change in future versions of CMake.  Be sure to use the value
+These UUIDs may change in future versions of CMake.  Be sure to use the values
 documented here by the source tree of the version of CMake with which you are
 experimenting.
 
 When activated, this experimental feature provides the following:
 
-* The experimental ``install(PACKAGE_INFO)`` command is available to export
-  package information in the |CPS|_ format.
+* Setting ``CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO`` enables generation of
+  package information in the |CPS|_ format via the ``install(EXPORT)`` command.
 
-Find/Import |CPS| Packages
-==========================
-
-In order to activate support for this experimental feature, set
-
-* variable ``CMAKE_EXPERIMENTAL_FIND_CPS_PACKAGES`` to
-* value ``e82e467b-f997-4464-8ace-b00808fff261``.
-
-This UUID may change in future versions of CMake.  Be sure to use the value
-documented here by the source tree of the version of CMake with which you are
-experimenting.
-
-When activated, this experimental feature provides the following:
-
-* The :command:`find_package` command will also search for packages which are
-  described using |CPS|_. Refer to the :command:`find_package` documentation
-  for details.
+.. _CPS: https://cps-org.github.io/cps/
+.. |CPS| replace:: Common Package Specification
 
 C++ ``import std`` support
 ==========================
@@ -81,24 +66,21 @@
 set
 
 * variable ``CMAKE_EXPERIMENTAL_CXX_IMPORT_STD`` to
-* value ``d0edc3af-4c50-42ea-a356-e2862fe7a444``.
+* value ``451f2fe2-a8a2-47c3-bc32-94786d8fc91b``.
 
 This UUID may change in future versions of CMake.  Be sure to use the value
 documented here by the source tree of the version of CMake with which you are
 experimenting.  It must be set before the ``CXX`` toolchain is discovered by
-CMake, usually as part of a :command:`project` call.
+CMake, usually as part of a ``project()`` call.
 
 When activated, this experimental feature provides the following:
 
-* The :prop_tgt:`CXX_MODULE_STD` target property and its initializing variable
-  :variable:`CMAKE_CXX_MODULE_STD`.
+* The ``CXX_MODULE_STD`` target property and its initializing variable
+  ``CMAKE_CXX_MODULE_STD``.
 
 * Targets with the property set to a true value and at least ``cxx_std_23``
   may use ``import std;`` in any scanned C++ source file.
 
-.. _CPS: https://cps-org.github.io/cps/
-.. |CPS| replace:: Common Package Specification
-
 Build database support
 ======================
 
@@ -120,22 +102,33 @@
 * Targets with the property set to a true value will have their C++ build
   information exported to the build database.
 
-Instrumentation
-===============
+Software Bill Of Materials |SBOM|
+=================================
 
-In order to activate support for the :command:`cmake_instrumentation` command,
+In order to activate support for the :command:`install(SBOM)` command,
 set
 
-* variable ``CMAKE_EXPERIMENTAL_INSTRUMENTATION`` to
-* value ``ec7aa2dc-b87f-45a3-8022-fe01c5f59984``.
+* variable ``CMAKE_EXPERIMENTAL_GENERATE_SBOM`` to
+* value ``ca494ed3-b261-4205-a01f-603c95e4cae0``.
 
-To enable instrumentation at the user-level, files should be placed under
-either
-``<CMAKE_CONFIG_DIR>/instrumentation-ec7aa2dc-b87f-45a3-8022-fe01c5f59984`` or
-``<CMAKE_BINARY_DIR>/.cmake/instrumentation-ec7aa2dc-b87f-45a3-8022-fe01c5f59984``.
+This UUID may change in future versions of CMake.  Be sure to use the value
+documented here by the source tree of the version of CMake with which you are
+experimenting.
 
-To include instrumentation data in CTest XML files (for submission to CDash),
-you need to set the following environment variables:
+When activated, this experimental feature provides the following:
 
-* ``CTEST_USE_INSTRUMENTATION=1``
-* ``CTEST_EXPERIMENTAL_INSTRUMENTATION=ec7aa2dc-b87f-45a3-8022-fe01c5f59984``
+* The experimental ``export(SBOM)`` and ``install(SBOM)`` commands are
+  available to generate a Software Bill of Materials or "SBOM" for the current
+  project. See :command:`install(SBOM)` for a complete overview of the command.
+
+Rust Support
+============
+
+In order to activate support for Rust, set
+
+* variable ``CMAKE_EXPERIMENTAL_RUST`` to
+* value ``3cc9b32c-47d3-4056-8953-d74e69fc0d6c``.
+
+This UUID may change in future versions of CMake.  Be sure to use the value
+documented here by the source tree of the version of CMake with which you are
+experimenting.
diff --git a/Help/dev/maint.rst b/Help/dev/maint.rst
index 33408c0..787cd23 100644
--- a/Help/dev/maint.rst
+++ b/Help/dev/maint.rst
@@ -302,7 +302,7 @@
   set(CMake_VERSION_PATCH $date)
   #set(CMake_VERSION_RC 0)
 
-Update ``Help/manual/cmake-policies.7.rst`` to set the ``...<max>``
+Update ``Help/manual/cmake-policies.7.rst`` to set the ``...<policy_max>``
 example to ``...$major.$minor``:
 
 .. code-block:: cmake
diff --git a/Help/dev/source.rst b/Help/dev/source.rst
index d8de4e1..3aad194 100644
--- a/Help/dev/source.rst
+++ b/Help/dev/source.rst
@@ -61,6 +61,11 @@
 be used in place of the standard ones when extended features are needed.
 For example ``<cm/memory>`` can be used in place of ``<memory>``.
 
+The class ``cm::filesystem::path``, from the ``<cm/filesystem>`` header, is
+fully compatible with the class ``std::filesystem::path`` regarding the API but
+is a specific implementation (derived from the ``std::filesystem::path`` class)
+to ensure a behavior independent of the current locale.
+
 Available features are:
 
 * From ``C++14``:
@@ -111,7 +116,8 @@
     ``cm::shared_lock``
 
   * ``<cm/type_traits>``:
-    ``cm::enable_if_t``
+    ``cm::conditional_t``, ``cm::decay_t``, ``cm::enable_if_t``,
+    ``cm::remove_cv_t``, ``cm::remove_reference_t``
 
   * ``<cm/unordered_map>``:
     ``cm::cbegin``, ``cm::cend``, ``cm::rbegin``, ``cm::rend``,
@@ -169,7 +175,7 @@
 
   * ``<cm/type_traits>``:
     ``cm::bool_constant``, ``cm::invoke_result_t``, ``cm::invoke_result``,
-    ``cm::void_t``
+    ``cm::is_same_v``, ``cm::void_t``
 
   * ``<cm/unordered_map>``:
     ``cm::size``, ``cm::empty``, ``cm::data``
diff --git a/Help/envvar/CMAKE_CONFIG_DIR.rst b/Help/envvar/CMAKE_CONFIG_DIR.rst
index 8f93a56..ce812db 100644
--- a/Help/envvar/CMAKE_CONFIG_DIR.rst
+++ b/Help/envvar/CMAKE_CONFIG_DIR.rst
@@ -6,7 +6,7 @@
 .. include:: include/ENV_VAR.rst
 
 Specify a CMake user-wide configuration directory for
-:manual:`cmake-file-api(7)` queries.
+:manual:`cmake-file-api(7)` and :manual:`cmake-instrumentation(7)` queries.
 
 If this environment variable is not set, the default user-wide
 configuration directory is platform-specific:
diff --git a/Help/envvar/CTEST_USE_INSTRUMENTATION.rst b/Help/envvar/CTEST_USE_INSTRUMENTATION.rst
index b00c92d..5ee3785 100644
--- a/Help/envvar/CTEST_USE_INSTRUMENTATION.rst
+++ b/Help/envvar/CTEST_USE_INSTRUMENTATION.rst
@@ -1,15 +1,10 @@
 CTEST_USE_INSTRUMENTATION
 -------------------------
 
-.. versionadded:: 4.0
+.. versionadded:: 4.3
 
 .. include:: include/ENV_VAR.rst
 
-.. note::
-
-   This feature is only available when experimental support for instrumentation
-   has been enabled by the ``CMAKE_EXPERIMENTAL_INSTRUMENTATION`` gate.
-
 Setting this environment variable to ``1``, ``True``, or ``ON`` enables
 :manual:`instrumentation <cmake-instrumentation(7)>` for CTest in
 :ref:`Dashboard Client` mode.
diff --git a/Help/envvar/CTEST_USE_VERBOSE_INSTRUMENTATION.rst b/Help/envvar/CTEST_USE_VERBOSE_INSTRUMENTATION.rst
index 4a119aa..a1dd5c7 100644
--- a/Help/envvar/CTEST_USE_VERBOSE_INSTRUMENTATION.rst
+++ b/Help/envvar/CTEST_USE_VERBOSE_INSTRUMENTATION.rst
@@ -1,15 +1,10 @@
 CTEST_USE_VERBOSE_INSTRUMENTATION
 ---------------------------------
 
-.. versionadded:: 4.0
+.. versionadded:: 4.3
 
 .. include:: include/ENV_VAR.rst
 
-.. note::
-
-   This feature is only available when experimental support for instrumentation
-   has been enabled by the ``CMAKE_EXPERIMENTAL_INSTRUMENTATION`` gate.
-
 Setting this environment variable to ``1``, ``True``, or ``ON`` causes CTest to
 report the full command line (including arguments) to CDash for each
 instrumented command. By default, CTest truncates the command line at the first
diff --git a/Help/guide/tutorial/Getting Started with CMake.rst b/Help/guide/tutorial/Getting Started with CMake.rst
index d72acb0..19c811d 100644
--- a/Help/guide/tutorial/Getting Started with CMake.rst
+++ b/Help/guide/tutorial/Getting Started with CMake.rst
@@ -430,7 +430,7 @@
 Solution
 --------
 
-We start by adding the library target in the same manner as the the Tutorial
+We start by adding the library target in the same manner as the Tutorial
 executable.
 
 .. raw:: html
diff --git a/Help/guide/tutorial/In-Depth CMake Library Concepts.rst b/Help/guide/tutorial/In-Depth CMake Library Concepts.rst
index d59ab93..6181cf7 100644
--- a/Help/guide/tutorial/In-Depth CMake Library Concepts.rst
+++ b/Help/guide/tutorial/In-Depth CMake Library Concepts.rst
@@ -384,7 +384,7 @@
 ``MathFunctions`` library as part of its own build step, and we want the
 headers to be available to consumers of the library.
 
-Then we add the ``MathExtensions`` subdirectoy to the project.
+Then we add the ``MathExtensions`` subdirectory to the project.
 
 .. raw:: html
 
diff --git a/Help/guide/tutorial/In-Depth CMake Target Commands.rst b/Help/guide/tutorial/In-Depth CMake Target Commands.rst
index 842b0d5..c4f6465 100644
--- a/Help/guide/tutorial/In-Depth CMake Target Commands.rst
+++ b/Help/guide/tutorial/In-Depth CMake Target Commands.rst
@@ -162,6 +162,7 @@
 Files to Edit
 -------------
 
+* ``CMakeLists.txt``
 * ``Tutorial/CMakeLists.txt``
 * ``MathFunctions/CMakeLists.txt``
 * ``MathFunctions/MathFunctions.cxx``
diff --git a/Help/guide/tutorial/In-Depth System Introspection.rst b/Help/guide/tutorial/In-Depth System Introspection.rst
index f872c56..463d887 100644
--- a/Help/guide/tutorial/In-Depth System Introspection.rst
+++ b/Help/guide/tutorial/In-Depth System Introspection.rst
@@ -49,7 +49,7 @@
 A fast and easy check to perform is if a given header file is available on
 a certain platform, for which CMake provides :module:`CheckIncludeFiles`. This
 is most appropriate for system and intrinsic headers, which may not be provided
-by a specific package by are expected to be available in many build environments.
+by a specific package yet are expected to be available in many build environments.
 
 .. code-block:: cmake
 
diff --git a/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt
index 7aebf48..2c33965 100644
--- a/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt
@@ -14,9 +14,10 @@
 #        MathLogger will only be used in the MathFunctions implementation,
 #        not the headers
 
-# TODO8: Add links to MathLogger for the OpAdd, OpMul, and OpSub libraries.
-#        Note that their headers will be exposed in the MathFunctions.h
-#        header, and must be available to consumers.
+# TODO8: Add links to OpAdd, OpMul, and OpSub libraries for the
+#        MathFunctions library.  Note that their headers will be
+#        exposed in the MathFunctions.h header, and must be available
+#        to consumers.
 
 target_compile_features(MathFunctions PRIVATE cxx_std_20)
 
diff --git a/Help/manual/cmake-buildsystem.7.rst b/Help/manual/cmake-buildsystem.7.rst
index 61413f1..e9b90fb 100644
--- a/Help/manual/cmake-buildsystem.7.rst
+++ b/Help/manual/cmake-buildsystem.7.rst
@@ -404,9 +404,14 @@
   These are passed to the compiler with ``-D`` flags, or equivalent,
   in an unspecified order.
 
-  The :prop_tgt:`DEFINE_SYMBOL` target property is also used
-  as a compile definition as a special convenience case for
-  ``SHARED`` and ``MODULE`` library targets.
+  When compiling sources of a ``SHARED`` library, a ``MODULE`` library,
+  or an ``EXECUTABLE`` with :prop_tgt:`ENABLE_EXPORTS` enabled, CMake
+  automatically defines a target-specific preprocessor symbol.
+  By default the definition is of the form ``<target>_EXPORTS``, but it
+  can be overridden by the :prop_tgt:`DEFINE_SYMBOL` target property.
+  This allows headers to detect whether they are included from inside
+  their implementation sources, and to correctly set up export/import
+  annotations or visibility of symbols.
 
 :prop_tgt:`COMPILE_OPTIONS`
   List of compile options for compiling sources in the target.
diff --git a/Help/manual/cmake-cxxmodules.7.rst b/Help/manual/cmake-cxxmodules.7.rst
index ee16e27..9dc14d2 100644
--- a/Help/manual/cmake-cxxmodules.7.rst
+++ b/Help/manual/cmake-cxxmodules.7.rst
@@ -5,61 +5,46 @@
 
 .. versionadded:: 3.28
 
-C++ 20 introduced the concept of "modules" to the language.  The design
-requires build systems to order compilations among each other to satisfy
-``import`` statements reliably.  CMake's implementation asks the compiler
-to scan source files for module dependencies during the build, collates
-scanning results to infer ordering constraints, and tells the build tool
-how to dynamically update the build graph.
+C++ 20 introduced the concept of ":term:`modules <C++ module>`" to the
+language.  The design requires :term:`build systems <build system>` to order
+compilations to satisfy ``import`` statements reliably.  CMake's
+implementation asks the compiler to scan source files for module dependencies
+during the build, collates scanning results to infer ordering constraints, and
+tells the :term:`build tool` how to dynamically update the
+build graph.
 
 Compilation Strategy
 ====================
 
-With C++ modules, compiling a set of C++ sources is no longer embarrassingly
-parallel. That is, any given source may first require the compilation of
-another source file first in order to provide a "CMI" (compiled module
-interface) or "BMI" (binary module interface) that C++ compilers use to
-satisfy ``import`` statements in other sources. With headers, sources could
+With C++ modules, compiling a set of C++ sources is no longer
+:term:`embarrassingly parallel`.  That is, any given source may require the
+compilation of another source file first in order to provide a
+":abbr:`BMI (built module interface)`" (or
+":abbr:`CMI (compiled module interface)`") that C++ compilers use to satisfy
+``import`` statements in other sources.  With included headers, sources could
 share their declarations so that any consumers could compile independently.
-With modules, declarations are now generated into these BMI files by the
-compiler during compilation based on the contents of the source file and its
-``export`` statements.
+With modules, the compiler now generates :term:`BMI` files during compilation
+based on the contents of the source file and its ``export`` statements.  This
+means that, to ensure a correct build without having to regenerate the build
+graph (by running configure and generate steps) for every source change, the
+correct ordering must be determined from the source files during the build
+phase.
 
-The order necessary for compilation requires build-time resolution of the
-ordering because the order is controlled by the contents of the sources. This
-means that the ordering needs extracted from the source during the build to
-avoid regenerating the build graph via a configure and generate phase for
-every source change to get a correct build.
+:term:`Build systems <build system>` must be able to order these compilations
+within the build graph.  There are multiple strategies that are suitable for
+this, but each has advantages and disadvantages.  CMake uses a "scanning" step
+strategy, which is the most visible modules-related change for CMake users in
+the context of the build.  CMake provides multiple ways to control the
+scanning behavior of source files.
 
-The general strategy is to use a "scanner" to extract the ordering dependency
-information and update the build graph with new edges between existing edges
-by taking the per-source scan results (represented by `P1689R5`_ files) and
-"collating" the dependencies within a target and to modules produced by
-targets visible to the target. The primary task is to generate "module map"
-files to pass to each compile rule with the paths to the BMIs needed to
-satisfy ``import`` statements. The collator also has tasks to use the
-build-time information to fill out information including ``install`` rules for
-the module interface units, their BMIs, and properties for any exported
-targets with C++ modules.
-
-.. _`P1689R5`: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1689r5.html
-
-.. note::
-
-   CMake is focusing on correct builds before looking at performance
-   improvements. There are known tactics within the chosen strategy which may
-   offer build performance improvements. However, they are being deferred
-   until we have a working model against which to compare them. It is also
-   important to note that a tactic useful in one situation (e.g., clean
-   builds) may not be performant in a different situation (e.g., incremental
-   builds). Finding a balance and offering controls to select the tactics is
-   future work.
+.. _cxxmodules-scanning-control:
 
 Scanning Control
 ================
 
 Whether or not sources get scanned for C++ module usage is dependent on the
-following queries. The first query that provides a yes/no answer is used.
+following queries.  The first query that provides a decision of whether to
+scan or not is used.
 
 - If the source file belongs to a file set of type ``CXX_MODULES``, it will
   be scanned.
@@ -80,11 +65,12 @@
 Compiler Support
 ================
 
-Compilers which CMake natively supports module dependency scanning include:
+The list of compilers for which CMake supports scanning sources for C++
+modules includes:
 
 * MSVC toolset 14.34 and newer (provided with Visual Studio 17.4 and newer)
 * LLVM/Clang 16.0 and newer
-* GCC 14 (for the in-development branch, after 2023-09-20) and newer
+* GCC 14 and newer
 
 ``import std`` Support
 ======================
@@ -92,51 +78,887 @@
 Support for ``import std`` is limited to the following toolchain and standard
 library combinations:
 
-* Clang 18.1.2 and newer with ``-stdlib=libc++`` or ``-stdlib=libstdc++``
-* MSVC toolset 14.36 and newer (provided with Visual Studio 17.6 Preview 2 and
-  newer)
-* GCC 15 and newer.
+* Clang 18.1.2 and newer with standard library ``libc++`` or ``libstdc++``
+* MSVC toolset 14.36 and newer (provided with Visual Studio 17.6 and newer)
+* GCC 15 and newer
 
-The :variable:`CMAKE_CXX_COMPILER_IMPORT_STD` variable may be used to detect
-support for a standard level with the active C++ toolchain.
+  .. note::
+
+    Ubuntu prior to 26.04 ships broken ``libstdc++.modules.json`` files.
+    See `Ubuntu issue 2141579`_.
+
+.. _`Ubuntu issue 2141579`: https://bugs.launchpad.net/ubuntu/+source/gcc-15/+bug/2141579
+
+The :variable:`CMAKE_CXX_COMPILER_IMPORT_STD` variable lists standard levels
+which have support for ``import std`` in the active C++ toolchain.
+
+Additionally, only the :ref:`Ninja Generators` currently support
+``import std`` at this time because :ref:`Visual Studio Generators` do not
+support building :term:`BMIs <BMI>` for ``IMPORTED`` targets.
 
 .. note::
 
    This support is provided only when experimental support for
-   ``import std;`` has been enabled by the
+   ``import std`` has been enabled by the
    ``CMAKE_EXPERIMENTAL_CXX_IMPORT_STD`` gate.
 
 Generator Support
 =================
 
-The list of generators which support scanning sources for C++ modules include:
+The list of generators which support scanning sources for C++ modules
+includes:
 
 - :generator:`Ninja`
 - :generator:`Ninja Multi-Config`
 - :generator:`Visual Studio 17 2022`
+- :generator:`Visual Studio 18 2026`
+
+Note that the :ref:`Ninja Generators` require ``ninja`` 1.11 or newer.
 
 Limitations
 -----------
 
 There are a number of known limitations of the current C++ module support in
-CMake.  This does not document known limitations or bugs in compilers as these
+CMake.  Known limitations or bugs in compilers are not listed here, as these
 can change over time.
 
 For all generators:
 
-- Header units are not supported.
-- No builtin support for ``import std;`` or other compiler-provided modules.
-
-For the Ninja Generators:
-
-- ``ninja`` 1.11 or newer is required.
+- :term:`Header units <header unit>` are not supported.
 
 For the :ref:`Visual Studio Generators`:
 
 - Only Visual Studio 2022 and MSVC toolsets 14.34 (Visual Studio
-  17.4) and newer.
-- No support for exporting or installing BMI or module information.
-- No support for compiling BMIs from ``IMPORTED`` targets with C++ modules
-  (including ``import std``).
-- No diagnosis of using modules provided by ``PRIVATE`` sources from
-  ``PUBLIC`` module sources.
+  17.4) and newer are supported.
+- Exporting or installing :term:`BMI` or module information is not supported.
+- Compiling :term:`BMIs <BMI>` from ``IMPORTED`` targets with C++ modules
+  (including ``import std``) is not supported.
+- Use of modules provided by ``PRIVATE`` sources from ``PUBLIC`` module
+  sources is not diagnosed.
+
+Separately, as a design choice, CMake does not express configuration-agnostic
+module maps for imported targets. The :prop_tgt:`IMPORTED_CXX_MODULES_<CONFIG>`
+target property is always tied to a specific configuration. This can lead to
+some friction when importing/exporting targets from/to configuration-unaware
+build systems. Future work will alleviate this restriction.
+
+Usage
+=====
+
+Troubleshooting CMake
+---------------------
+
+This section aims to answer common questions about CMake's implementation and
+to help diagnose or explain errors in CMake's C++ modules support.
+
+File Extension Support
+^^^^^^^^^^^^^^^^^^^^^^
+
+CMake imposes no requirements upon file extensions for modules of any unit
+type.  While there are preferences that differ between toolchains (e.g.,
+``.ixx`` on MSVC and ``.cppm`` on Clang), there is no universally agreed-upon
+extension.  As such, CMake only requires that the file be recognized as a
+``CXX``-language source file.  By default, any recognized extension will
+suffice, but the :prop_sf:`LANGUAGE` property may be used with any other
+extension as well.
+
+File Name Requirements
+^^^^^^^^^^^^^^^^^^^^^^
+
+The name of a module has no relation to the name or path of the file in which
+its declaration resides.  The C++ standard has no requirements here and
+neither does CMake.  However, it may be useful to have some pattern in use
+within a project for easier navigation within environments that lack IDE-like
+"find symbol" functionality (e.g., on code review platforms).
+
+Scanning Without Modules
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+A common problem for projects that have not yet adopted modules is unnecessary
+scanning of sources.  This typically happens when a C++20 project becomes
+aware of CMake 3.28, or a 3.28-aware project starts using C++20.  Either case
+ends up setting :policy:`CMP0155` to ``NEW``, which enables scanning of C++
+sources with C++20 or newer by default.  The easiest way for projects to turn
+this off is to add:
+
+.. code-block:: cmake
+
+   set(CMAKE_CXX_SCAN_FOR_MODULES 0)
+
+near the top of their top-level ``CMakeLists.txt`` file.  Note that it should
+**not** be in the cache, as it may otherwise affect projects using it via
+``FetchContent``.  Attention should also be paid to vendored projects which
+may want to enable scanning for their own sources, as this would change the
+default for them as well.
+
+Debugging Module Builds
+-----------------------
+
+This section aims to help diagnose or explain common errors that may arise on
+the build side of CMake's C++ modules support.
+
+Import Cycles
+^^^^^^^^^^^^^
+
+The C++ standard does not allow for cycles in the ``import`` graph of a
+:term:`translation unit`; therefore, CMake does not either.  Currently, CMake
+will leave it to the :term:`build tool` to detect this based on the
+:term:`dynamic dependencies` used to order module compilations.
+`CMake Issue 26119`_ tracks the desire to improve the user experience in this
+case.
+
+.. _`CMake Issue 26119`: https://gitlab.kitware.com/cmake/cmake/-/issues/26119
+
+Internal Module Partition Extension
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When the implementation of building C++ modules was first investigated, it
+appeared as though there existed a type of :term:`translation unit` that
+represented the intersection of a :term:`partition unit` and an
+:term:`implementation unit`.  Initial CMake designs included specific support
+for these translation units; however, after a closer reading of the standard,
+these did not actually exist.  These units would have had ``module M:part;``
+as their module declaration statement.  The problem is that this is also the
+exact syntax also used for declaring module partitions that do not contribute
+to the external interface of the primary module.  Only MSVC supports this
+distinction.  Other compilers do not and will treat such files as an
+:term:`internal partition unit` and CMake will raise an error that a
+module-providing C++ source must be in a ``FILE_SET`` of type ``CXX_MODULES``.
+
+The fix is to not use the extension, as it provides no further expressivity
+over not using the extension.  All :term:`implementation unit` source files
+should instead only use ``module M;`` as their module declaration statement
+regardless of what partition the defined entities are declared within.  As an
+example:
+
+.. code-block:: cpp
+
+   // module-interface.cpp
+   export module M;
+   export int foo();
+
+   // module-impl.cpp
+   module M:part; // module M:part; looks like an internal partition
+   int foo() { return 42; }
+
+Instead use explicit interface/implementation separation:
+
+.. code-block:: cpp
+
+   // module-interface.cpp
+   export module M;
+   export int foo();
+
+   // module-impl.cpp
+   module M;
+   int foo() { return 42; }
+
+Module Visibility
+^^^^^^^^^^^^^^^^^
+
+CMake enforces :term:`module visibility` between and within targets.  This
+essentially means that a module (say, ``I``) provided from a ``PRIVATE``
+``FILE_SET`` on a target ``T`` may not be imported by:
+
+- other targets depending on ``T``; or
+- modules provided from a ``PUBLIC`` ``FILE_SET`` on target ``T`` itself.
+
+This is because, in general, all imported entities from a module must also be
+importable by all potential importers of that module.  Even if module ``I`` is
+only used within parts of a module without the ``export`` keyword, it may
+affect things within it in such a way that consumers of the module need to be
+able to transitively ``import`` it to work correctly.  As CMake uses the
+module visibility to determine whether to install :term:`module interface
+units <module interface unit>`, a ``PRIVATE`` module interface unit will not
+be installed, meaning that usage of any installed module which imports ``I``
+would not work.
+
+Instead, import ``PRIVATE`` C++ modules only from within an
+:term:`implementation unit`, as these are not exposed to consumers of any
+module.
+
+Design
+======
+
+The design of CMake's C++ module support makes a number of trade-offs compared
+to other designs.  First, CMake's chosen design will be covered.  Later
+sections cover alternative designs that were not chosen for CMake's
+implementation.
+
+Overall, the designs fall somewhere along two axes:
+
+.. list-table::
+
+   * - Explicit Dynamic
+     - Explicit Static
+     - Explicit Fixed
+   * - Implicit Dynamic
+     - Implicit Static
+     - Implicit Fixed
+
+* **Explicit** builds control which modules are visible to each translation
+  unit directly.  For example, when compiling a source requiring a module
+  ``M``, the compiler will be given information which states the exact BMI
+  file to use when importing the ``M`` module.
+* **Implicit** builds can control module visibility as well, but do so by
+  instead grouping :term:`BMIs <BMI>` into directories which are then searched
+  for files to satisfy ``import`` statements in the source file.
+* **Static** builds use a static set of build commands in order to complete
+  the build.  There must be support to add edges between nodes at build time.
+* **Dynamic** builds may create new build commands during the build and
+  schedule any discovered work during the build.
+* **Fixed** builds are generated with all module dependencies already known.
+
+Design Goals
+------------
+
+CMake's implementation of building C++ modules focuses on the following design
+goals:
+
+1. `Correct Builds <design-goal-correct-builds_>`__
+2. `Deterministic Builds <design-goal-deterministic-builds_>`__
+3. `Support Generated Sources <design-goal-generated-sources_>`__
+4. `Static Communication <design-goal-static-communication_>`__
+5. `Minimize Regeneration <design-goal-minimize-regeneration_>`__
+
+.. _design-goal-correct-builds:
+
+Correct Builds
+^^^^^^^^^^^^^^
+
+Above all else, an incorrect build is a frustrating experience for all
+involved.  A build which does not detect errors and instead lets a build with
+detectable problems run to completion is a good way to start wild goose chase
+debugging sessions.  CMake errs on the side of avoiding such situations.
+
+.. _design-goal-deterministic-builds:
+
+Deterministic Builds
+^^^^^^^^^^^^^^^^^^^^
+
+Given an on-disk state of a build, it should be possible to determine what
+steps will happen next.  This does not mean that the exact order of rules
+within the build that can be run concurrently is deterministic, but instead
+that the set of work to be done and its results are deterministic.  For
+example, if there is no dependency between tasks ``A`` and ``B``, ``A`` should
+have no effects on the execution of ``B`` and vice versa.
+
+.. _design-goal-generated-sources:
+
+Support Generated Sources
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Code generation is prevalent in the C++ ecosystem, so only supporting modules
+in files whose content is known at configure time is not suitable.  Without
+supporting generated sources which use or provide modules, code generation
+tools are effectively cut off from the use of modules, and any dependencies of
+generated sources must also provide non-modular ways of using their interfaces
+(i.e., provide headers).  Given that all C++ implementations use :term:`strong
+module ownership` for symbol mangling, this is problematic when such
+interfaces end up referring to compiled symbols in other libraries.
+
+.. _design-goal-static-communication:
+
+Static Communication
+^^^^^^^^^^^^^^^^^^^^
+
+All communication between different steps of the build should be handled
+statically.  Given the :term:`build tools <build tool>` that CMake supports,
+it is challenging to establish a controlled lifetime for a companion tool that
+needs to interact during compilation.  Neither ``make`` nor ``ninja`` offer a
+way to start a tool at the beginning of a build and ensure it is stopped at
+the end.  Instead, communication with compilers is managed through input and
+output files, using dependencies in the :term:`build tool` to keep everything
+up-to-date.  This approach enables standard debugging strategies for builds
+and allows developers to run build commands directly when investigating
+issues, without needing to account for other tools running in the background.
+
+.. _design-goal-minimize-regeneration:
+
+Minimize Regeneration
+^^^^^^^^^^^^^^^^^^^^^
+
+Active development of a build with modules should not require the build graph
+to be regenerated on every change.  This means that the module dependencies
+must be constructed after the build graph is available.  Without this, a
+`correct build <design-goal-correct-builds_>`__ would need to regenerate the
+build graph any time a module-aware source file is edited, as any changes may
+alter module dependencies.
+
+It also means that all module-aware sources must be known at configure time
+(even if they do not yet exist) so that the build graph can include the
+commands to :term:`scan` for their dependencies.
+
+.. note::
+
+  There is a known issue with ``ninja`` which can result in an erroneous
+  detection of a dependency cycle when the dependency order between two
+  sources reverses (i.e., ``a`` importing ``b`` becomes ``b`` importing
+  ``a``) between two builds.  See `ninja issue 2666`_ for details.
+
+.. _`ninja issue 2666`: https://github.com/ninja-build/ninja/issues/2666
+
+Use Case Considerations
+-----------------------
+
+The design goals described above constrain the implementation.  Additionally,
+mixed configurations are supported by CMake via multi-config generators such
+as :generator:`Ninja Multi-Config` and :ref:`Visual Studio Generators`.  This
+section describes how CMake addresses these constraints.
+
+Selected Design
+---------------
+
+The general strategy CMake uses is to ":term:`scan`" sources to extract the
+ordering dependency information and update the build graph with new edges
+between existing edges.  This is done by taking the per-source scan results
+(represented by `P1689R5`_ files) and then ":term:`collating <collate>`" them
+for each target with information from its dependencies.  The primary task of
+the collator is to generate ":term:`module map`" files to pass to each compile
+rule with the paths to the :term:`BMIs <BMI>` needed to satisfy ``import``
+statements, and to inform the :term:`build tool` of dependencies needed to
+satisfy those ``import`` statements during the compilation.  The collator also
+uses the build-time information to generate ``install`` rules for the module
+interface units, their :term:`BMIs <BMI>`, and properties for any exported
+targets with C++ modules.  It also enforces that ``PRIVATE`` modules may not
+be used by other targets or by any ``PUBLIC`` :term:`module interface unit`
+within the target.
+
+.. _`P1689R5`: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1689r5.html
+
+Implementation Details
+----------------------
+
+.. warning::
+
+  The implementation details are not a stable interface.  Each version
+  of CMake may revise them without any attempt at providing compatibility.
+  External toolchain maintainers are responsible for updating their
+  implementations for each version of CMake they support.
+
+This section describes how CMake actually structures the build graph, the data
+passed between various parts, and the files which contain that data.  It is
+intended to be used both as functional documentation and as a guide to help
+those debugging a module build to understand where to locate various bits of
+data.
+
+.. note::
+
+   This section documents internal implementation details that may be useful
+   for :manual:`toolchain file <cmake-toolchains(7)>` authors or during
+   debugging of a module-related issue.  Projects should not need to inspect
+   or modify any of the variables, properties, files, or targets mentioned
+   here.
+
+Toolchain (scanning)
+^^^^^^^^^^^^^^^^^^^^
+
+Compilers which support modules must also provide a scanning tool.  This will
+usually be either the compiler itself with some extra flags or a tool shipped
+with the compiler.  The command template for scanning is stored in the
+``CMAKE_CXX_SCANDEP_SOURCE`` variable.  The command is expected to write
+`P1689R5`_ results to the ``<DYNDEP_FILE>`` placeholder.  Additionally, the
+command should provide any :term:`discovered dependencies` to the
+``<DEP_FILE>`` placeholder.  This allows :term:`build tools <build tool>` to
+rerun the scan if any of the dependencies of the scanning command change.
+
+Additionally, toolchains should set the following variables:
+
+* ``CMAKE_CXX_MODULE_MAP_FORMAT``: The format of the :term:`module map`
+  describing where dependent :term:`BMI` files for imported modules exist
+  during compilation.  Must be one of ``gcc``, ``clang``, or ``msvc``.
+* ``CMAKE_CXX_MODULE_MAP_FLAG``: The arguments used to inform the compiler of
+  the :term:`module map` file.  It should use the ``<MODULE_MAP_FILE>``
+  placeholder.
+* ``CMAKE_CXX_COMPILE_BMI``: The command template to compile a :term:`BMI`
+  file from a :term:`module interface unit`.  Used when
+  ``CMAKE_CXX_MODULE_BMI_ONLY_FLAG`` is not completely additive to an
+  object compilation template.
+* ``CMAKE_CXX_MODULE_BMI_ONLY_FLAG``: The arguments used to compile only a
+  :term:`BMI` file from a :term:`module interface unit`.  This is used when
+  consuming modules from external projects to compile :term:`BMI` files for
+  use within the current build.
+
+If a toolchain does not provide the ``CMAKE_CXX_COMPILE_BMI`` or
+``CMAKE_CXX_MODULE_BMI_ONLY_FLAG`` variables, it will not be able to consume
+modules provided by ``IMPORTED`` targets.
+
+Configure
+^^^^^^^^^
+
+During the configure step, CMake needs to track which sources care about
+modules at all.  See :ref:`Scanning Control <cxxmodules-scanning-control>` for
+how each source determines whether it cares about modules or not.  CMake
+tracks these in its internal target representation structure (``cmTarget``).
+The set of sources which need to be scanned may be modified using the
+:command:`target_sources`, :command:`target_compile_features`, and
+:command:`set_property` commands.
+
+Additionally, targets may use the :prop_tgt:`CXX_MODULE_STD` target property
+to indicate that ``import std`` is desired within the target's sources.
+
+Generate
+^^^^^^^^
+
+During generation, CMake needs to add additional rules to ensure that the
+sources providing modules can be built before sources that import those
+modules.  Since CMake uses a :term:`static build`, the build graph must
+contain all possible commands for scanning and module generation.  The
+dependency edges between commands to ensure that modules are provided will
+then ensure that the build graph executes correctly.  This means that, while
+all sources may get scanned, only modules that are actually used will be
+generated.
+
+The first step CMake performs is to generate a :term:`synthetic target` for
+each unique usage of a module-providing target.  These targets are based on
+other targets, but provide only :term:`BMI` files for other targets rather
+than object files.  This is because the compatibility of :term:`BMI` files is
+extremely narrow and cannot be shared between arbitrary ``import`` instances.
+Due to the internal workings of toolchains, there can generally only be a
+single set of settings for a variety of flags for any one compilation,
+including :term:`BMI` files for imported modules.  As an example, the C++
+standard in use needs to be consistent across all modules, but there are many
+settings which may cause incompatibilities.
+
+.. note::
+
+   CMake currently assumes that all usages are compatible and will only create
+   one set of :term:`BMIs <BMI>` for each target.  This may cause build
+   failures where multiple :term:`BMI` files are required, but CMake only
+   provides one set.  See `CMake Issue 25916`_ for progress on removing this
+   assumption.
+
+.. _`CMake Issue 25916`: https://gitlab.kitware.com/cmake/cmake/-/issues/25916
+
+Once all of the :term:`synthetic targets <synthetic target>` are created,
+CMake looks at each target that has any source that might use C++ modules and
+creates a command to :term:`scan` each of them.  This command will output a
+`P1689R5`_-formatted file describing the C++ modules it uses and provides (if
+any).  It will also create a command to :term:`collate` module dependencies
+for the eligible compilations.  This command depends on the :term:`scan`
+results of all eligible sources, information about the target itself, as well
+as the :term:`collate` results of any dependent targets which provide C++
+modules.  The :term:`collate` step uses a target-specific
+``CXXDependInfo.json`` file which contains the following information:
+
+- ``compiler-*``: basic compiler information (``id``, ``frontend-variant``,
+  and ``simulate-id``) which is used to generate correctly formatted paths
+  when generating paths for the compiler
+- ``cxx-modules``: a map of object files to the ``FILE_SET`` information,
+  which is used to enforce :term:`module visibility` and generate install
+  rules for :term:`module interface unit` sources
+- ``module-dir``: where to place :term:`BMI` files for this target
+- ``dir-{cur,top}-{src,bld}``: the source (``src``) and build (``bld``)
+  directories for the current directory (``cur``) and the top (``top``) of the
+  project, used to compute accurate relative paths for the :term:`build tool`
+  dynamic dependencies
+- ``exports``: The list of exports which both contain the target and are
+  providing C++ module information, used to provide accurate module properties
+  on ``IMPORTED`` targets from the exported targets.
+- ``bmi-installation``: installation information, used to generate install
+  scripts for :term:`BMI` files
+- ``database-info``: information required to generate :term:`build database`
+  information if requested by :prop_tgt:`EXPORT_BUILD_DATABASE`
+- ``sources``: list of other source files in the target, used to add to the
+  :term:`build database` if requested
+- ``config``: the configuration for the target, used to set the appropriate
+  properties in generated export files
+- ``language``: the language (e.g., C++ or Fortran) the
+  :term:`collation <collate>` metadata file is describing
+- ``include-dirs`` and ``forward-modules-from-target-dirs``: unused for C++
+
+Each entry in the ``cxx-modules`` map records the following:
+
+- ``bmi-only`` (bool): True if only the BMI, not the source of the BMI, is
+  available
+- ``compile-features`` (list[string]): :manual:`cmake-compile-features(7)` used
+  to build the object
+- ``compile-options`` (list[string]): compilation options/flags used to build
+  the object, except for those derived from ``compile-features``
+- ``definitions`` (list[string]): preprocessor defines used to build the object
+- ``destination`` (string): intended install destination of the source file
+- ``include-directories`` (list[string]): include directories used to build the
+  object
+- ``name`` (string): name of the file set which owns the source file
+- ``relative-directory`` (string): base path relative to which the source file
+  will be relocated into the install destination
+- ``source`` (string): path to the source file
+- ``type`` (string): type of the file set which owns the source file
+- ``visibility`` (string): visibility of the file set which owns the source file
+
+For each compilation, CMake will also provide a :term:`module map` which will
+be created during the build by the :term:`collate` command.  How this is
+provided to the compiler is specified by the ``CMAKE_CXX_MODULE_MAP_FORMAT``
+and ``CMAKE_CXX_MODULE_MAP_FLAG`` toolchain variables.
+
+Scan
+^^^^
+
+The compiler is expected to implement the :term:`scan` command.  This is
+because only the compiler itself can reliably answer preprocessor predicates
+like ``__has_builtin`` in order to provide accurate module usage information
+in the face of arbitrary flags that may be used when compiling sources.
+
+CMake names these files with the ``.ddi`` extension, which stands for "dynamic
+dependency information".  These files are in `P1689R5`_ format and are used by
+the :term:`collate` command to perform its tasks.
+
+Collate
+^^^^^^^
+
+The :term:`collate` command performs the bulk of the work to make C++ modules
+work within the build graph.  It consumes the following files as input:
+
+- ``CXXDependInfo.json`` from the generate step
+- ``.ddi`` files from the :term:`scanning <scan>` results of the target's
+  sources
+- ``CXXModules.json`` files output from eligible dependent targets'
+  :term:`collate` commands
+
+It uses the information from these files to generate:
+
+- ``CXX.dd`` files to inform the :term:`build tool` of dependencies that exist
+  between the compilation of a source and the :term:`BMI` files of the modules
+  that it imports
+- ``CXXModules.json`` files for use in :term:`collate` commands of depending
+  targets
+- ``*.modmap`` files for each compilation to find :term:`BMI` files for
+  imported modules
+- ``install-cxx-module-bmi-$<CONFIG>.cmake`` scripts for the installation of
+  any :term:`BMI` files (included by the ``install`` scripts)
+- ``target-*-$<CONFIG>.cmake`` export files for any exports of the target to
+  provide the :prop_tgt:`IMPORTED_CXX_MODULES_<CONFIG>` properties
+- ``CXX_build_database.json`` :term:`build database` files for the target when
+  the its :prop_tgt:`EXPORT_BUILD_DATABASE` property is set
+
+During its processing, it enforces the following guarantees:
+
+- :term:`BMI` usage is consistent
+- :term:`module visibility` is respected
+
+C++ modules have the rule that only a single module of a given name may
+exist within a program.  This is not exactly enforceable with the existence of
+private modules, but it is enforceable for public modules.  The enforcement is
+done by the :term:`collate` command.  Part of the ``CXXModules.json`` files is
+the set of modules that are transitively imported by each module it provides.
+When a module is then imported, the :term:`collate` command ensures that all
+modules with a given name agree upon a given :term:`BMI` file to provide that
+module.
+
+Compile
+^^^^^^^
+
+Compilation uses the :term:`module map` file generated by the :term:`collate`
+command to find imported modules during compilation.  Because CMake only
+provides the locations of modules that are discovered by the :term:`scan`
+command, any modules missed by it will not be provided to the compilation.
+
+It is possible for toolchains to reject the :term:`BMI` file that CMake
+provides to a compilation as incompatible.  This is because CMake assumes that
+all usages are compatible at the moment.  See `CMake Issue 25916`_ for
+progress on removing this assumption.
+
+Install
+^^^^^^^
+
+During installation, install scripts which have been written by the
+:term:`collate` command during the build are included so that any :term:`BMI`
+files are installed as needed.  These need to be generated, as it is not
+known what the :term:`BMI` file names will be during CMake's generation
+(because CMake names the :term:`BMI` files after the module name itself).
+These install scripts are included with the ``OPTIONAL`` keyword, so an
+incomplete build may result in an incomplete installation as well.
+
+Alternative Designs
+-------------------
+
+There are alternative designs that CMake does not implement.  This section
+aims to give a brief overview and to explain why they were not chosen for
+CMake's implementation.
+
+Implicit Builds
+^^^^^^^^^^^^^^^
+
+An implicit build performs module builds using compile-time search paths to
+make the implementation of the build simpler.  This is certainly something
+that can be made to work.  However, CMake's goals exclude it as a solution.
+
+When a build uses search directory management, the compiler is directed to
+place module output files into a specified directory.  These directories are
+then provided as search paths to any compilation allowed to use the modules
+within them.
+
+This strategy risks running into problems with the
+`Correct Builds <design-goal-correct-builds_>`__ goal.  This stems from the
+hazard of stale files being present in the search directories.  Since the
+build system is unaware of the actual files being written, it is difficult to
+know which files are allowed to be deleted (e.g., using ``ninja -t cleandead``
+to remove outputs ``ninja`` has encountered but are no longer generated).
+Removal of intermediate files may also cause the build to become stuck if the
+outputs are not known to the build system beyond consumers reporting "usage of
+file X".
+
+There is also a need to at least do some level of ordering of :term:`BMI`
+generation commands which share an output directory.  Separate directories may
+be used to order groups of modules (e.g., one directory per target);
+otherwise, modules within the same directory may not assume that other modules
+writing to the shared directory will complete first.  If module paths are
+grouped accurately according to the module dependency graph, it is a small
+step to being an explicit build where the files are directly specified.
+
+Static Scanning
+^^^^^^^^^^^^^^^
+
+A :term:`fixed build` performs a scan while generating the build graph and
+includes the necessary dependencies up-front.  In CMake's case, it would look
+at the source files during the generate phase and add the dependencies
+directly to the build graph.  This is more likely to be suitable for a
+:term:`build system` that is also its own :term:`build tool` where build graph
+manipulation can be done cooperatively.
+
+No matter whether it is integrated or not, this strategy necessitates either a
+suitable C++ parser to extract the information in the first place, or toolchain
+cooperation to obtain it.  While module dependency information is available to
+a simpler C++ parser, dependencies may be hidden behind preprocessor
+conditionals that need to be understood in order to be accurate.  Of course,
+choosing to not support preprocessor conditionals around ``import`` statements
+is also an option, but this may severely limit external library support.
+
+For CMake, this strategy would mean that any change to a module-aware source
+file may need to trigger regeneration of the build graph.  A benign edit would
+at least need to trigger the *check* for changed imports, but may skip
+actually regenerating if it is unchanged.  This may be less critical for a
+:term:`build system` which is also its own :term:`build tool`, but it is a
+direct violation of the
+`Minimize Regeneration <design-goal-minimize-regeneration_>`__ goal.
+
+Additionally, CMake's
+`Support Generated Sources <design-goal-generated-sources_>`__ goal would be
+unsupportable with this strategy.  CMake could defer scanning until the
+generated files are available, but those sources cannot be compiled until such
+a scan has been performed.  This would mean that there would be some unbounded
+(but finite) number of regenerations of the build graph as sources become
+available.
+
+Module Mapping Service
+^^^^^^^^^^^^^^^^^^^^^^
+
+Another strategy is to run a service alongside the build that can act as an
+oracle for where to place and discover modules.  The compiler is instructed to
+query the service with questions such as "this source is exporting module X"
+and "this source is importing module Y" and receive the path to either create
+or find the :term:`BMI`, respectively.  In this case, the service dynamically
+implements the collation logic.
+
+Of particular note, this conflicts with the
+`Deterministic Builds <design-goal-deterministic-builds_>`__ and
+`Static Communication <design-goal-static-communication_>`__ goals because the
+on-disk state may not match the actual state, and coordinating the lifetime of
+the :term:`build tool` itself with the service is difficult.  The primary
+missing feature is some signal when a build session starts and ends so that
+such a service can know in what context it is answering requests.  There also
+needs to be a way to resume a session and detect when a session is
+invalidated.  No :term:`build tool` that CMake supports today has such
+features.
+
+There are also hazards which conflict with the
+`Correct Builds <design-goal-correct-builds_>`__ goal.  When a module is
+imported, the compiler waits for a response before continuing.  However, there
+is no guarantee that a (visible) module of that name even exists, so it may
+wait indefinitely.  While waiting for a compilation to report that it creates
+that module, it may run into a dependency cycle which leaves the compilations
+hanging until some resource limit is reached (probably time, or that all
+possible providers of the module have not reported a module of that name).
+While these compilations are waiting on answers, there is the question of how
+they affect the parallelism limits of the :term:`build tool` in use.  Do
+compilations waiting on an answer count towards the limit and block other
+compilations from launching to potentially discover the module?  If they do
+not, what about other resources that may be held in use by those compilations
+(e.g., memory or available file descriptors)?
+
+Possible Future Enhancements
+============================
+
+This section documents possible future enhancements to CMake's support of C++
+modules.  Nothing here is a guarantee of future implementation, and the
+ordering is arbitrary.
+
+Batch Scanning
+--------------
+
+It is possible to scan all sources within a target at once, which should be
+faster when sources share transitive includes.  This does have side effects
+for incremental builds, as the update of any source in the target means that
+all sources in the target are scanned again.  Given how much faster scanning
+can be, it should be negligible to do such "extra" scanning assuming that
+unchanged results do not trigger recompilations.
+
+BMI Modification Optimization
+-----------------------------
+
+Currently, as with object files, compilers always update a :term:`BMI` file
+even if the contents have not changed.  Because modules increase the potential
+scope of "non-changes" to cause (conceptually) unnecessary recompilation, it
+might be useful to avoid recompilation of module consumers if the :term:`BMI`
+file has not changed.  This might be achieved by wrapping the compilation to
+juggle the :term:`BMI` through a ``cmake -E copy_if_different`` pass with
+``ninja``'s ``restat = 1`` feature to avoid recompiling importers if the
+:term:`BMI` file doesn't actually change.
+
+.. _`easier-source-specification`:
+
+Easier Source Specification
+---------------------------
+
+The initial implementation of CMake's module support had used the "just list
+sources; CMake will figure it out" pattern.  However, this ran into issues
+related to other metadata requirements.  These were discovered while
+implementing CMake support beyond just building the modules-using code.
+
+Conflicts with `Separate BMI Generation <separate-bmi-generation_>`__ on a
+single target, as that requires knowledge of all :term:`BMI`-generating rules
+at generate time.
+
+.. _`separate-bmi-generation`:
+
+Separate BMI Generation
+-----------------------
+
+CMake currently uses a single rule to generate both the :term:`BMI` and the
+object file for a compilation.  At least Clang supports compiling an object
+directly from the :term:`BMI`.  This would be beneficial because :term:`BMI`
+generation is typically faster than compilation and generating the :term:`BMI`
+as a separate step allows importers to start compiling without waiting for the
+object to also be generated.
+
+This is not supported in the current implementation as only Clang supports
+generating an object directly from the :term:`BMI`.  Other compilers either do
+not support such a two-phase generation (GCC) or need to start object
+compilation from the source again.
+
+Conflicts with `Easier Source Specification <easier-source-specification_>`__
+on a single target because CMake must know all :term:`BMI`-generating sources
+at generate time rather than build time to create the two-phase rules.
+
+Module Compilation Glossary
+===========================
+
+.. glossary::
+
+   BMI
+     Built Module Interface.  A compiler-generated binary representation of a
+     C++ module's interface that is required by consumers of the module.  File
+     extensions vary by compiler.
+
+   CMI
+     Compiled Module Interface.  Alternative name for :term:`BMI` used by some
+     compilers.
+
+   build database
+     A JSON file containing compilation commands, module dependencies, and
+     grouping information.  Used for IDE integration and build analysis.
+
+   build system
+     A tool that facilitates the building of software which includes a model
+     of how components of the build relate to each other.  For example, CMake,
+     Meson, build2, and more.
+
+   build tool
+     A build graph execution tool.  For example, `ninja` and `make`.  Some
+     build tools are also their own :term:`build system`.
+
+   C++ module
+     A C++20 language feature for describing the API of a piece of software.
+     Intended as a replacement for headers for this purpose.
+
+   collate
+     The process of aggregating module information from scanned sources to
+     ensure correct compilation order and to provide metadata for other parts
+     of the build (e.g., installation or a :term:`build database`).
+
+   discovered dependencies
+     Dependencies found during the processing of a command that do not need to
+     be explicitly declared.
+
+   dynamic dependencies
+     Dependencies which require a separate command to detect so that a further
+     command may have its dependencies satisfied.
+
+   embarrassingly parallel
+     A set of tasks which, due to having minimal dependencies between them,
+     can be easily divided into many independent tasks that can be executed
+     concurrently.
+
+   explicit build
+     A build strategy where module dependencies are explicitly specified
+     rather than discovered.
+
+   fixed build
+     A build strategy where all module dependencies are computed and inserted
+     directly into the build graph.
+
+   header unit
+     A header file which is used via an ``import`` statement rather than an
+     ``#include`` preprocessor directive.  Implementations may provide support
+     for treating ``#include`` as ``import`` as well.
+
+   implementation unit
+     A C++ :term:`translation unit` that implements module entities declared
+     in a module interface unit.
+
+   implicit build
+     A build strategy where module dependencies are discovered by searching
+     for :term:`BMI` files during compilation.
+
+   internal partition unit
+     A :term:`translation unit` which contains a partition name and is not
+     exported from the :term:`primary module interface unit`.
+
+   module interface unit
+     A :term:`translation unit` that declares a module's public interface
+     using ``export module``.  Such a unit may or may not be also be a
+     :term:`partition unit`.
+
+   module map
+     A compiler-specific file mapping module names to BMI locations.
+
+   module visibility
+     CMake's enforcement of access rules for modules based on their
+     declaration scope (PUBLIC/PRIVATE).
+
+   ODR
+     One Definition Rule.  The C++ requirement that any entity be defined
+     exactly once per program.
+
+   partition unit
+     A :term:`translation unit` which describes a module with a partition name
+     (i.e., `module MODNAME:PARTITION;`).  The partition may or may not use
+     the ``export`` keyword.  If it does, it is also a
+     :term:`module interface unit`; otherwise, it is a
+     :term:`internal partition unit`.
+
+   primary module interface unit
+     A :term:`module interface unit` which exports a named module that is not
+     a :term:`partition unit`.
+
+   scan
+     The process of analyzing a :term:`translation unit` to discover module
+     imports and exports.
+
+   static build
+     A build configuration where all compilation rules are determined at
+     generate time.
+
+   strong module ownership
+     C++ implementations have settled on a model where the module "owns" the
+     symbols declared within it.  In practice, this means that the module name
+     is included into the symbol mangling of entities declared within it.
+
+   synthetic target
+     A CMake-generated build target used to supply :term:`BMIs <BMI>` to a
+     specific user of a module-providing target.
+
+   translation unit
+     The smallest component of a compilation for a C++ program.  Generally,
+     there is one translation unit per source file.  C++ source files which do
+     not use C++ modules may be combined into a single translation unit.
diff --git a/Help/manual/cmake-developer.7.rst b/Help/manual/cmake-developer.7.rst
index 86f135d..f43b025 100644
--- a/Help/manual/cmake-developer.7.rst
+++ b/Help/manual/cmake-developer.7.rst
@@ -29,9 +29,9 @@
 .. versionadded:: 3.24
 
 The :command:`cmake_host_system_information` command offers the possibility to
-query the registry on the local computer. See
-:ref:`cmake_host_system(QUERY_WINDOWS_REGISTRY) <Query Windows registry>` for
-more information.
+query the registry on the local computer. See the
+:command:`cmake_host_system_information(QUERY WINDOWS_REGISTRY)` sub-command
+for more information.
 
 .. _`Find Using Windows Registry`:
 
diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst
index e892ed1..857d498 100644
--- a/Help/manual/cmake-file-api.7.rst
+++ b/Help/manual/cmake-file-api.7.rst
@@ -1637,6 +1637,35 @@
     available.  The value is an unsigned integer 0-based index into
     the ``backtraceGraph`` member's ``nodes`` array.
 
+``interfaceSources``
+  An optional member that is present when a target defines one or more
+  interface sources.  The value is a JSON array of entries corresponding
+  to the target's interface source files.  Each entry is a JSON object
+  with members:
+
+  ``path``
+    A string specifying the path to the source file on disk, represented
+    with forward slashes.  If the file is inside the top-level source
+    directory then the path is specified relative to that directory.
+    Otherwise the path is absolute.
+
+  ``sourceGroupIndex``
+    Optional member that is present when the source is part of a source
+    group either via the :command:`source_group` command or by default.
+    The value is an unsigned integer 0-based index into the
+    ``sourceGroups`` array.
+
+  ``isGenerated``
+    Optional member that is present with boolean value ``true`` if
+    the source is :prop_sf:`GENERATED`.
+
+  ``fileSetIndex``
+    Optional member that is present when the source is part of a file set.
+    The value is an unsigned integer 0-based index into the ``fileSets``
+    array.
+
+  This field was added in codemodel version 2.10.
+
 ``sourceGroups``
   Optional member that is present when sources are grouped together by
   the :command:`source_group` command or by default.  The value is a
@@ -1651,6 +1680,15 @@
     Each entry is an unsigned integer 0-based index into the
     main ``sources`` array for the target.
 
+  ``interfaceSourceIndexes``
+    Optional member that is present when at least one interface source file
+    is part of the source group.  The value is a JSON array listing the
+    interface sources belonging to the group.  Each entry is an unsigned
+    integer 0-based index into the main ``interfaceSources`` array for the
+    target.
+
+    This field was added in codemodel version 2.10.
+
 ``compileGroups``
   Optional member that is present when the target has sources that compile.
   The value is a JSON array of entries corresponding to groups of sources
@@ -2109,12 +2147,13 @@
 
   {
     "kind": "toolchains",
-    "version": { "major": 1, "minor": 0 },
+    "version": { "major": 1, "minor": 1 },
     "toolchains": [
       {
         "language": "C",
         "compiler": {
           "path": "/usr/bin/cc",
+          "commandFragment": "--config x86_64-linux-gnu.cfg",
           "id": "GNU",
           "version": "9.3.0",
           "implicit": {
@@ -2193,6 +2232,16 @@
       :variable:`CMAKE_<LANG>_COMPILER` variable is defined for the current
       language. Its value is a JSON string holding the path to the compiler.
 
+    ``commandFragment``
+      Optional member that is present when the
+      :variable:`CMAKE_<LANG>_COMPILER` variable is a list containing multiple
+      elements or the :envvar:`CC` or similar environment variable contains
+      command line arguments after the compiler executable.
+      Its value is a JSON string holding the second and further elements
+      (mandatory arguments to the compiler) as a command line fragment.
+
+      This field was added in toolchains version 1.1.
+
     ``id``
       Optional member that is present when the
       :variable:`CMAKE_<LANG>_COMPILER_ID` variable is defined for the current
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index d5dc281..ac25627 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -115,6 +115,17 @@
     VERBATIM
   )
 
+For tools that expect ``-I``'s value to be a separate argument, use the
+semicolon trick learned earlier:
+
+.. code-block:: cmake
+
+  add_custom_target(run_some_tool
+    COMMAND some_tool "$<LIST:TRANSFORM,$<TARGET_PROPERTY:tgt,INCLUDE_DIRECTORIES>,PREPEND,-I;>"
+    COMMAND_EXPAND_LISTS
+    VERBATIM
+  )
+
 A common mistake is to try to split a generator expression across multiple
 lines with indenting:
 
@@ -273,20 +284,8 @@
 Other more specific comparison types are documented in their own separate
 sections further below.
 
-String Comparisons
-^^^^^^^^^^^^^^^^^^
-
-.. genex:: $<STREQUAL:string1,string2>
-
-  ``1`` if ``string1`` and ``string2`` are equal, else ``0``.
-  The comparison is case-sensitive.  For a case-insensitive comparison,
-  combine with a :ref:`string transforming generator expression
-  <String Transforming Generator Expressions>`.  For example, the following
-  evaluates to ``1`` if ``${foo}`` is any of ``BAR``, ``Bar``, ``bar``, etc.
-
-  .. code-block:: cmake
-
-    $<STREQUAL:$<UPPER_CASE:${foo}>,BAR>
+Numeric Comparisons
+^^^^^^^^^^^^^^^^^^^
 
 .. genex:: $<EQUAL:value1,value2>
 
@@ -319,10 +318,401 @@
 
   ``1`` if ``v1`` is a version greater than or equal to ``v2``, else ``0``.
 
+String Expressions
+------------------
+
+Most of the expressions in this section are closely associated with the
+:command:`string` command, providing the same capabilities, but in
+the form of a generator expression.
+
+In each of the following string-related generator expressions, the ``string``
+must not contain any commas if that generator expression expects something to
+be provided after the ``string``.  For example, the expression
+``$<STRING:FIND,string,value>`` requires a ``value`` after the ``string``.
+Since a comma is used to separate the ``string`` and the ``value``, the
+``string`` cannot itself contain a comma.  This restriction does not apply to
+the :command:`string` command, it is specific to the string-handling generator
+expressions only. The :genex:`$<COMMA>` generator expression can be used to
+specify a comma as part of the arguments of the string-related generator
+expressions.
+
+.. _`String Comparisons Generator Expressions`:
+
+String Comparisons
+^^^^^^^^^^^^^^^^^^
+
+The comparisons are case-sensitive.  For a case-insensitive comparison,
+combine with a :ref:`string transforming generator expression
+<String Transforming Generator Expressions>`.  For example, the following
+evaluates to ``1`` if ``${foo}`` is any of ``BAR``, ``Bar``, ``bar``, etc.
+
+  .. code-block:: cmake
+
+    $<STREQUAL:$<STRING:TOUPPER,${foo}>,BAR>
+
+.. genex:: $<STREQUAL:string1,string2>
+
+  ``1`` if ``string1`` and ``string2`` are lexicographically equal, else ``0``.
+
+.. genex:: $<STRLESS:string1,string2>
+
+  .. versionadded:: 4.3
+
+  ``1`` if ``string1`` is lexicographically less than ``string2``, else ``0``.
+
+.. genex:: $<STRGREATER:string1,string2>
+
+  .. versionadded:: 4.3
+
+  ``1`` if ``string1`` is lexicographically greater than ``string2``, else
+  ``0``.
+
+.. genex:: $<STRLESS_EQUAL:string1,string2>
+
+  .. versionadded:: 4.3
+
+  ``1`` if ``string1`` is lexicographically less than or equal to ``string2``,
+  else ``0``.
+
+.. genex:: $<STRGREATER_EQUAL:string1,string2>
+
+  .. versionadded:: 4.3
+
+  ``1`` if ``string1`` is lexicographically greater than or equal to
+  ``string2``, else ``0``.
+
+.. _`String Queries Generator Expressions`:
+
+String Queries
+^^^^^^^^^^^^^^
+
+.. genex:: $<STRING:LENGTH,string>
+
+  .. versionadded:: 4.3
+
+  The given string's length in bytes. Note that this means, if ``string``
+  contains multi-byte characters, the result will *not* be the number of
+  characters.
+
+.. genex:: $<STRING:SUBSTRING,string,begin,length>
+
+  .. versionadded:: 4.3
+
+  The substring of the given ``string``. If ``length`` is ``-1`` or greater
+  than the ``string`` length the remainder of the string starting at ``begin``
+  will be returned.
+
+  Both ``begin`` and ``length`` are counted in bytes, so care must
+  be exercised if ``string`` could contain multi-byte characters.
+
+.. genex:: $<STRING:FIND,string[,FROM:(BEGIN|END)],substring>
+
+  .. versionadded:: 4.3
+
+  The position where the given ``substring`` was found in the supplied
+  ``string``. If the ``substring`` is not found, a position of -1 is returned.
+
+  The ``FROM:`` option defines how the search will be done:
+
+  ``BEGIN``
+    The search will start at the beginning of the ``string``. This the default.
+
+  ``END``
+    The search will start from the end of the ``string``.
+
+  The ``$<STRING:FIND>`` generator expression treats all strings as ASCII-only
+  characters. The index returned will also be counted in bytes, so strings
+  containing multi-byte characters may lead to unexpected results.
+
+.. genex:: $<STRING:MATCH,string[,SEEK:(ONCE|ALL)],regular_expression>
+
+  .. versionadded:: 4.3
+
+  Match, in the ``string``, the ``regular_expression``.
+
+  The ``SEEK:`` option specifies the match behavior:
+
+  ``ONCE``
+    Match only the first occurrence. This is the default.
+
+  ``ALL``
+    Match as many times as possible and return the matches as a list.
+
+  See the :ref:`Regular expressions specification <Regex Specification>` for
+  the syntax of the ``regular_expression`` parameter.
+
+.. _`String Generating Generator Expressions`:
+
+String Generations
+^^^^^^^^^^^^^^^^^^
+
+.. genex:: $<STRING:JOIN,glue,input[,input]...>
+
+  .. versionadded:: 4.3
+
+  Join all the ``input`` arguments together using the ``glue`` string.
+
+.. genex:: $<STRING:ASCII,number[,number]...>
+
+  .. versionadded:: 4.3
+
+  Convert all numbers, in the range 1-255, into corresponding ASCII
+  characters. Any number outside this range will raise an error.
+
+.. genex:: $<STRING:TIMESTAMP[,(UTC|format)]...>
+
+  .. versionadded:: 4.3
+
+  Produce a string representation of the current date and/or time.
+
+  If the generator expression is unable to obtain a timestamp, the result will
+  be the empty string ``""``.
+
+  The optional ``UTC`` flag requests the current date/time representation to
+  be in Coordinated Universal Time (UTC) rather than local time.
+
+  If the ``SOURCE_DATE_EPOCH`` environment variable is set, its value will be
+  used instead of the current time.
+  See https://reproducible-builds.org/specs/source-date-epoch/ for details.
+
+  The optional ``<format>`` may contain the following format specifiers:
+
+  ``%%``
+    A literal percent sign (%).
+
+  ``%d``
+    The day of the current month (01-31).
+
+  ``%H``
+    The hour on a 24-hour clock (00-23).
+
+  ``%I``
+    The hour on a 12-hour clock (01-12).
+
+  ``%j``
+    The day of the current year (001-366).
+
+  ``%m``
+    The month of the current year (01-12).
+
+  ``%b``
+    Abbreviated month name (e.g. Oct).
+
+  ``%B``
+    Full month name (e.g. October).
+
+  ``%M``
+    The minute of the current hour (00-59).
+
+  ``%s``
+    Seconds since midnight (UTC) 1-Jan-1970 (UNIX time).
+
+  ``%S``
+    The second of the current minute.  60 represents a leap second. (00-60)
+
+  ``%f``
+    The microsecond of the current second (000000-999999).
+
+  ``%U``
+    The week number of the current year (00-53).
+
+  ``%V``
+    The ISO 8601 week number of the current year (01-53).
+
+  ``%w``
+    The day of the current week. 0 is Sunday. (0-6)
+
+  ``%a``
+    Abbreviated weekday name (e.g. Fri).
+
+  ``%A``
+    Full weekday name (e.g. Friday).
+
+  ``%y``
+    The last two digits of the current year (00-99).
+
+  ``%Y``
+    The current year.
+
+  ``%z``
+    The offset of the time zone from UTC, in hours and minutes,
+    with format ``+hhmm`` or ``-hhmm``.
+
+  ``%Z``
+    The time zone name.
+
+  Unknown format specifiers will be ignored and copied to the output
+  as-is.
+
+  If no explicit ``format`` is given, it will default to:
+
+  * ``%Y-%m-%dT%H:%M:%S`` for local time.
+  * ``%Y-%m-%dT%H:%M:%SZ`` for UTC.
+
+.. genex:: $<STRING:RANDOM[,(LENGTH:length|ALPHABET:alphabet|RANDOM_SEED:seed)]...>
+
+  .. versionadded:: 4.3
+
+  Produce a random string of ASCII characters. The possible options are:
+
+  ``LENGTH:length``
+    Define the length of the string. The default length is 5 characters.
+
+  ``ALPHABET:alphabet``
+    Define the characters used for the generation. The alphabet is always
+    interpreted as holding ASCII characters. The default alphabet is all
+    numbers and upper and lower case letters.
+
+  ``RANDOM_SEED:seed``
+    Specify an integer which will be used to seed the random number generator.
+
+.. genex:: $<STRING:UUID,NAMESPACE:namespace,TYPE:(MD5|SHA1)[,NAME:name][,CASE:(LOWER|UPPER)]>
+
+  .. versionadded:: 4.3
+
+  Create a universally unique identifier (aka GUID) as per RFC4122.
+  A UUID has the format ``xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx``
+  where each ``x`` represents an hexadecimal character.
+
+  The UUID is based on the hash of the combined values of:
+
+  ``NAMESPACE:namespace``
+    ``namespace`` which has to be a valid UUID.
+
+  ``NAME:name``
+    ``name`` is an arbitrary string.
+
+  ``TYPE:``
+    The hash algorithm can be either:
+
+    ``MD5``
+      Version 3 UUID.
+
+    ``SHA1``
+      Version 5 UUID.
+
+  ``CASE:``
+    Specify the case of the hexadecimal characters.
+
+    ``LOWER``
+      Hexadecimal characters are all of lowercase. This is the default.
+
+    ``UPPER``
+      Hexadecimal characters are all of uppercase.
+
 .. _`String Transforming Generator Expressions`:
 
 String Transformations
-----------------------
+^^^^^^^^^^^^^^^^^^^^^^
+
+.. genex:: $<STRING:REPLACE[,(STRING|REGEX)],string,match_string,replace_string>
+
+  .. versionadded:: 4.3
+
+  Replace all occurrences of ``match_string`` in the ``string`` with
+  ``replace_string``.
+
+  The ``match_string`` can be of two different types:
+
+  ``STRING``
+    ``match_string`` is a literal string and match will be done by simple
+    string comparison. This is the default.
+
+  ``REGEX``
+    ``match_string`` is a regular expression. Match this regular_expression as
+    many times as possible and substitute the ``replace_string`` for the match
+    in the ``string``.
+
+    The ``replace_string`` may refer to parenthesis-delimited subexpressions of
+    the match using \\1, \\2, ..., \\9. Note that two backslashes (\\\\1) are
+    required in CMake code to get a backslash through argument parsing.
+
+.. genex:: $<STRING:APPEND,string,input[,input]...>
+
+  .. versionadded:: 4.3
+
+  Append all the ``input`` arguments to the ``string``.
+
+.. genex:: $<STRING:PREPEND,string,input[,input]...>
+
+  .. versionadded:: 4.3
+
+  Prepend all the ``input`` arguments to the ``string``.
+
+.. genex:: $<STRING:TOLOWER,string>
+
+  .. versionadded:: 4.3
+
+  Content of ``string`` converted to lower case.
+
+.. genex:: $<STRING:TOUPPER,string>
+
+  .. versionadded:: 4.3
+
+  Content of ``string`` converted to upper case.
+
+.. genex:: $<STRING:STRIP,SPACES,string>
+
+  .. versionadded:: 4.3
+
+  Remove the specified elements from the ``string``. The possible options are:
+
+  ``SPACES``
+    Remove the leading and trailing spaces of the ``string``.
+
+.. genex:: $<STRING:QUOTE,REGEX,string>
+
+  .. versionadded:: 4.3
+
+  Escape the specified elements of the ``string``. The possible options are:
+
+  ``REGEX``
+    Escape all characters that have special meaning in a regular expressions,
+    such that the ``string`` can be used as part of a regular expression to
+    match the input literally.
+
+.. genex:: $<STRING:HEX,string>
+
+  .. versionadded:: 4.3
+
+  Convert each byte in the ``string`` to its hexadecimal representation.
+  Letters in the result (a through f) are in lowercase.
+
+.. genex:: $<STRING:HASH,string,ALGORITHM:algorithm>
+
+  .. versionadded:: 4.3
+
+  Compute a cryptographic hash of the ``string``. The supported algorithm
+  names, as specified by the ``ALGORITHM:`` option are:
+
+  ``MD5``
+    Message-Digest Algorithm 5, RFC 1321.
+  ``SHA1``
+    US Secure Hash Algorithm 1, RFC 3174.
+  ``SHA224``
+    US Secure Hash Algorithms, RFC 4634.
+  ``SHA256``
+    US Secure Hash Algorithms, RFC 4634.
+  ``SHA384``
+    US Secure Hash Algorithms, RFC 4634.
+  ``SHA512``
+    US Secure Hash Algorithms, RFC 4634.
+  ``SHA3_224``
+    Keccak SHA-3.
+  ``SHA3_256``
+    Keccak SHA-3.
+  ``SHA3_384``
+    Keccak SHA-3.
+  ``SHA3_512``
+    Keccak SHA-3.
+
+.. genex:: $<STRING:MAKE_C_IDENTIFIER,string>
+
+  .. versionadded:: 4.3
+
+  Convert each non-alphanumeric character in the ``string`` to an underscore.
+  If the first character of the ``string`` is a digit, an underscore will also
+  be prepended.
 
 .. genex:: $<LOWER_CASE:string>
 
@@ -332,10 +722,10 @@
 
   Content of ``string`` converted to upper case.
 
-.. genex:: $<MAKE_C_IDENTIFIER:...>
+.. genex:: $<MAKE_C_IDENTIFIER:string>
 
-  Content of ``...`` converted to a C identifier.  The conversion follows the
-  same behavior as :command:`string(MAKE_C_IDENTIFIER)`.
+  Content of ``string`` converted to a C identifier.  The conversion follows
+  the same behavior as :command:`string(MAKE_C_IDENTIFIER)`.
 
 List Expressions
 ----------------
@@ -568,9 +958,9 @@
 
   Joins the ``list`` with the content of the ``glue`` string inserted between
   each item.  This is conceptually the same operation as
-  :ref:`$\<LIST:JOIN,list,glue\> <GenEx LIST-JOIN>`, but the two have
+  :cref:`$\<LIST:JOIN,list,glue\> <GenEx LIST-JOIN>`, but the two have
   different behavior with regard to empty items.
-  :ref:`$\<LIST:JOIN,list,glue\> <GenEx LIST-JOIN>` preserves all empty items,
+  :cref:`$\<LIST:JOIN,list,glue\> <GenEx LIST-JOIN>` preserves all empty items,
   whereas ``$<JOIN:list,glue>`` drops all empty items from the list.
 
 .. genex:: $<REMOVE_DUPLICATES:list>
@@ -580,7 +970,7 @@
   Removes duplicated items in the given ``list``. The relative order of items
   is preserved, and if duplicates are encountered, only the first instance is
   retained.  The result is the same as
-  :ref:`$\<LIST:REMOVE_DUPLICATES,list\> <GenEx LIST-REMOVE_DUPLICATES>`.
+  :cref:`$\<LIST:REMOVE_DUPLICATES,list\> <GenEx LIST-REMOVE_DUPLICATES>`.
 
 .. genex:: $<FILTER:list,INCLUDE|EXCLUDE,regex>
 
@@ -588,7 +978,7 @@
 
   Includes or removes items from ``list`` that match the regular expression
   ``regex``.  The result is the same as
-  :ref:`$\<LIST:FILTER,list,INCLUDE|EXCLUDE,regex\> <GenEx LIST-FILTER>`.
+  :cref:`$\<LIST:FILTER,list,INCLUDE|EXCLUDE,regex\> <GenEx LIST-FILTER>`.
 
 .. _GenEx List Ordering:
 
@@ -660,7 +1050,7 @@
 the form of a generator expression.
 
 For all generator expressions in this section, paths are expected to be in
-cmake-style format. The :ref:`$\<PATH:CMAKE_PATH\> <GenEx PATH-CMAKE_PATH>`
+cmake-style format. The :cref:`$\<PATH:CMAKE_PATH\> <GenEx PATH-CMAKE_PATH>`
 generator expression can be used to convert a native path to a cmake-style
 one.
 
@@ -2032,6 +2422,135 @@
   any one of the entries in ``variant_ids``, otherwise ``0``.
 
 
+.. _`Source-Dependent Expressions`:
+
+Source-Dependent Expressions
+----------------------------
+
+The source file, as specified in the following expressions, can be nonexistent
+on the file system (i.e. generated file) but must be known from CMake. A source
+file becomes known from CMake if it is part of some target (library or
+executable) or when a source file property is defined. Moreover, this
+information is specific to the directory where the declaration occurred.
+
+For example, these generator expressions enable to offer a uniform behavior,
+for the :command:`add_custom_command` and :command:`add_custom_target`
+commands, regarding the source properties:
+
+.. code-block:: cmake
+
+  function(custom_add_library target)
+    unset(sources)
+    foreach(source IN LISTS ARGN)
+      add_custom_command(
+        OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${source}.bin
+        COMMAND my-compiler -o ${CMAKE_CURRENT_BINARY_DIR}/${source}.bin
+                            "$<$<SOURCE_EXISTS:${source}>:$<SOURCE_PROPERTY:${source},COMPILE_OPTIONS>>"
+                            ${source})
+      list(APPEND sources ${CMAKE_CURRENT_BINARY_DIR}/${source}.bin)
+    endforeach()
+    add_custom_target(${target}
+                      DEPENDS ${sources})
+  endfunction()
+
+  custom_add_library(my-lib file1.x file2.x file3.x)
+  set_property(SOURCE file1.x PROPERTY COMPILE_OPTIONS -X)
+  set_property(SOURCE file2.x PROPERTY COMPILE_OPTIONS -Y)
+
+Source Meta-Data
+^^^^^^^^^^^^^^^^
+
+These expressions look up information about a source file.
+
+.. genex:: $<SOURCE_EXISTS:src[,(DIRECTORY:dir|TARGET_DIRECTORY:tgt)]>
+
+  .. versionadded:: 4.3
+
+  ``1`` if ``src`` exists as a CMake source file, else ``0``. By default, the
+  source file is searched in the scope of the current source directory or the
+  directory of the consuming target.
+
+  Directory scope can be overridden with one of the following sub-options:
+
+  ``DIRECTORY:dir``
+    The source file will be searched in the ``dir`` directory's scope.
+    CMake must know about the directory, either by having added  it through a
+    call to :command:`add_subdirectory` or ``dir`` being the top level
+    directory. Relative paths are treated as relative to the current source
+    directory.
+
+  ``TARGET_DIRECTORY:target``
+      The source file will be searched in the directory scope in which
+      ``target`` was created (``target`` must therefore exist).
+
+Source Properties
+^^^^^^^^^^^^^^^^^
+
+These expressions look up the values of
+:ref:`source file properties <Source File Properties>`.
+
+.. genex:: $<SOURCE_PROPERTY:src[,(DIRECTORY:dir|TARGET_DIRECTORY:target)],prop>
+
+  .. versionadded:: 4.3
+
+  Value of the property ``prop`` on the source file ``src``, or empty if
+  the property is not set. An error will be raised if the source file is not
+  known by CMake. By default, the source file's property will be read from the
+  current source directory's scope or the directory of the consuming target.
+
+  Directory scope can be overridden with one of the following sub-options:
+
+  ``DIRECTORY:dir``
+    The source file property will be read from the ``dir`` directory's scope.
+    CMake must know about the directory, either by having added  it through a
+    call to :command:`add_subdirectory` or ``dir`` being the top level
+    directory. Relative paths are treated as relative to the current source
+    directory.
+
+  ``TARGET_DIRECTORY:target``
+      The source file property will be read from the directory scope in which
+      ``target`` was created (``target`` must therefore exist).
+
+.. _`FileSet-Dependent Expressions`:
+
+FileSet-Dependent Expressions
+-----------------------------
+
+FileSet Meta-Data
+^^^^^^^^^^^^^^^^^
+
+These expressions look up information about a file set.
+
+.. genex:: $<FILE_SET_EXISTS:fileset,TARGET:target>
+
+  .. versionadded:: 4.3
+
+  ``1`` if the ``fileset`` exists as a CMake file set attached to the
+  ``target``, else ``0``.
+
+  The possible sub-options are:
+
+  ``TARGET:target``
+    The target on which the file set depends.
+
+FileSet Properties
+^^^^^^^^^^^^^^^^^^
+
+These expressions look up the values of file set properties.
+
+.. genex:: $<FILE_SET_PROPERTY:fileset,TARGET:target,prop>
+
+  .. versionadded:: 4.3
+
+  Value of the property ``prop`` on the file set ``fileset``, or empty if
+  the property is not set. An error will be raised if the file set is not
+  known by CMake.
+
+  The possible sub-options are:
+
+  ``TARGET:target``
+    The target on which the file set depends.
+
 .. _`Target-Dependent Expressions`:
 
 Target-Dependent Expressions
diff --git a/Help/manual/cmake-instrumentation.7.rst b/Help/manual/cmake-instrumentation.7.rst
index 967b5a2..582adf8 100644
--- a/Help/manual/cmake-instrumentation.7.rst
+++ b/Help/manual/cmake-instrumentation.7.rst
@@ -3,7 +3,7 @@
 cmake-instrumentation(7)
 ************************
 
-.. versionadded:: 4.0
+.. versionadded:: 4.3
 
 .. only:: html
 
@@ -12,75 +12,107 @@
 Introduction
 ============
 
-.. note::
-
-   This feature is only available when experimental support for instrumentation
-   has been enabled by the ``CMAKE_EXPERIMENTAL_INSTRUMENTATION`` gate.
-
 The CMake Instrumentation API allows for the collection of timing data, target
 information and system diagnostic information during the configure, generate,
 build, test and install steps for a CMake project.
 
-This feature is only available for projects using the
-:ref:`Makefile Generators`, :ref:`Ninja Generators` or :generator:`FASTBuild`.
-
 All interactions with the CMake instrumentation API must specify both an API
 version and a Data version. At this time, there is only one version for each of
 these: the `API v1`_ and `Data v1`_.
 
+.. note::
+
+  This feature is only available for projects using the
+  :ref:`Makefile Generators`, :ref:`Ninja Generators` or :generator:`FASTBuild`.
+
+Overview
+--------
+
+CMake Instrumentation works in 2 major stages: `Data Collection`_, and
+`Indexing`_.
+
+`Data Collection`_ is the process by which CMake writes out instrumentation
+data into a project build tree. The commands instrumented in this way range
+from overall builds, to individual compile commands. The full list of commands
+instrumented is documented under the `v1 Snippet File`_.
+
+Collected data will accumulate until `Indexing`_ occurs: the process of
+collating the generated data. Indexing occurs on events called "hooks",
+which can be configured as part of the `v1 Query Files`_. A `v1 Index File`_ is
+created and passed to any user-defined `Callbacks`_ provided to process
+the data. Once all `Callbacks`_ have run, CMake deletes the files.
+
+Without the need for any custom `Callbacks`_, CMake can submit instrumentation
+data to `CDash`_, or generate a `Google Trace File`_ for visualization.
+
 Data Collection
 ---------------
 
-Whenever a command is executed with
-instrumentation enabled, a `v1 Snippet File`_ is created in the project build
-tree with data specific to that command. These files remain until after
-`Indexing`_ occurs.
+Whenever a command is executed with instrumentation enabled, a
+`v1 Snippet File`_ is created in the project build tree with data specific to
+that command. These files remain until after `Indexing`_ occurs.
 
 CMake sets the :prop_gbl:`RULE_LAUNCH_COMPILE`, :prop_gbl:`RULE_LAUNCH_LINK`
-and :prop_gbl:`RULE_LAUNCH_CUSTOM` global properties to use the
-``ctest --instrument`` launcher in order to capture details of each compile,
-link, and custom command respectively. If the project has been configured with
-:module:`CTestUseLaunchers`, ``ctest --instrument`` will also include the
-behavior usually performed by ``ctest --launch``.
+and :prop_gbl:`RULE_LAUNCH_CUSTOM` global properties to wrap each compile, link
+and custom command invocation in a launcher that performs instrumentation and
+writes out a `v1 Snippet File`_. If the project has been configured with
+:module:`CTestUseLaunchers`, the launcher will collect instrumentation data in
+addition to performing the communication typically handled by that module.
+
+.. _`cmake-instrumentation Indexing`:
 
 Indexing
 --------
 
-Indexing is the process of collating generated instrumentation data. Indexing
-occurs at specific intervals called hooks, such as after every build. These
-hooks are configured as part of the `v1 Query Files`_. Whenever a hook is
-triggered, an index file is generated containing a list of snippet files newer
-than the previous indexing.
+Indexing is the process of collating generated instrumentation data. The
+available hooks to trigger indexing include options such as after every build,
+or every :manual:`ctest <ctest(1)>` invocation, and are configured as part of
+the `v1 Query Files`_. Whenever a hook is triggered, an index file is generated
+containing a list of snippet files newer than the previous indexing. This index
+file is passed to user-defined `Callbacks`_ commands to process the data.
 
 Indexing and can also be performed by manually invoking
-``ctest --collect-instrumentation <build>``.
+:option:`ctest --collect-instrumentation`.
+
+Indexing, and the subsequent callbacks, will not occur concurrently in a
+single build tree. When multiple hooks trigger indexing at the same time,
+a file-based lock is used to ensure one indexing completes, executes all of its
+callbacks, and deletes the instrumentation data before the next indexing can
+begin.
+
+.. _`cmake-instrumentation Callbacks`:
 
 Callbacks
----------
+^^^^^^^^^
 
 As part of the `v1 Query Files`_, users can provide a list of callbacks
 intended to handle data collected by this feature.
 
 Whenever `Indexing`_ occurs, each provided callback is executed, passing the
-path to the generated index file as an argument.
+path to the generated `v1 Index File`_ as an additional argument.
 
-These callbacks, defined either at the user-level or project-level should read
+These callbacks, defined either at the user-level or project-level, should read
 the instrumentation data and perform any desired handling of it. The index file
 and its listed snippets are automatically deleted by CMake once all callbacks
 have completed. Note that a callback should never move or delete these data
 files manually as they may be needed by other callbacks.
 
+If indexing is triggered again before `Callbacks`_ have finished running,
+the generated index file will contain only instrumentation data generated since
+the previous indexing.
+
 Enabling Instrumentation
 ========================
 
 Instrumentation can be enabled either for an individual CMake project, or
-for all CMake projects configured and built by a user. For both cases,
-see the `v1 Query Files`_ for details on configuring this feature.
+for all CMake projects configured and built by a user. In all cases, a "query"
+represents a request for instrumentation behavior. See the `v1 Query Files`_
+for details on configuring this feature.
 
 Enabling Instrumentation at the Project-Level
 ---------------------------------------------
 
-Project code can contain instrumentation queries with the
+Project code can contain instrumentation queries by using the
 :command:`cmake_instrumentation` command.
 
 In addition, query files can be placed manually under
@@ -94,12 +126,15 @@
 the :envvar:`CMAKE_CONFIG_DIR` under
 ``<config_dir>/instrumentation/<version>/query/``.
 
+.. _`CDash`:
+
 Enabling Instrumentation for CDash Submissions
 ----------------------------------------------
 
-You can enable instrumentation when using CTest in :ref:`Dashboard Client`
-mode by setting the :envvar:`CTEST_USE_INSTRUMENTATION` environment variable.
-Doing so automatically enables the ``dynamicSystemInformation`` option.
+You can enable instrumentation when using :module:`CTest` in
+:ref:`Dashboard Client` mode by setting the :envvar:`CTEST_USE_INSTRUMENTATION`
+environment variable. Doing so automatically enables the
+``dynamicSystemInformation`` option.
 
 The following table shows how each type of instrumented command gets mapped
 to a corresponding type of CTest XML file.
@@ -155,7 +190,8 @@
   Holds query files generated by a CMake project with the
   :command:`cmake_instrumentation` command or the
   :envvar:`CTEST_USE_INSTRUMENTATION` variable. These files are owned by CMake
-  and are deleted and regenerated automatically during the CMake configure step.
+  and are deleted and regenerated automatically during the CMake configure
+  step.
 
 ``data/``
   Holds instrumentation data collected on the project. CMake owns all data
@@ -209,15 +245,16 @@
   * ``postGenerate``
   * ``preBuild`` (called when ``ninja``  or ``make`` is invoked)
   * ``postBuild`` (called when ``ninja`` or ``make`` completes)
-  * ``preCMakeBuild`` (called when ``cmake --build`` is invoked)
-  * ``postCMakeBuild`` (called when ``cmake --build`` completes)
+  * ``preCMakeBuild`` (called when :option:`cmake --build` is invoked)
+  * ``postCMakeBuild`` (called when :option:`cmake --build` completes)
   * ``postCMakeInstall``
+  * ``postCMakeWorkflow``
   * ``postCTest``
 
   ``preBuild`` and ``postBuild`` are not supported when using the
   :generator:`MSYS Makefiles` or :generator:`FASTBuild` generators.
   Additionally, they will not be triggered when the build tool is invoked by
-  ``cmake --build``.
+  :option:`cmake --build`.
 
 ``options``
   A list of strings used to enable certain optional behavior, including the
@@ -236,15 +273,15 @@
       after the command is executed.
 
     ``cdashSubmit``
-      Enables including instrumentation data in CDash. This does not
-      automatically enable ``dynamicSystemInformation``, but is otherwise
+      Enables including instrumentation data in CDash. This is
       equivalent to having the :envvar:`CTEST_USE_INSTRUMENTATION` environment
       variable enabled.
 
     ``cdashVerbose``
       Enables including the full untruncated commands in data submitted to
       CDash. Equivalent to having the
-      :envvar:`CTEST_USE_VERBOSE_INSTRUMENTATION` environment variable enabled.
+      :envvar:`CTEST_USE_VERBOSE_INSTRUMENTATION` and
+      :envvar:`CTEST_USE_INSTRUMENTATION` environment variables enabled.
 
     ``trace``
       Enables generation of a `Google Trace File`_ during `Indexing`_ to
@@ -260,6 +297,9 @@
 handle the presence of this optional data, since it may be requested by an
 unrelated query.
 
+The JSON format is described in machine-readable form by
+:download:`this JSON schema </manual/instrumentation/query-v1-schema.json>`.
+
 Example:
 
 .. code-block:: json
@@ -282,20 +322,21 @@
     ]
   }
 
-In this example, after every ``cmake --build`` or ``cmake --install``
-invocation, an index file ``index-<timestamp>.json`` will be generated in
-``<build>/.cmake/instrumentation/v1/data/index`` containing a list of data
-snippet files created since the previous indexing. The commands
-``/usr/bin/python callback.py index-<timestamp>.json`` and
-``/usr/bin/cmake -P callback.cmake arg index-<timestamp>.json`` will be executed
-in that order. The index file will contain the ``staticSystemInformation`` data
-and each snippet file listed in the index will contain the
-``dynamicSystemInformation`` data. Additionally, the index file will contain
-the path to the generated `Google Trace File`_. Once both callbacks have completed,
-the index file and data files listed by it (including snippet files, but not
-the trace file) will be deleted from the project build tree. The instrumentation
-data will be present in the XML files submitted to CDash, but with truncated
-command strings because ``cdashVerbose`` was not enabled.
+In this example, after every :option:`cmake --build` or
+:option:`cmake --install` invocation, an index file ``index-<timestamp>.json``
+will be generated in ``<build>/.cmake/instrumentation/v1/data/index``
+containing a list of data snippet files created since the previous indexing.
+The commands ``/usr/bin/python callback.py index-<timestamp>.json`` and
+``/usr/bin/cmake -P callback.cmake arg index-<timestamp>.json`` will be
+executed in that order. The index file will contain the
+``staticSystemInformation`` data and each snippet file listed in the index will
+contain the ``dynamicSystemInformation`` data. Additionally, the index file
+will contain the path to the generated `Google Trace File`_. Once both
+callbacks have completed, the index file and data files listed by it (including
+snippet files, but not the trace file) will be deleted from the project build
+tree. The instrumentation data will be present in the XML files submitted to
+CDash, but with truncated command strings because ``cdashVerbose`` was not
+enabled.
 
 .. _`cmake-instrumentation Data v1`:
 
@@ -317,21 +358,32 @@
 ---------------
 
 Snippet files are generated for every compile, link and custom command invoked
-as part of the CMake build or install step and contain instrumentation data about
-the command executed. Additionally, snippet files are created for the following:
+as part of the CMake build or install step and contain instrumentation data
+about the command executed. Additionally, snippet files are created for the
+following:
 
 * The CMake configure step
 * The CMake generate step
-* Entire build step (executed with ``cmake --build``)
-* Entire install step (executed with ``cmake --install``)
-* Each ``ctest`` invocation
-* Each individual test executed by ``ctest``.
+* Entire build step (executed with :option:`cmake --build`)
+* Entire install step (executed with :option:`cmake --install`)
+* Each time :manual:`ctest <ctest(1)>` is invoked to
+  :ref:`run tests <Run Tests>` (even if no tests are found)
+* Each individual test executed by :manual:`ctest <ctest(1)>`
 
 These files remain in the build tree until after `Indexing`_ occurs and any
 user-specified `Callbacks`_ are executed.
 
-Snippet files have a filename with the syntax ``<role>-<hash>-<timestamp>.json``
-and contain the following data:
+.. note::
+
+  Configure and generate snippet files are not written by CMake until the
+  generate step is complete. When using :manual:`cmake-gui(1)` or
+  :manual:`ccmake(1)`, triggering only configure step(s) without generating the
+  project files will not generate any configure snippets. Once the generate
+  step is run, there will be one configure snippet for each time the configure
+  step was run.
+
+Snippet files have a filename with the syntax
+``<role>-<hash>-<timestamp>.json`` and contain the following data:
 
   ``version``
     The Data version of the snippet file, an integer. Currently the version is
@@ -356,17 +408,19 @@
     * ``link``: an individual link step invoked during the build
     * ``custom``: an individual custom command invoked during the build
     * ``build``: a complete ``make`` or ``ninja`` invocation
-      (not through ``cmake --build``).
-    * ``cmakeBuild``: a complete ``cmake --build`` invocation
-    * ``cmakeInstall``: a complete ``cmake --install`` invocation
+      (not through :option:`cmake --build`).
+    * ``cmakeBuild``: a complete :option:`cmake --build` invocation
+    * ``cmakeInstall``: a complete :option:`cmake --install` invocation
     * ``install``: an individual ``cmake -P cmake_install.cmake`` invocation
-    * ``ctest``: a complete ``ctest`` invocation
-    * ``test``: a single test executed by CTest
+    * ``ctest``: a complete :manual:`ctest <ctest(1)>` command invocation
+    * ``test``: a single test executed by :manual:`ctest <ctest(1)>`
 
   ``target``
-    The CMake target associated with the command. Only included when ``role`` is
-    ``compile`` or ``link``. In conjunction with ``cmakeContent``, this can
-    be used to look up the target type and labels.
+    The CMake target associated with the command. Only included when ``role``
+    is ``compile`` or ``link``, or when ``role`` is ``custom`` and the custom
+    command is attached to a target with :command:`add_custom_command(TARGET)`.
+    In conjunction with ``cmakeContent``, this can be used to look up the
+    target :prop_tgt:`TYPE` and :prop_tgt:`LABELS`.
 
   ``timeStart``
     Time at which the command started, expressed as the number of milliseconds
@@ -388,16 +442,17 @@
     The source file being compiled. Only included when ``role`` is ``compile``.
 
   ``language``
-    The language of the source file being compiled. Only included when ``role`` is
-    ``compile`` or ``link``.
+    The language of the source file being compiled. Only included when ``role``
+    is ``compile`` or ``link``.
 
   ``testName``
-    The name of the test being executed. Only included when ``role`` is ``test``.
+    The name of the test being executed. Only included when ``role`` is
+    ``test``.
 
   ``config``
-    The type of build, such as ``Release`` or ``Debug``. Only included when
-    ``role`` is one of: ``compile``, ``link``, ``custom``, ``install``,
-    ``test``.
+    The :ref:`Build Configuration <Build Configurations>`, such as ``Release``
+    or ``Debug``. Only included when ``role`` is one of: ``compile``, ``link``,
+    ``custom``, ``install``, ``test``.
 
   ``dynamicSystemInformation``
     Specifies the dynamic information collected about the host machine
@@ -416,17 +471,20 @@
       determined.
 
     ``afterCPULoadAverage``
-      The Average CPU Load at ``timeStart + duration``, or ``null`` if it cannot
-      be determined.
+      The Average CPU Load at ``timeStart + duration``, or ``null`` if it
+      cannot be determined.
 
   ``cmakeContent``
     The path to a `v1 CMake Content File`_ located under ``data``, which
     contains information about the CMake configure and generate steps
-    responsible for generating the ``command`` in this snippet.
+    responsible for generating the ``command`` in this snippet. When using
+    :manual:`cmake-gui(1)` or :manual:`ccmake(1)`, this field may be ``null``
+    for all configure steps up to the most recent one before the generate step.
 
   ``showOnly``
-    A boolean representing whether the ``--show-only`` option was passed to
-    ``ctest``. Only included when ``role`` is ``ctest``.
+    A boolean representing whether the
+    :option:`--show-only <ctest --show-only>` option was passed to
+    :manual:`ctest <ctest(1)>`. Only included when ``role`` is ``ctest``.
 
 Example:
 
@@ -436,7 +494,7 @@
     "version": 1,
     "command" : "\"/usr/bin/c++\" \"-MD\" \"-MT\" \"CMakeFiles/main.dir/main.cxx.o\" \"-MF\" \"CMakeFiles/main.dir/main.cxx.o.d\" \"-o\" \"CMakeFiles/main.dir/main.cxx.o\" \"-c\" \"<src>/main.cxx\"",
     "role" : "compile",
-    "return" : 1,
+    "result" : 1,
     "target": "main",
     "language" : "C++",
     "outputs" : [ "CMakeFiles/main.dir/main.cxx.o" ],
@@ -475,23 +533,35 @@
 
 ``hook``
   The name of the hook responsible for generating the index file. In addition
-  to the hooks that can be specified by one of the `v1 Query Files`_, this value may
-  be set to ``manual`` if indexing is performed by invoking
-  ``ctest --collect-instrumentation <build>``.
+  to the hooks that can be specified by one of the `v1 Query Files`_, this
+  value may be set to ``manual`` if indexing is performed by invoking
+  :option:`ctest --collect-instrumentation`.
+
+  Note that the hook is not directly tied to what data may be available.
+  A ``postBuild`` hook, for example, may include ``test`` or ``install``
+  snippets, if these steps were run since the previous indexing.
 
 ``snippets``
   Contains a list of `v1 Snippet Files <v1 Snippet File_>`_. This includes all
   snippet files generated since the previous index file was created. The file
   paths are relative to ``dataDir``.
 
-``trace``:
+  This list may be empty if indexing was run twice in succession, such as when
+  building multiple times with both the ``preBuild`` and ``postBuild`` hooks
+  enabled.
+
+``trace``
   Contains the path to the `Google Trace File`_. This includes data from all
   corresponding ``snippets`` in the index file. The file path is relative to
   ``dataDir``. Only included when enabled by the `v1 Query Files`_.
 
 ``staticSystemInformation``
   Specifies the static information collected about the host machine
-  CMake is being run from. Only included when enabled by the `v1 Query Files`_.
+  CMake is being run from. If CMake is unable to determine the value of any
+  given field, it will be ``null``. See :command:`cmake_host_system_information`
+  for a description of each of the following fields.
+
+  Only included when enabled by the `v1 Query Files`_.
 
   * ``OSName``
   * ``OSPlatform``
@@ -501,6 +571,7 @@
   * ``hostname``
   * ``is64Bits``
   * ``modelId``
+  * ``modelName``
   * ``numberOfLogicalCPU``
   * ``numberOfPhysicalCPU``
   * ``processorAPICID``
@@ -546,29 +617,42 @@
 
 Each CMake content file contains the following:
 
+  ``project``
+    The value of :variable:`CMAKE_PROJECT_NAME`.
+
   ``custom``
     An object containing arbitrary JSON data specified by the user with the
     :ref:`cmake_instrumentation CUSTOM_CONTENT` functionality of the
     :command:`cmake_instrumentation` command.
 
   ``targets``
-    An object containing CMake targets, indexed by name, that have corresponding
-    instrumentation data. Each target contains the following:
+    An object containing CMake targets, indexed by name, that have
+    corresponding instrumentation data. Each target contains the following:
 
     ``type``
-      The target type. One of ``EXECUTABLE``, ``STATIC_LIBRARY``,
-      ``SHARED_LIBRARY`` or ``OBJECT_LIBRARY``.
+      The :prop_tgt:`TYPE` property of the target. Only ``EXECUTABLE``,
+      ``STATIC_LIBRARY``, ``SHARED_LIBRARY``, ``MODULE_LIBRARY`` and
+      ``OBJECT_LIBRARY`` targets are included.
 
     ``labels``
       The :prop_tgt:`LABELS` property of the target.
 
+.. _`cmake-instrumentation Google Trace File`:
+
 Google Trace File
 -----------------
 
-Trace files follow the `Google Trace Event Format`_. They include data from
-all `v1 Snippet Files <v1 Snippet File_>`_ listed in the current index file.
-These files remain in the build tree even after `Indexing`_ occurs and all
-`Callbacks`_ are executed, until the next time `Indexing`_ occurs.
+CMake can generate a file in the `Google Trace Event Format`_ to help visualize
+collected instrumentation data. Enabling the ``trace`` option in the
+`v1 Query Files`_ causes such a file to be generated under
+``<build>/.cmake/instrumentation/v1/data/trace`` whenever `Indexing`_ occurs.
+
+Generated trace files include data from all
+`v1 Snippet Files <v1 Snippet File_>`_ listed in the current index file.
+
+When instrumentation data is deleted by CMake after `Indexing`_, the most
+recent trace file remains so that it can be manually inspected without the need
+for any custom `Callbacks`_.
 
 Trace files are stored in the ``JSON Array Format``, where each
 `v1 Snippet File`_ corresponds to a single trace event object. Each trace
@@ -581,7 +665,7 @@
   The ``role`` from the `v1 Snippet File`_.
 
 ``ph``
-  Currently, always ``"X"`` to represent ``Complete Events``.
+  Currently, always ``"X"`` to represent "Complete Events".
 
 ``ts``
   The ``timeStart`` from the `v1 Snippet File`_, converted from milliseconds to
@@ -601,6 +685,7 @@
   order to produce a more useful visualization of the process concurrency.
 
 ``args``
-  Contains all data from the `v1 Snippet File`_ corresponding to this trace event.
+  Contains all data from the `v1 Snippet File`_ corresponding to this trace
+  event.
 
 .. _`Google Trace Event Format`: https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
diff --git a/Help/manual/cmake-language.7.rst b/Help/manual/cmake-language.7.rst
index 908c46c..777ef0b 100644
--- a/Help/manual/cmake-language.7.rst
+++ b/Help/manual/cmake-language.7.rst
@@ -78,6 +78,11 @@
 
 .. _Byte-Order Mark: https://en.wikipedia.org/wiki/Byte_order_mark
 
+.. versionadded:: 4.3
+
+  The :command:`cmake_host_system_information` command's ``LOCALE_CHARSET``
+  query returns the expected character set encoding.
+
 Source Files
 ------------
 
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index 51a3197..c6bdacb 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -7,6 +7,8 @@
 
    .. contents::
 
+.. _cmake-policies-intro:
+
 Introduction
 ============
 
@@ -34,10 +36,10 @@
 
 .. code-block:: cmake
 
-  cmake_minimum_required(VERSION 3.10...4.1)
+  cmake_minimum_required(VERSION 3.10...4.2)
 
-This uses the ``<min>...<max>`` syntax to enable the ``NEW`` behaviors
-of policies introduced in CMake 4.1 and earlier while only requiring a
+This uses the ``<min>...<policy_max>`` syntax to enable the ``NEW`` behaviors
+of policies introduced in CMake 4.2 and earlier while only requiring a
 minimum version of CMake 3.10.  The project is expected to work with
 both the ``OLD`` and ``NEW`` behaviors of policies introduced between
 those versions.
@@ -92,6 +94,19 @@
 
 The following policies are supported.
 
+Policies Introduced by CMake 4.3
+--------------------------------
+
+.. toctree::
+   :maxdepth: 1
+
+   CMP0210: CMAKE_<LANG>_LINK_FLAGS adds link flags to all target types. </policy/CMP0210>
+   CMP0209: Verify interface header sets checks executables without exports. </policy/CMP0209>
+   CMP0208: export(EXPORT) does not allow empty arguments. </policy/CMP0208>
+   CMP0207: file(GET_RUNTIME_DEPENDENCIES) normalizes paths before matching. </policy/CMP0207>
+   CMP0206: The CPack Archive Generator defaults to UID 0 and GID 0. </policy/CMP0206>
+   CMP0205: file(CREATE_LINK) with COPY_ON_ERROR copies directory content. </policy/CMP0205>
+
 Policies Introduced by CMake 4.2
 --------------------------------
 
diff --git a/Help/manual/cmake-presets.7.rst b/Help/manual/cmake-presets.7.rst
index b0f8e03..8bbee0f 100644
--- a/Help/manual/cmake-presets.7.rst
+++ b/Help/manual/cmake-presets.7.rst
@@ -44,6 +44,8 @@
 
 The root object recognizes the following fields:
 
+.. _`CMakePresets schema`:
+
 ``$schema``
   An optional string that provides a URI to the JSON schema that describes the
   structure of this JSON document. This field is used for validation and
@@ -51,41 +53,11 @@
   behavior of the document itself. If this field is not specified, the JSON
   document will still be valid, but tools that use JSON schema for validation
   and autocompletion may not function correctly.
-  This is allowed in preset files specifying version ``8`` or above.
 
 ``version``
-  A required integer representing the version of the JSON schema.
-  The supported versions are:
-
-  ``1``
-    .. versionadded:: 3.19
-
-  ``2``
-    .. versionadded:: 3.20
-
-  ``3``
-    .. versionadded:: 3.21
-
-  ``4``
-    .. versionadded:: 3.23
-
-  ``5``
-    .. versionadded:: 3.24
-
-  ``6``
-    .. versionadded:: 3.25
-
-  ``7``
-    .. versionadded:: 3.27
-
-  ``8``
-    .. versionadded:: 3.28
-
-  ``9``
-    .. versionadded:: 3.30
-
-  ``10``
-    .. versionadded:: 3.31
+  A required integer representing the version of the JSON schema. See
+  `Versions`_ for discussion of the supported versions and the corresponding
+  version of CMake in which they were added.
 
 ``cmakeMinimumRequired``
   An optional object representing the minimum version of CMake needed to
@@ -168,7 +140,7 @@
 
 ``name``
   A required string representing the machine-friendly name of the preset.
-  This identifier is used in the :ref:`cmake --preset <CMake Options>` option.
+  This identifier is used in the :option:`cmake --preset` option.
   There must not be two configure presets in the union of ``CMakePresets.json``
   and ``CMakeUserPresets.json`` in the same directory with the same name.
   However, a configure preset may have the same name as a build, test,
@@ -176,11 +148,12 @@
 
 ``hidden``
   An optional boolean specifying whether or not a preset should be hidden.
-  If a preset is hidden, it cannot be used in the ``--preset=`` argument,
-  will not show up in the :manual:`CMake GUI <cmake-gui(1)>`, and does not
-  have to have a valid ``generator`` or ``binaryDir``, even from
-  inheritance. ``hidden`` presets are intended to be used as a base for
-  other presets to inherit via the ``inherits`` field.
+  If a preset is hidden, it cannot be used in the
+  :option:`--preset <cmake --preset>` argument, will not show up in the
+  :manual:`CMake GUI <cmake-gui(1)>`, and does not have to have a valid
+  ``generator`` or ``binaryDir``, even from inheritance. ``hidden`` presets are
+  intended to be used as a base for other presets to inherit via the
+  ``inherits`` field.
 
 ``inherits``
   An optional array of strings representing the names of presets to inherit
@@ -217,14 +190,16 @@
 ``description``
   An optional string with a human-friendly description of the preset.
 
-``generator``
-  An optional string representing the generator to use for the preset. If
-  ``generator`` is not specified, it must be inherited from the
-  ``inherits`` preset (unless this preset is ``hidden``). In version ``3``
-  or above, this field may be omitted to fall back to regular generator
-  discovery procedure.
+.. _`CMakePresets generator`:
 
-  Note that for Visual Studio generators, unlike in the command line
+``generator``
+  An optional string representing the :manual:`generator <cmake-generators(7)>`
+  to use for the preset. If ``generator`` is not specified, it must be
+  inherited from the ``inherits`` preset (unless this preset is ``hidden``).
+  In version ``3`` or above, this field may be omitted to fall back to regular
+  generator discovery procedure.
+
+  Note that for :ref:`Visual Studio generators`, unlike in the command line
   :option:`-G <cmake -G>` argument, you cannot include the platform name
   in the generator name. Use the ``architecture`` field instead.
 
@@ -259,6 +234,8 @@
     If no ``strategy`` field is given, or if the field uses the string form
     rather than the object form, the behavior is the same as ``"set"``.
 
+.. _`CMakePresets toolchainFile`:
+
 ``toolchainFile``
   An optional string representing the path to the toolchain file.
   This field supports `macro expansion`_. If a relative path is specified,
@@ -267,6 +244,8 @@
   :variable:`CMAKE_TOOLCHAIN_FILE` value. It is allowed in preset files
   specifying version ``3`` or above.
 
+.. _`CMakePresets graphviz`:
+
 ``graphviz``
   An optional string representing the path to the graphviz input file,
   that will contain all the library and executable dependencies
@@ -277,6 +256,8 @@
   it is calculated relative to the current working directory. It is allowed
   in preset files specifying version ``10`` or above.
 
+.. _`CMakePresets binaryDir`:
+
 ``binaryDir``
   An optional string representing the path to the output binary directory.
   This field supports `macro expansion`_. If a relative path is specified,
@@ -285,8 +266,11 @@
   preset is ``hidden``). In version ``3`` or above, this field may be
   omitted.
 
+.. _`CMakePresets installDir`:
+
 ``installDir``
-  An optional string representing the path to the installation directory.
+  An optional string representing the path to the installation directory,
+  which will be used as the :variable:`CMAKE_INSTALL_PREFIX` variable.
   This field supports `macro expansion`_. If a relative path is specified,
   it is calculated relative to the source directory. This is allowed in
   preset files specifying version ``3`` or above.
@@ -403,6 +387,8 @@
     An optional boolean. Setting this to ``true`` is equivalent to passing
     :option:`--debug-find <cmake --debug-find>` on the command line.
 
+.. _`CMakePresets trace`:
+
 ``trace``
   An optional object specifying trace options. This is allowed in preset
   files specifying version ``7``. The object may contain the following fields:
@@ -458,7 +444,7 @@
 ``name``
   A required string representing the machine-friendly name of the preset.
   This identifier is used in the
-  :ref:`cmake --build --preset <Build Tool Mode>` option.
+  :option:`cmake --build --preset <cmake--build --preset>` option.
   There must not be two build presets in the union of ``CMakePresets.json``
   and ``CMakeUserPresets.json`` in the same directory with the same name.
   However, a build preset may have the same name as a configure, test,
@@ -467,7 +453,7 @@
 ``hidden``
   An optional boolean specifying whether or not a preset should be hidden.
   If a preset is hidden, it cannot be used in the
-  :option:`--preset <cmake --preset>` argument
+  :option:`--preset <cmake--build --preset>` argument
   and does not have to have a valid ``configurePreset``, even from
   inheritance. ``hidden`` presets are intended to be used as a base for
   other presets to inherit via the ``inherits`` field.
@@ -507,6 +493,8 @@
 ``description``
   An optional string with a human-friendly description of the preset.
 
+.. _`CMakePresets build environment`:
+
 ``environment``
   An optional map of environment variables. The key is the variable name
   (which may not be an empty string), and the value is either ``null`` or
@@ -530,16 +518,16 @@
 
   .. note::
 
-    For a CMake project using ExternalProject with a configuration preset
-    having environment variables needed in the ExternalProject, use a build
-    preset that inherits that configuration preset or the ExternalProject
+    For a CMake project using :module:`ExternalProject` with a configuration
+    preset having environment variables needed in the ExternalProject, use a
+    build preset that inherits that configuration preset or the ExternalProject
     will not have the environment variables set in the configuration preset.
     Example: suppose the host defaults to one compiler (say Clang)
     and the user wishes to use another compiler (say GCC). Set configuration
-    preset environment variables ``CC`` and ``CXX`` and use a build preset
-    that inherits that configuration preset. Otherwise the ExternalProject
-    may use a different (system default) compiler than the top-level CMake
-    project.
+    preset environment variables :envvar:`CC` and :envvar:`CXX` and use a build
+    preset that inherits that configuration preset. Otherwise the
+    ExternalProject may use a different (system default) compiler than the
+    top-level CMake project.
 
 ``configurePreset``
   An optional string specifying the name of a configure preset to
@@ -555,9 +543,20 @@
   inherited build preset environments, but before environment variables
   explicitly specified in this build preset.
 
+.. _`CMakePresets build jobs`:
+
 ``jobs``
   An optional integer. Equivalent to passing
   :option:`--parallel <cmake--build --parallel>` or ``-j`` on the command line.
+  If the value is ``0``, it is equivalent to passing ``--parallel`` with
+  ``<jobs>`` omitted; alternatively, one can define the environment variable
+  :envvar:`CMAKE_BUILD_PARALLEL_LEVEL` as an empty string using the
+  ``environment`` field.
+
+  .. versionchanged:: 4.3
+
+    This field does not accept negative integer values, regardless of the
+    version in the preset file.
 
 ``targets``
   An optional string or array of strings. Equivalent to passing
@@ -573,14 +572,16 @@
   An optional bool. If true, equivalent to passing
   :option:`--clean-first <cmake--build --clean-first>` on the command line.
 
+.. _`CMakePresets resolvePackageReferences`:
+
 ``resolvePackageReferences``
   An optional string that specifies the package resolve mode. This is
   allowed in preset files specifying version ``4`` or above.
 
   Package references are used to define dependencies to packages from
   external package managers. Currently only NuGet in combination with the
-  Visual Studio generator is supported. If there are no targets that define
-  package references, this option does nothing. Valid values are:
+  :ref:`Visual Studio generators` is supported. If there are no targets that
+  define package references, this option does nothing. Valid values are:
 
   ``on``
     Causes package references to be resolved before attempting a build.
@@ -601,11 +602,11 @@
     variable will be evaluated to decide, if package restoration should be
     performed.
 
-    When using the Visual Studio generator, package references are defined
-    using the :prop_tgt:`VS_PACKAGE_REFERENCES` property. Package references
-    are restored using NuGet. It can be disabled by setting the
-    ``CMAKE_VS_NUGET_PACKAGE_RESTORE`` variable to ``OFF``. This can also be
-    done from within a configure preset.
+    When using the :ref:`Visual Studio generators`, package references are
+    defined using the :prop_tgt:`VS_PACKAGE_REFERENCES` property. Package
+    references are restored using NuGet. It can be disabled by setting the
+    :variable:`CMAKE_VS_NUGET_PACKAGE_RESTORE` variable to ``OFF``. This can
+    also be done from within a configure preset.
 
 ``verbose``
   An optional bool. If true, equivalent to passing
@@ -717,6 +718,8 @@
   :option:`--overwrite <ctest --overwrite>` for each value in the array.
   The array values support macro expansion.
 
+.. _`CMakePresets output`:
+
 ``output``
   An optional object specifying output options. The object may contain the
   following fields.
@@ -758,6 +761,8 @@
     passing :option:`--output-log <ctest --output-log>` on the command line.
     This field supports macro expansion.
 
+.. _`CMakePresets outputJUnitFile`:
+
   ``outputJUnitFile``
     An optional string specifying a path to a JUnit file. Equivalent to
     passing :option:`--output-junit <ctest --output-junit>` on the command line.
@@ -786,6 +791,8 @@
     :option:`--test-output-size-failed <ctest --test-output-size-failed>`
     on the command line.
 
+.. _`CMakePresets testOutputTruncation`:
+
   ``testOutputTruncation``
     An optional string specifying the test output truncation mode. Equivalent
     to passing
@@ -890,9 +897,21 @@
     An optional bool. If true, equivalent to passing :option:`-F <ctest -F>`
     on the command line.
 
+.. _`CMakePresets test jobs`:
+
   ``jobs``
     An optional integer. Equivalent to passing
-    :option:`--parallel <ctest --parallel>` on the command line.
+    :option:`--parallel <ctest --parallel>` on the command line. If the value
+    is ``0``, it is equivalent to unbounded parallelism.
+
+    In preset files specifying version ``11`` or above, this field can also be
+    a string, in which case it must be empty, and is equivalent to passing
+    ``--parallel`` with ``<jobs>`` omitted.
+
+    .. versionchanged:: 4.3
+
+      This field does not accept negative integer values, regardless of the
+      version in the preset file.
 
   ``resourceSpecFile``
     An optional string. Equivalent to passing
@@ -1120,8 +1139,8 @@
 ``name``
   A required string representing the machine-friendly name of the preset.
   This identifier is used in the
-  :ref:`cmake --workflow --preset <Workflow Mode>` option. There must not be
-  two workflow presets in the union of ``CMakePresets.json`` and
+  :option:`cmake --workflow --preset <cmake--workflow --preset>` option. There
+  must not be two workflow presets in the union of ``CMakePresets.json`` and
   ``CMakeUserPresets.json`` in the same directory with the same name. However,
   a workflow preset may have the same name as a configure, build, test, or
   package preset.
@@ -1275,11 +1294,15 @@
 
   This is a preset-specific macro.
 
+.. _`CMakePresets hostSystemName`:
+
 ``${hostSystemName}``
   The name of the host operating system. Contains the same value as
   :variable:`CMAKE_HOST_SYSTEM_NAME`. This is allowed in preset files
   specifying version ``3`` or above.
 
+.. _`CMakePresets fileDir`:
+
 ``${fileDir}``
   Path to the directory containing the preset file which contains the macro.
   This is allowed in preset files specifying version ``4`` or above.
@@ -1287,6 +1310,8 @@
 ``${dollar}``
   A literal dollar sign (``$``).
 
+.. _`CMakePresets pathListSep`:
+
 ``${pathListSep}``
   Native character for separating lists of paths, such as ``:`` or ``;``.
 
@@ -1330,6 +1355,123 @@
   identifier prefix, followed by a ``.``, followed by the macro name. For
   example, the Example IDE could have ``$vendor{xide.ideInstallDir}``.
 
+Versions
+========
+
+The JSON schema of ``CMakePresets.json`` and ``CMakeUserPresets.json``
+follows a version scheme where new versions are added and allowed in newer
+versions of CMake.
+
+A list of the supported versions along with the version of CMake in which
+they were added and a summary of the new features and changes is given below.
+
+  ``1``
+    .. versionadded:: 3.19
+
+    The initial version supports `Configure Presets <Configure Preset_>`_
+    and `Macro Expansion`_.
+
+  ``2``
+    .. versionadded:: 3.20
+
+    * `Build Presets <Build Preset_>`_ were added.
+    * `Test Presets <Test Preset_>`_ were added.
+
+  ``3``
+    .. versionadded:: 3.21
+
+    * The `Condition`_ object was added for `Configure <Configure Preset_>`_,
+      `Build <Build Preset_>`_, and `Test Presets <Test Preset_>`_.
+    * Changes to `Configure Presets <Configure Preset_>`_
+
+      * The `installDir <CMakePresets installDir_>`_ field was added.
+      * The `toolchainFile <CMakePresets toolchainFile_>`_ field was added.
+      * The `binaryDir <CMakePresets binaryDir_>`_ field is now optional.
+      * The `generator <CMakePresets generator_>`_ field is now optional.
+
+    * Changes to `Macro Expansion`_
+
+      * The `${hostSystemName} <CMakePresets hostSystemName_>`_ macro was
+        added.
+
+  ``4``
+    .. versionadded:: 3.23
+
+    * `Includes`_ were added to support including other JSON files in
+      ``CMakePresets.json`` and ``CMakeUserPresets.json``.
+    * Changes to `Build Presets <Build Preset_>`_
+
+      * The
+        `resolvePackageReferences <CMakePresets resolvePackageReferences_>`_
+        field was added.
+
+    * Changes to `Macro Expansion`_
+
+      * The `${fileDir} <CMakePresets fileDir_>`_ macro was added.
+
+  ``5``
+    .. versionadded:: 3.24
+
+    * Changes to `Test Presets <Test Preset_>`_
+
+      * The `testOutputTruncation <CMakePresets testOutputTruncation_>`_
+        field was added to the `output <CMakePresets output_>`_ object.
+
+    * Changes to `Macro Expansion`_
+
+      * The `${pathListSep} <CMakePresets pathListSep_>`_ macro was added.
+
+  ``6``
+    .. versionadded:: 3.25
+
+    * `Package Presets <Package Preset_>`_ were added.
+    * `Workflow Presets <Workflow Preset_>`_ were added.
+    * Changes to `Test Presets <Test Preset_>`_
+
+      * The `outputJUnitFile <CMakePresets outputJUnitFile_>`_ field was added
+        to the `output <CMakePresets output_>`_ object.
+
+  ``7``
+    .. versionadded:: 3.27
+
+    * Changes to `Configure Presets <Configure Preset_>`_
+
+      * The `trace <CMakePresets trace_>`_ field was added.
+
+    * Changes to `Includes`_
+
+      * The ``include`` field now supports ``$penv{}`` `macro expansion`_.
+
+  ``8``
+    .. versionadded:: 3.28
+
+    * The `$schema <CMakePresets schema_>`_ field was added to the root object.
+
+  ``9``
+    .. versionadded:: 3.30
+
+    * Changes to `Includes`_
+
+      * The ``include`` field now supports other types of `macro expansion`_.
+
+  ``10``
+    .. versionadded:: 3.31
+
+    * The optional ``$comment`` field was added to support documentation
+      throughout ``CMakePresets.json`` and ``CMakeUserPresets.json``.
+    * Changes to `Configure Presets <Configure Preset_>`_:
+
+      * The `graphviz <CMakePresets graphviz_>`_ field was added.
+
+  ``11``
+    .. versionadded:: 4.3
+
+    * Changes to `Test Presets <Test Preset_>`_
+
+      * The `jobs <CMakePresets test jobs_>`_ field now accepts an empty string
+        representing :option:`--parallel <ctest --parallel>` with ``<jobs>``
+        omitted.
+
 Schema
 ======
 
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 5de9ccf..2102fc5 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -257,6 +257,7 @@
    /prop_tgt/IMPORTED_CXX_MODULES_COMPILE_DEFINITIONS
    /prop_tgt/IMPORTED_CXX_MODULES_COMPILE_FEATURES
    /prop_tgt/IMPORTED_CXX_MODULES_COMPILE_OPTIONS
+   /prop_tgt/IMPORTED_CXX_MODULES_CONFIG
    /prop_tgt/IMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES
    /prop_tgt/IMPORTED_CXX_MODULES_LINK_LIBRARIES
    /prop_tgt/IMPORTED_GLOBAL
@@ -326,6 +327,7 @@
    /prop_tgt/LANG_ICSTAT
    /prop_tgt/LANG_INCLUDE_WHAT_YOU_USE
    /prop_tgt/LANG_LINKER_LAUNCHER
+   /prop_tgt/LANG_PVS_STUDIO
    /prop_tgt/LANG_STANDARD
    /prop_tgt/LANG_STANDARD_REQUIRED
    /prop_tgt/LANG_VISIBILITY_PRESET
@@ -392,6 +394,7 @@
    /prop_tgt/PRECOMPILE_HEADERS_REUSE_FROM
    /prop_tgt/PREFIX
    /prop_tgt/PRIVATE_HEADER
+   /prop_tgt/PRIVATE_HEADER_SETS_TO_VERIFY
    /prop_tgt/PROJECT_LABEL
    /prop_tgt/PUBLIC_HEADER
    /prop_tgt/RESOURCE
@@ -432,6 +435,7 @@
    /prop_tgt/UNITY_BUILD_RELOCATABLE
    /prop_tgt/UNITY_BUILD_UNIQUE_ID
    /prop_tgt/VERIFY_INTERFACE_HEADER_SETS
+   /prop_tgt/VERIFY_PRIVATE_HEADER_SETS
    /prop_tgt/VERSION
    /prop_tgt/VISIBILITY_INLINES_HIDDEN
    /prop_tgt/VS_CONFIGURATION_TYPE
diff --git a/Help/manual/cmake-toolchains.7.rst b/Help/manual/cmake-toolchains.7.rst
index bb32490..21363c7 100644
--- a/Help/manual/cmake-toolchains.7.rst
+++ b/Help/manual/cmake-toolchains.7.rst
@@ -70,9 +70,16 @@
 :variable:`CMAKE_<LANG>_COMPILER_VERSION`
   The version of the compiler.
 :variable:`CMAKE_<LANG>_FLAGS`
-  The variables and the configuration-specific equivalents contain flags that
-  will be added to the compile command when compiling a file of a particular
-  language.
+  These variables and the configuration-specific equivalents contain flags that
+  will be added to all invocations of the compiler for a particular language,
+  including those driving compiling and linking.
+
+:variable:`CMAKE_<LANG>_LINK_FLAGS`
+  .. versionadded:: 4.3
+
+  These variables and the configuration-specific equivalents contain flags that
+  will be added to all invocations of the compiler for a particular language
+  when driving linking only.
 
 CMake needs a way to determine which compiler to use to invoke the linker.
 This is determined by the :prop_sf:`LANGUAGE` property of source files of the
@@ -234,11 +241,11 @@
 
   set(CMAKE_SYSTEM_NAME QNX)
 
-  set(arch gcc_ntoarmv7le)
+  set(arch gcc_ntoaarch64)
 
   set(CMAKE_C_COMPILER qcc)
   set(CMAKE_C_COMPILER_TARGET ${arch})
-  set(CMAKE_CXX_COMPILER QCC)
+  set(CMAKE_CXX_COMPILER q++)
   set(CMAKE_CXX_COMPILER_TARGET ${arch})
 
   set(CMAKE_SYSROOT $ENV{QNX_TARGET})
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 2a23383..f9ca444 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -263,6 +263,7 @@
    /variable/CMAKE_INCLUDE_PATH
    /variable/CMAKE_INSTALL_DEFAULT_COMPONENT_NAME
    /variable/CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
+   /variable/CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO
    /variable/CMAKE_INSTALL_MESSAGE
    /variable/CMAKE_INSTALL_PREFIX
    /variable/CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
@@ -483,7 +484,6 @@
    /variable/CMAKE_DEPENDS_USE_COMPILER
    /variable/CMAKE_DISABLE_PRECOMPILE_HEADERS
    /variable/CMAKE_DLL_NAME_WITH_SOVERSION
-   /variable/CMAKE_ENABLE_EXPORTS
    /variable/CMAKE_EXECUTABLE_ENABLE_EXPORTS
    /variable/CMAKE_EXE_LINKER_FLAGS
    /variable/CMAKE_EXE_LINKER_FLAGS_CONFIG
@@ -529,6 +529,7 @@
    /variable/CMAKE_LANG_LINK_LIBRARY_USING_FEATURE_SUPPORTED
    /variable/CMAKE_LANG_LINK_WHAT_YOU_USE_FLAG
    /variable/CMAKE_LANG_LINKER_LAUNCHER
+   /variable/CMAKE_LANG_PVS_STUDIO
    /variable/CMAKE_LANG_USING_LINKER_TYPE
    /variable/CMAKE_LANG_VISIBILITY_PRESET
    /variable/CMAKE_LIBRARY_OUTPUT_DIRECTORY
@@ -598,6 +599,7 @@
    /variable/CMAKE_UNITY_BUILD_RELOCATABLE
    /variable/CMAKE_UNITY_BUILD_UNIQUE_ID
    /variable/CMAKE_VERIFY_INTERFACE_HEADER_SETS
+   /variable/CMAKE_VERIFY_PRIVATE_HEADER_SETS
    /variable/CMAKE_VISIBILITY_INLINES_HIDDEN
    /variable/CMAKE_VS_DEBUGGER_COMMAND
    /variable/CMAKE_VS_DEBUGGER_COMMAND_ARGUMENTS
@@ -702,6 +704,8 @@
    /variable/CMAKE_LANG_IMPLICIT_LINK_LIBRARIES
    /variable/CMAKE_LANG_LIBRARY_ARCHITECTURE
    /variable/CMAKE_LANG_LINK_EXECUTABLE
+   /variable/CMAKE_LANG_LINK_FLAGS
+   /variable/CMAKE_LANG_LINK_FLAGS_CONFIG
    /variable/CMAKE_LANG_LINKER_WRAPPER_FLAG
    /variable/CMAKE_LANG_LINKER_WRAPPER_FLAG_SEP
    /variable/CMAKE_LANG_OUTPUT_EXTENSION
@@ -896,6 +900,7 @@
 .. toctree::
    :maxdepth: 1
 
+   /variable/CMAKE_ENABLE_EXPORTS
    /variable/CMAKE_IOS_INSTALL_COMBINED
    /variable/CMAKE_LANG_USING_LINKER_MODE
    /variable/CMAKE_USE_RELATIVE_PATHS
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index 316ba25..62b8074 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -707,6 +707,11 @@
  if the preset sets a variable called ``MYVAR`` to ``1``, but the user sets
  it to ``2`` with a ``-D`` argument, the value ``2`` is preferred.
 
+ .. versionadded:: 3.21
+   The ``-B`` option may optionally be specified with a different binary
+   directory than the one specified by the ``binaryDir`` key of the
+   configure preset.
+
 .. option:: --list-presets[=<type>]
 
  Lists the available presets of the specified ``<type>``.  Valid values for
@@ -790,9 +795,13 @@
 .. option:: --preset <preset>, --preset=<preset>
 
   Use a build preset to specify build options. The project binary directory
-  is inferred from the ``configurePreset`` key. The current working directory
-  must contain CMake preset files.
-  See :manual:`preset <cmake-presets(7)>` for more details.
+  is inferred from the ``configurePreset`` key unless a directory is specified
+  after ``--build``. The current working directory must contain CMake preset
+  files. See :manual:`preset <cmake-presets(7)>` for more details.
+
+  .. versionadded:: 4.3
+    ``cmake --build`` now supports specifying a build directory and
+    preset together.
 
 .. option:: --list-presets
 
@@ -919,7 +928,23 @@
 
 .. option:: --prefix <prefix>
 
-  Override the installation prefix, :variable:`CMAKE_INSTALL_PREFIX`.
+  Specifies an alternative installation prefix, temporarily replacing the
+  value of the :variable:`CMAKE_INSTALL_PREFIX` variable at the installation
+  phase.
+
+  The main purpose of this option is to allow installation to occur in an
+  arbitrary location.  This is commonly used in certain installation and
+  packaging workflows.  It is analogous to selecting the installation
+  directory during the installation phase.  For example, on Windows, where
+  a user may choose the destination folder for the project.
+
+  .. note::
+
+    When the project is using the :module:`GNUInstallDirs` module, there are
+    some :ref:`special cases <GNUInstallDirs special cases>` that are
+    evaluated based on the value of the :variable:`CMAKE_INSTALL_PREFIX`
+    variable during the configuration phase.  The results persist even if an
+    alternative prefix is used during installation.
 
 .. option:: --strip
 
@@ -1007,6 +1032,78 @@
 
 Available commands are:
 
+.. option:: bin2c [<options>...] [--] [<input-file> [<output-file>]]
+
+  .. versionadded:: 4.3
+
+  Convert a binary file to a C array. If input file is unspecified or ``-``,
+  read from standard input instead of a file. If output file is unspecified or
+  ``-``, write to standard output instead of a file.
+
+  By default, this prints only the bytes. Enclosing text can be added with the
+  ``--template-file`` argument. You can also ``#include`` the bytes from
+  another file, acting as a drop-in replacement for the ``#embed`` directive
+  from C23 and C++26:
+
+  .. code-block:: c
+
+    unsigned char my_bytes[] = {
+    /* #embed "bin2c_input.bin" */
+    #include "bin2c_output.c.txt"
+    };
+
+  .. program:: cmake-E_bin2c
+
+  .. option:: --signed
+
+    Print the bytes as signed integers rather than unsigned.
+
+  .. option:: --decimal
+
+    Print the bytes as decimal rather than hexadecimal.
+
+  .. option:: --trailing-comma
+
+    Append a trailing comma after the last byte (not included by default.)
+
+  .. option:: --template-file <template-file>
+
+    Format from a template file. The template file contains placeholders for
+    the array and optionally the length (which will be a non-negative decimal
+    integer). Such placeholders are enclosed in ``@`` at the beginning and end
+    of the placeholder. This functionality is similar to
+    :command:`configure_file` called with the ``@ONLY`` argument, but only the
+    array and length placeholders will be replaced, and any other placeholders
+    will be left as-is.
+
+    An example of a potential template file:
+
+    .. code-block:: text
+
+      unsigned char my_bytes[] = {@array@};
+
+      size_t length = @length@;
+
+    The array placeholder may occur at most once in the template file. The
+    length placeholder may occur zero or more times after the array
+    placeholder, but not before it.
+
+    Note that the length is the number of elements printed, and may not match
+    the ``sizeof`` the resulting array if a type other than ``unsigned char``
+    is used.
+
+  .. option:: --template-array-placeholder <placeholder-name>
+
+    Specify a name for the array placeholder in the template file. Set to
+    ``array`` by default.
+
+  .. option:: --template-length-placeholder <placeholder-name>
+
+    Specify a name for the length placeholder in the template file. Set to
+    ``length`` by default.
+
+.. program:: cmake-E
+
 .. option:: capabilities
 
   .. versionadded:: 3.7
@@ -1292,6 +1389,9 @@
      351abe79cd3800b38cdfb25d45015a15  file1.txt
      052f86c15bbde68af55c7f7b340ab639  file2.txt
 
+  .. versionchanged:: 4.3
+    Passing ``-`` reads from standard input.
+
 .. option:: sha1sum <file>...
 
   .. versionadded:: 3.10
@@ -1301,6 +1401,9 @@
      4bb7932a29e6f73c97bb9272f2bdc393122f86e0  file1.txt
      1df4c8f318665f9a5f2ed38f55adadb7ef9f559c  file2.txt
 
+  .. versionchanged:: 4.3
+    Passing ``-`` reads from standard input.
+
 .. option:: sha224sum <file>...
 
   .. versionadded:: 3.10
@@ -1310,6 +1413,9 @@
      b9b9346bc8437bbda630b0b7ddfc5ea9ca157546dbbf4c613192f930  file1.txt
      6dfbe55f4d2edc5fe5c9197bca51ceaaf824e48eba0cc453088aee24  file2.txt
 
+  .. versionchanged:: 4.3
+    Passing ``-`` reads from standard input.
+
 .. option:: sha256sum <file>...
 
   .. versionadded:: 3.10
@@ -1319,6 +1425,9 @@
      76713b23615d31680afeb0e9efe94d47d3d4229191198bb46d7485f9cb191acc  file1.txt
      15b682ead6c12dedb1baf91231e1e89cfc7974b3787c1e2e01b986bffadae0ea  file2.txt
 
+  .. versionchanged:: 4.3
+    Passing ``-`` reads from standard input.
+
 .. option:: sha384sum <file>...
 
   .. versionadded:: 3.10
@@ -1328,6 +1437,9 @@
      acc049fedc091a22f5f2ce39a43b9057fd93c910e9afd76a6411a28a8f2b8a12c73d7129e292f94fc0329c309df49434  file1.txt
      668ddeb108710d271ee21c0f3acbd6a7517e2b78f9181c6a2ff3b8943af92b0195dcb7cce48aa3e17893173c0a39e23d  file2.txt
 
+  .. versionchanged:: 4.3
+    Passing ``-`` reads from standard input.
+
 .. option:: sha512sum <file>...
 
   .. versionadded:: 3.10
@@ -1337,6 +1449,9 @@
      2a78d7a6c5328cfb1467c63beac8ff21794213901eaadafd48e7800289afbc08e5fb3e86aa31116c945ee3d7bf2a6194489ec6101051083d1108defc8e1dba89  file1.txt
      7a0b54896fe5e70cca6dd643ad6f672614b189bf26f8153061c4d219474b05dad08c4e729af9f4b009f1a1a280cb625454bf587c690f4617c27e3aebdf3b7a2d  file2.txt
 
+  .. versionchanged:: 4.3
+    Passing ``-`` reads from standard input.
+
 .. option:: remove [-f] <file>...
 
   .. deprecated:: 3.17
@@ -1416,6 +1531,10 @@
       When extracting selected files or directories, you must provide their exact
       names including the path, as printed by list (``-t``).
 
+    .. versionchanged:: 4.3
+      Archive entries containing path traversal sequences (``..``), or
+      absolute paths, are rejected for security.
+
   .. option:: t
 
     List archive contents.
@@ -1430,7 +1549,7 @@
 
   .. option:: z
 
-    Compress the resulting archive with gzip.
+    Compress the resulting archive with gzip (Deflate).
 
   .. option:: j
 
@@ -1440,7 +1559,7 @@
 
     .. versionadded:: 3.1
 
-    Compress the resulting archive with XZ.
+    Compress the resulting archive with XZ (LZMA2).
 
   .. option:: --zstd
 
@@ -1448,6 +1567,12 @@
 
     Compress the resulting archive with Zstandard.
 
+  .. option:: --lzma
+
+    .. versionadded:: 4.3
+
+    Compress the resulting archive with LZMA algorithm.
+
   .. option:: --files-from=<file>
 
     .. versionadded:: 3.1
@@ -1462,8 +1587,33 @@
     .. versionadded:: 3.3
 
     Specify the format of the archive to be created.
-    Supported formats are: ``7zip``, ``gnutar``, ``pax``,
-    ``paxr`` (restricted pax, default), and ``zip``.
+    Supported formats are:
+
+    * ``7zip``
+    * ``gnutar``
+    * ``pax``
+    * ``paxr`` (restricted pax, default)
+    * ``raw``
+
+      .. versionadded:: 4.3
+
+      If this format is used, only one file will be compressed
+      with the compression type specified by the
+      :option:`--cmake-tar-compression-method <cmake-E_tar --cmake-tar-compression-method>`.
+
+    * ``zip``
+
+    If the compression method is not specified, the compression method
+    depends on the format:
+
+    * ``7zip`` uses ``LZMA`` compression
+    * ``zip`` uses ``Deflate`` compression
+    * others uses no compression by default
+
+    .. versionadded:: 4.3
+
+      The ``7zip`` and ``zip`` formats support changing the default compression
+      method and compression level.
 
   .. option:: --mtime=<date>
 
@@ -1471,6 +1621,57 @@
 
     Specify modification time recorded in tarball entries.
 
+  .. option:: --cmake-tar-compression-method=<compression-method>
+
+    .. versionadded:: 4.3
+
+    The ``<compression-method>`` must be one of the following:
+
+    * ``none`` or ``store`` - no compression is used
+    * ``deflate`` or ``gzip`` - Deflate-based
+    * ``bzip2`` - BZip2-based
+    * ``lzma`` - LZMA-based
+    * ``lzma2`` or ``xz`` - LZMA2-based
+    * ``ppmd`` - PPMd-based
+
+      This compression method is only supported by the ``7zip`` archive format.
+
+    * ``zstd`` - Zstandard-based
+
+    This is the second variant for the compression method selection.
+    It provide more compression methods, that the classic ``tar``-like interface.
+    You can use any of them.
+
+    The default value depends on the :option:`--format <cmake-E_tar --format>`
+    option value and described in the corresponding section.
+
+  .. option:: --cmake-tar-compression-level=<compression-level>
+
+    .. versionadded:: 4.3
+
+    The ``<compression-level>`` should be between ``0`` and ``9``, with the
+    default being ``0``.  The compression algorithm must be selected when
+    the ``--cmake-tar-compression-level`` option is given.
+
+    The ``<compression-level>`` of the ``Zstd`` algorithm can be set
+    between ``0`` and ``19``, except for the ``zip`` format.
+
+    The value ``0`` is used to specify the default compression level.
+    It is selected automatically by the archive library backend and
+    not directly set by CMake itself. The default compression level
+    may vary between archive formats, platforms, etc.
+
+  .. option:: --cmake-tar-threads=<number>
+
+    .. versionadded:: 4.3
+
+    Use the ``<number>`` threads to operate on the archive. Currently only
+    multi-threaded compression is supported.
+
+    If set to ``0``, the number of available cores on the machine will be
+    used instead. Note that not all compression modes support threading
+    in all environments.
+
   .. option:: --touch
 
     .. versionadded:: 3.24
diff --git a/Help/manual/cmake/version-schema.json b/Help/manual/cmake/version-schema.json
new file mode 100644
index 0000000..71b7ea6
--- /dev/null
+++ b/Help/manual/cmake/version-schema.json
@@ -0,0 +1,109 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "type": "object",
+  "properties": {
+    "dependencies": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "description": "Information about a single dependency.",
+        "properties": {
+          "name": {
+            "type": "string",
+            "description": "The name of the dependency."
+          },
+          "type": {
+            "type": "string",
+            "description": "The type of the dependency.",
+            "enum": [
+              "system",
+              "bundled"
+            ]
+          },
+          "version": {
+            "type": "string",
+            "description": "The version of the dependency if available."
+          },
+          "via": {
+            "type": "string",
+            "description": "The source from which the dependency is came from. Not presented for direct CMake dependencies."
+          }
+        },
+        "required": [
+          "name",
+          "type"
+        ],
+        "additionalProperties": false
+      },
+      "additionalItems": false
+    },
+    "program": {
+      "type": "object",
+      "description": "Information about the CMake tool.",
+      "properties": {
+        "name": {
+          "type": "string",
+          "description": "The name of the CMake tool."
+        },
+        "version": {
+          "type": "object",
+          "description": "Information about the version of the CMake tool.",
+          "properties": {
+            "major": {
+              "type": "integer",
+              "description": "The major version of the CMake tool."
+            },
+            "minor": {
+              "type": "integer",
+              "description": "The minor version of the CMake tool."
+            },
+            "patch": {
+              "type": "integer",
+              "description": "The patch version of the CMake tool."
+            },
+            "string": {
+              "type": "string",
+              "description": "The full version string of the CMake tool."
+            }
+          },
+          "required": [
+            "major",
+            "minor",
+            "patch",
+            "string"
+          ],
+          "additionalProperties": false
+        }
+      },
+      "required": [
+        "name",
+        "version"
+      ],
+      "additionalProperties": false
+    },
+    "version": {
+      "type": "object",
+      "properties": {
+        "major": {
+          "type": "integer",
+          "description": "The major version of the JSON output format."
+        },
+        "minor": {
+          "type": "integer",
+          "description": "The minor version of the JSON output format."
+        }
+      },
+      "required": [
+        "major",
+        "minor"
+      ],
+      "additionalProperties": false
+    }
+  },
+  "required": [
+    "dependencies",
+    "program",
+    "version"
+  ],
+  "additionalProperties": false
+}
diff --git a/Help/manual/ctest.1.rst b/Help/manual/ctest.1.rst
index 3a871bb..2cbb41b 100644
--- a/Help/manual/ctest.1.rst
+++ b/Help/manual/ctest.1.rst
@@ -51,6 +51,11 @@
  must contain CMake preset files.
  See :manual:`preset <cmake-presets(7)>` for more details.
 
+ .. versionadded:: 3.30
+   The ``--test-dir`` option may optionally be specified with a different
+   binary directory than the one specified by the ``configurePreset`` key
+   of the test preset.
+
 .. option:: --list-presets
 
  Lists the available test presets. The current working directory must contain
@@ -497,6 +502,14 @@
  This option can also be set by setting the :envvar:`CTEST_NO_TESTS_ACTION`
  environment variable.
 
+.. option:: --collect-instrumentation <build>
+
+ .. versionadded:: 4.0
+
+ Manually collect instrumentation data from the specified build directory. See
+ the :ref:`cmake-instrumentation Indexing` section of CMake instrumentation for
+ more details.
+
 View Help
 =========
 
diff --git a/Help/manual/file_api/schema_target.json b/Help/manual/file_api/schema_target.json
index 909c49f..68cb14e 100644
--- a/Help/manual/file_api/schema_target.json
+++ b/Help/manual/file_api/schema_target.json
@@ -31,6 +31,9 @@
     },
     {
       "$ref": "#/definitions/codemodelV2_9"
+    },
+    {
+      "$ref": "#/definitions/codemodelV2_10"
     }
   ],
   "definitions": {
@@ -47,7 +50,25 @@
         },
         "minor": {
           "type": "integer",
-          "minimum": 9
+          "const": 9
+        }
+      },
+      "additionalProperties": false
+    },
+    "codemodelVersionV2_10": {
+      "type": "object",
+      "required": [
+        "major",
+        "minor"
+      ],
+      "properties": {
+        "major": {
+          "type": "integer",
+          "const": 2
+        },
+        "minor": {
+          "type": "integer",
+          "minimum": 10
         }
       },
       "additionalProperties": false
@@ -615,7 +636,31 @@
         "additionalProperties": false
       }
     },
-    "sourceGroups": {
+    "interfaceSourcesV2_10": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "path"
+        ],
+        "properties": {
+          "path": {
+            "$ref": "#/definitions/sourcesPath"
+          },
+          "sourceGroupIndex": {
+            "$ref": "#/definitions/sourcesSourceGroupIndex"
+          },
+          "isGenerated": {
+            "$ref": "#/definitions/sourcesIsGenerated"
+          },
+          "fileSetIndex": {
+            "$ref": "#/definitions/sourcesFileSetIndexV2_5"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "sourceGroupsV2_0": {
       "type": "array",
       "items": {
         "type": "object",
@@ -640,6 +685,39 @@
         "additionalProperties": false
       }
     },
+    "sourceGroupsV2_10": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "name",
+          "sourceIndexes"
+        ],
+        "properties": {
+          "name": {
+            "type": "string",
+            "description": "Name of source group"
+          },
+          "sourceIndexes": {
+            "type": "array",
+            "items": {
+              "type": "integer",
+              "minimum": 0
+            },
+            "description": "Indices into sources array"
+          },
+          "interfaceSourceIndexes": {
+            "type": "array",
+            "items": {
+              "type": "integer",
+              "minimum": 0
+            },
+            "description": "Indices into interfaceSources array"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
     "compileGroupsSourceIndexes": {
       "type": "array",
       "items": {
@@ -1052,7 +1130,7 @@
           "$ref": "#/definitions/sourcesV2_0"
         },
         "sourceGroups": {
-          "$ref": "#/definitions/sourceGroups"
+          "$ref": "#/definitions/sourceGroupsV2_0"
         },
         "compileGroups": {
           "$ref": "#/definitions/compileGroupsV2_0"
@@ -1116,7 +1194,7 @@
           "$ref": "#/definitions/sourcesV2_0"
         },
         "sourceGroups": {
-          "$ref": "#/definitions/sourceGroups"
+          "$ref": "#/definitions/sourceGroupsV2_0"
         },
         "compileGroups": {
           "$ref": "#/definitions/compileGroupsV2_1"
@@ -1180,7 +1258,7 @@
           "$ref": "#/definitions/sourcesV2_0"
         },
         "sourceGroups": {
-          "$ref": "#/definitions/sourceGroups"
+          "$ref": "#/definitions/sourceGroupsV2_0"
         },
         "compileGroups": {
           "$ref": "#/definitions/compileGroupsV2_2"
@@ -1247,7 +1325,7 @@
           "$ref": "#/definitions/sourcesV2_5"
         },
         "sourceGroups": {
-          "$ref": "#/definitions/sourceGroups"
+          "$ref": "#/definitions/sourceGroupsV2_0"
         },
         "compileGroups": {
           "$ref": "#/definitions/compileGroupsV2_2"
@@ -1314,7 +1392,7 @@
           "$ref": "#/definitions/sourcesV2_5"
         },
         "sourceGroups": {
-          "$ref": "#/definitions/sourceGroups"
+          "$ref": "#/definitions/sourceGroupsV2_0"
         },
         "compileGroups": {
           "$ref": "#/definitions/compileGroupsV2_6"
@@ -1384,7 +1462,7 @@
           "$ref": "#/definitions/sourcesV2_5"
         },
         "sourceGroups": {
-          "$ref": "#/definitions/sourceGroups"
+          "$ref": "#/definitions/sourceGroupsV2_0"
         },
         "compileGroups": {
           "$ref": "#/definitions/compileGroupsV2_6"
@@ -1457,7 +1535,7 @@
           "$ref": "#/definitions/sourcesV2_5"
         },
         "sourceGroups": {
-          "$ref": "#/definitions/sourceGroups"
+          "$ref": "#/definitions/sourceGroupsV2_0"
         },
         "compileGroups": {
           "$ref": "#/definitions/compileGroupsV2_6"
@@ -1564,7 +1642,117 @@
           "$ref": "#/definitions/symbolicV2_9"
         },
         "sourceGroups": {
-          "$ref": "#/definitions/sourceGroups"
+          "$ref": "#/definitions/sourceGroupsV2_0"
+        },
+        "compileGroups": {
+          "$ref": "#/definitions/compileGroupsV2_6"
+        },
+        "backtraceGraph": {
+          "$ref": "#/definitions/backtraceGraph"
+        }
+      },
+      "additionalProperties": false
+    },
+    "codemodelV2_10": {
+      "required": [
+        "codemodelVersion",
+        "name",
+        "id",
+        "type",
+        "paths",
+        "sources",
+        "backtraceGraph"
+      ],
+      "properties": {
+        "codemodelVersion": {
+          "$ref": "#/definitions/codemodelVersionV2_10"
+        },
+        "name": {
+          "$ref": "#/definitions/name"
+        },
+        "id": {
+          "$ref": "#/definitions/id"
+        },
+        "type": {
+          "$ref": "#/definitions/typeV2_9"
+        },
+        "imported": {
+          "$ref": "#/definitions/importedV2_9"
+        },
+        "local": {
+          "$ref": "#/definitions/localV2_9"
+        },
+        "abstract": {
+          "$ref": "#/definitions/abstractV2_9"
+        },
+        "backtrace": {
+          "$ref": "#/definitions/backtrace"
+        },
+        "folder": {
+          "$ref": "#/definitions/folder"
+        },
+        "paths": {
+          "$ref": "#/definitions/paths"
+        },
+        "nameOnDisk": {
+          "$ref": "#/definitions/nameOnDisk"
+        },
+        "artifacts": {
+          "$ref": "#/definitions/artifacts"
+        },
+        "isGeneratorProvided": {
+          "$ref": "#/definitions/isGeneratorProvided"
+        },
+        "install": {
+          "$ref": "#/definitions/install"
+        },
+        "launchers": {
+          "$ref": "#/definitions/launchersV2_7"
+        },
+        "link": {
+          "$ref": "#/definitions/link"
+        },
+        "archive": {
+          "$ref": "#/definitions/archive"
+        },
+        "debugger": {
+          "$ref": "#/definitions/debuggerV2_8"
+        },
+        "dependencies": {
+          "$ref": "#/definitions/dependencies"
+        },
+        "linkLibraries": {
+          "$ref": "#/definitions/linkLibrariesV2_9"
+        },
+        "interfaceLinkLibraries": {
+          "$ref": "#/definitions/interfaceLinkLibrariesV2_9"
+        },
+        "compileDependencies": {
+          "$ref": "#/definitions/compileDependenciesV2_9"
+        },
+        "interfaceCompileDependencies": {
+          "$ref": "#/definitions/interfaceCompileDependenciesV2_9"
+        },
+        "objectDependencies": {
+          "$ref": "#/definitions/onlyTargetDependenciesArrayV2_9"
+        },
+        "orderDependencies": {
+          "$ref": "#/definitions/onlyTargetDependenciesArrayV2_9"
+        },
+        "fileSets": {
+          "$ref": "#/definitions/fileSetsV2_5"
+        },
+        "sources": {
+          "$ref": "#/definitions/sourcesV2_5"
+        },
+        "interfaceSources": {
+          "$ref": "#/definitions/interfaceSourcesV2_10"
+        },
+        "symbolic": {
+          "$ref": "#/definitions/symbolicV2_9"
+        },
+        "sourceGroups": {
+          "$ref": "#/definitions/sourceGroupsV2_10"
         },
         "compileGroups": {
           "$ref": "#/definitions/compileGroupsV2_6"
diff --git a/Help/manual/file_api/schema_toolchains.json b/Help/manual/file_api/schema_toolchains.json
index 8ac4f29..d82e439 100644
--- a/Help/manual/file_api/schema_toolchains.json
+++ b/Help/manual/file_api/schema_toolchains.json
@@ -7,13 +7,21 @@
     "version",
     "toolchains"
   ],
-  "properties": {
+  "oneOf": [
+    {
+      "$ref": "#/definitions/toolchainsObjV1_0"
+    },
+    {
+      "$ref": "#/definitions/toolchainsObjV1_1"
+    }
+  ],
+  "definitions": {
     "kind": {
       "type": "string",
       "const": "toolchains",
       "description": "Specifies the object kind"
     },
-    "version": {
+    "versionV1_0": {
       "type": "object",
       "required": [
         "major",
@@ -31,87 +39,203 @@
       },
       "additionalProperties": false
     },
-    "toolchains": {
+    "versionV1_1": {
+      "type": "object",
+      "required": [
+        "major",
+        "minor"
+      ],
+      "properties": {
+        "major": {
+          "type": "integer",
+          "const": 1
+        },
+        "minor": {
+          "type": "integer",
+          "const": 1
+        }
+      },
+      "additionalProperties": false
+    },
+    "language": {
+      "type": "string",
+      "description": "Toolchain language identifier (e.g. C, CXX)"
+    },
+    "sourceFileExtensions": {
       "type": "array",
-      "description": "Array of toolchain configurations per language",
       "items": {
-        "type": "object",
-        "required": [
-          "language",
-          "compiler"
-        ],
-        "properties": {
-          "language": {
-            "type": "string",
-            "description": "Toolchain language identifier (e.g. C, CXX)"
+        "type": "string"
+      },
+      "description": "List of source file extensions (without leading dot) supported by this toolchain"
+    },
+    "compilerPath": {
+      "type": "string",
+      "description": "Path to the compiler executable. This is present when the CMAKE_<LANG>_COMPILER variable is defined."
+    },
+    "compilerCommandFragment": {
+      "type": "string",
+      "description": "Mandatory arguments to the compiler, as a command line fragment. This is present when the CMAKE_<LANG>_COMPILER variable is a list containing multiple elements or the CC or similar environment variable contains command line arguments."
+    },
+    "compilerId": {
+      "type": "string",
+      "description": "Compiler identifier (e.g. GNU, MSVC). This is present when the CMAKE_<LANG>_COMPILER_ID variable is defined."
+    },
+    "compilerVersion": {
+      "type": "string",
+      "description": "Version of the compiler. This is present when the CMAKE_<LANG>_COMPILER_VERSION variable is defined."
+    },
+    "compilerTarget": {
+      "type": "string",
+      "description": "Cross-compiling target of the compiler. This is present when the CMAKE_<LANG>_COMPILER_TARGET variable is defined."
+    },
+    "compilerImplicit": {
+      "type": "object",
+      "properties": {
+        "includeDirectories": {
+          "type": "array",
+          "items": {
+            "type": "string"
           },
-          "compiler": {
+          "description": "List of implicit include directories for the compiler. This is present when the CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES variable is defined."
+        },
+        "linkDirectories": {
+          "type": "array",
+          "items": {
+            "type": "string"
+          },
+          "description": "List of implicit link directories for the compiler front end. This is present when the CMAKE_<LANG>_IMPLICIT_LINK_DIRECTORIES variable is defined."
+        },
+        "linkFrameworkDirectories": {
+          "type": "array",
+          "items": {
+            "type": "string"
+          },
+          "description": "List of implicit link framework directories for the compiler front end. This is present when the CMAKE_<LANG>_IMPLICIT_FRAMEWORK_DIRECTORIES variable is defined."
+        },
+        "linkLibraries": {
+          "type": "array",
+          "items": {
+            "type": "string"
+          },
+          "description": "List of implicit link libraries for the compiler front end. This is present when the CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES variable is defined."
+        }
+      },
+      "additionalProperties": false
+    },
+    "compilerV1_0": {
+      "type": "object",
+      "properties": {
+        "path": {
+          "$ref": "#/definitions/compilerPath"
+        },
+        "id": {
+          "$ref": "#/definitions/compilerId"
+        },
+        "version": {
+          "$ref": "#/definitions/compilerVersion"
+        },
+        "target": {
+          "$ref": "#/definitions/compilerTarget"
+        },
+        "implicit": {
+          "$ref": "#/definitions/compilerImplicit"
+        }
+      },
+      "additionalProperties": false
+    },
+    "compilerV1_1": {
+      "type": "object",
+      "properties": {
+        "path": {
+          "$ref": "#/definitions/compilerPath"
+        },
+        "commandFragment": {
+          "$ref": "#/definitions/compilerCommandFragment"
+        },
+        "id": {
+          "$ref": "#/definitions/compilerId"
+        },
+        "version": {
+          "$ref": "#/definitions/compilerVersion"
+        },
+        "target": {
+          "$ref": "#/definitions/compilerTarget"
+        },
+        "implicit": {
+          "$ref": "#/definitions/compilerImplicit"
+        }
+      },
+      "additionalProperties": false
+    },
+    "toolchainsObjV1_0": {
+      "type": "object",
+      "properties": {
+        "kind": {
+          "$ref": "#/definitions/kind"
+        },
+        "version": {
+          "$ref": "#/definitions/versionV1_0"
+        },
+        "toolchains": {
+          "type": "array",
+          "description": "Array of toolchain configurations per language",
+          "items": {
             "type": "object",
+            "required": [
+              "language",
+              "compiler"
+            ],
             "properties": {
-              "path": {
-                "type": "string",
-                "description": "Path to the compiler executable. This is present when the CMAKE_<LANG>_COMPILER variable is defined."
+              "language": {
+                "$ref": "#/definitions/language"
               },
-              "id": {
-                "type": "string",
-                "description": "Compiler identifier (e.g. GNU, MSVC). This is present when the CMAKE_<LANG>_COMPILER_ID variable is defined."
+              "compiler": {
+                "$ref": "#/definitions/compilerV1_0"
               },
-              "version": {
-                "type": "string",
-                "description": "Version of the compiler. This is present when the CMAKE_<LANG>_COMPILER_VERSION variable is defined."
-              },
-              "target": {
-                "type": "string",
-                "description": "Cross-compiling target of the compiler. This is present when the CMAKE_<LANG>_COMPILER_TARGET variable is defined."
-              },
-              "implicit": {
-                "type": "object",
-                "properties": {
-                  "includeDirectories": {
-                    "type": "array",
-                    "items": {
-                      "type": "string"
-                    },
-                    "description": "List of implicit include directories for the compiler. This is present when the CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES variable is defined."
-                  },
-                  "linkDirectories": {
-                    "type": "array",
-                    "items": {
-                      "type": "string"
-                    },
-                    "description": "List of implicit link directories for the compiler front end. This is present when the CMAKE_<LANG>_IMPLICIT_LINK_DIRECTORIES variable is defined."
-                  },
-                  "linkFrameworkDirectories": {
-                    "type": "array",
-                    "items": {
-                      "type": "string"
-                    },
-                    "description": "List of implicit link framework directories for the compiler front end. This is present when the CMAKE_<LANG>_IMPLICIT_FRAMEWORK_DIRECTORIES variable is defined."
-                  },
-                  "linkLibraries": {
-                    "type": "array",
-                    "items": {
-                      "type": "string"
-                    },
-                    "description": "List of implicit link libraries for the compiler front end. This is present when the CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES variable is defined."
-                  }
-                },
-                "additionalProperties": false
+              "sourceFileExtensions": {
+                "$ref": "#/definitions/sourceFileExtensions"
               }
             },
             "additionalProperties": false
-          },
-          "sourceFileExtensions": {
-            "type": "array",
-            "items": {
-              "type": "string"
-            },
-            "description": "List of source file extensions (without leading dot) supported by this toolchain"
           }
+        }
+      },
+      "additionalProperties": false
+    },
+    "toolchainsObjV1_1": {
+      "type": "object",
+      "properties": {
+        "kind": {
+          "$ref": "#/definitions/kind"
         },
-        "additionalProperties": false
-      }
+        "version": {
+          "$ref": "#/definitions/versionV1_1"
+        },
+        "toolchains": {
+          "type": "array",
+          "description": "Array of toolchain configurations per language",
+          "items": {
+            "type": "object",
+            "required": [
+              "language",
+              "compiler"
+            ],
+            "properties": {
+              "language": {
+                "$ref": "#/definitions/language"
+              },
+              "compiler": {
+                "$ref": "#/definitions/compilerV1_1"
+              },
+              "sourceFileExtensions": {
+                "$ref": "#/definitions/sourceFileExtensions"
+              }
+            },
+            "additionalProperties": false
+          }
+        }
+      },
+      "additionalProperties": false
     }
-  },
-  "additionalProperties": false
+  }
 }
diff --git a/Help/manual/include/OPTIONS_HELP.rst b/Help/manual/include/OPTIONS_HELP.rst
index f4f2dbe..aaa6b03 100644
--- a/Help/manual/include/OPTIONS_HELP.rst
+++ b/Help/manual/include/OPTIONS_HELP.rst
@@ -1,10 +1,16 @@
 .. |file| replace:: The output is printed to a named ``<file>`` if given.
 
-.. option:: -version [<file>], --version [<file>], /V [<file>]
+.. option:: -version[=json-v1] [<file>], --version[=json-v1] [<file>], /V[=json-v1] [<file>], /version[=json-v1] [<file>]
 
- Show program name/version banner and exit.
+ Show program name/version banner and exit. If ``json-v1`` is
+ specified, print extended version information in JSON format.
+ The JSON output contains the versions for the CMake and its
+ dependencies.
  |file|
 
+ The JSON output format is described in machine-readable form by
+ :download:`this JSON schema </manual/cmake/version-schema.json>`.
+
 .. option:: -h, -H, --help, -help, -usage, /?
 
  Print usage information and exit.
diff --git a/Help/manual/instrumentation/query-v1-schema.json b/Help/manual/instrumentation/query-v1-schema.json
new file mode 100644
index 0000000..23d4554
--- /dev/null
+++ b/Help/manual/instrumentation/query-v1-schema.json
@@ -0,0 +1,54 @@
+{
+  "$schema": "http://json-schema.org/draft/2020-12/schema#",
+  "type": "object",
+  "required": ["version"],
+  "properties": {
+    "version": {
+      "type": "integer",
+      "description": "The data version of snippet file to generate.",
+      "enum": [
+        1
+      ]
+    },
+    "callbacks": {
+      "type": "array",
+      "description": "A list of command-line strings for callbacks to handle collected instrumentation data. Whenever these callbacks are executed, the full path to a v1 Index File is appended to the arguments included in the string.",
+      "items": {
+        "type": "string"
+      }
+    },
+    "hooks": {
+      "type": "array",
+      "description": "A list of strings specifying when indexing should occur automatically. These are the intervals when instrumentation data should be collated and user callbacks should be invoked to handle the data.",
+      "items": {
+        "enum": [
+          "postGenerate",
+          "preBuild",
+          "postBuild",
+          "preCMakeBuild",
+          "postCMakeBuild",
+          "postCMakeInstall",
+          "postCMakeWorkflow",
+          "postCTest"
+        ],
+        "type": "string"
+      },
+      "uniqueItems": true
+    },
+    "options": {
+      "type": "array",
+      "description": "A list of strings used to enable certain optional behavior, including the collection of certain additional data.",
+      "uniqueItems": true,
+      "items": {
+        "enum": [
+          "staticSystemInformation",
+          "dynamicSystemInformation",
+          "cdashSubmit",
+          "cdashVerbose",
+          "trace"
+        ],
+        "type": "string"
+      }
+    }
+  }
+}
diff --git a/Help/manual/presets/schema.json b/Help/manual/presets/schema.json
index 63fbdb7..6b60967 100644
--- a/Help/manual/presets/schema.json
+++ b/Help/manual/presets/schema.json
@@ -1,5 +1,5 @@
 {
-  "$schema": "http://json-schema.org/draft-07/schema#",
+  "$schema": "http://json-schema.org/draft/2020-12/schema#",
   "type": "object",
   "description": "The presets specify the generator and the build directory, and optionally a list of variables and other arguments to pass to CMake.",
   "oneOf": [
@@ -161,6 +161,25 @@
         "include": { "$ref": "#/definitions/include" }
       },
       "additionalProperties": false
+    },
+    {
+      "properties": {
+        "$schema": { "$ref": "#/definitions/$schema" },
+        "$comment": { "$ref": "#/definitions/$comment" },
+        "version": {
+          "const": 11,
+          "description": "A required integer representing the version of the JSON schema."
+        },
+        "cmakeMinimumRequired": { "$ref": "#/definitions/cmakeMinimumRequiredV10" },
+        "vendor": { "$ref": "#/definitions/vendor" },
+        "configurePresets": { "$ref": "#/definitions/configurePresetsV10" },
+        "buildPresets": { "$ref": "#/definitions/buildPresetsV10" },
+        "testPresets": { "$ref": "#/definitions/testPresetsV11" },
+        "packagePresets": { "$ref": "#/definitions/packagePresetsV10" },
+        "workflowPresets": { "$ref": "#/definitions/workflowPresetsV10" },
+        "include": { "$ref": "#/definitions/include" }
+      },
+      "additionalProperties": false
     }
   ],
   "required": [
@@ -189,16 +208,58 @@
         }
       ]
     },
-    "cmakeMinimumRequiredPropertiesV10": {
-      "type": "object",
-      "description": "An optional object representing the minimum version of CMake needed to build this project. Available in version 10 and higher.",
+    "commonPropertiesAll": {
+      "properties": {
+        "name": {
+          "type": "string",
+          "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, package, or workflow) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
+          "minLength": 1
+        },
+        "vendor": {
+          "type": "object",
+          "description": "An optional map containing vendor-specific information. CMake does not interpret the contents of this field except to verify that it is a map if it does exist. However, it should follow the same conventions as the root-level vendor field.",
+          "properties": {}
+        },
+        "displayName": {
+          "type": "string",
+          "description": "An optional string with a human-friendly name of the preset."
+        },
+        "description": {
+          "type": "string",
+          "description": "An optional string with a human-friendly description of the preset."
+        }
+      }
+    },
+    "configureBuildTestPackagePresetsEnvironmentProperty": {
+      "properties": {
+        "environment": {
+          "type": "object",
+          "description": "An optional map of environment variables. The key is the variable name (which must not be an empty string). Each variable is set regardless of whether or not a value was given to it by the process's environment. This field supports macro expansion, and environment variables in this map may reference each other, and may be listed in any order, as long as such references do not cause a cycle (for example,if ENV_1 is $env{ENV_2}, ENV_2 may not be $env{ENV_1}.) Environment variables are inherited through the inherits field, and the preset's environment will be the union of its own environment and the environment from all its parents. If multiple presets in this union define the same variable, the standard rules of inherits are applied. Setting a variable to null causes it to not be set, even if a value was inherited from another preset.",
+          "properties": {},
+          "additionalProperties": {
+            "anyOf": [
+              {
+                "type": "null",
+                "description": "Setting a variable to null causes it to not be set, even if a value was inherited from another preset."
+              },
+              {
+                "type": "string",
+                "description": "A string representing the value of the variable."
+              }
+            ]
+          },
+          "propertyNames": {
+            "pattern": "^.+$"
+          }
+        }
+      }
+    },
+    "commentAsProperty": {
       "properties": {
         "$comment": { "$ref": "#/definitions/$comment" }
       }
     },
-    "cmakeMinimumRequiredPropertiesV1": {
-      "type": "object",
-      "description": "An optional object representing the minimum version of CMake needed to build this project. Available in version 1 and higher.",
+    "cmakeMinimumRequiredObject": {
       "properties": {
         "major": {
           "type": "integer",
@@ -218,29 +279,18 @@
       "type": "object",
       "description": "An optional object representing the minimum version of CMake needed to build this project. Available in version 10 and higher.",
       "allOf": [
-        { "$ref": "#/definitions/cmakeMinimumRequiredPropertiesV10" },
-        { "$ref": "#/definitions/cmakeMinimumRequiredPropertiesV1" }
+        { "$ref": "#/definitions/cmakeMinimumRequiredObject" },
+        { "$ref": "#/definitions/commentAsProperty" }
       ],
-      "properties": {
-        "$comment": {},
-        "major": {},
-        "minor": {},
-        "patch": {}
-      },
-      "additionalProperties": false
+      "unevaluatedProperties": false
     },
     "cmakeMinimumRequiredV1": {
       "type": "object",
       "description": "An optional object representing the minimum version of CMake needed to build this project. Available in version 1 and higher.",
       "allOf": [
-        { "$ref": "#/definitions/cmakeMinimumRequiredPropertiesV1" }
+        { "$ref": "#/definitions/cmakeMinimumRequiredObject" }
       ],
-      "properties": {
-        "major": {},
-        "minor": {},
-        "patch": {}
-      },
-      "additionalProperties": false
+      "unevaluatedProperties": false
     },
     "vendor": {
       "type": "object",
@@ -251,16 +301,7 @@
       "type": "string",
       "description": "An optional string representing the platform for generators that support it."
     },
-    "configurePresetsArchitectureAsObjectV10": {
-      "type": "object",
-      "description": "An optional object representing the platform for generators that support it. Available in version 10 and higher.",
-      "properties": {
-        "$comment": { "$ref": "#/definitions/$comment" }
-      }
-    },
     "configurePresetsArchitectureAsObjectV1": {
-      "type": "object",
-      "description": "An optional object representing the platform for generators that support it. Available in version 1 and higher.",
       "properties": {
         "value": {
           "type": "string",
@@ -283,15 +324,10 @@
           "type": "object",
           "description": "An optional object representing the platform for generators that support it. Available in version 10 and higher.",
           "allOf": [
-            { "$ref": "#/definitions/configurePresetsArchitectureAsObjectV10" },
-            { "$ref": "#/definitions/configurePresetsArchitectureAsObjectV1" }
+            { "$ref": "#/definitions/configurePresetsArchitectureAsObjectV1" },
+            { "$ref": "#/definitions/commentAsProperty" }
           ],
-          "properties": {
-            "$comment": {},
-            "value": {},
-            "strategy": {}
-          },
-          "additionalProperties": false
+          "unevaluatedProperties": false
         }
       ]
     },
@@ -304,11 +340,7 @@
           "allOf": [
             { "$ref": "#/definitions/configurePresetsArchitectureAsObjectV1" }
           ],
-          "properties": {
-            "value": {},
-            "strategy": {}
-          },
-          "additionalProperties": false
+          "unevaluatedProperties": false
         }
       ]
     },
@@ -316,16 +348,7 @@
       "type": "string",
       "description": "An optional string representing the toolset for generators that support it."
     },
-    "configurePresetsToolsetAsObjectV10": {
-      "type": "object",
-      "description": "An optional object representing the toolset for generators that support it. Available in version 10 and higher.",
-      "properties": {
-        "$comment": { "$ref": "#/definitions/$comment" }
-      }
-    },
     "configurePresetsToolsetAsObjectV1": {
-      "type": "object",
-      "description": "An optional object representing the toolset for generators that support it. Available in version 1 and higher.",
       "properties": {
         "value": {
           "type": "string",
@@ -348,15 +371,10 @@
           "type": "object",
           "description": "An optional object representing the toolset for generators that support it. Available in version 10 and higher.",
           "allOf": [
-            { "$ref": "#/definitions/configurePresetsToolsetAsObjectV10" },
-            { "$ref": "#/definitions/configurePresetsToolsetAsObjectV1" }
+            { "$ref": "#/definitions/configurePresetsToolsetAsObjectV1" },
+            { "$ref": "#/definitions/commentAsProperty" }
           ],
-          "properties": {
-            "$comment": {},
-            "value": {},
-            "strategy": {}
-          },
-          "additionalProperties": false
+          "unevaluatedProperties": false
         }
       ]
     },
@@ -369,905 +387,646 @@
           "allOf": [
             { "$ref": "#/definitions/configurePresetsToolsetAsObjectV1" }
           ],
-          "properties": {
-            "value": {},
-            "strategy": {}
-          },
-          "additionalProperties": false
+          "unevaluatedProperties": false
         }
       ]
     },
-    "configurePresetsCacheVariablesAdditionalPropertiesAsNullV1": {
+    "configurePresetsCacheVariablesAdditionalPropertiesAsNull": {
       "type": "null",
       "description": "Setting a variable to null causes it to not be set, even if a value was inherited from another preset."
     },
-    "configurePresetsCacheVariablesAdditionalPropertiesAsBooleanV1": {
+    "configurePresetsCacheVariablesAdditionalPropertiesAsBoolean": {
       "type": "boolean",
       "description": "A boolean representing the value of the variable. Equivalent to \"TRUE\" or \"FALSE\"."
     },
-    "configurePresetsCacheVariablesAdditionalPropertiesAsStringV1": {
+    "configurePresetsCacheVariablesAdditionalPropertiesAsString": {
       "type": "string",
       "description": "A string representing the value of the variable (which supports macro expansion)."
     },
-    "configurePresetsCacheVariablesAdditionalPropertiesAsObjectV10": {
-      "type": "object",
-      "description": "An optional object representing the cache variables for generators that support it. Available in version 10 and higher.",
-      "properties": {
-        "$comment": { "$ref": "#/definitions/$comment" }
-      }
-    },
-    "configurePresetsCacheVariablesAdditionalPropertiesAsObjectV1": {
-      "type": "object",
-      "description": "An optional object representing the cache variables for generators that support it. Available in version 1 and higher.",
+    "configurePresetsCacheVariablesAdditionalPropertiesAsObject": {
       "properties": {
         "type": {
           "type": "string",
-          "description": "An optional string representing the type of the variable. It should be BOOL, FILEPATH, PATH, STRING, or INTERNAL."
+          "description": "An optional string representing the type of the variable. It should be BOOL, FILEPATH, PATH, STRING, or INTERNAL.",
+          "enum": [
+            "BOOL", "FILEPATH", "PATH", "STRING", "INTERNAL"
+          ]
         },
         "value": {
           "anyOf": [
-            {
-              "type": "boolean",
-              "description": "A required boolean representing the value of the variable. Equivalent to \"TRUE\" or \"FALSE\"."
-            },
-            {
-              "type": "string",
-              "description": "A required string representing the value of the variable. This field supports macro expansion."
-            }
+            { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsBoolean" },
+            { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsString" }
           ]
         }
-      }
+      },
+      "required": [
+        "value"
+      ]
     },
     "configurePresetsCacheVariablesAdditionalPropertiesV10": {
       "anyOf": [
-        { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsNullV1" },
-        { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsBooleanV1" },
-        { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsStringV1" },
+        { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsNull" },
+        { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsBoolean" },
+        { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsString" },
         {
           "type": "object",
-          "description": "An object representing the type and value of the variable. Available in version 10 and higher.",
+          "description": "An optional object representing the cache variables for generators that support it. Available in version 10 and higher.",
           "allOf": [
-            { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsObjectV10" },
-            { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsObjectV1" }
+            { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsObject" },
+            { "$ref": "#/definitions/commentAsProperty" }
           ],
-          "properties": {
-            "$comment": {},
-            "type": {},
-            "value": {}
-          },
-          "required": [
-            "value"
-          ],
-          "additionalProperties": false
+          "unevaluatedProperties": false
         }
       ]
     },
     "configurePresetsCacheVariablesAdditionalPropertiesV1": {
       "anyOf": [
-        { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsNullV1" },
-        { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsBooleanV1" },
-        { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsStringV1" },
+        { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsNull" },
+        { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsBoolean" },
+        { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsString" },
         {
           "type": "object",
-          "description": "An object representing the type and value of the variable. Available in version 1 and higher.",
+          "description": "An optional object representing the cache variables for generators that support it. Available in version 1 and higher.",
           "allOf": [
-            { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsObjectV1" }
+            { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesAsObject" }
           ],
-          "properties": {
-            "type": {},
-            "value": {}
-          },
-          "required": [
-            "value"
-          ],
-          "additionalProperties": false
+          "unevaluatedProperties": false
         }
       ]
     },
-    "configurePresetsItemsV10": {
-      "type": "array",
-      "description": "An optional array of configure preset objects. Available in version 10 and higher.",
-      "items": {
-        "type": "object",
-        "description": "A configure preset object. Available in version 10 and higher.",
-        "properties": {
-          "$comment": { "$ref": "#/definitions/$comment" },
-          "warnings": {
-            "properties": {
-              "$comment": { "$ref": "#/definitions/$comment" }
+    "configurePresetsTraceV10": {
+      "type": "object",
+      "description": "An optional object specifying trace options.",
+      "allOf": [
+        { "$ref": "#/definitions/configurePresetsTraceObject" },
+        { "$ref": "#/definitions/commentAsProperty" }
+      ],
+      "unevaluatedProperties": false
+    },
+    "configurePresetsTraceV7": {
+      "type": "object",
+      "description": "An optional object specifying trace options.",
+      "allOf": [
+        { "$ref": "#/definitions/configurePresetsTraceObject" }
+      ],
+      "unevaluatedProperties": false
+    },
+    "configurePresetsTraceObject": {
+      "properties": {
+        "mode": {
+          "type": "string",
+          "description": "An optional string that specifies the trace mode.",
+          "enum": [
+            "on", "off", "expand"
+          ]
+        },
+        "format": {
+          "type": "string",
+          "description": "An optional string that specifies the trace output format.",
+          "enum": [
+            "human", "json-v1"
+          ]
+        },
+        "source": {
+          "anyOf": [
+            {
+              "type": "string",
+              "description": "An optional string representing the path to one source file to be traced.",
+              "minLength": 1
+            },
+            {
+              "type": "array",
+              "description": "An optional array of strings representing the paths to source files to be traced.",
+              "items": {
+                "type": "string",
+                "description": "A string representing the path to one source file to be traced.",
+                "minLength": 1
+              }
             }
-          },
-          "errors": {
-            "properties": {
-              "$comment": { "$ref": "#/definitions/$comment" }
-            }
-          },
-          "debug": {
-            "properties": {
-              "$comment": { "$ref": "#/definitions/$comment" }
-            }
-          },
-          "trace": {
-            "properties": {
-              "$comment": { "$ref": "#/definitions/$comment" }
-            }
-          },
-          "graphviz": {
-            "type": "string",
-            "description": "An optional string specifying the path to graphviz dot file. Available in version 10 and higher."
-          }
+          ]
+        },
+        "redirect": {
+          "type": "string",
+          "description": "An optional string specifying a path to a trace output file."
         }
       }
     },
-    "configurePresetsItemsV7": {
-      "type": "array",
-      "description": "An optional array of configure preset objects. Available in version 7 and higher.",
-      "items": {
-        "type": "object",
-        "description": "A configure preset object. Available in version 7 and higher.",
-        "properties": {
-          "trace": {
-            "type": "object",
-            "description": "An optional object specifying trace options.",
-            "properties": {
-              "mode": {
-                "type": "string",
-                "description": "An optional string that specifies the trace mode.",
-                "enum": [
-                  "on", "off", "expand"
-                ]
-              },
-              "format": {
-                "type": "string",
-                "description": "An optional string that specifies the trace output format.",
-                "enum": [
-                  "human", "json-v1"
-                ]
-              },
-              "source": {
-                "anyOf": [
-                  {
-                    "type": "string",
-                    "description": "An optional string representing the path to one source file to be traced.",
-                    "minLength": 1
-                  },
-                  {
-                    "type": "array",
-                    "description": "An optional array of strings representing the paths to source files to be traced.",
-                    "items": {
-                      "type": "string",
-                      "description": "A string representing the path to one source file to be traced.",
-                      "minLength": 1
-                    }
-                  }
-                ]
-              },
-              "redirect": {
-                "type": "string",
-                "description": "An optional string specifying a path to a trace output file."
-              }
-            }
-          }
+    "configurePresetsDebugV10": {
+      "type": "object",
+      "description": "An optional object specifying debug options.",
+      "allOf": [
+        { "$ref": "#/definitions/configurePresetsDebugObject" },
+        { "$ref": "#/definitions/commentAsProperty" }
+      ],
+      "unevaluatedProperties": false
+    },
+    "configurePresetsDebugV1": {
+      "type": "object",
+      "description": "An optional object specifying debug options.",
+      "allOf": [
+        { "$ref": "#/definitions/configurePresetsDebugObject" }
+      ],
+      "unevaluatedProperties": false
+    },
+    "configurePresetsErrorsV10": {
+      "type": "object",
+      "description": "An optional object specifying errors.",
+      "allOf": [
+        { "$ref": "#/definitions/configurePresetsErrorsObject" },
+        { "$ref": "#/definitions/commentAsProperty" }
+      ],
+      "unevaluatedProperties": false
+    },
+    "configurePresetsErrorsV1": {
+      "type": "object",
+      "description": "An optional object specifying errors.",
+      "allOf": [
+        { "$ref": "#/definitions/configurePresetsErrorsObject" }
+      ],
+      "unevaluatedProperties": false
+    },
+    "configurePresetsWarningsV10": {
+      "type": "object",
+      "description": "An optional object specifying warnings.",
+      "allOf": [
+        { "$ref": "#/definitions/configurePresetsWarningsObject" },
+        { "$ref": "#/definitions/commentAsProperty" }
+      ],
+      "unevaluatedProperties": false
+    },
+    "configurePresetsWarningsV1": {
+      "type": "object",
+      "description": "An optional object specifying warnings.",
+      "allOf": [
+        { "$ref": "#/definitions/configurePresetsWarningsObject" }
+      ],
+      "unevaluatedProperties": false
+    },
+    "configurePresetsDebugObject": {
+      "properties": {
+        "output": {
+          "type": "boolean",
+          "description": "An optional boolean. Setting this to true is equivalent to passing --debug-output on the command line."
+        },
+        "tryCompile": {
+          "type": "boolean",
+          "description": "An optional boolean. Setting this to true is equivalent to passing --debug-trycompile on the command line."
+        },
+        "find": {
+          "type": "boolean",
+          "description": "An optional boolean. Setting this to true is equivalent to passing --debug-find on the command line."
+        }
+      }
+    },
+    "configurePresetsErrorsObject": {
+      "properties": {
+        "dev": {
+          "type": "boolean",
+          "description": "An optional boolean. Equivalent to passing -Werror=dev or -Wno-error=dev on the command line. This may not be set to true if warnings.dev is set to false."
+        },
+        "deprecated": {
+          "type": "boolean",
+          "description": "An optional boolean. Equivalent to passing -Werror=deprecated or -Wno-error=deprecated on the command line. This may not be set to true if warnings.deprecated is set to false."
+        }
+      }
+    },
+    "configurePresetsWarningsObject": {
+      "properties": {
+        "dev": {
+          "type": "boolean",
+          "description": "An optional boolean. Equivalent to passing -Wdev or -Wno-dev on the command line. This may not be set to false if errors.dev is set to true."
+        },
+        "deprecated": {
+          "type": "boolean",
+          "description": "An optional boolean. Equivalent to passing -Wdeprecated or -Wno-deprecated on the command line. This may not be set to false if errors.deprecated is set to true."
+        },
+        "uninitialized": {
+          "type": "boolean",
+          "description": "An optional boolean. Setting this to true is equivalent to passing --warn-uninitialized on the command line."
+        },
+        "unusedCli": {
+          "type": "boolean",
+          "description": "An optional boolean. Setting this to false is equivalent to passing --no-warn-unused-cli on the command line."
+        },
+        "systemVars": {
+          "type": "boolean",
+          "description": "An optional boolean. Setting this to true is equivalent to passing --check-system-vars on the command line."
+        }
+      }
+    },
+    "configurePresetsItemsV10": {
+      "properties": {
+        "graphviz": {
+          "type": "string",
+          "description": "An optional string specifying the path to graphviz dot file. Available in version 10 and higher."
         }
       }
     },
     "configurePresetsItemsV3": {
-      "type": "array",
-      "description": "An optional array of configure preset objects. Available in version 3 and higher.",
-      "items": {
-        "type": "object",
-        "description": "A configure preset object. Available in version 3 and higher.",
-        "properties": {
-          "binaryDir": {
-            "type": "string",
-            "description": "An optional string representing the path to the output binary directory. This field supports macro expansion. If a relative path is specified, it is calculated relative to the source directory. If binaryDir is not specified, the path is calculated using regular methods."
-          },
-          "generator": {
-            "type": "string",
-            "description": "An optional string representing the generator to use for the preset. If generator is not specified, the normal generator discovery procedure is used. Note that for Visual Studio generators, unlike in the command line -G argument, you cannot include the platform name in the generator name. Use the architecture field instead."
-          },
-          "toolchainFile": {
-            "type": "string",
-            "description": "An optional string representing the path to the toolchain file. This field supports macro expansion. If a relative path is specified, it is calculated relative to the build directory, and if not found, relative to the source directory."
-          },
-          "installDir": {
-            "type": "string",
-            "description": "An optional string representing the path to the installation directory. This field supports macro expansion. If a relative path is specified, it is calculated relative to the source directory."
-          }
+      "properties": {
+        "toolchainFile": {
+          "type": "string",
+          "description": "An optional string representing the path to the toolchain file. This field supports macro expansion. If a relative path is specified, it is calculated relative to the build directory, and if not found, relative to the source directory."
+        },
+        "installDir": {
+          "type": "string",
+          "description": "An optional string representing the path to the installation directory, which will be used as the CMAKE_INSTALL_PREFIX variable. This field supports macro expansion. If a relative path is specified, it is calculated relative to the source directory."
         }
       }
     },
     "configurePresetsItemsV1": {
-      "type": "array",
-      "description": "An optional array of configure preset objects. Available in version 1 and higher.",
-      "items": {
-        "type": "object",
-        "description": "A configure preset object. Available in version 1 and higher.",
-        "properties": {
-          "name": {
-            "type": "string",
-            "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
-            "minLength": 1
-          },
-          "hidden": {
-            "type": "boolean",
-            "description": "An optional boolean specifying whether or not a preset should be hidden. If a preset is hidden, it cannot be used in the --preset= argument, will not show up in the CMake GUI, and does not have to have a valid generator or binaryDir, even from inheritance. Hidden presets are intended to be used as a base for other presets to inherit via the inherits field."
-          },
-          "inherits": {
-            "anyOf": [
-              {
-                "type": "string",
-                "description": "An optional string representing the name of the preset to inherit from.",
-                "minLength": 1
-              },
-              {
-                "type": "array",
-                "description": "An optional array of strings representing the names of presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json must not inherit from presets in CMakeUserPresets.json.",
-                "items": {
+      "allOf": [
+        { "$ref": "#/definitions/commonPropertiesAll" },
+        { "$ref": "#/definitions/configureBuildTestPackagePresetsEnvironmentProperty" },
+        {
+          "properties": {
+            "hidden": {
+              "type": "boolean",
+              "description": "An optional boolean specifying whether or not a preset should be hidden. If a preset is hidden, it cannot be used in the --preset= argument, will not show up in the CMake GUI, and does not have to have a valid generator or binaryDir, even from inheritance. Hidden presets are intended to be used as a base for other presets to inherit via the inherits field."
+            },
+            "inherits": {
+              "anyOf": [
+                {
                   "type": "string",
                   "description": "An optional string representing the name of the preset to inherit from.",
                   "minLength": 1
-                }
-              }
-            ]
-          },
-          "vendor": {
-            "type": "object",
-            "description": "An optional map containing vendor-specific information. CMake does not interpret the contents of this field except to verify that it is a map if it does exist. However, it should follow the same conventions as the root-level vendor field. If vendors use their own per-preset vendor field, they should implement inheritance in a sensible manner when appropriate.",
-            "properties": {}
-          },
-          "displayName": {
-            "type": "string",
-            "description": "An optional string with a human-friendly name of the preset."
-          },
-          "description": {
-            "type": "string",
-            "description": "An optional string with a human-friendly description of the preset."
-          },
-          "generator": {
-            "type": "string",
-            "description": "An optional string representing the generator to use for the preset. If generator is not specified, it must be inherited from the inherits preset (unless this preset is hidden). Note that for Visual Studio generators, unlike in the command line -G argument, you cannot include the platform name in the generator name. Use the architecture field instead."
-          },
-          "binaryDir": {
-            "type": "string",
-            "description": "An optional string representing the path to the output binary directory. This field supports macro expansion. If a relative path is specified, it is calculated relative to the source directory. If binaryDir is not specified, it must be inherited from the inherits preset (unless this preset is hidden)."
-          },
-          "cmakeExecutable": {
-            "type": "string",
-            "description": "An optional string representing the path to the CMake executable to use for this preset. This is reserved for use by IDEs, and is not used by CMake itself. IDEs that use this field should expand any macros in it."
-          },
-          "cacheVariables": {
-            "type": "object",
-            "description": "An optional map of cache variables. The key is the variable name (which must not be an empty string). Cache variables are inherited through the inherits field, and the preset's variables will be the union of its own cacheVariables and the cacheVariables from all its parents. If multiple presets in this union define the same variable, the standard rules of inherits are applied.",
-            "properties": {},
-            "propertyNames": {
-              "pattern": "^.+$"
-            }
-          },
-          "environment": {
-            "type": "object",
-            "description": "An optional map of environment variables. The key is the variable name (which must not be an empty string). Each variable is set regardless of whether or not a value was given to it by the process's environment. This field supports macro expansion, and environment variables in this map may reference each other, and may be listed in any order, as long as such references do not cause a cycle (for example,if ENV_1 is $env{ENV_2}, ENV_2 may not be $env{ENV_1}.) Environment variables are inherited through the inherits field, and the preset's environment will be the union of its own environment and the environment from all its parents. If multiple presets in this union define the same variable, the standard rules of inherits are applied. Setting a variable to null causes it to not be set, even if a value was inherited from another preset.",
-            "properties": {},
-            "additionalProperties": {
-              "anyOf": [
-                {
-                  "type": "null",
-                  "description": "Setting a variable to null causes it to not be set, even if a value was inherited from another preset."
                 },
                 {
-                  "type": "string",
-                  "description": "A string representing the value of the variable."
+                  "type": "array",
+                  "description": "An optional array of strings representing the names of presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json must not inherit from presets in CMakeUserPresets.json.",
+                  "items": {
+                    "type": "string",
+                    "description": "An optional string representing the name of the preset to inherit from.",
+                    "minLength": 1
+                  }
                 }
               ]
             },
-            "propertyNames": {
-              "pattern": "^.+$"
-            }
-          },
-          "warnings": {
-            "type": "object",
-            "description": "An optional object specifying warnings.",
-            "properties": {
-              "dev": {
-                "type": "boolean",
-                "description": "An optional boolean. Equivalent to passing -Wdev or -Wno-dev on the command line. This may not be set to false if errors.dev is set to true."
-              },
-              "deprecated": {
-                "type": "boolean",
-                "description": "An optional boolean. Equivalent to passing -Wdeprecated or -Wno-deprecated on the command line. This may not be set to false if errors.deprecated is set to true."
-              },
-              "uninitialized": {
-                "type": "boolean",
-                "description": "An optional boolean. Setting this to true is equivalent to passing --warn-uninitialized on the command line."
-              },
-              "unusedCli": {
-                "type": "boolean",
-                "description": "An optional boolean. Setting this to false is equivalent to passing --no-warn-unused-cli on the command line."
-              },
-              "systemVars": {
-                "type": "boolean",
-                "description": "An optional boolean. Setting this to true is equivalent to passing --check-system-vars on the command line."
-              }
-            }
-          },
-          "errors": {
-            "type": "object",
-            "description": "An optional object specifying errors.",
-            "properties": {
-              "dev": {
-                "type": "boolean",
-                "description": "An optional boolean. Equivalent to passing -Werror=dev or -Wno-error=dev on the command line. This may not be set to true if warnings.dev is set to false."
-              },
-              "deprecated": {
-                "type": "boolean",
-                "description": "An optional boolean. Equivalent to passing -Werror=deprecated or -Wno-error=deprecated on the command line. This may not be set to true if warnings.deprecated is set to false."
-              }
-            }
-          },
-          "debug": {
-            "type": "object",
-            "description": "An optional object specifying debug options.",
-            "properties": {
-              "output": {
-                "type": "boolean",
-                "description": "An optional boolean. Setting this to true is equivalent to passing --debug-output on the command line."
-              },
-              "tryCompile": {
-                "type": "boolean",
-                "description": "An optional boolean. Setting this to true is equivalent to passing --debug-trycompile on the command line."
-              },
-              "find": {
-                "type": "boolean",
-                "description": "An optional boolean. Setting this to true is equivalent to passing --debug-find on the command line."
-              }
+            "cmakeExecutable": {
+              "type": "string",
+              "description": "An optional string representing the path to the CMake executable to use for this preset. This is reserved for use by IDEs, and is not used by CMake itself. IDEs that use this field should expand any macros in it."
             }
           }
         }
+      ],
+      "required": [
+        "name"
+      ]
+    },
+    "configurePresetsAdditionalPropertiesV10": {
+      "properties": {
+        "toolset": { "$ref": "#/definitions/configurePresetsToolsetV10" },
+        "architecture": { "$ref": "#/definitions/configurePresetsArchitectureV10" },
+        "cacheVariables": {
+          "type": "object",
+          "description": "An optional map of cache variables. The key is the variable name (which must not be an empty string). Cache variables are inherited through the inherits field, and the preset's variables will be the union of its own cacheVariables and the cacheVariables from all its parents. If multiple presets in this union define the same variable, the standard rules of inherits are applied.",
+          "properties": {},
+          "propertyNames": {
+            "pattern": "^.+$"
+          },
+          "additionalProperties": { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesV10" }
+        },
+        "binaryDir": {
+          "type": "string",
+          "description": "An optional string representing the path to the output binary directory. This field supports macro expansion. If a relative path is specified, it is calculated relative to the source directory. If binaryDir is not specified, the path is calculated using regular methods."
+        },
+        "generator": {
+          "type": "string",
+          "description": "An optional string representing the generator to use for the preset. If generator is not specified, the normal generator discovery procedure is used. Note that for Visual Studio generators, unlike in the command line -G argument, you cannot include the platform name in the generator name. Use the architecture field instead."
+        },
+        "condition": { "$ref": "#/definitions/topConditionV10" },
+        "warnings": { "$ref": "#/definitions/configurePresetsWarningsV10" },
+        "errors": { "$ref": "#/definitions/configurePresetsErrorsV10" },
+        "debug": { "$ref": "#/definitions/configurePresetsDebugV10" },
+        "trace": { "$ref": "#/definitions/configurePresetsTraceV10" }
+      }
+    },
+    "configurePresetsAdditionalPropertiesV7": {
+      "allOf": [
+        { "$ref": "#/definitions/configurePresetsAdditionalPropertiesV3" },
+        {
+          "properties": {
+            "trace": { "$ref": "#/definitions/configurePresetsTraceV7" }
+          }
+        }
+      ]
+    },
+    "configurePresetsAdditionalPropertiesV3": {
+      "allOf": [
+        { "$ref": "#/definitions/configurePresetsAdditionalPropertiesV1" },
+        {
+          "properties": {
+            "condition": { "$ref": "#/definitions/topConditionV3" },
+            "binaryDir": {
+              "type": "string",
+              "description": "An optional string representing the path to the output binary directory. This field supports macro expansion. If a relative path is specified, it is calculated relative to the source directory. If binaryDir is not specified, the path is calculated using regular methods."
+            },
+            "generator": {
+              "type": "string",
+              "description": "An optional string representing the generator to use for the preset. If generator is not specified, the normal generator discovery procedure is used. Note that for Visual Studio generators, unlike in the command line -G argument, you cannot include the platform name in the generator name. Use the architecture field instead."
+            }
+          }
+        }
+      ]
+    },
+    "configurePresetsAdditionalPropertiesV1": {
+      "properties": {
+        "toolset": { "$ref": "#/definitions/configurePresetsToolsetV1" },
+        "architecture": { "$ref": "#/definitions/configurePresetsArchitectureV1" },
+        "cacheVariables": {
+          "type": "object",
+          "description": "An optional map of cache variables. The key is the variable name (which must not be an empty string). Cache variables are inherited through the inherits field, and the preset's variables will be the union of its own cacheVariables and the cacheVariables from all its parents. If multiple presets in this union define the same variable, the standard rules of inherits are applied.",
+          "properties": {},
+          "propertyNames": {
+            "pattern": "^.+$"
+          },
+          "additionalProperties": { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesV1" }
+        },
+        "binaryDir": {
+          "type": "string",
+          "description": "An optional string representing the path to the output binary directory. This field supports macro expansion. If a relative path is specified, it is calculated relative to the source directory. If binaryDir is not specified, it must be inherited from the inherits preset (unless this preset is hidden)."
+        },
+        "generator": {
+          "type": "string",
+          "description": "An optional string representing the generator to use for the preset. If generator is not specified, it must be inherited from the inherits preset (unless this preset is hidden). Note that for Visual Studio generators, unlike in the command line -G argument, you cannot include the platform name in the generator name. Use the architecture field instead."
+        },
+        "warnings": { "$ref": "#/definitions/configurePresetsWarningsV1" },
+        "errors": { "$ref": "#/definitions/configurePresetsErrorsV1" },
+        "debug": { "$ref": "#/definitions/configurePresetsDebugV1" }
       }
     },
     "configurePresetsV10": {
       "type": "array",
       "description": "An optional array of configure preset objects. Available in version 10 and higher.",
-      "allOf": [
-        { "$ref": "#/definitions/configurePresetsItemsV10" },
-        { "$ref": "#/definitions/configurePresetsItemsV7" },
-        { "$ref": "#/definitions/configurePresetsItemsV3" },
-        { "$ref": "#/definitions/configurePresetsItemsV1" }
-      ],
       "items": {
-        "properties": {
-          "$comment": {},
-          "name": {},
-          "hidden": {},
-          "inherits": {},
-          "vendor": {},
-          "displayName": {},
-          "description": {},
-          "generator": {},
-          "architecture": { "$ref": "#/definitions/configurePresetsArchitectureV10" },
-          "toolset": { "$ref": "#/definitions/configurePresetsToolsetV10" },
-          "toolchainFile": {},
-          "graphviz": {},
-          "binaryDir": {},
-          "installDir": {},
-          "cmakeExecutable": {},
-          "cacheVariables": {
-            "additionalProperties": { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesV10" }
-          },
-          "environment": {},
-          "warnings": {
-            "properties": {
-              "$comment": {},
-              "dev": {},
-              "deprecated": {},
-              "uninitialized": {},
-              "unusedCli": {},
-              "systemVars": {}
-            },
-            "additionalProperties": false
-          },
-          "errors": {
-            "properties": {
-              "$comment": {},
-              "dev": {},
-              "deprecated": {}
-            },
-            "additionalProperties": false
-          },
-          "debug": {
-            "properties": {
-              "$comment": {},
-              "output": {},
-              "tryCompile": {},
-              "find": {}
-            },
-            "additionalProperties": false
-          },
-          "condition": { "$ref": "#/definitions/topConditionV10" },
-          "trace": {
-            "properties": {
-              "$comment": {},
-              "mode": {},
-              "format": {},
-              "source": {},
-              "redirect": {}
-            },
-            "additionalProperties": false
-          }
-        },
-        "required": [
-          "name"
+        "type": "object",
+        "description": "A configure preset object.",
+        "allOf": [
+          { "$ref": "#/definitions/configurePresetsItemsV10" },
+          { "$ref": "#/definitions/configurePresetsItemsV3" },
+          { "$ref": "#/definitions/configurePresetsItemsV1" },
+          { "$ref": "#/definitions/configurePresetsAdditionalPropertiesV10" },
+          { "$ref": "#/definitions/commentAsProperty" }
         ],
-        "additionalProperties": false
+        "unevaluatedProperties": false
       }
     },
     "configurePresetsV7": {
       "type": "array",
       "description": "An optional array of configure preset objects. Available in version 7 and higher.",
-      "allOf": [
-        { "$ref": "#/definitions/configurePresetsItemsV7" },
-        { "$ref": "#/definitions/configurePresetsItemsV3" },
-        { "$ref": "#/definitions/configurePresetsItemsV1" }
-      ],
       "items": {
-        "properties": {
-          "name": {},
-          "hidden": {},
-          "inherits": {},
-          "vendor": {},
-          "displayName": {},
-          "description": {},
-          "generator": {},
-          "architecture": { "$ref": "#/definitions/configurePresetsArchitectureV1" },
-          "toolset": { "$ref": "#/definitions/configurePresetsToolsetV1" },
-          "toolchainFile": {},
-          "binaryDir": {},
-          "installDir": {},
-          "cmakeExecutable": {},
-          "cacheVariables": {
-            "additionalProperties": { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesV1" }
-          },
-          "environment": {},
-          "warnings": {
-            "properties": {
-              "dev": {},
-              "deprecated": {},
-              "uninitialized": {},
-              "unusedCli": {},
-              "systemVars": {}
-            },
-            "additionalProperties": false
-          },
-          "errors": {
-            "properties": {
-              "dev": {},
-              "deprecated": {}
-            },
-            "additionalProperties": false
-          },
-          "debug": {
-            "properties": {
-              "output": {},
-              "tryCompile": {},
-              "find": {}
-            },
-            "additionalProperties": false
-          },
-          "condition": { "$ref": "#/definitions/topConditionV3" },
-          "trace": {
-            "properties": {
-              "mode": {},
-              "format": {},
-              "source": {},
-              "redirect": {}
-            },
-            "additionalProperties": false
-          }
-        },
-        "required": [
-          "name"
+        "type": "object",
+        "description": "A configure preset object.",
+        "allOf": [
+          { "$ref": "#/definitions/configurePresetsItemsV3" },
+          { "$ref": "#/definitions/configurePresetsItemsV1" },
+          { "$ref": "#/definitions/configurePresetsAdditionalPropertiesV7" }
         ],
-        "additionalProperties": false
+        "unevaluatedProperties": false
       }
     },
     "configurePresetsV3": {
       "type": "array",
       "description": "An optional array of configure preset objects. Available in version 3 and higher.",
-      "allOf": [
-        { "$ref": "#/definitions/configurePresetsItemsV3" },
-        { "$ref": "#/definitions/configurePresetsItemsV1" }
-      ],
       "items": {
-        "properties": {
-          "name": {},
-          "hidden": {},
-          "inherits": {},
-          "vendor": {},
-          "displayName": {},
-          "description": {},
-          "generator": {},
-          "architecture": { "$ref": "#/definitions/configurePresetsArchitectureV1" },
-          "toolset": { "$ref": "#/definitions/configurePresetsToolsetV1" },
-          "toolchainFile": {},
-          "binaryDir": {},
-          "installDir": {},
-          "cmakeExecutable": {},
-          "cacheVariables": {
-            "additionalProperties": { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesV1" }
-          },
-          "environment": {},
-          "warnings": {
-            "properties": {
-              "dev": {},
-              "deprecated": {},
-              "uninitialized": {},
-              "unusedCli": {},
-              "systemVars": {}
-            },
-            "additionalProperties": false
-          },
-          "errors": {
-            "properties": {
-              "dev": {},
-              "deprecated": {}
-            },
-            "additionalProperties": false
-          },
-          "debug": {
-            "properties": {
-              "output": {},
-              "tryCompile": {},
-              "find": {}
-            },
-            "additionalProperties": false
-          },
-          "condition": { "$ref": "#/definitions/topConditionV3" }
-        },
-        "required": [
-          "name"
+        "type": "object",
+        "description": "A configure preset object.",
+        "allOf": [
+          { "$ref": "#/definitions/configurePresetsItemsV3" },
+          { "$ref": "#/definitions/configurePresetsItemsV1" },
+          { "$ref": "#/definitions/configurePresetsAdditionalPropertiesV3" }
         ],
-        "additionalProperties": false
+        "unevaluatedProperties": false
       }
     },
     "configurePresetsV1": {
       "type": "array",
       "description": "An optional array of configure preset objects. Available in version 1 and higher.",
-      "allOf": [
-        { "$ref": "#/definitions/configurePresetsItemsV1" }
-      ],
-      "items": {
-        "properties": {
-          "name": {},
-          "hidden": {},
-          "inherits": {},
-          "vendor": {},
-          "displayName": {},
-          "description": {},
-          "generator": {},
-          "architecture": { "$ref": "#/definitions/configurePresetsArchitectureV1" },
-          "toolset": { "$ref": "#/definitions/configurePresetsToolsetV1" },
-          "binaryDir": {},
-          "cmakeExecutable": {},
-          "cacheVariables": {
-            "additionalProperties": { "$ref": "#/definitions/configurePresetsCacheVariablesAdditionalPropertiesV1" }
-          },
-          "environment": {},
-          "warnings": {
-            "properties": {
-              "dev": {},
-              "deprecated": {},
-              "uninitialized": {},
-              "unusedCli": {},
-              "systemVars": {}
-            },
-            "additionalProperties": false
-          },
-          "errors": {
-            "properties": {
-              "dev": {},
-              "deprecated": {}
-            },
-            "additionalProperties": false
-          },
-          "debug": {
-            "properties": {
-              "output": {},
-              "tryCompile": {},
-              "find": {}
-            },
-            "additionalProperties": false
-          }
-        },
-        "required": [
-          "name"
-        ],
-        "additionalProperties": false
-      }
-    },
-    "buildPresetsItemsV10": {
-      "type": "array",
-      "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 10 and higher.",
       "items": {
         "type": "object",
-        "properties": {
-          "$comment": { "$ref": "#/definitions/$comment" }
-        }
+        "description": "A configure preset object.",
+        "allOf": [
+          { "$ref": "#/definitions/configurePresetsItemsV1" },
+          { "$ref": "#/definitions/configurePresetsAdditionalPropertiesV1" }
+        ],
+        "unevaluatedProperties": false
       }
     },
     "buildPresetsItemsV4": {
-      "type": "array",
-      "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 4 and higher.",
-      "items": {
-        "type": "object",
-        "properties": {
-          "resolvePackageReferences": {
-            "type": "string",
-            "description": "An optional string specifying the package resolve behavior. Valid values are \"on\" (packages are resolved prior to the build), \"off\" (packages are not resolved prior to the build), and \"only\" (packages are resolved, but no build will be performed).",
-            "enum": [
-              "on", "off", "only"
-            ]
-          }
+      "properties": {
+        "resolvePackageReferences": {
+          "type": "string",
+          "description": "An optional string specifying the package resolve behavior. Valid values are \"on\" (packages are resolved prior to the build), \"off\" (packages are not resolved prior to the build), and \"only\" (packages are resolved, but no build will be performed).",
+          "enum": [
+            "on", "off", "only"
+          ]
         }
       }
     },
-    "buildPresetsItemsV3": {
-      "type": "array",
-      "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 3 and higher."
-    },
     "buildPresetsItemsV2": {
-      "type": "array",
-      "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 2 and higher.",
-      "items": {
-        "type": "object",
-        "properties": {
-          "name": {
-            "type": "string",
-            "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, package, or workflow) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
-            "minLength": 1
-          },
-          "hidden": {
-            "type": "boolean",
-            "description": "An optional boolean specifying whether or not a preset should be hidden. If a preset is hidden, it cannot be used in the --preset argument and does not have to have a valid configurePreset, even from inheritance. Hidden presets are intended to be used as a base for other presets to inherit via the inherits field."
-          },
-          "inherits": {
-            "anyOf": [
-              {
-                "type": "string",
-                "description": "An optional string representing the name of the build preset to inherit from.",
-                "minLength": 1
-              },
-              {
-                "type": "array",
-                "description": "An optional array of strings representing the names of build presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json must not inherit from presets in CMakeUserPresets.json.",
-                "items": {
-                  "type": "string",
-                  "description": "An optional string representing the name of the preset to inherit from.",
-                  "minLength": 1
-                }
-              }
-            ]
-          },
-          "configurePreset": {
-            "type": "string",
-            "description": "An optional string specifying the name of a configure preset to associate with this build preset. If configurePreset is not specified, it must be inherited from the inherits preset (unless this preset is hidden). The build tree directory is inferred from the configure preset.",
-            "minLength": 1
-          },
-          "vendor": {
-            "type": "object",
-            "description": "An optional map containing vendor-specific information. CMake does not interpret the contents of this field except to verify that it is a map if it does exist. However, it should follow the same conventions as the root-level vendor field. If vendors use their own per-preset vendor field, they should implement inheritance in a sensible manner when appropriate.",
-            "properties": {}
-          },
-          "displayName": {
-            "type": "string",
-            "description": "An optional string with a human-friendly name of the preset."
-          },
-          "description": {
-            "type": "string",
-            "description": "An optional string with a human-friendly description of the preset."
-          },
-          "inheritConfigureEnvironment": {
-            "type": "boolean",
-            "description": "An optional boolean that defaults to true. If true, the environment variables from the associated configure preset are inherited after all inherited build preset environments, but before environment variables explicitly specified in this build preset."
-          },
-          "environment": {
-            "type": "object",
-            "description": "An optional map of environment variables. The key is the variable name (which must not be an empty string). Each variable is set regardless of whether or not a value was given to it by the process's environment. This field supports macro expansion, and environment variables in this map may reference each other, and may be listed in any order, as long as such references do not cause a cycle (for example,if ENV_1 is $env{ENV_2}, ENV_2 may not be $env{ENV_1}.) Environment variables are inherited through the inherits field, and the preset's environment will be the union of its own environment and the environment from all its parents. If multiple presets in this union define the same variable, the standard rules of inherits are applied. Setting a variable to null causes it to not be set, even if a value was inherited from another preset.",
-            "properties": {},
-            "additionalProperties": {
+      "allOf": [
+        { "$ref": "#/definitions/commonPropertiesAll" },
+        { "$ref": "#/definitions/configureBuildTestPackagePresetsEnvironmentProperty" },
+        {
+          "properties": {
+            "hidden": {
+              "type": "boolean",
+              "description": "An optional boolean specifying whether or not a preset should be hidden. If a preset is hidden, it cannot be used in the --preset argument and does not have to have a valid configurePreset, even from inheritance. Hidden presets are intended to be used as a base for other presets to inherit via the inherits field."
+            },
+            "inherits": {
               "anyOf": [
                 {
-                  "type": "null",
-                  "description": "Setting a variable to null causes it to not be set, even if a value was inherited from another preset."
+                  "type": "string",
+                  "description": "An optional string representing the name of the build preset to inherit from.",
+                  "minLength": 1
                 },
                 {
-                  "type": "string",
-                  "description": "A string representing the value of the variable."
+                  "type": "array",
+                  "description": "An optional array of strings representing the names of build presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json must not inherit from presets in CMakeUserPresets.json.",
+                  "items": {
+                    "type": "string",
+                    "description": "An optional string representing the name of the preset to inherit from.",
+                    "minLength": 1
+                  }
                 }
               ]
             },
-            "propertyNames": {
-              "pattern": "^.+$"
-            }
-          },
-          "jobs": {
-            "type": "integer",
-            "description": "An optional integer. Equivalent to passing --parallel or -j on the command line."
-          },
-          "targets": {
-            "anyOf": [
-              {
-                "type": "string",
-                "description": "An optional string. Equivalent to passing --target or -t on the command line. Vendors may ignore the targets property or hide build presets that explicitly specify targets."
-              },
-              {
-                "type": "array",
-                "description": "An optional array of strings. Equivalent to passing --target or -t on the command line. Vendors may ignore the targets property or hide build presets that explicitly specify targets.",
-                "items": {
+            "configurePreset": {
+              "type": "string",
+              "description": "An optional string specifying the name of a configure preset to associate with this build preset. If configurePreset is not specified, it must be inherited from the inherits preset (unless this preset is hidden). The build tree directory is inferred from the configure preset.",
+              "minLength": 1
+            },
+            "inheritConfigureEnvironment": {
+              "type": "boolean",
+              "description": "An optional boolean that defaults to true. If true, the environment variables from the associated configure preset are inherited after all inherited build preset environments, but before environment variables explicitly specified in this build preset."
+            },
+            "jobs": {
+              "type": "integer",
+              "description": "An optional non-negative integer. Equivalent to passing --parallel or -j on the command line.",
+              "minimum": 0
+            },
+            "targets": {
+              "anyOf": [
+                {
                   "type": "string",
                   "description": "An optional string. Equivalent to passing --target or -t on the command line. Vendors may ignore the targets property or hide build presets that explicitly specify targets."
+                },
+                {
+                  "type": "array",
+                  "description": "An optional array of strings. Equivalent to passing --target or -t on the command line. Vendors may ignore the targets property or hide build presets that explicitly specify targets.",
+                  "items": {
+                    "type": "string",
+                    "description": "An optional string. Equivalent to passing --target or -t on the command line. Vendors may ignore the targets property or hide build presets that explicitly specify targets."
+                  }
                 }
-              }
-            ]
-          },
-          "configuration": {
-            "type": "string",
-            "description": "An optional string. Equivalent to passing --config on the command line."
-          },
-          "cleanFirst": {
-            "type": "boolean",
-            "description": "An optional boolean. If true, equivalent to passing --clean-first on the command line."
-          },
-          "verbose": {
-            "type": "boolean",
-            "description": "An optional boolean. If true, equivalent to passing --verbose on the command line."
-          },
-          "nativeToolOptions": {
-            "type": "array",
-            "description": "An optional array of strings. Equivalent to passing options after -- on the command line.",
-            "items": {
+              ]
+            },
+            "configuration": {
               "type": "string",
-              "description": "An optional string representing an option to pass after -- on the command line."
+              "description": "An optional string. Equivalent to passing --config on the command line."
+            },
+            "cleanFirst": {
+              "type": "boolean",
+              "description": "An optional boolean. If true, equivalent to passing --clean-first on the command line."
+            },
+            "verbose": {
+              "type": "boolean",
+              "description": "An optional boolean. If true, equivalent to passing --verbose on the command line."
+            },
+            "nativeToolOptions": {
+              "type": "array",
+              "description": "An optional array of strings. Equivalent to passing options after -- on the command line.",
+              "items": {
+                "type": "string",
+                "description": "An optional string representing an option to pass after -- on the command line."
+              }
             }
           }
         }
+      ],
+      "required": [
+        "name"
+      ]
+    },
+    "buildPresetsAdditionalPropertiesV10": {
+      "properties": {
+        "condition": { "$ref": "#/definitions/topConditionV10" }
+      }
+    },
+    "buildPresetsAdditionalPropertiesV3": {
+      "properties": {
+        "condition": { "$ref": "#/definitions/topConditionV3" }
       }
     },
     "buildPresetsV10": {
       "type": "array",
       "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 10 and higher.",
-      "allOf": [
-        { "$ref": "#/definitions/buildPresetsItemsV10" },
-        { "$ref": "#/definitions/buildPresetsItemsV4" },
-        { "$ref": "#/definitions/buildPresetsItemsV3" },
-        { "$ref": "#/definitions/buildPresetsItemsV2" }
-      ],
       "items": {
         "type": "object",
-        "properties": {
-          "$comment": {},
-          "name": {},
-          "hidden": {},
-          "inherits": {},
-          "configurePreset": {},
-          "vendor": {},
-          "displayName": {},
-          "description": {},
-          "inheritConfigureEnvironment": {},
-          "environment": {},
-          "jobs": {},
-          "targets": {},
-          "configuration": {},
-          "cleanFirst": {},
-          "resolvePackageReferences": {},
-          "verbose": {},
-          "nativeToolOptions": {},
-          "condition": { "$ref": "#/definitions/topConditionV10" }
-        },
-        "required": [
-          "name"
+        "description": "A build preset object.",
+        "allOf": [
+          { "$ref": "#/definitions/buildPresetsItemsV4" },
+          { "$ref": "#/definitions/buildPresetsItemsV2" },
+          { "$ref": "#/definitions/buildPresetsAdditionalPropertiesV10" },
+          { "$ref": "#/definitions/commentAsProperty" }
         ],
-        "additionalProperties": false
+        "unevaluatedProperties": false
       }
     },
     "buildPresetsV4": {
       "type": "array",
       "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 4 and higher.",
-      "allOf": [
-        { "$ref": "#/definitions/buildPresetsItemsV4" },
-        { "$ref": "#/definitions/buildPresetsItemsV3" },
-        { "$ref": "#/definitions/buildPresetsItemsV2" }
-      ],
       "items": {
         "type": "object",
-        "properties": {
-          "name": {},
-          "hidden": {},
-          "inherits": {},
-          "configurePreset": {},
-          "vendor": {},
-          "displayName": {},
-          "description": {},
-          "inheritConfigureEnvironment": {},
-          "environment": {},
-          "jobs": {},
-          "targets": {},
-          "configuration": {},
-          "cleanFirst": {},
-          "resolvePackageReferences": {},
-          "verbose": {},
-          "nativeToolOptions": {},
-          "condition": { "$ref": "#/definitions/topConditionV3" }
-        },
-        "required": [
-          "name"
+        "description": "A build preset object.",
+        "allOf": [
+          { "$ref": "#/definitions/buildPresetsItemsV4" },
+          { "$ref": "#/definitions/buildPresetsItemsV2" },
+          { "$ref": "#/definitions/buildPresetsAdditionalPropertiesV3" }
         ],
-        "additionalProperties": false
+        "unevaluatedProperties": false
       }
     },
     "buildPresetsV3": {
       "type": "array",
       "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 3 and higher.",
-      "allOf": [
-        { "$ref": "#/definitions/buildPresetsItemsV3" },
-        { "$ref": "#/definitions/buildPresetsItemsV2" }
-      ],
       "items": {
         "type": "object",
-        "properties": {
-          "name": {},
-          "hidden": {},
-          "inherits": {},
-          "configurePreset": {},
-          "vendor": {},
-          "displayName": {},
-          "description": {},
-          "inheritConfigureEnvironment": {},
-          "environment": {},
-          "jobs": {},
-          "targets": {},
-          "configuration": {},
-          "cleanFirst": {},
-          "verbose": {},
-          "nativeToolOptions": {},
-          "condition": { "$ref": "#/definitions/topConditionV3" }
-        },
-        "required": [
-          "name"
+        "description": "A build preset object.",
+        "allOf": [
+          { "$ref": "#/definitions/buildPresetsItemsV2" },
+          { "$ref": "#/definitions/buildPresetsAdditionalPropertiesV3" }
         ],
-        "additionalProperties": false
+        "unevaluatedProperties": false
       }
     },
     "buildPresetsV2": {
       "type": "array",
       "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 2 and higher.",
-      "allOf": [
-        { "$ref": "#/definitions/buildPresetsItemsV2" }
-      ],
       "items": {
         "type": "object",
-        "properties": {
-          "name": {},
-          "hidden": {},
-          "inherits": {},
-          "configurePreset": {},
-          "vendor": {},
-          "displayName": {},
-          "description": {},
-          "inheritConfigureEnvironment": {},
-          "environment": {},
-          "jobs": {},
-          "targets": {},
-          "configuration": {},
-          "cleanFirst": {},
-          "verbose": {},
-          "nativeToolOptions": {}
-        },
-        "required": [
-          "name"
+        "description": "A build preset object.",
+        "allOf": [
+          { "$ref": "#/definitions/buildPresetsItemsV2" }
         ],
-        "additionalProperties": false
+        "unevaluatedProperties": false
       }
     },
+    "testPresetsExecutionJobsV11": {
+      "oneOf": [
+        {
+          "type": "integer",
+          "description": "An optional non-negative integer. Equivalent to passing --parallel or -j on the command line.",
+          "minimum": 0
+        },
+        {
+          "type": "string",
+          "description": "An optional string. Equivalent to passing --parallel or -j on the command line with the number of jobs omitted.",
+          "minLength": 0,
+          "maxLength": 0
+        }
+      ]
+    },
+    "testPresetsExecutionJobsV2": {
+      "type": "integer",
+      "description": "An optional non-negative integer. Equivalent to passing --parallel or -j on the command line.",
+      "minimum": 0
+    },
+    "testPresetsExecutionRepeatV10": {
+      "type": "object",
+      "description": "An optional object specifying how to repeat tests. Equivalent to passing --repeat on the command line.",
+      "allOf": [
+        { "$ref": "#/definitions/testPresetsExecutionRepeatObject" },
+        { "$ref": "#/definitions/commentAsProperty" }
+      ],
+      "unevaluatedProperties": false
+    },
+    "testPresetsExecutionRepeatV2": {
+      "type": "object",
+      "description": "An optional object specifying how to repeat tests. Equivalent to passing --repeat on the command line.",
+      "allOf": [
+        { "$ref": "#/definitions/testPresetsExecutionRepeatObject" }
+      ],
+      "unevaluatedProperties": false
+    },
+    "testPresetsExecutionRepeatObject": {
+      "properties": {
+        "mode": {
+          "type": "string",
+          "description": "A required string. Must be one of the following values: \"until-fail\", \"until-pass\", or \"after-timeout\".",
+          "enum": [
+            "until-fail", "until-pass", "after-timeout"
+          ]
+        },
+        "count": {
+          "type": "integer",
+          "description": "A required integer."
+        }
+      },
+      "required": [
+        "mode", "count"
+      ]
+    },
     "testPresetsFilterIncludeIndexAsStringV2": {
       "type": "string",
       "description": "An optional string specifying a file with the command line syntax for --tests-information. Available in version 2 and higher."
@@ -1312,17 +1071,10 @@
           "type": "object",
           "description": "An optional object specifying test preset filters. Available in version 10 and higher.",
           "allOf": [
-            { "$ref": "#/definitions/testPresetsFilterIncludeIndexAsObjectV10" },
-            { "$ref": "#/definitions/testPresetsFilterIncludeIndexAsObjectV2" }
+            { "$ref": "#/definitions/testPresetsFilterIncludeIndexAsObjectV2" },
+            { "$ref": "#/definitions/commentAsProperty" }
           ],
-          "properties": {
-            "$comment": {},
-            "start": {},
-            "end": {},
-            "stride": {},
-            "specificTests": {}
-          },
-          "additionalProperties": false
+          "unevaluatedProperties": false
         }
       ]
     },
@@ -1335,1310 +1087,781 @@
           "allOf": [
             { "$ref": "#/definitions/testPresetsFilterIncludeIndexAsObjectV2" }
           ],
-          "properties": {
-            "start": {},
-            "end": {},
-            "stride": {},
-            "specificTests": {}
-          },
-          "additionalProperties": false
+          "unevaluatedProperties": false
         }
       ]
     },
-    "testPresetsItemsV10": {
-      "type": "array",
-      "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 10 and higher.",
-      "items": {
-        "type": "object",
-        "properties": {
-          "$comment": { "$ref": "#/definitions/$comment" },
-          "filter": {
-            "type": "object",
-            "properties": {
-              "$comment": { "$ref": "#/definitions/$comment" },
-              "include": {
-                "type": "object",
-                "properties": {
-                  "$comment": { "$ref": "#/definitions/$comment" }
-                }
-              },
-              "exclude": {
-                "type": "object",
-                "properties": {
-                  "$comment": { "$ref": "#/definitions/$comment" },
-                  "fixtures": {
-                    "type": "object",
-                    "properties": {
-                      "$comment": { "$ref": "#/definitions/$comment" }
-                    }
-                  }
-                }
-              }
+    "testPresetsFilterIncludeV10": {
+      "type": "object",
+      "description": "An optional object specifying which tests to include.",
+      "allOf": [
+        { "$ref": "#/definitions/testPresetsFilterIncludeObject" },
+        { "$ref": "#/definitions/commentAsProperty" },
+        {
+          "properties": {
+            "index": { "$ref": "#/definitions/testPresetsFilterIncludeIndexV10" }
+          }
+        }
+      ]
+    },
+    "testPresetsFilterIncludeV2": {
+      "type": "object",
+      "description": "An optional object specifying which tests to include.",
+      "allOf": [
+        { "$ref": "#/definitions/testPresetsFilterIncludeObject" },
+        {
+          "properties": {
+            "index": { "$ref": "#/definitions/testPresetsFilterIncludeIndexV2" }
+          }
+        }
+      ]
+    },
+    "testPresetsFilterIncludeObject": {
+      "properties": {
+        "name": {
+          "type": "string",
+          "description": "An optional string specifying a regex for test names. Equivalent to passing --tests-regex on the command line."
+        },
+        "label": {
+          "type": "string",
+          "description": "An optional string specifying a regex for test labels. Equivalent to passing --label-regex on the command line."
+        },
+        "useUnion": {
+          "type": "boolean",
+          "description": "An optional boolean. Equivalent to passing --union on the command line."
+        }
+      }
+    },
+    "testPresetsFilterExcludeV10": {
+      "type": "object",
+      "description": "An optional object specifying which tests to exclude.",
+      "allOf": [
+        { "$ref": "#/definitions/testPresetsFilterExcludeObject" },
+        { "$ref": "#/definitions/commentAsProperty" },
+        {
+          "properties": {
+            "fixtures": {
+              "allOf": [
+                { "$ref": "#/definitions/testPresetsFilterExcludeFixturesV2" },
+                { "$ref": "#/definitions/commentAsProperty" }
+              ]
             }
+          }
+        }
+      ]
+    },
+    "testPresetsFilterExcludeV2": {
+      "type": "object",
+      "description": "An optional object specifying which tests to exclude.",
+      "allOf": [
+        { "$ref": "#/definitions/testPresetsFilterExcludeObject" },
+        {
+          "properties": {
+            "fixtures": { "$ref": "#/definitions/testPresetsFilterExcludeFixturesV2" }
+          }
+        }
+      ]
+    },
+    "testPresetsFilterExcludeFixturesV2": {
+        "type": "object",
+        "description": "An optional object specifying which fixtures to exclude from adding tests.",
+        "properties": {
+          "any": {
+            "type": "string",
+            "description": "An optional string specifying a regex for text fixtures to exclude from adding any tests. Equivalent to --fixture-exclude-any on the command line."
           },
-          "execution": {
-            "type": "object",
-            "properties": {
-              "$comment": { "$ref": "#/definitions/$comment" },
-              "repeat": {
-                "type": "object",
-                "properties": {
-                  "$comment": { "$ref": "#/definitions/$comment" }
-                }
-              }
-            }
+          "setup": {
+            "type": "string",
+            "description": "An optional string specifying a regex for text fixtures to exclude from adding setup tests. Equivalent to --fixture-exclude-setup on the command line."
+          },
+          "cleanup": {
+            "type": "string",
+            "description": "An optional string specifying a regex for text fixtures to exclude from adding cleanup tests. Equivalent to --fixture-exclude-cleanup on the command line."
           }
         }
+    },
+    "testPresetsFilterExcludeObject": {
+      "properties": {
+        "name": {
+          "type": "string",
+          "description": "An optional string specifying a regex for test names. Equivalent to passing --exclude-regex on the command line."
+        },
+        "label": {
+          "type": "string",
+          "description": "An optional string specifying a regex for test labels. Equivalent to passing --label-exclude on the command line."
+        }
       }
     },
-    "testPresetsItemsV6": {
-      "type": "array",
-      "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 6 and higher.",
-      "items": {
-        "type": "object",
-        "properties": {
-          "output": {
-            "type": "object",
-            "description": "An optional object specifying output options.",
-            "properties": {
-              "outputJUnitFile": {
-                "type": "string",
-                "description": "An optional string specifying a path to a JUnit file. Equivalent to passing --output-junit on the command line."
-              }
-            }
+    "testPresetsExecutionV11": {
+      "type": "object",
+      "description": "An optional object specifying options for test execution.",
+      "allOf": [
+        { "$ref": "#/definitions/testPresetsExecutionObject" },
+        { "$ref": "#/definitions/commentAsProperty" },
+        {
+          "properties": {
+            "repeat": { "$ref": "#/definitions/testPresetsExecutionRepeatV10" },
+            "jobs": { "$ref": "#/definitions/testPresetsExecutionJobsV11" }
           }
         }
+      ],
+      "unevaluatedProperties": false
+    },
+    "testPresetsExecutionV10": {
+      "type": "object",
+      "description": "An optional object specifying options for test execution.",
+      "allOf": [
+        { "$ref": "#/definitions/testPresetsExecutionObject" },
+        { "$ref": "#/definitions/commentAsProperty" },
+        {
+          "properties": {
+            "repeat": { "$ref": "#/definitions/testPresetsExecutionRepeatV10" },
+            "jobs": { "$ref": "#/definitions/testPresetsExecutionJobsV2" }
+          }
+        }
+      ],
+      "unevaluatedProperties": false
+    },
+    "testPresetsExecutionV2": {
+      "type": "object",
+      "description": "An optional object specifying options for test execution.",
+      "allOf": [
+        { "$ref": "#/definitions/testPresetsExecutionObject" },
+        {
+          "properties": {
+            "repeat": { "$ref": "#/definitions/testPresetsExecutionRepeatV2" },
+            "jobs": { "$ref": "#/definitions/testPresetsExecutionJobsV2" }
+          }
+        }
+      ],
+      "unevaluatedProperties": false
+    },
+    "testPresetsExecutionObject": {
+      "properties": {
+        "stopOnFailure": {
+          "type": "boolean",
+          "description": "An optional boolean. If true, equivalent to passing --stop-on-failure on the command line."
+        },
+        "enableFailover": {
+          "type": "boolean",
+          "description": "An optional boolean. If true, equivalent to passing -F on the command line."
+        },
+        "resourceSpecFile": {
+          "type": "string",
+          "description": "An optional string. Equivalent to passing --resource-spec-file on the command line."
+        },
+        "testLoad": {
+          "type": "integer",
+          "description": "An optional integer. Equivalent to passing --test-load on the command line."
+        },
+        "showOnly": {
+          "type": "string",
+          "description": "An optional string. Equivalent to passing --show-only on the command line. Value must be \"human\" or \"json-v1\".",
+          "enum": [
+            "human", "json-v1"
+          ]
+        },
+        "interactiveDebugging": {
+          "type": "boolean",
+          "description": "An optional boolean. If true, equivalent to passing --interactive-debug-mode 1 on the command line. If false, equivalent to passing --interactive-debug-mode 0 on the command line."
+        },
+        "scheduleRandom": {
+          "type": "boolean",
+          "description": "An optional boolean. If true, equivalent to passing --schedule-random on the command line."
+        },
+        "timeout": {
+          "type": "integer",
+          "description": "An optional integer. Equivalent to passing --timeout on the command line."
+        },
+        "noTestsAction": {
+          "type": "string",
+          "description": "An optional string specifying the behavior if no tests are found. Must be one of the following values: \"default\" (equivalent to not passing any value on the command line), \"error\" (equivalent to passing --no-tests=error on the command line), or \"ignore\" (equivalent to passing --no-tests-ignore on the command line).",
+          "enum": [
+            "default", "error", "ignore"
+          ]
+        }
       }
     },
-    "testPresetsItemsV5": {
-      "type": "array",
-      "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 5 and higher.",
-      "items": {
-        "type": "object",
-        "properties": {
-          "output": {
-            "type": "object",
-            "description": "An optional object specifying output options.",
-            "properties": {
-              "testOutputTruncation": {
-                "type": "string",
-                "description": "An optional string specifying the test output truncation mode. Equivalent to passing --test-output-truncation on the command line. Must be one of the following values: \"tail\", \"middle\", or \"head\".",
-                "enum": [
-                  "tail", "middle", "head"
-                ]
-              }
-            }
+    "testPresetsOutputJUnitFile": {
+      "type": "string",
+      "description": "An optional string specifying a path to a JUnit file. Equivalent to passing --output-junit on the command line."
+    },
+    "testPresetsTestOutputTruncation": {
+      "type": "string",
+      "description": "An optional string specifying the test output truncation mode. Equivalent to passing --test-output-truncation on the command line. Must be one of the following values: \"tail\", \"middle\", or \"head\".",
+      "enum": [
+        "tail", "middle", "head"
+      ]
+    },
+    "testPresetsOutputV10": {
+      "type": "object",
+      "description": "An optional object specifying output options.",
+      "allOf": [
+        { "$ref": "#/definitions/testPresetsOutputObject" },
+        {
+          "properties": {
+            "outputJUnitFile": { "$ref": "#/definitions/testPresetsOutputJUnitFile" },
+            "testOutputTruncation": { "$ref": "#/definitions/testPresetsTestOutputTruncation" },
+            "$comment": { "$ref": "#/definitions/$comment" }
           }
         }
+      ],
+      "unevaluatedProperties": false
+    },
+    "testPresetsOutputV6": {
+      "type": "object",
+      "description": "An optional object specifying output options.",
+      "allOf": [
+        { "$ref": "#/definitions/testPresetsOutputObject" },
+        {
+          "properties": {
+            "outputJUnitFile": { "$ref": "#/definitions/testPresetsOutputJUnitFile" },
+            "testOutputTruncation": { "$ref": "#/definitions/testPresetsTestOutputTruncation" }
+          }
+        }
+      ],
+      "unevaluatedProperties": false
+    },
+    "testPresetsOutputV5": {
+      "type": "object",
+      "description": "An optional object specifying output options.",
+      "allOf": [
+        { "$ref": "#/definitions/testPresetsOutputObject" },
+        {
+          "properties": {
+            "testOutputTruncation": { "$ref": "#/definitions/testPresetsTestOutputTruncation" }
+          }
+        }
+      ],
+      "unevaluatedProperties": false
+    },
+    "testPresetsOutputV2": {
+      "type": "object",
+      "description": "An optional object specifying output options.",
+      "allOf": [
+        { "$ref": "#/definitions/testPresetsOutputObject" }
+      ],
+      "unevaluatedProperties": false
+    },
+    "testPresetsOutputObject": {
+      "properties": {
+        "shortProgress": {
+          "type": "boolean",
+          "description": "An optional boolean. If true, equivalent to passing --progress on the command line."
+        },
+        "verbosity": {
+          "type": "string",
+          "description": "An optional string specifying verbosity level. Valid values are \"default\" (equivalent to passing no verbosity flags on the command line), \"verbose\" (equivalent to passing --verbose on the command line), and \"extra\" (equivalent to passing --extra-verbose on the command line).",
+          "enum": [
+            "default", "verbose", "extra"
+          ]
+        },
+        "debug": {
+          "type": "boolean",
+          "description": "An optional boolean. If true, equivalent to passing --debug on the command line."
+        },
+        "outputOnFailure": {
+          "type": "boolean",
+          "description": "An optional boolean. If true, equivalent to passing --output-on-failure on the command line."
+        },
+        "quiet": {
+          "type": "boolean",
+          "description": "An optional boolean. If true, equivalent to passing --quiet on the command line."
+        },
+        "outputLogFile": {
+          "type": "string",
+          "description": "An optional string specifying a path to a log file. Equivalent to passing --output-log on the command line."
+        },
+        "labelSummary": {
+          "type": "boolean",
+          "description": "An optional boolean. If false, equivalent to passing --no-label-summary on the command line."
+        },
+        "subprojectSummary": {
+          "type": "boolean",
+          "description": "An optional boolean. If false, equivalent to passing --no-subproject-summary on the command line."
+        },
+        "maxPassedTestOutputSize": {
+          "type": "integer",
+          "description": "An optional integer specifying the maximum output for passed tests in bytes. Equivalent to passing --test-output-size-passed on the command line."
+        },
+        "maxFailedTestOutputSize": {
+          "type": "integer",
+          "description": "An optional integer specifying the maximum output for failed tests in bytes. Equivalent to passing --test-output-size-failed on the command line."
+        },
+        "maxTestNameWidth": {
+          "type": "integer",
+          "description": "An optional integer specifying the maximum width of a test name to output. Equivalent to passing --max-width on the command line."
+        }
       }
     },
-    "testPresetsItemsV3": {
-      "type": "array",
-      "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 3 and higher."
+    "testPresetsAdditionalPropertiesV11": {
+      "properties": {
+        "execution": { "$ref": "#/definitions/testPresetsExecutionV11" },
+        "filter": {
+          "type": "object",
+          "description": "An optional object specifying how to filter the tests to run.",
+          "properties": {
+            "include": { "$ref": "#/definitions/testPresetsFilterIncludeV10" },
+            "exclude": { "$ref": "#/definitions/testPresetsFilterExcludeV10" },
+            "$comment": { "$ref": "#/definitions/$comment" }
+          }
+        },
+        "output": { "$ref": "#/definitions/testPresetsOutputV6" },
+        "condition": { "$ref": "#/definitions/topConditionV10" }
+      }
+    },
+    "testPresetsAdditionalPropertiesV10": {
+      "properties": {
+        "execution": { "$ref": "#/definitions/testPresetsExecutionV10" },
+        "filter": {
+          "type": "object",
+          "description": "An optional object specifying how to filter the tests to run.",
+          "properties": {
+            "include": { "$ref": "#/definitions/testPresetsFilterIncludeV10" },
+            "exclude": { "$ref": "#/definitions/testPresetsFilterExcludeV10" },
+            "$comment": { "$ref": "#/definitions/$comment" }
+          }
+        },
+        "output": { "$ref": "#/definitions/testPresetsOutputV6" },
+        "condition": { "$ref": "#/definitions/topConditionV10" }
+      }
+    },
+    "testPresetsAdditionalPropertiesV6": {
+      "properties": {
+        "execution": { "$ref": "#/definitions/testPresetsExecutionV2" },
+        "filter": {
+          "type": "object",
+          "description": "An optional object specifying how to filter the tests to run.",
+          "properties": {
+            "include": { "$ref": "#/definitions/testPresetsFilterIncludeV2" },
+            "exclude": { "$ref": "#/definitions/testPresetsFilterExcludeV2" }
+          }
+        },
+        "output": { "$ref": "#/definitions/testPresetsOutputV6" },
+        "condition": { "$ref": "#/definitions/topConditionV3" }
+      }
+    },
+    "testPresetsAdditionalPropertiesV5": {
+      "properties": {
+        "execution": { "$ref": "#/definitions/testPresetsExecutionV2" },
+        "filter": {
+          "type": "object",
+          "description": "An optional object specifying how to filter the tests to run.",
+          "properties": {
+            "include": { "$ref": "#/definitions/testPresetsFilterIncludeV2" },
+            "exclude": { "$ref": "#/definitions/testPresetsFilterExcludeV2" }
+          }
+        },
+        "output": { "$ref": "#/definitions/testPresetsOutputV5" },
+        "condition": { "$ref": "#/definitions/topConditionV3" }
+      }
+    },
+    "testPresetsAdditionalPropertiesV3": {
+      "allOf": [
+        { "$ref": "#/definitions/testPresetsAdditionalPropertiesV2" },
+        {
+          "properties": {
+            "condition": { "$ref": "#/definitions/topConditionV3" }
+          }
+        }
+      ]
+    },
+    "testPresetsAdditionalPropertiesV2": {
+      "properties": {
+        "execution": { "$ref": "#/definitions/testPresetsExecutionV2" },
+        "filter": {
+          "type": "object",
+          "description": "An optional object specifying how to filter the tests to run.",
+          "properties": {
+            "include": { "$ref": "#/definitions/testPresetsFilterIncludeV2" },
+            "exclude": { "$ref": "#/definitions/testPresetsFilterExcludeV2" }
+          }
+        },
+        "output": { "$ref": "#/definitions/testPresetsOutputV2" }
+      }
     },
     "testPresetsItemsV2": {
-      "type": "array",
-      "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 2 and higher.",
-      "items": {
-        "type": "object",
-        "properties": {
-          "name": {
-            "type": "string",
-            "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, package, or workflow) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
-            "minLength": 1
-          },
-          "hidden": {
-            "type": "boolean",
-            "description": "An optional boolean specifying whether or not a preset should be hidden. If a preset is hidden, it cannot be used in the --preset argument and does not have to have a valid configurePreset, even from inheritance. Hidden presets are intended to be used as a base for other presets to inherit via the inherits field."
-          },
-          "inherits": {
-            "anyOf": [
-              {
-                "type": "string",
-                "description": "An optional string representing the name of the test preset to inherit from.",
-                "minLength": 1
-              },
-              {
-                "type": "array",
-                "description": "An optional array of strings representing the names of test presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json must not inherit from presets in CMakeUserPresets.json.",
-                "items": {
-                  "type": "string",
-                  "description": "An optional string representing the name of the preset to inherit from.",
-                  "minLength": 1
-                }
-              }
-            ]
-          },
-          "configurePreset": {
-            "type": "string",
-            "description": "An optional string specifying the name of a configure preset to associate with this test preset. If configurePreset is not specified, it must be inherited from the inherits preset (unless this preset is hidden). The build tree directory is inferred from the configure preset.",
-            "minLength": 1
-          },
-          "vendor": {
-            "type": "object",
-            "description": "An optional map containing vendor-specific information. CMake does not interpret the contents of this field except to verify that it is a map if it does exist. However, it should follow the same conventions as the root-level vendor field. If vendors use their own per-preset vendor field, they should implement inheritance in a sensible manner when appropriate.",
-            "properties": {}
-          },
-          "displayName": {
-            "type": "string",
-            "description": "An optional string with a human-friendly name of the preset."
-          },
-          "description": {
-            "type": "string",
-            "description": "An optional string with a human-friendly description of the preset."
-          },
-          "inheritConfigureEnvironment": {
-            "type": "boolean",
-            "description": "An optional boolean that defaults to true. If true, the environment variables from the associated configure preset are inherited after all inherited test preset environments, but before environment variables explicitly specified in this test preset."
-          },
-          "environment": {
-            "type": "object",
-            "description": "An optional map of environment variables. The key is the variable name (which must not be an empty string). Each variable is set regardless of whether or not a value was given to it by the process's environment. This field supports macro expansion, and environment variables in this map may reference each other, and may be listed in any order, as long as such references do not cause a cycle (for example,if ENV_1 is $env{ENV_2}, ENV_2 may not be $env{ENV_1}.) Environment variables are inherited through the inherits field, and the preset's environment will be the union of its own environment and the environment from all its parents. If multiple presets in this union define the same variable, the standard rules of inherits are applied. Setting a variable to null causes it to not be set, even if a value was inherited from another preset.",
-            "properties": {},
-            "additionalProperties": {
+      "allOf": [
+        { "$ref": "#/definitions/commonPropertiesAll" },
+        { "$ref": "#/definitions/configureBuildTestPackagePresetsEnvironmentProperty" },
+        {
+          "properties": {
+            "hidden": {
+              "type": "boolean",
+              "description": "An optional boolean specifying whether or not a preset should be hidden. If a preset is hidden, it cannot be used in the --preset argument and does not have to have a valid configurePreset, even from inheritance. Hidden presets are intended to be used as a base for other presets to inherit via the inherits field."
+            },
+            "inherits": {
               "anyOf": [
                 {
-                  "type": "null",
-                  "description": "Setting a variable to null causes it to not be set, even if a value was inherited from another preset."
+                  "type": "string",
+                  "description": "An optional string representing the name of the test preset to inherit from.",
+                  "minLength": 1
                 },
                 {
-                  "type": "string",
-                  "description": "A string representing the value of the variable."
+                  "type": "array",
+                  "description": "An optional array of strings representing the names of test presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json must not inherit from presets in CMakeUserPresets.json.",
+                  "items": {
+                    "type": "string",
+                    "description": "An optional string representing the name of the preset to inherit from.",
+                    "minLength": 1
+                  }
                 }
               ]
             },
-            "propertyNames": {
-              "pattern": "^.+$"
-            }
-          },
-          "configuration": {
-            "type": "string",
-            "description": "An optional string. Equivalent to passing --build-config on the command line."
-          },
-          "overwriteConfigurationFile": {
-            "type": "array",
-            "description": "An optional array of configuration options to overwrite options specified in the CTest configuration file. Equivalent to passing ``--overwrite`` for each value in the array.",
-            "items": {
+            "configurePreset": {
               "type": "string",
-              "description": "An option written as a key-value pair in the form \"key=value\"."
-            }
-          },
-          "output": {
-            "type": "object",
-            "description": "An optional object specifying output options.",
-            "properties": {
-              "shortProgress": {
-                "type": "boolean",
-                "description": "An optional boolean. If true, equivalent to passing --progress on the command line."
-              },
-              "verbosity": {
+              "description": "An optional string specifying the name of a configure preset to associate with this test preset. If configurePreset is not specified, it must be inherited from the inherits preset (unless this preset is hidden). The build tree directory is inferred from the configure preset.",
+              "minLength": 1
+            },
+            "inheritConfigureEnvironment": {
+              "type": "boolean",
+              "description": "An optional boolean that defaults to true. If true, the environment variables from the associated configure preset are inherited after all inherited test preset environments, but before environment variables explicitly specified in this test preset."
+            },
+            "configuration": {
+              "type": "string",
+              "description": "An optional string. Equivalent to passing --build-config on the command line."
+            },
+            "overwriteConfigurationFile": {
+              "type": "array",
+              "description": "An optional array of configuration options to overwrite options specified in the CTest configuration file. Equivalent to passing ``--overwrite`` for each value in the array.",
+              "items": {
                 "type": "string",
-                "description": "An optional string specifying verbosity level. Valid values are \"default\" (equivalent to passing no verbosity flags on the command line), \"verbose\" (equivalent to passing --verbose on the command line), and \"extra\" (equivalent to passing --extra-verbose on the command line).",
-                "enum": [
-                  "default", "verbose", "extra"
-                ]
-              },
-              "debug": {
-                "type": "boolean",
-                "description": "An optional boolean. If true, equivalent to passing --debug on the command line."
-              },
-              "outputOnFailure": {
-                "type": "boolean",
-                "description": "An optional boolean. If true, equivalent to passing --output-on-failure on the command line."
-              },
-              "quiet": {
-                "type": "boolean",
-                "description": "An optional boolean. If true, equivalent to passing --quiet on the command line."
-              },
-              "outputLogFile": {
-                "type": "string",
-                "description": "An optional string specifying a path to a log file. Equivalent to passing --output-log on the command line."
-              },
-              "labelSummary": {
-                "type": "boolean",
-                "description": "An optional boolean. If false, equivalent to passing --no-label-summary on the command line."
-              },
-              "subprojectSummary": {
-                "type": "boolean",
-                "description": "An optional boolean. If false, equivalent to passing --no-subproject-summary on the command line."
-              },
-              "maxPassedTestOutputSize": {
-                "type": "integer",
-                "description": "An optional integer specifying the maximum output for passed tests in bytes. Equivalent to passing --test-output-size-passed on the command line."
-              },
-              "maxFailedTestOutputSize": {
-                "type": "integer",
-                "description": "An optional integer specifying the maximum output for failed tests in bytes. Equivalent to passing --test-output-size-failed on the command line."
-              },
-              "maxTestNameWidth": {
-                "type": "integer",
-                "description": "An optional integer specifying the maximum width of a test name to output. Equivalent to passing --max-width on the command line."
-              }
-            }
-          },
-          "filter": {
-            "type": "object",
-            "description": "An optional object specifying how to filter the tests to run.",
-            "properties": {
-              "include": {
-                "type": "object",
-                "description": "An optional object specifying which tests to include.",
-                "properties": {
-                  "name": {
-                    "type": "string",
-                    "description": "An optional string specifying a regex for test names. Equivalent to passing --tests-regex on the command line."
-                  },
-                  "label": {
-                    "type": "string",
-                    "description": "An optional string specifying a regex for test labels. Equivalent to passing --label-regex on the command line."
-                  },
-                  "useUnion": {
-                    "type": "boolean",
-                    "description": "An optional boolean. Equivalent to passing --union on the command line."
-                  }
-                }
-              },
-              "exclude": {
-                "type": "object",
-                "description": "An optional object specifying which tests to exclude.",
-                "properties": {
-                  "name": {
-                    "type": "string",
-                    "description": "An optional string specifying a regex for test names. Equivalent to passing --exclude-regex on the command line."
-                  },
-                  "label": {
-                    "type": "string",
-                    "description": "An optional string specifying a regex for test labels. Equivalent to passing --label-exclude on the command line."
-                  },
-                  "fixtures": {
-                    "type": "object",
-                    "description": "An optional object specifying which fixtures to exclude from adding tests.",
-                    "properties": {
-                      "any": {
-                        "type": "string",
-                        "description": "An optional string specifying a regex for text fixtures to exclude from adding any tests. Equivalent to --fixture-exclude-any on the command line."
-                      },
-                      "setup": {
-                        "type": "string",
-                        "description": "An optional string specifying a regex for text fixtures to exclude from adding setup tests. Equivalent to --fixture-exclude-setup on the command line."
-                      },
-                      "cleanup": {
-                        "type": "string",
-                        "description": "An optional string specifying a regex for text fixtures to exclude from adding cleanup tests. Equivalent to --fixture-exclude-cleanup on the command line."
-                      }
-                    }
-                  }
-                }
-              }
-            }
-          },
-          "execution": {
-            "type": "object",
-            "description": "An optional object specifying options for test execution.",
-            "properties": {
-              "stopOnFailure": {
-                "type": "boolean",
-                "description": "An optional boolean. If true, equivalent to passing --stop-on-failure on the command line."
-              },
-              "enableFailover": {
-                "type": "boolean",
-                "description": "An optional boolean. If true, equivalent to passing -F on the command line."
-              },
-              "jobs": {
-                "type": "integer",
-                "description": "An optional integer. Equivalent to passing --parallel on the command line."
-              },
-              "resourceSpecFile": {
-                "type": "string",
-                "description": "An optional string. Equivalent to passing --resource-spec-file on the command line."
-              },
-              "testLoad": {
-                "type": "integer",
-                "description": "An optional integer. Equivalent to passing --test-load on the command line."
-              },
-              "showOnly": {
-                "type": "string",
-                "description": "An optional string. Equivalent to passing --show-only on the command line. Value must be \"human\" or \"json-v1\".",
-                "enum": [
-                  "human", "json-v1"
-                ]
-              },
-              "repeat": {
-                "type": "object",
-                "description": "An optional object specifying how to repeat tests. Equivalent to passing --repeat on the command line.",
-                "properties": {
-                  "mode": {
-                    "type": "string",
-                    "description": "A required string. Must be one of the following values: \"until-fail\", \"until-pass\", or \"after-timeout\".",
-                    "enum": [
-                      "until-fail", "until-pass", "after-timeout"
-                    ]
-                  },
-                  "count": {
-                    "type": "integer",
-                    "description": "A required integer."
-                  }
-                }
-              },
-              "interactiveDebugging": {
-                "type": "boolean",
-                "description": "An optional boolean. If true, equivalent to passing --interactive-debug-mode 1 on the command line. If false, equivalent to passing --interactive-debug-mode 0 on the command line."
-              },
-              "scheduleRandom": {
-                "type": "boolean",
-                "description": "An optional boolean. If true, equivalent to passing --schedule-random on the command line."
-              },
-              "timeout": {
-                "type": "integer",
-                "description": "An optional integer. Equivalent to passing --timeout on the command line."
-              },
-              "noTestsAction": {
-                "type": "string",
-                "description": "An optional string specifying the behavior if no tests are found. Must be one of the following values: \"default\" (equivalent to not passing any value on the command line), \"error\" (equivalent to passing --no-tests=error on the command line), or \"ignore\" (equivalent to passing --no-tests-ignore on the command line).",
-                "enum": [
-                  "default", "error", "ignore"
-                ]
+                "description": "An option written as a key-value pair in the form \"key=value\"."
               }
             }
           }
         }
+      ],
+      "required": [
+        "name"
+      ]
+    },
+    "testPresetsV11": {
+      "type": "array",
+      "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 11 and higher.",
+      "items": {
+        "type": "object",
+        "description": "A test preset object",
+        "allOf": [
+          { "$ref": "#/definitions/testPresetsItemsV2" },
+          { "$ref": "#/definitions/testPresetsAdditionalPropertiesV11" },
+          { "$ref": "#/definitions/commentAsProperty" }
+        ],
+        "unevaluatedProperties": false
       }
     },
     "testPresetsV10": {
       "type": "array",
       "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 10 and higher.",
-      "allOf": [
-        { "$ref": "#/definitions/testPresetsItemsV10" },
-        { "$ref": "#/definitions/testPresetsItemsV6" },
-        { "$ref": "#/definitions/testPresetsItemsV5" },
-        { "$ref": "#/definitions/testPresetsItemsV3" },
-        { "$ref": "#/definitions/testPresetsItemsV2" }
-      ],
       "items": {
         "type": "object",
-        "properties": {
-          "$comment": {},
-          "name": {},
-          "hidden": {},
-          "inherits": {},
-          "configurePreset": {},
-          "vendor": {},
-          "displayName": {},
-          "description": {},
-          "inheritConfigureEnvironment": {},
-          "environment": {},
-          "configuration": {},
-          "overwriteConfigurationFile": {},
-          "output": {
-            "type": "object",
-            "properties": {
-              "shortProgress": {},
-              "verbosity": {},
-              "debug": {},
-              "outputOnFailure": {},
-              "quiet": {},
-              "outputLogFile": {},
-              "outputJUnitFile": {},
-              "labelSummary": {},
-              "subprojectSummary": {},
-              "maxPassedTestOutputSize": {},
-              "maxFailedTestOutputSize": {},
-              "maxTestNameWidth": {},
-              "testOutputTruncation": {}
-            },
-            "additionalProperties": false
-          },
-          "filter": {
-            "type": "object",
-            "properties": {
-              "$comment": {},
-              "include": {
-                "type": "object",
-                "properties": {
-                  "$comment": {},
-                  "name": {},
-                  "label": {},
-                  "useUnion": {},
-                  "index": { "$ref": "#/definitions/testPresetsFilterIncludeIndexV10" }
-                },
-                "additionalProperties": false
-              },
-              "exclude": {
-                "type": "object",
-                "properties": {
-                  "$comment": {},
-                  "name": {},
-                  "label": {},
-                  "fixtures": {
-                    "type": "object",
-                    "properties": {
-                      "$comment": {},
-                      "any": {},
-                      "setup": {},
-                      "cleanup": {}
-                    },
-                    "additionalProperties": false
-                  }
-                },
-                "additionalProperties": false
-              }
-            },
-            "additionalProperties": false
-          },
-          "execution": {
-            "type": "object",
-            "properties": {
-              "$comment": {},
-              "stopOnFailure": {},
-              "enableFailover": {},
-              "jobs": {},
-              "resourceSpecFile": {},
-              "testLoad": {},
-              "showOnly": {},
-              "repeat": {
-                "type": "object",
-                "properties": {
-                  "$comment": {},
-                  "mode": {},
-                  "count": {}
-                },
-                "required": [
-                  "mode", "count"
-                ],
-                "additionalProperties": false
-              },
-              "interactiveDebugging": {},
-              "scheduleRandom": {},
-              "timeout": {},
-              "noTestsAction": {}
-            },
-            "additionalProperties": false
-          },
-          "condition": { "$ref": "#/definitions/topConditionV10" }
-        },
-        "required": [
-          "name"
+        "description": "A test preset object",
+        "allOf": [
+          { "$ref": "#/definitions/testPresetsItemsV2" },
+          { "$ref": "#/definitions/testPresetsAdditionalPropertiesV10" },
+          { "$ref": "#/definitions/commentAsProperty" }
         ],
-        "additionalProperties": false
+        "unevaluatedProperties": false
       }
     },
     "testPresetsV6": {
       "type": "array",
       "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 6 and higher.",
-      "allOf": [
-        { "$ref": "#/definitions/testPresetsItemsV6" },
-        { "$ref": "#/definitions/testPresetsItemsV5" },
-        { "$ref": "#/definitions/testPresetsItemsV3" },
-        { "$ref": "#/definitions/testPresetsItemsV2" }
-      ],
       "items": {
         "type": "object",
-        "properties": {
-          "name": {},
-          "hidden": {},
-          "inherits": {},
-          "configurePreset": {},
-          "vendor": {},
-          "displayName": {},
-          "description": {},
-          "inheritConfigureEnvironment": {},
-          "environment": {},
-          "configuration": {},
-          "overwriteConfigurationFile": {},
-          "output": {
-            "type": "object",
-            "properties": {
-              "shortProgress": {},
-              "verbosity": {},
-              "debug": {},
-              "outputOnFailure": {},
-              "quiet": {},
-              "outputLogFile": {},
-              "outputJUnitFile": {},
-              "labelSummary": {},
-              "subprojectSummary": {},
-              "maxPassedTestOutputSize": {},
-              "maxFailedTestOutputSize": {},
-              "maxTestNameWidth": {},
-              "testOutputTruncation": {}
-            },
-            "additionalProperties": false
-          },
-          "filter": {
-            "type": "object",
-            "properties": {
-              "include": {
-                "type": "object",
-                "properties": {
-                  "name": {},
-                  "label": {},
-                  "useUnion": {},
-                  "index": { "$ref": "#/definitions/testPresetsFilterIncludeIndexV2" }
-                },
-                "additionalProperties": false
-              },
-              "exclude": {
-                "type": "object",
-                "properties": {
-                  "name": {},
-                  "label": {},
-                  "fixtures": {
-                    "type": "object",
-                    "properties": {
-                      "any": {},
-                      "setup": {},
-                      "cleanup": {}
-                    },
-                    "additionalProperties": false
-                  }
-                },
-                "additionalProperties": false
-              }
-            },
-            "additionalProperties": false
-          },
-          "execution": {
-            "type": "object",
-            "properties": {
-              "stopOnFailure": {},
-              "enableFailover": {},
-              "jobs": {},
-              "resourceSpecFile": {},
-              "testLoad": {},
-              "showOnly": {},
-              "repeat": {
-                "type": "object",
-                "properties": {
-                  "mode": {},
-                  "count": {}
-                },
-                "required": [
-                  "mode", "count"
-                ],
-                "additionalProperties": false
-              },
-              "interactiveDebugging": {},
-              "scheduleRandom": {},
-              "timeout": {},
-              "noTestsAction": {}
-            },
-            "additionalProperties": false
-          },
-          "condition": { "$ref": "#/definitions/topConditionV3" }
-        },
-        "required": [
-          "name"
+        "description": "A test preset object",
+        "allOf": [
+          { "$ref": "#/definitions/testPresetsItemsV2" },
+          { "$ref": "#/definitions/testPresetsAdditionalPropertiesV6" }
         ],
-        "additionalProperties": false
+        "unevaluatedProperties": false
       }
     },
     "testPresetsV5": {
       "type": "array",
       "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 5 and higher.",
-      "allOf": [
-        { "$ref": "#/definitions/testPresetsItemsV5" },
-        { "$ref": "#/definitions/testPresetsItemsV3" },
-        { "$ref": "#/definitions/testPresetsItemsV2" }
-      ],
       "items": {
         "type": "object",
-        "properties": {
-          "name": {},
-          "hidden": {},
-          "inherits": {},
-          "configurePreset": {},
-          "vendor": {},
-          "displayName": {},
-          "description": {},
-          "inheritConfigureEnvironment": {},
-          "environment": {},
-          "configuration": {},
-          "overwriteConfigurationFile": {},
-          "output": {
-            "type": "object",
-            "properties": {
-              "shortProgress": {},
-              "verbosity": {},
-              "debug": {},
-              "outputOnFailure": {},
-              "quiet": {},
-              "outputLogFile": {},
-              "labelSummary": {},
-              "subprojectSummary": {},
-              "maxPassedTestOutputSize": {},
-              "maxFailedTestOutputSize": {},
-              "maxTestNameWidth": {},
-              "testOutputTruncation": {}
-            },
-            "additionalProperties": false
-          },
-          "filter": {
-            "type": "object",
-            "properties": {
-              "include": {
-                "type": "object",
-                "properties": {
-                  "name": {},
-                  "label": {},
-                  "useUnion": {},
-                  "index": { "$ref": "#/definitions/testPresetsFilterIncludeIndexV2" }
-                },
-                "additionalProperties": false
-              },
-              "exclude": {
-                "type": "object",
-                "properties": {
-                  "name": {},
-                  "label": {},
-                  "fixtures": {
-                    "type": "object",
-                    "properties": {
-                      "any": {},
-                      "setup": {},
-                      "cleanup": {}
-                    },
-                    "additionalProperties": false
-                  }
-                },
-                "additionalProperties": false
-              }
-            },
-            "additionalProperties": false
-          },
-          "execution": {
-            "type": "object",
-            "properties": {
-              "stopOnFailure": {},
-              "enableFailover": {},
-              "jobs": {},
-              "resourceSpecFile": {},
-              "testLoad": {},
-              "showOnly": {},
-              "repeat": {
-                "type": "object",
-                "properties": {
-                  "mode": {},
-                  "count": {}
-                },
-                "required": [
-                  "mode", "count"
-                ],
-                "additionalProperties": false
-              },
-              "interactiveDebugging": {},
-              "scheduleRandom": {},
-              "timeout": {},
-              "noTestsAction": {}
-            },
-            "additionalProperties": false
-          },
-          "condition": { "$ref": "#/definitions/topConditionV3" }
-        },
-        "required": [
-          "name"
+        "description": "A test preset object",
+        "allOf": [
+          { "$ref": "#/definitions/testPresetsItemsV2" },
+          { "$ref": "#/definitions/testPresetsAdditionalPropertiesV5" }
         ],
-        "additionalProperties": false
+        "unevaluatedProperties": false
       }
     },
     "testPresetsV3": {
       "type": "array",
       "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 3 and higher.",
-      "allOf": [
-        { "$ref": "#/definitions/testPresetsItemsV3" },
-        { "$ref": "#/definitions/testPresetsItemsV2" }
-      ],
       "items": {
         "type": "object",
-        "properties": {
-          "name": {},
-          "hidden": {},
-          "inherits": {},
-          "configurePreset": {},
-          "vendor": {},
-          "displayName": {},
-          "description": {},
-          "inheritConfigureEnvironment": {},
-          "environment": {},
-          "configuration": {},
-          "overwriteConfigurationFile": {},
-          "output": {
-            "type": "object",
-            "properties": {
-              "shortProgress": {},
-              "verbosity": {},
-              "debug": {},
-              "outputOnFailure": {},
-              "quiet": {},
-              "outputLogFile": {},
-              "labelSummary": {},
-              "subprojectSummary": {},
-              "maxPassedTestOutputSize": {},
-              "maxFailedTestOutputSize": {},
-              "maxTestNameWidth": {}
-            },
-            "additionalProperties": false
-          },
-          "filter": {
-            "type": "object",
-            "properties": {
-              "include": {
-                "type": "object",
-                "properties": {
-                  "name": {},
-                  "label": {},
-                  "useUnion": {},
-                  "index": { "$ref": "#/definitions/testPresetsFilterIncludeIndexV2" }
-                },
-                "additionalProperties": false
-              },
-              "exclude": {
-                "type": "object",
-                "properties": {
-                  "name": {},
-                  "label": {},
-                  "fixtures": {
-                    "type": "object",
-                    "properties": {
-                      "any": {},
-                      "setup": {},
-                      "cleanup": {}
-                    },
-                    "additionalProperties": false
-                  }
-                },
-                "additionalProperties": false
-              }
-            },
-            "additionalProperties": false
-          },
-          "execution": {
-            "type": "object",
-            "properties": {
-              "stopOnFailure": {},
-              "enableFailover": {},
-              "jobs": {},
-              "resourceSpecFile": {},
-              "testLoad": {},
-              "showOnly": {},
-              "repeat": {
-                "type": "object",
-                "properties": {
-                  "mode": {},
-                  "count": {}
-                },
-                "required": [
-                  "mode", "count"
-                ],
-                "additionalProperties": false
-              },
-              "interactiveDebugging": {},
-              "scheduleRandom": {},
-              "timeout": {},
-              "noTestsAction": {}
-            },
-            "additionalProperties": false
-          },
-          "condition": { "$ref": "#/definitions/topConditionV3" }
-        },
-        "required": [
-          "name"
+        "description": "A test preset object",
+        "allOf": [
+          { "$ref": "#/definitions/testPresetsItemsV2" },
+          { "$ref": "#/definitions/testPresetsAdditionalPropertiesV3" }
         ],
-        "additionalProperties": false
+        "unevaluatedProperties": false
       }
     },
     "testPresetsV2": {
       "type": "array",
       "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 2 and higher.",
-      "allOf": [
-        { "$ref": "#/definitions/testPresetsItemsV2" }
-      ],
       "items": {
         "type": "object",
-        "properties": {
-          "name": {},
-          "hidden": {},
-          "inherits": {},
-          "configurePreset": {},
-          "vendor": {},
-          "displayName": {},
-          "description": {},
-          "inheritConfigureEnvironment": {},
-          "environment": {},
-          "configuration": {},
-          "overwriteConfigurationFile": {},
-          "output": {
-            "type": "object",
-            "properties": {
-              "shortProgress": {},
-              "verbosity": {},
-              "debug": {},
-              "outputOnFailure": {},
-              "quiet": {},
-              "outputLogFile": {},
-              "labelSummary": {},
-              "subprojectSummary": {},
-              "maxPassedTestOutputSize": {},
-              "maxFailedTestOutputSize": {},
-              "maxTestNameWidth": {}
-            },
-            "additionalProperties": false
-          },
-          "filter": {
-            "type": "object",
-            "properties": {
-              "include": {
-                "type": "object",
-                "properties": {
-                  "name": {},
-                  "label": {},
-                  "useUnion": {},
-                  "index": { "$ref": "#/definitions/testPresetsFilterIncludeIndexV2" }
-                },
-                "additionalProperties": false
-              },
-              "exclude": {
-                "type": "object",
-                "properties": {
-                  "name": {},
-                  "label": {},
-                  "fixtures": {
-                    "type": "object",
-                    "properties": {
-                      "any": {},
-                      "setup": {},
-                      "cleanup": {}
-                    },
-                    "additionalProperties": false
-                  }
-                },
-                "additionalProperties": false
-              }
-            },
-            "additionalProperties": false
-          },
-          "execution": {
-            "type": "object",
-            "properties": {
-              "stopOnFailure": {},
-              "enableFailover": {},
-              "jobs": {},
-              "resourceSpecFile": {},
-              "testLoad": {},
-              "showOnly": {},
-              "repeat": {
-                "type": "object",
-                "properties": {
-                  "mode": {},
-                  "count": {}
-                },
-                "required": [
-                  "mode", "count"
-                ],
-                "additionalProperties": false
-              },
-              "interactiveDebugging": {},
-              "scheduleRandom": {},
-              "timeout": {},
-              "noTestsAction": {}
-            },
-            "additionalProperties": false
-          }
-        },
-        "required": [
-          "name"
+        "description": "A test preset object",
+        "allOf": [
+          { "$ref": "#/definitions/testPresetsItemsV2" },
+          { "$ref": "#/definitions/testPresetsAdditionalPropertiesV2" }
         ],
-        "additionalProperties": false
+        "unevaluatedProperties": false
       }
     },
-    "packagePresetsItemsV10": {
-      "type": "array",
-      "description": "An optional array of package preset objects. Used to specify arguments to cpack. Available in version 10 and higher.",
-      "items": {
-        "type": "object",
-        "properties": {
-          "$comment": { "$ref": "#/definitions/$comment" },
-          "output": {
-            "type": "object",
-            "properties": {
-              "$comment": { "$ref": "#/definitions/$comment" }
-            }
-          }
+    "packagePresetsOutputV10": {
+      "type": "object",
+      "description": "An optional object specifying output options.",
+      "allOf": [
+        { "$ref": "#/definitions/packagePresetsOutputObject" },
+        { "$ref": "#/definitions/commentAsProperty" }
+      ],
+      "unevaluatedProperties": false
+    },
+    "packagePresetsOutputV6": {
+      "type": "object",
+      "description": "An optional object specifying output options.",
+      "allOf": [
+        { "$ref": "#/definitions/packagePresetsOutputObject" }
+      ],
+      "unevaluatedProperties": false
+    },
+    "packagePresetsOutputObject": {
+      "properties": {
+        "debug": {
+          "type": "boolean",
+          "description": "An optional boolean specifying whether or not to print debug information. A value of true is equivalent to passing --debug on the command line."
+        },
+        "verbose": {
+          "type": "boolean",
+          "description": "An optional boolean specifying whether or not to print verbosely. A value of true is equivalent to passing --verbose on the command line."
         }
       }
     },
+    "packagePresetsAdditionalPropertiesV10": {
+      "properties": {
+        "output": { "$ref": "#/definitions/packagePresetsOutputV10" },
+        "condition": { "$ref": "#/definitions/topConditionV10" },
+        "$comment": { "$ref": "#/definitions/$comment" }
+      }
+    },
+    "packagePresetsAdditionalPropertiesV6": {
+      "properties": {
+        "output": { "$ref": "#/definitions/packagePresetsOutputV6" },
+        "condition": { "$ref": "#/definitions/topConditionV3" }
+      }
+    },
     "packagePresetsItemsV6": {
-      "type": "array",
-      "description": "An optional array of package preset objects. Used to specify arguments to cpack. Available in version 6 and higher.",
-      "items": {
-        "type": "object",
-        "properties": {
-          "name": {
-            "type": "string",
-            "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, package, or workflow) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
-            "minLength": 1
-          },
-          "hidden": {
-            "type": "boolean",
-            "description": "An optional boolean specifying whether or not a preset should be hidden. If a preset is hidden, it cannot be used in the --preset argument and does not have to have a valid configurePreset, even from inheritance. Hidden presets are intended to be used as a base for other presets to inherit via the inherits field."
-          },
-          "inherits": {
-            "anyOf": [
-              {
-                "type": "string",
-                "description": "An optional string representing the name of the package preset to inherit from.",
-                "minLength": 1
-              },
-              {
-                "type": "array",
-                "description": "An optional array of strings representing the names of package presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json must not inherit from presets in CMakeUserPresets.json.",
-                "items": {
-                  "type": "string",
-                  "description": "An optional string representing the name of the preset to inherit from.",
-                  "minLength": 1
-                }
-              }
-            ]
-          },
-          "configurePreset": {
-            "type": "string",
-            "description": "An optional string specifying the name of a configure preset to associate with this package preset. If configurePreset is not specified, it must be inherited from the inherits preset (unless this preset is hidden). The build tree directory is inferred from the configure preset.",
-            "minLength": 1
-          },
-          "vendor": {
-            "type": "object",
-            "description": "An optional map containing vendor-specific information. CMake does not interpret the contents of this field except to verify that it is a map if it does exist. However, it should follow the same conventions as the root-level vendor field. If vendors use their own per-preset vendor field, they should implement inheritance in a sensible manner when appropriate.",
-            "properties": {}
-          },
-          "displayName": {
-            "type": "string",
-            "description": "An optional string with a human-friendly name of the preset."
-          },
-          "description": {
-            "type": "string",
-            "description": "An optional string with a human-friendly description of the preset."
-          },
-          "inheritConfigureEnvironment": {
-            "type": "boolean",
-            "description": "An optional boolean that defaults to true. If true, the environment variables from the associated configure preset are inherited after all inherited package preset environments, but before environment variables explicitly specified in this package preset."
-          },
-          "environment": {
-            "type": "object",
-            "description": "An optional map of environment variables. The key is the variable name (which must not be an empty string). Each variable is set regardless of whether or not a value was given to it by the process's environment. This field supports macro expansion, and environment variables in this map may reference each other, and may be listed in any order, as long as such references do not cause a cycle (for example,if ENV_1 is $env{ENV_2}, ENV_2 may not be $env{ENV_1}.) Environment variables are inherited through the inherits field, and the preset's environment will be the union of its own environment and the environment from all its parents. If multiple presets in this union define the same variable, the standard rules of inherits are applied. Setting a variable to null causes it to not be set, even if a value was inherited from another preset.",
-            "properties": {},
-            "additionalProperties": {
+      "allOf": [
+        { "$ref": "#/definitions/commonPropertiesAll" },
+        { "$ref": "#/definitions/configureBuildTestPackagePresetsEnvironmentProperty" },
+        {
+          "properties": {
+            "hidden": {
+              "type": "boolean",
+              "description": "An optional boolean specifying whether or not a preset should be hidden. If a preset is hidden, it cannot be used in the --preset argument and does not have to have a valid configurePreset, even from inheritance. Hidden presets are intended to be used as a base for other presets to inherit via the inherits field."
+            },
+            "inherits": {
               "anyOf": [
                 {
-                  "type": "null",
-                  "description": "Setting a variable to null causes it to not be set, even if a value was inherited from another preset."
+                  "type": "string",
+                  "description": "An optional string representing the name of the package preset to inherit from.",
+                  "minLength": 1
                 },
                 {
-                  "type": "string",
-                  "description": "A string representing the value of the variable."
+                  "type": "array",
+                  "description": "An optional array of strings representing the names of package presets to inherit from. The preset will inherit all of the fields from the inherits presets by default (except name, hidden, inherits, description, and displayName), but can override them as desired. If multiple inherits presets provide conflicting values for the same field, the earlier preset in the inherits list will be preferred. Presets in CMakePresets.json must not inherit from presets in CMakeUserPresets.json.",
+                  "items": {
+                    "type": "string",
+                    "description": "An optional string representing the name of the preset to inherit from.",
+                    "minLength": 1
+                  }
                 }
               ]
             },
-            "propertyNames": {
-              "pattern": "^.+$"
-            }
-          },
-          "generators": {
-            "type": "array",
-            "description": "An optional list of strings representing generators for CPack to use.",
-            "items": {
+            "configurePreset": {
               "type": "string",
-              "description": "An optional string representing the name of the CPack generator to use."
-            }
-          },
-          "configurations": {
-            "type": "array",
-            "description": "An optional list of strings representing build configurations for CPack to package.",
-            "items": {
-              "type": "string",
-              "description": "An optional string representing the name of the configuration to use."
-            }
-          },
-          "variables": {
-            "type": "object",
-            "description": "An optional map of variables to pass to CPack, equivalent to -D arguments. Each key is the name of a variable, and the value is the string to assign to that variable.",
-            "items": {
-              "type": "string",
-              "description": "An optional string representing the value of the variable."
-            }
-          },
-          "configFile": {
-            "type": "string",
-            "description": "An optional string representing the config file for CPack to use."
-          },
-          "output": {
-            "type": "object",
-            "description": "An optional object specifying output options.",
-            "properties": {
-              "debug": {
-                "type": "boolean",
-                "description": "An optional boolean specifying whether or not to print debug information. A value of true is equivalent to passing --debug on the command line."
-              },
-              "verbose": {
-                "type": "boolean",
-                "description": "An optional boolean specifying whether or not to print verbosely. A value of true is equivalent to passing --verbose on the command line."
+              "description": "An optional string specifying the name of a configure preset to associate with this package preset. If configurePreset is not specified, it must be inherited from the inherits preset (unless this preset is hidden). The build tree directory is inferred from the configure preset.",
+              "minLength": 1
+            },
+            "inheritConfigureEnvironment": {
+              "type": "boolean",
+              "description": "An optional boolean that defaults to true. If true, the environment variables from the associated configure preset are inherited after all inherited package preset environments, but before environment variables explicitly specified in this package preset."
+            },
+            "generators": {
+              "type": "array",
+              "description": "An optional list of strings representing generators for CPack to use.",
+              "items": {
+                "type": "string",
+                "description": "An optional string representing the name of the CPack generator to use."
               }
+            },
+            "configurations": {
+              "type": "array",
+              "description": "An optional list of strings representing build configurations for CPack to package.",
+              "items": {
+                "type": "string",
+                "description": "An optional string representing the name of the configuration to use."
+              }
+            },
+            "variables": {
+              "type": "object",
+              "description": "An optional map of variables to pass to CPack, equivalent to -D arguments. Each key is the name of a variable, and the value is the string to assign to that variable.",
+              "items": {
+                "type": "string",
+                "description": "An optional string representing the value of the variable."
+              }
+            },
+            "configFile": {
+              "type": "string",
+              "description": "An optional string representing the config file for CPack to use."
+            },
+            "packageName": {
+              "type": "string",
+              "description": "An optional string representing the package name."
+            },
+            "packageVersion": {
+              "type": "string",
+              "description": "An optional string representing the package version."
+            },
+            "packageDirectory": {
+              "type": "string",
+              "description": "An optional string representing the directory in which to place the package."
+            },
+            "vendorName": {
+              "type": "string",
+              "description": "An optional string representing the vendor name."
             }
-          },
-          "packageName": {
-            "type": "string",
-            "description": "An optional string representing the package name."
-          },
-          "packageVersion": {
-            "type": "string",
-            "description": "An optional string representing the package version."
-          },
-          "packageDirectory": {
-            "type": "string",
-            "description": "An optional string representing the directory in which to place the package."
-          },
-          "vendorName": {
-            "type": "string",
-            "description": "An optional string representing the vendor name."
           }
         }
-      }
+      ],
+      "required": [
+        "name"
+      ]
     },
     "packagePresetsV10": {
       "type": "array",
       "description": "An optional array of package preset objects. Used to specify arguments to cpack. Available in version 10 and higher.",
-      "allOf": [
-        { "$ref": "#/definitions/packagePresetsItemsV10" },
-        { "$ref": "#/definitions/packagePresetsItemsV6" }
-      ],
       "items": {
         "type": "object",
-        "properties": {
-          "$comment": {},
-          "name": {},
-          "hidden": {},
-          "inherits": {},
-          "configurePreset": {},
-          "vendor": {},
-          "displayName": {},
-          "description": {},
-          "inheritConfigureEnvironment": {},
-          "environment": {},
-          "condition": { "$ref": "#/definitions/topConditionV10" },
-          "generators": {},
-          "configurations": {},
-          "variables": {},
-          "configFile": {},
-          "output": {
-            "type": "object",
-            "properties": {
-              "$comment": {},
-              "debug": {},
-              "verbose": {}
-            },
-            "additionalProperties": false
-          },
-          "packageName": {},
-          "packageVersion": {},
-          "packageDirectory": {},
-          "vendorName": {}
-        },
-        "required": [
-          "name"
+        "description": "An optional package preset object.",
+        "allOf": [
+          { "$ref": "#/definitions/packagePresetsItemsV6" },
+          { "$ref": "#/definitions/packagePresetsAdditionalPropertiesV10" }
         ],
-        "additionalProperties": false
+        "unevaluatedProperties": false
       }
     },
     "packagePresetsV6": {
       "type": "array",
       "description": "An optional array of package preset objects. Used to specify arguments to cpack. Available in version 6 and higher.",
-      "allOf": [
-        { "$ref": "#/definitions/packagePresetsItemsV6" }
-      ],
       "items": {
         "type": "object",
-        "properties": {
-          "name": {},
-          "hidden": {},
-          "inherits": {},
-          "configurePreset": {},
-          "vendor": {},
-          "displayName": {},
-          "description": {},
-          "inheritConfigureEnvironment": {},
-          "environment": {},
-          "condition": { "$ref": "#/definitions/topConditionV3" },
-          "generators": {},
-          "configurations": {},
-          "variables": {},
-          "configFile": {},
-          "output": {
-            "type": "object",
-            "properties": {
-              "debug": {},
-              "verbose": {}
-            },
-            "additionalProperties": false
-          },
-          "packageName": {},
-          "packageVersion": {},
-          "packageDirectory": {},
-          "vendorName": {}
-        },
-        "required": [
-          "name"
+        "description": "An optional package preset object.",
+        "allOf": [
+          { "$ref": "#/definitions/packagePresetsItemsV6" },
+          { "$ref": "#/definitions/packagePresetsAdditionalPropertiesV6" }
         ],
-        "additionalProperties": false
+        "unevaluatedProperties": false
       }
     },
-    "workflowPresetsItemsV10": {
+    "workflowPresetsStepsV10": {
       "type": "array",
-      "description": "An optional array of workflow preset objects. Used to execute configure, build, test, and package presets in order. Available in version 10 and higher.",
+      "description": "A required array of objects describing the steps of the workflow. The first step must be a configure preset, and all subsequent steps must be non-configure presets whose configurePreset field matches the starting configure preset.",
       "items": {
         "type": "object",
-        "properties": {
-          "$comment": { "$ref": "#/definitions/$comment" },
-          "steps": {
-            "type": "array",
-            "items": {
-              "type": "object",
-              "properties": {
-                "$comment": { "$ref": "#/definitions/$comment" }
-              }
-            }
-          }
-        }
+        "allOf": [
+          { "$ref": "#/definitions/workflowPresetsStepsObject" },
+          { "$ref": "#/definitions/commentAsProperty" }
+        ],
+        "unevaluatedProperties": false
       }
     },
-    "workflowPresetsItemsV6": {
+    "workflowPresetsStepsV6": {
       "type": "array",
-      "description": "An optional array of workflow preset objects. Used to execute configure, build, test, and package presets in order. Available in version 6 and higher.",
+      "description": "A required array of objects describing the steps of the workflow. The first step must be a configure preset, and all subsequent steps must be non-configure presets whose configurePreset field matches the starting configure preset.",
       "items": {
         "type": "object",
-        "properties": {
-          "name": {
-            "type": "string",
-            "description": "A required string representing the machine-friendly name of the preset. This identifier is used in the --preset argument. There must not be two presets (configure, build, test, package, or workflow) in the union of CMakePresets.json and CMakeUserPresets.json in the same directory with the same name.",
-            "minLength": 1
-          },
-          "vendor": {
-            "type": "object",
-            "description": "An optional map containing vendor-specific information. CMake does not interpret the contents of this field except to verify that it is a map if it does exist. However, it should follow the same conventions as the root-level vendor field.",
-            "properties": {}
-          },
-          "displayName": {
-            "type": "string",
-            "description": "An optional string with a human-friendly name of the preset."
-          },
-          "description": {
-            "type": "string",
-            "description": "An optional string with a human-friendly description of the preset."
-          },
-          "steps": {
-            "type": "array",
-            "description": "A required array of objects describing the steps of the workflow. The first step must be a configure preset, and all subsequent steps must be non-configure presets whose configurePreset field matches the starting configure preset.",
-            "items": {
-              "type": "object",
-              "properties": {
-                "type": {
-                  "type": "string",
-                  "description": "A required string. The first step must be configure. Subsequent steps must be either build, test, or package.",
-                  "enum": ["configure", "build", "test", "package"]
-                },
-                "name": {
-                  "type": "string",
-                  "description": "A required string representing the name of the configure, build, test, or package preset to run as this workflow step.",
-                  "minLength": 1
-                }
-              }
-            }
-          }
+        "allOf": [
+          { "$ref": "#/definitions/workflowPresetsStepsObject" }
+        ],
+        "unevaluatedProperties": false
+      }
+    },
+    "workflowPresetsStepsObject": {
+      "properties": {
+        "type": {
+          "type": "string",
+          "description": "A required string. The first step must be configure. Subsequent steps must be either build, test, or package.",
+          "enum": ["configure", "build", "test", "package"]
+        },
+        "name": {
+          "type": "string",
+          "description": "A required string representing the name of the configure, build, test, or package preset to run as this workflow step.",
+          "minLength": 1
         }
+      },
+      "required": [
+        "type",
+        "name"
+      ]
+    },
+    "workflowPresetsAdditionalPropertiesV10": {
+      "properties": {
+        "steps": { "$ref": "#/definitions/workflowPresetsStepsV10" },
+        "$comment": { "$ref": "#/definitions/$comment" }
+      }
+    },
+    "workflowPresetsAdditionalPropertiesV6": {
+      "properties": {
+        "steps": { "$ref": "#/definitions/workflowPresetsStepsV6" }
       }
     },
     "workflowPresetsV10": {
       "type": "array",
       "description": "An optional array of workflow preset objects. Used to execute configure, build, test, and package presets in order. Available in version 10 and higher.",
-      "allOf": [
-        { "$ref": "#/definitions/workflowPresetsItemsV10" },
-        { "$ref": "#/definitions/workflowPresetsItemsV6" }
-      ],
       "items": {
         "type": "object",
-        "properties": {
-          "$comment": {},
-          "name": {},
-          "vendor": {},
-          "displayName": {},
-          "description": {},
-          "steps": {
-            "type": "array",
-            "items": {
-              "type": "object",
-              "properties": {
-                "$comment": {},
-                "type": {},
-                "name": {}
-              },
-              "required": [
-                "type",
-                "name"
-              ],
-              "additionalProperties": false
-            }
-          }
-        },
+        "description": "An optional workflow preset object",
+        "allOf": [
+          { "$ref": "#/definitions/commonPropertiesAll" },
+          { "$ref": "#/definitions/workflowPresetsAdditionalPropertiesV10" }
+        ],
         "required": [
           "name",
           "steps"
         ],
-        "additionalProperties": false
+        "unevaluatedProperties": false
       }
     },
     "workflowPresetsV6": {
       "type": "array",
       "description": "An optional array of workflow preset objects. Used to execute configure, build, test, and package presets in order. Available in version 6 and higher.",
-      "allOf": [
-        { "$ref": "#/definitions/workflowPresetsItemsV6" }
-      ],
       "items": {
         "type": "object",
-        "properties": {
-          "name": {},
-          "vendor": {},
-          "displayName": {},
-          "description": {},
-          "steps": {
-            "type": "array",
-            "items": {
-              "type": "object",
-              "properties": {
-                "type": {},
-                "name": {}
-              },
-              "required": [
-                "type",
-                "name"
-              ],
-              "additionalProperties": false
-            }
-          }
-        },
+        "description": "An optional workflow preset object",
+        "allOf": [
+          { "$ref": "#/definitions/commonPropertiesAll" },
+          { "$ref": "#/definitions/workflowPresetsAdditionalPropertiesV6" }
+        ],
         "required": [
           "name",
           "steps"
         ],
-        "additionalProperties": false
+        "unevaluatedProperties": false
       }
     },
     "conditionAsBooleanV3": {
       "type": "boolean",
       "description": "A boolean which provides a constant value for the condition's evaluation."
     },
-    "conditionAsObjectConstV10": {
-      "type": "object",
-      "properties": {
-        "$comment": { "$ref": "#/definitions/$comment" }
-      }
-    },
     "conditionAsObjectConstV3": {
       "type": "object",
       "properties": {
@@ -2651,13 +1874,11 @@
           "type": "boolean",
           "description": "A required boolean which provides a constant value for the condition's evaluation."
         }
-      }
-    },
-    "conditionAsObjectEqualsV10": {
-      "type": "object",
-      "properties": {
-        "$comment": { "$ref": "#/definitions/$comment" }
-      }
+      },
+      "required": [
+        "type",
+        "value"
+      ]
     },
     "conditionAsObjectEqualsV3": {
       "type": "object",
@@ -2675,13 +1896,12 @@
           "type": "string",
           "description": "Second string to compare. This field supports macro expansion."
         }
-      }
-    },
-    "conditionAsObjectInListV10": {
-      "type": "object",
-      "properties": {
-        "$comment": { "$ref": "#/definitions/$comment" }
-      }
+      },
+      "required": [
+        "type",
+        "lhs",
+        "rhs"
+      ]
     },
     "conditionAsObjectInListV3": {
       "type": "object",
@@ -2702,13 +1922,12 @@
             "type": "string"
           }
         }
-      }
-    },
-    "conditionAsObjectMatchesV10": {
-      "type": "object",
-      "properties": {
-        "$comment": { "$ref": "#/definitions/$comment" }
-      }
+      },
+      "required": [
+        "type",
+        "string",
+        "list"
+      ]
     },
     "conditionAsObjectMatchesV3": {
       "type": "object",
@@ -2726,13 +1945,12 @@
           "type": "string",
           "description": "A required regular expression to search for. This field supports macro expansion."
         }
-      }
-    },
-    "conditionAsObjectAggregationV10": {
-      "type": "object",
-      "properties": {
-        "$comment": { "$ref": "#/definitions/$comment" }
-      }
+      },
+      "required": [
+        "type",
+        "string",
+        "regex"
+      ]
     },
     "conditionAsObjectAggregationV3": {
       "type": "object",
@@ -2744,15 +1962,18 @@
         },
         "conditions": {
           "type": "array",
-          "description": "A required array of condition objects. These conditions use short-circuit evaluation."
+          "description": "A required array of condition objects. These conditions use short-circuit evaluation.",
+          "items": {
+            "properties": {
+              "condition": { "$ref": "#/definitions/conditionV3" }
+            }
+          }
         }
-      }
-    },
-    "conditionAsObjectNotV10": {
-      "type": "object",
-      "properties": {
-        "$comment": { "$ref": "#/definitions/$comment" }
-      }
+      },
+      "required": [
+        "type",
+        "conditions"
+      ]
     },
     "conditionAsObjectNotV3": {
       "type": "object",
@@ -2761,8 +1982,13 @@
           "type": "string",
           "description": "A required string specifying the type of the condition.",
           "const": "not"
-        }
-      }
+        },
+        "condition": { "$ref": "#/definitions/conditionV3" }
+      },
+      "required": [
+        "type",
+        "condition"
+      ]
     },
     "conditionV10": {
       "anyOf": [
@@ -2770,113 +1996,63 @@
         {
           "type": "object",
           "allOf": [
-            { "$ref": "#/definitions/conditionAsObjectConstV10" },
-            { "$ref": "#/definitions/conditionAsObjectConstV3" }
+            { "$ref": "#/definitions/conditionAsObjectConstV3" },
+            { "$ref": "#/definitions/commentAsProperty" }
           ],
-          "properties": {
-            "$comment": {},
-            "type": {},
-            "value": {}
-          },
-          "required": [
-            "type",
-            "value"
-          ],
-          "additionalProperties": false
+          "unevaluatedProperties": false
         },
         {
           "type": "object",
           "allOf": [
-            { "$ref": "#/definitions/conditionAsObjectEqualsV10" },
-            { "$ref": "#/definitions/conditionAsObjectEqualsV3" }
+            { "$ref": "#/definitions/conditionAsObjectEqualsV3" },
+            { "$ref": "#/definitions/commentAsProperty" }
           ],
-          "properties": {
-            "$comment": {},
-            "type": {},
-            "lhs": {},
-            "rhs": {}
-          },
-          "required": [
-            "type",
-            "lhs",
-            "rhs"
-          ],
-          "additionalProperties": false
+          "unevaluatedProperties": false
         },
         {
           "type": "object",
           "allOf": [
-            { "$ref": "#/definitions/conditionAsObjectInListV10" },
-            { "$ref": "#/definitions/conditionAsObjectInListV3" }
+            { "$ref": "#/definitions/conditionAsObjectInListV3" },
+            { "$ref": "#/definitions/commentAsProperty" }
           ],
-          "properties": {
-            "$comment": {},
-            "type": {},
-            "string": {},
-            "list": {}
-          },
-          "required": [
-            "type",
-            "string",
-            "list"
-          ],
-          "additionalProperties": false
+          "unevaluatedProperties": false
         },
         {
           "type": "object",
           "allOf": [
-            { "$ref": "#/definitions/conditionAsObjectMatchesV10" },
-            { "$ref": "#/definitions/conditionAsObjectMatchesV3" }
+            { "$ref": "#/definitions/conditionAsObjectMatchesV3" },
+            { "$ref": "#/definitions/commentAsProperty" }
           ],
-          "properties": {
-            "$comment": {},
-            "type": {},
-            "string": {},
-            "regex": {}
-          },
-          "required": [
-            "type",
-            "string",
-            "regex"
-          ],
-          "additionalProperties": false
+          "unevaluatedProperties": false
         },
         {
           "type": "object",
           "allOf": [
-            { "$ref": "#/definitions/conditionAsObjectAggregationV10" },
-            { "$ref": "#/definitions/conditionAsObjectAggregationV3" }
-          ],
-          "properties": {
-            "$comment": {},
-            "type": {},
-            "conditions": {
-              "type": "array",
-              "items": { "$ref": "#/definitions/conditionV10" }
+            { "$ref": "#/definitions/conditionAsObjectAggregationV3" },
+            { "$ref": "#/definitions/commentAsProperty" },
+            {
+              "properties": {
+                "conditions": {
+                  "type": "array",
+                  "items": { "$ref": "#/definitions/conditionV10" }
+                }
+              }
             }
-          },
-          "required": [
-            "type",
-            "conditions"
           ],
-          "additionalProperties": false
+          "unevaluatedProperties": false
         },
         {
           "type": "object",
           "allOf": [
-            { "$ref": "#/definitions/conditionAsObjectNotV10" },
-            { "$ref": "#/definitions/conditionAsObjectNotV3" }
+            { "$ref": "#/definitions/conditionAsObjectNotV3" },
+            { "$ref": "#/definitions/commentAsProperty" },
+            {
+              "properties": {
+                "condition": { "$ref": "#/definitions/conditionV10" }
+              }
+            }
           ],
-          "properties": {
-            "$comment": {},
-            "type": {},
-            "condition": { "$ref": "#/definitions/conditionV10" }
-          },
-          "required": [
-            "type",
-            "condition"
-          ],
-          "additionalProperties": false
+          "unevaluatedProperties": false
         }
       ]
     },
@@ -2888,99 +2064,42 @@
           "allOf": [
             { "$ref": "#/definitions/conditionAsObjectConstV3" }
           ],
-          "properties": {
-            "type": {},
-            "value": {}
-          },
-          "required": [
-            "type",
-            "value"
-          ],
-          "additionalProperties": false
+          "unevaluatedProperties": false
         },
         {
           "type": "object",
           "allOf": [
             { "$ref": "#/definitions/conditionAsObjectEqualsV3" }
           ],
-          "properties": {
-            "type": {},
-            "lhs": {},
-            "rhs": {}
-          },
-          "required": [
-            "type",
-            "lhs",
-            "rhs"
-          ],
-          "additionalProperties": false
+          "unevaluatedProperties": false
         },
         {
           "type": "object",
           "allOf": [
             { "$ref": "#/definitions/conditionAsObjectInListV3" }
           ],
-          "properties": {
-            "type": {},
-            "string": {},
-            "list": {}
-          },
-          "required": [
-            "type",
-            "string",
-            "list"
-          ],
-          "additionalProperties": false
+          "unevaluatedProperties": false
         },
         {
           "type": "object",
           "allOf": [
             { "$ref": "#/definitions/conditionAsObjectMatchesV3" }
           ],
-          "properties": {
-            "type": {},
-            "string": {},
-            "regex": {}
-          },
-          "required": [
-            "type",
-            "string",
-            "regex"
-          ],
-          "additionalProperties": false
+          "unevaluatedProperties": false
         },
         {
           "type": "object",
           "allOf": [
             { "$ref": "#/definitions/conditionAsObjectAggregationV3" }
           ],
-          "properties": {
-            "type": {},
-            "conditions": {
-              "type": "array",
-              "items": { "$ref": "#/definitions/conditionV3" }
-            }
-          },
-          "required": [
-            "type",
-            "conditions"
-          ],
-          "additionalProperties": false
+          "unevaluatedProperties": false
         },
         {
           "type": "object",
           "allOf": [
             { "$ref": "#/definitions/conditionAsObjectNotV3" }
           ],
-          "properties": {
-            "type": {},
-            "condition": { "$ref": "#/definitions/conditionV3" }
-          },
-          "required": [
-            "type",
-            "condition"
-          ],
-          "additionalProperties": false
+          "unevaluatedProperties": false
         }
       ]
     },
diff --git a/Help/policy/CMP0205.rst b/Help/policy/CMP0205.rst
new file mode 100644
index 0000000..b08ef4a
--- /dev/null
+++ b/Help/policy/CMP0205.rst
@@ -0,0 +1,23 @@
+CMP0205
+-------
+
+.. versionadded:: 4.3
+
+:command:`file(CREATE_LINK)` with ``COPY_ON_ERROR`` copies directory content.
+
+The :command:`file(CREATE_LINK)` command's ``COPY_ON_ERROR`` option copies
+the source file to the destination as a fallback if linking it fails.
+If the source is a directory, CMake 4.2 and below create the destination
+directory but do not copy its contents.  CMake 4.3 and above prefer to
+copy the directory contents too.  This policy provides compatibility with
+projects that have not been updated to expect the contents to be copied.
+
+The ``OLD`` behavior for this policy is to create the destination directory
+without copying contents.  The ``NEW`` behavior for this policy to create
+the destination directory and copy contents from the source directory.
+
+.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 4.3
+.. |WARNS_OR_DOES_NOT_WARN| replace:: warns
+.. include:: include/STANDARD_ADVICE.rst
+
+.. include:: include/DEPRECATED.rst
diff --git a/Help/policy/CMP0206.rst b/Help/policy/CMP0206.rst
new file mode 100644
index 0000000..f6ed03d
--- /dev/null
+++ b/Help/policy/CMP0206.rst
@@ -0,0 +1,30 @@
+CMP0206
+-------
+
+.. versionadded:: 4.3
+
+The :cpack_gen:`CPack Archive Generator` defaults to UID 0 and GID 0.
+
+In CMake 4.2 and below, the :cpack_gen:`CPack Archive Generator` always used
+the current user's UID/GID in archive entries.  CMake 4.3 added the
+:variable:`CPACK_ARCHIVE_UID` and :variable:`CPACK_ARCHIVE_GID` variables
+to control them.  If either is set, the default for the other is ``0``.
+If neither is set, CMake 4.3 and above prefer to default both UID and GID
+to ``0`` so that unpacking by ``root`` produces paths owned by ``root``.
+This policy provides compatibility with projects that have not been updated
+to expect the new behavior.
+
+The ``OLD`` behavior for this policy is to produce archive entries with
+the current user's UID/GID by default.
+The ``NEW`` behavior for this policy is to produce archive entries with
+the UID/GID set to 0/0 by default.
+
+.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 4.3
+.. |WARNS_OR_DOES_NOT_WARN| replace:: does *not* warn
+.. include:: include/STANDARD_ADVICE.rst
+
+See documentation of the
+:variable:`CMAKE_POLICY_WARNING_CMP0206 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
+variable to control the warning.
+
+.. include:: include/DEPRECATED.rst
diff --git a/Help/policy/CMP0207.rst b/Help/policy/CMP0207.rst
new file mode 100644
index 0000000..b544bd2
--- /dev/null
+++ b/Help/policy/CMP0207.rst
@@ -0,0 +1,26 @@
+CMP0207
+-------
+
+.. versionadded:: 4.3
+
+:command:`file(GET_RUNTIME_DEPENDENCIES)` normalizes paths before matching.
+
+The :command:`file(GET_RUNTIME_DEPENDENCIES)` and
+:command:`install(RUNTIME_DEPENDENCY_SET)` commands support filtering
+resolved dependencies using regular expressions matching their paths.
+In CMake 4.2 and below, callers were responsible for matching both forward
+and backward slashes as path separators on Windows, e.g., via ``[\/]``.
+CMake 4.3 and above prefer to normalize paths to use forward slashes before
+matching.  This policy provides compaitiblity for projects that may have
+been relying on matching backslashes only.
+
+The ``OLD`` behavior for this policy matches filters against paths that
+may contain any combination of forward and backward slashes on Windows.
+The ``NEW`` behavior for this policy to convert all paths to forward
+slashes before matching filters.
+
+.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 4.3
+.. |WARNS_OR_DOES_NOT_WARN| replace:: warns
+.. include:: include/STANDARD_ADVICE.rst
+
+.. include:: include/DEPRECATED.rst
diff --git a/Help/policy/CMP0208.rst b/Help/policy/CMP0208.rst
new file mode 100644
index 0000000..ae91daf
--- /dev/null
+++ b/Help/policy/CMP0208.rst
@@ -0,0 +1,30 @@
+CMP0208
+-------
+
+.. versionadded:: 4.3
+
+:command:`export(EXPORT)` does not allow empty arguments.
+
+In CMake 4.2 and below, the :command:`export(EXPORT)` command silently
+accepted ``NAMESPACE``, ``FILE`` or ``CXX_MODULES_DIRECTORY`` arguments with
+empty or missing values.
+
+CMake 4.3 and above issue a diagnostic if any of these keywords are present
+without an associated value, or of the value given to ``FILE`` or
+``CXX_MODULES_DIRECTORY`` is empty.  (``NAMESPACE`` is allowed to have an empty
+value, but an empty value must be quoted.)  A diagnostic is also issued
+immediately if the value of ``EXPORT`` is missing or empty.  (Previously, this
+would result in an error at generate-time because no export set whose name is
+empty can exist.)
+
+This policy provides compatibility with projects which may have relied on the
+previous lack of enforcement.  The ``OLD`` behavior for this policy permits
+these keywords to be present without an accompanying value, or to be given an
+empty value.  The ``NEW`` behavior requires that a value be given, and that
+the value (except for ``NAMESPACE``) is non-empty.
+
+.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 4.3
+.. |WARNS_OR_DOES_NOT_WARN| replace:: warns
+.. include:: include/STANDARD_ADVICE.rst
+
+.. include:: include/DEPRECATED.rst
diff --git a/Help/policy/CMP0209.rst b/Help/policy/CMP0209.rst
new file mode 100644
index 0000000..f8fa22e
--- /dev/null
+++ b/Help/policy/CMP0209.rst
@@ -0,0 +1,27 @@
+CMP0209
+-------
+
+.. versionadded:: 4.3
+
+Verify interface header sets checks executables without exports.
+
+When :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` is set to true on an executable
+target, CMake 4.2 and below would only perform those checks if the target's
+:prop_tgt:`ENABLE_EXPORTS` property was true.  The reasoning behind this
+exclusion was that no other target could consume the headers of an executable
+target if that executable target didn't export symbols.  Since then, other
+use cases have emerged for verifying header file sets where exporting symbols
+is no longer a requirement.  Therefore, CMake 4.3 and above prefer to verify
+interface file sets of executable targets regardless of whether they export
+symbols or not.
+
+The ``OLD`` behavior of this policy only verifies interface file sets of an
+executable target if its :prop_tgt:`ENABLE_EXPORTS` property is set to true.
+The ``NEW`` behavior always verifies interface file sets of an executable
+target when :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` is set to true.
+
+.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 4.3
+.. |WARNS_OR_DOES_NOT_WARN| replace:: warns
+.. include:: include/STANDARD_ADVICE.rst
+
+.. include:: include/DEPRECATED.rst
diff --git a/Help/policy/CMP0210.rst b/Help/policy/CMP0210.rst
new file mode 100644
index 0000000..f615604
--- /dev/null
+++ b/Help/policy/CMP0210.rst
@@ -0,0 +1,30 @@
+CMP0210
+-------
+
+.. versionadded:: 4.3
+
+:variable:`CMAKE_<LANG>_LINK_FLAGS` adds link flags to all target types.
+
+In CMake 4.2 and below, :variable:`CMAKE_<LANG>_LINK_FLAGS` held flags
+relevant to target creation and applied when linking executables only. It was
+undocumented and originally intended for internal use only, but still
+available for projects and users to set in order to control linking behavior.
+
+CMake 4.3 and above repurpose this variable to add per-language link flags for
+all target types that link (executables, shared libraries, and module
+libraries).
+
+This policy provides compatibility with projects that relied on this variable
+and have not been updated to be aware of the change.
+
+The ``OLD`` behavior for this policy is to apply
+:variable:`CMAKE_<LANG>_LINK_FLAGS` to invocations of the compiler which drive
+linking for executables only. The ``NEW`` behavior is to apply the flags to
+all target types.
+
+.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 4.3
+.. |WARNS_OR_DOES_NOT_WARN| replace::
+    warns when :variable:`CMAKE_<LANG>_LINK_FLAGS` is set
+.. include:: include/STANDARD_ADVICE.rst
+
+.. include:: include/DEPRECATED.rst
diff --git a/Help/policy/include/DEPRECATED.rst b/Help/policy/include/DEPRECATED.rst
index f66de55..4cec1bb 100644
--- a/Help/policy/include/DEPRECATED.rst
+++ b/Help/policy/include/DEPRECATED.rst
@@ -1,4 +1,4 @@
 .. note::
   The ``OLD`` behavior of a policy is
-  :manual:`deprecated by definition <cmake-policies(7)>`
+  :ref:`deprecated by definition <cmake-policies-intro>`
   and may be removed in a future version of CMake.
diff --git a/Help/prop_dir/ADDITIONAL_CLEAN_FILES.rst b/Help/prop_dir/ADDITIONAL_CLEAN_FILES.rst
index 6097d14..8bb5f01 100644
--- a/Help/prop_dir/ADDITIONAL_CLEAN_FILES.rst
+++ b/Help/prop_dir/ADDITIONAL_CLEAN_FILES.rst
@@ -3,11 +3,11 @@
 
 .. versionadded:: 3.15
 
-A :ref:`;-list <CMake Language Lists>` of files or directories that will be
-removed as a part of the global ``clean`` target.  It is useful for
-specifying generated files or directories that are used by multiple targets
-or by CMake itself, or that are generated in ways which cannot be captured as
-outputs or byproducts of custom commands.
+A :ref:`semicolon-separated list <CMake Language Lists>` of files or
+directories that will be removed as a part of the global ``clean`` target.
+It is useful for specifying generated files or directories that are used by
+multiple targets or by CMake itself, or that are generated in ways which cannot
+be captured as outputs or byproducts of custom commands.
 
 If an additional clean file is specific to a single target only, then the
 :prop_tgt:`ADDITIONAL_CLEAN_FILES` target property would usually be a better
diff --git a/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst b/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst
index a19cc4e..12b50d6 100644
--- a/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst
+++ b/Help/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.rst
@@ -7,8 +7,8 @@
 
 Additional files to remove during the clean stage.
 
-A :ref:`;-list <CMake Language Lists>` of files that will be removed as a
-part of the ``make clean`` target.
+A :ref:`semicolon-separated list <CMake Language Lists>` of files that will be
+removed as a part of the ``make clean`` target.
 
 Arguments to ``ADDITIONAL_MAKE_CLEAN_FILES`` may use
 :manual:`generator expressions <cmake-generator-expressions(7)>`.
diff --git a/Help/prop_sf/SKIP_LINTING.rst b/Help/prop_sf/SKIP_LINTING.rst
index f995cb4..5d2c0c4 100644
--- a/Help/prop_sf/SKIP_LINTING.rst
+++ b/Help/prop_sf/SKIP_LINTING.rst
@@ -6,11 +6,12 @@
 This property allows you to exclude a specific source file
 from the linting process. The linting process involves running
 tools such as :prop_tgt:`<LANG>_CPPLINT`, :prop_tgt:`<LANG>_CLANG_TIDY`,
-:prop_tgt:`<LANG>_CPPCHECK`, :prop_tgt:`<LANG>_ICSTAT` and
-:prop_tgt:`<LANG>_INCLUDE_WHAT_YOU_USE` on the source files, as well
-as compiling header files as part of :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS`.
-By setting ``SKIP_LINTING`` on a source file, the mentioned linting tools
-will not be executed for that particular file.
+:prop_tgt:`<LANG>_CPPCHECK`, :prop_tgt:`<LANG>_ICSTAT`,
+:prop_tgt:`<LANG>_PVS_STUDIO` and :prop_tgt:`<LANG>_INCLUDE_WHAT_YOU_USE` on the
+source files, as well as compiling header files as part of
+:prop_tgt:`VERIFY_INTERFACE_HEADER_SETS`. By setting ``SKIP_LINTING`` on a
+source file, the mentioned linting tools will not be executed for that
+particular file.
 
 Example
 ^^^^^^^
diff --git a/Help/prop_tgt/ADDITIONAL_CLEAN_FILES.rst b/Help/prop_tgt/ADDITIONAL_CLEAN_FILES.rst
index dc87d23..97cfe13 100644
--- a/Help/prop_tgt/ADDITIONAL_CLEAN_FILES.rst
+++ b/Help/prop_tgt/ADDITIONAL_CLEAN_FILES.rst
@@ -3,11 +3,11 @@
 
 .. versionadded:: 3.15
 
-A :ref:`;-list <CMake Language Lists>` of files or directories that will be
-removed as a part of the global ``clean`` target.  It can be used to specify
-files and directories that are generated as part of building the target or
-that are directly associated with the target in some way (e.g. created as a
-result of running the target).
+A :ref:`semicolon-separated list <CMake Language Lists>` of files or
+directories that will be removed as a part of the global ``clean`` target.
+It can be used to specify files and directories that are generated as part of
+building the target or that are directly associated with the target in some way
+(e.g. created as a result of running the target).
 
 For custom targets, if such files can be captured as outputs or byproducts
 instead, then that should be preferred over adding them to this property.
diff --git a/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst b/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst
index 892dc5e..27f1fd3 100644
--- a/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst
+++ b/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst
@@ -18,9 +18,9 @@
 As this :ref:`<ORIGIN>_autogen <<ORIGIN>_autogen>` target is created
 at generate-time, it is not possible to define dependencies of it using e.g.
 :command:`add_dependencies`.  Instead the ``AUTOGEN_TARGET_DEPENDS`` target
-property can be set to a :ref:`;-list <CMake Language Lists>` of additional
-dependencies for the :ref:`<ORIGIN>_autogen <<ORIGIN>_autogen>`  target.
-Dependencies can be target names or file names.
+property can be set to a :ref:`semicolon-separated list <CMake Language Lists>`
+of additional dependencies for the :ref:`<ORIGIN>_autogen <<ORIGIN>_autogen>`
+target. Dependencies can be target names or file names.
 
 In total, the dependencies of the :ref:`<ORIGIN>_autogen <<ORIGIN>_autogen>`
 target are composed from
diff --git a/Help/prop_tgt/DEBUGGER_WORKING_DIRECTORY.rst b/Help/prop_tgt/DEBUGGER_WORKING_DIRECTORY.rst
index f8f2f30..0916f02 100644
--- a/Help/prop_tgt/DEBUGGER_WORKING_DIRECTORY.rst
+++ b/Help/prop_tgt/DEBUGGER_WORKING_DIRECTORY.rst
@@ -3,7 +3,9 @@
 
 .. versionadded:: 4.0
 
-Sets the local debugger working directory for C++ targets.
+Sets the local debugger working directory for targets,
+specifically the process launched by the debugger.
+
 The property value may use
 :manual:`generator expressions <cmake-generator-expressions(7)>`.
 This property is initialized by the value of the variable
diff --git a/Help/prop_tgt/DEFINE_SYMBOL.rst b/Help/prop_tgt/DEFINE_SYMBOL.rst
index 775cf89..6cd6472 100644
--- a/Help/prop_tgt/DEFINE_SYMBOL.rst
+++ b/Help/prop_tgt/DEFINE_SYMBOL.rst
@@ -1,17 +1,21 @@
 DEFINE_SYMBOL
 -------------
 
-Define a symbol when compiling this target's sources.
+Define a preprocessor symbol when compiling this target's sources.
 
-``DEFINE_SYMBOL`` sets the name of the preprocessor symbol defined when
-compiling sources in a shared library.  If not set here then it is set
-to ``target_EXPORTS`` by default (with some substitutions if the target is
-not a valid C identifier).  This is useful for headers to know whether
-they are being included from inside their library or outside to
-properly setup dllexport/dllimport decorations on Windows.
+CMake adds this definition when compiling sources of a ``SHARED`` library,
+a ``MODULE`` library, or an ``EXECUTABLE`` with :prop_tgt:`ENABLE_EXPORTS`
+enabled.  If ``DEFINE_SYMBOL`` is not set, the default definition is of
+the form ``<target>_EXPORTS`` (with some substitutions if the target is
+not a valid C identifier).
+
+The symbol is only defined while compiling the target itself and is not
+propagated to dependent targets.
 
 On POSIX platforms, this can optionally be used to control the visibility
 of symbols.
 
 CMake provides support for such decorations with the :module:`GenerateExportHeader`
 module.
+
+See also the ``COMPILE_DEFINITIONS`` under :ref:`Target Compile Properties`.
diff --git a/Help/prop_tgt/IMPORTED_CXX_MODULES_CONFIG.rst b/Help/prop_tgt/IMPORTED_CXX_MODULES_CONFIG.rst
new file mode 100644
index 0000000..b4106e1
--- /dev/null
+++ b/Help/prop_tgt/IMPORTED_CXX_MODULES_CONFIG.rst
@@ -0,0 +1,16 @@
+IMPORTED_CXX_MODULES_<CONFIG>
+-----------------------------
+
+.. versionadded:: 3.28
+
+A list of C++ module specifications available with the target for
+configuration ``<CONFIG>``.  Each item in the list is of the form
+``<NAME>=<INTERFACE>[,<BMI>]*`` where ``<NAME>`` is the name of the module,
+``<INTERFACE>`` is its module interface unit, and any number of available
+``<BMI>`` files are provided.
+
+.. note::
+
+   CMake currently does not use the ``<BMI>`` files as there is limited
+   support for determining whether an existing ``<BMI>`` file is suitable for
+   a given importer of the module it represents.
diff --git a/Help/prop_tgt/INTERFACE_HEADER_SETS_TO_VERIFY.rst b/Help/prop_tgt/INTERFACE_HEADER_SETS_TO_VERIFY.rst
index b0d63f3..7eb6ec3 100644
--- a/Help/prop_tgt/INTERFACE_HEADER_SETS_TO_VERIFY.rst
+++ b/Help/prop_tgt/INTERFACE_HEADER_SETS_TO_VERIFY.rst
@@ -4,10 +4,12 @@
 .. versionadded:: 3.24
 
 Used to specify which ``PUBLIC`` and ``INTERFACE`` header sets of a target
-should be verified.
+should be verified as interface headers.
 
 This property contains a semicolon-separated list of header sets which
-should be verified if :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` is set to
-``TRUE``. If the list is empty, all ``PUBLIC`` and ``INTERFACE`` header sets
-are verified. (If the project does not want to verify any header sets on the
-target, simply set :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` to ``FALSE``.)
+should be verified if :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` is set to true.
+If the list is empty, all ``PUBLIC`` and ``INTERFACE`` header sets are
+verified. If the project does not want to verify any interface header sets on
+the target, set :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` to false.
+
+See also :prop_tgt:`PRIVATE_HEADER_SETS_TO_VERIFY`.
diff --git a/Help/prop_tgt/LANG_PVS_STUDIO.rst b/Help/prop_tgt/LANG_PVS_STUDIO.rst
new file mode 100644
index 0000000..f7ae4de
--- /dev/null
+++ b/Help/prop_tgt/LANG_PVS_STUDIO.rst
@@ -0,0 +1,39 @@
+<LANG>_PVS_STUDIO
+-----------------
+
+.. versionadded:: 4.3
+
+This property is implemented only when ``<LANG>`` is ``C`` or ``CXX``.
+
+Specify a :ref:`semicolon-separated list <CMake Language Lists>` containing
+a command line for the ``pvs-studio-analyzer`` tool (named
+``CompilerCommandsAnalyzer`` on Windows).  The :ref:`Makefile Generators` and
+:ref:`Ninja Generators` will run this tool along with the compiler and
+report a warning if the tool reports any problems.
+
+The specified ``pvs-studio-analyzer`` command line will be invoked with
+the following additional arguments:
+
+- ``--source-file``: The source file.
+- ``--output-file``: A path adjacent to the object file to write the PVS log.
+- ``--cl-params``: The compile options.
+- ``--preprocessor``: The preprocessor, based on
+  :variable:`CMAKE_<LANG>_COMPILER_ID`, if determined to be one of:
+  ``visualcpp``, ``clang``, ``gcc``, ``bcc``, ``iar``.
+- ``--platform``: The target platform, if determined to be one of: ``arm``,
+  ``win32``, ``x64``, ``linux32``, ``linux64``, ``macOS``.
+
+See the
+`PVS-Studio documentation <https://pvs-studio.com/en/docs/manual/6615/#flags>`_
+for details on these and other available options.
+
+CMake will look for the ``plog-converter`` tool in the same directory as the
+provided ``pvs-studio-analyzer``, and in the user's path if not present in that
+directory. The ``plog-converter`` will run automatically with the ``Txt``
+output type on Windows, and ``errorfile`` on other platforms, and the contents
+of that file will be sent to ``stderr``. The PVS log file will be deleted after
+the converter runs.
+
+This property is initialized by the value of
+the :variable:`CMAKE_<LANG>_PVS_STUDIO` variable if it is set
+when a target is created.
diff --git a/Help/prop_tgt/PRIVATE_HEADER_SETS_TO_VERIFY.rst b/Help/prop_tgt/PRIVATE_HEADER_SETS_TO_VERIFY.rst
new file mode 100644
index 0000000..e7ad642
--- /dev/null
+++ b/Help/prop_tgt/PRIVATE_HEADER_SETS_TO_VERIFY.rst
@@ -0,0 +1,15 @@
+PRIVATE_HEADER_SETS_TO_VERIFY
+-----------------------------
+
+.. versionadded:: 4.3
+
+Used to specify which ``PUBLIC`` and ``PRIVATE`` header sets of a target
+should be verified as private headers.
+
+This property contains a semicolon-separated list of header sets which
+should be verified if :prop_tgt:`VERIFY_PRIVATE_HEADER_SETS` is set to true.
+If the list is empty, all ``PUBLIC`` and ``PRIVATE`` header sets are verified.
+If the project does not want to verify any private header sets on the target,
+set :prop_tgt:`VERIFY_PRIVATE_HEADER_SETS` to false.
+
+See also :prop_tgt:`INTERFACE_HEADER_SETS_TO_VERIFY`.
diff --git a/Help/prop_tgt/VERIFY_INTERFACE_HEADER_SETS.rst b/Help/prop_tgt/VERIFY_INTERFACE_HEADER_SETS.rst
index bdd7792..a14f7c8 100644
--- a/Help/prop_tgt/VERIFY_INTERFACE_HEADER_SETS.rst
+++ b/Help/prop_tgt/VERIFY_INTERFACE_HEADER_SETS.rst
@@ -7,35 +7,20 @@
 header sets can be included on their own.
 
 When this property is set to true, and the target is an object library, static
-library, shared library, interface library, or executable with exports enabled,
-and the target has one or more ``PUBLIC`` or ``INTERFACE`` header sets, an
-object library target named ``<target_name>_verify_interface_header_sets`` is
-created. This verification target has one source file per header in the
-``PUBLIC`` and ``INTERFACE`` header sets. Each source file only includes its
-associated header file. The verification target links against the original
-target to get all of its usage requirements. The verification target has its
-:prop_tgt:`EXCLUDE_FROM_ALL` and :prop_tgt:`DISABLE_PRECOMPILE_HEADERS`
-properties set to true, and its :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTORCC`,
-:prop_tgt:`AUTOUIC`, and :prop_tgt:`UNITY_BUILD` properties set to false.
+library, shared library, interface library, or executable (subject to policy
+:policy:`CMP0209`) and the target has one or more ``PUBLIC`` or ``INTERFACE``
+header sets, an object library target named
+``<target_name>_verify_interface_header_sets`` is created. This verification
+target has one source file per header in the ``PUBLIC`` and ``INTERFACE``
+header sets. Each source file only includes its associated header file.
+The verification target links against the original target to get all of its
+usage requirements.
 
-If the header's :prop_sf:`LANGUAGE` property is set, the value of that property
-is used to determine the language with which to compile the header file.
-Otherwise, if the target has any C++ sources, the header is compiled as C++.
-Otherwise, if the target has any C sources, the header is compiled as C.
-Otherwise, if C++ is enabled globally, the header is compiled as C++.
-Otherwise, if C is enabled globally, the header is compiled as C. Otherwise,
-the header file is not compiled.
-
-If the header's :prop_sf:`SKIP_LINTING` property is set to true, the file is
-not compiled.
-
-If any verification targets are created, a top-level target called
-``all_verify_interface_header_sets`` is created which depends on all
-verification targets.
-
-This property is initialized by the value of the
-:variable:`CMAKE_VERIFY_INTERFACE_HEADER_SETS` variable if it is set when
-a target is created.
-
-If the project wishes to control which header sets are verified by this
-property, it can set :prop_tgt:`INTERFACE_HEADER_SETS_TO_VERIFY`.
+.. |xxx| replace:: interface
+.. |THIS_PROPERTY| replace:: ``VERIFY_INTERFACE_HEADER_SETS``
+.. |COMPLEMENTARY_PROPERTY| replace:: :prop_tgt:`VERIFY_PRIVATE_HEADER_SETS`
+.. |THIS_ALL_TARGET| replace:: ``all_verify_interface_header_sets``
+.. |COMPLEMENTARY_ALL_TARGET| replace:: ``all_verify_private_header_sets``
+.. |INIT_VARIABLE| replace:: :variable:`CMAKE_VERIFY_INTERFACE_HEADER_SETS`
+.. |SETS_TO_VERIFY_PROPERTY| replace:: :prop_tgt:`INTERFACE_HEADER_SETS_TO_VERIFY`
+.. include:: include/VERIFY_XXX_HEADER_SETS.rst
diff --git a/Help/prop_tgt/VERIFY_PRIVATE_HEADER_SETS.rst b/Help/prop_tgt/VERIFY_PRIVATE_HEADER_SETS.rst
new file mode 100644
index 0000000..df9d183
--- /dev/null
+++ b/Help/prop_tgt/VERIFY_PRIVATE_HEADER_SETS.rst
@@ -0,0 +1,34 @@
+VERIFY_PRIVATE_HEADER_SETS
+--------------------------
+
+.. versionadded:: 4.3
+
+Used to verify that all headers in a target's ``PUBLIC`` and ``PRIVATE``
+header sets can be included on their own.
+
+When this property is set to true, and the target is an object library, static
+library, shared library, module library, interface library, or executable, and
+the target has one or more ``PUBLIC`` or ``PRIVATE`` header sets, an object
+library target named ``<target_name>_verify_private_header_sets`` is created.
+This verification target has one source file per header in the ``PUBLIC`` and
+``PRIVATE`` header sets. Each source file only includes its associated header
+file.
+
+Properties affecting compilation are copied from the original target to the
+verification target so that the headers will be interpreted the same way by
+the compiler as when compiling the original target's sources.  There are some
+caveats with this approach.  It cannot replicate the same conditions if any
+of those properties or properties inherited through build requirements from
+transitive dependencies contain
+:ref:`target-dependent generator expressions <Target-Dependent Expressions>`
+that do not specify the target for the expansion.  Such expressions can expand
+to different contents depending on the target they are being used on.
+
+.. |xxx| replace:: private
+.. |THIS_PROPERTY| replace:: ``VERIFY_PRIVATE_HEADER_SETS``
+.. |COMPLEMENTARY_PROPERTY| replace:: :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS`
+.. |THIS_ALL_TARGET| replace:: ``all_verify_private_header_sets``
+.. |COMPLEMENTARY_ALL_TARGET| replace:: ``all_verify_interface_header_sets``
+.. |INIT_VARIABLE| replace:: :variable:`CMAKE_VERIFY_PRIVATE_HEADER_SETS`
+.. |SETS_TO_VERIFY_PROPERTY| replace:: :prop_tgt:`PRIVATE_HEADER_SETS_TO_VERIFY`
+.. include:: include/VERIFY_XXX_HEADER_SETS.rst
diff --git a/Help/prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY.rst b/Help/prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY.rst
index 9dfa79f..aa62517 100644
--- a/Help/prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY.rst
+++ b/Help/prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY.rst
@@ -3,7 +3,9 @@
 
 .. versionadded:: 3.8
 
-Sets the local debugger working directory for Visual Studio C++ targets.
+Sets the local debugger working directory for Visual Studio targets,
+specifically the process launched by the debugger.
+
 The property value may use
 :manual:`generator expressions <cmake-generator-expressions(7)>`.
 This is defined in ``<LocalDebuggerWorkingDirectory>`` in the Visual Studio
diff --git a/Help/prop_tgt/include/VERIFY_XXX_HEADER_SETS.rst b/Help/prop_tgt/include/VERIFY_XXX_HEADER_SETS.rst
new file mode 100644
index 0000000..f190213
--- /dev/null
+++ b/Help/prop_tgt/include/VERIFY_XXX_HEADER_SETS.rst
@@ -0,0 +1,34 @@
+The verification target has its
+:prop_tgt:`EXCLUDE_FROM_ALL` and :prop_tgt:`DISABLE_PRECOMPILE_HEADERS`
+properties set to true, and its :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTORCC`,
+:prop_tgt:`AUTOUIC`, :prop_tgt:`UNITY_BUILD`, and
+:prop_tgt:`CXX_SCAN_FOR_MODULES` properties set to false.
+
+If the header's :prop_sf:`LANGUAGE` property is set, the value of that property
+is used to determine the language with which to compile the header file.
+Otherwise, if the target has any C++ sources, the header is compiled as C++.
+Otherwise, if the target has any C sources, the header is compiled as C.
+Otherwise, if C++ is enabled globally, the header is compiled as C++.
+Otherwise, if C is enabled globally, the header is compiled as C. Otherwise,
+the header file is not compiled.
+
+If the header's :prop_sf:`SKIP_LINTING` property is set to true, the file is
+not compiled.
+
+If |THIS_PROPERTY| and |COMPLEMENTARY_PROPERTY| are both set to true, headers
+belonging to ``PUBLIC`` file sets will be verified twice, but with different
+conditions.  The compiler flags used for private and interface contexts can be
+different, leading to the compiler interpreting the contents of the header
+differently.
+
+If any |xxx| file set verification targets are created, a top-level target
+called |THIS_ALL_TARGET| is created which depends on all |xxx| verification
+targets.  Another target called ``all_verify_header_sets`` is also created
+which depends on |THIS_ALL_TARGET|, and on |COMPLEMENTARY_ALL_TARGET| if it
+exists (see |COMPLEMENTARY_PROPERTY|).
+
+This property is initialized by the value of the |INIT_VARIABLE| variable if
+it is set when a target is created.
+
+If the project wishes to control which header sets are verified by this
+property, it can set |SETS_TO_VERIFY_PROPERTY|.
diff --git a/Help/release/3.16.rst b/Help/release/3.16.rst
index f9f9b33..c46e3dc 100644
--- a/Help/release/3.16.rst
+++ b/Help/release/3.16.rst
@@ -113,7 +113,7 @@
   :prop_tgt:`CUDA_RESOLVE_DEVICE_SYMBOLS` target property.
 
 * The :variable:`CMAKE_ECLIPSE_RESOURCE_ENCODING` variable was added to
-  specify the resource encoding for the the :generator:`Eclipse CDT4` extra
+  specify the resource encoding for the :generator:`Eclipse CDT4` extra
   generator.
 
 * The :variable:`CMAKE_UNITY_BUILD` variable was added to initialize the
diff --git a/Help/release/3.21.rst b/Help/release/3.21.rst
index 8da1c94..0372cd8 100644
--- a/Help/release/3.21.rst
+++ b/Help/release/3.21.rst
@@ -98,7 +98,6 @@
   * is now supported by the :generator:`Xcode` generator.
 
 * The :command:`add_custom_command(TARGET)` command
-  (for :ref:`Build Events <add_custom_command(TARGET)>`)
   gained support for resolving target-dependent generator expressions.
 
 * The :command:`build_command` command gained a ``PARALLEL_LEVEL`` option.
diff --git a/Help/release/3.24.rst b/Help/release/3.24.rst
index e7ddf2a..56342c0 100644
--- a/Help/release/3.24.rst
+++ b/Help/release/3.24.rst
@@ -85,7 +85,8 @@
 
 * The :command:`cmake_host_system_information` command, on Windows,
   gained a ``QUERY WINDOWS_REGISTRY`` mode.
-  See its :ref:`Query Windows registry` section.
+  See its :command:`cmake_host_system_information(QUERY WINDOWS_REGISTRY)`
+  signature.
 
 * The :command:`cmake_language` command gained a new
   ``SET_DEPENDENCY_PROVIDER`` sub-command.  When a dependency provider is set,
diff --git a/Help/release/3.29.rst b/Help/release/3.29.rst
index fbde3c6..4916ca4 100644
--- a/Help/release/3.29.rst
+++ b/Help/release/3.29.rst
@@ -50,7 +50,7 @@
 Commands
 --------
 
-* The :ref:`add_custom_command(TARGET) <add_custom_command(TARGET)>`
+* The :command:`add_custom_command(TARGET)`
   signature now supports adding build events through :ref:`Alias Targets`.
 
 * The :command:`cmake_language(EXIT)` sub-command was added to terminate
diff --git a/Help/release/4.3.rst b/Help/release/4.3.rst
new file mode 100644
index 0000000..b13656f
--- /dev/null
+++ b/Help/release/4.3.rst
@@ -0,0 +1,294 @@
+CMake 4.3 Release Notes
+***********************
+
+.. only:: html
+
+  .. contents::
+
+Changes made since CMake 4.2 include the following.
+
+New Features
+============
+
+Common Package Specification
+----------------------------
+
+* Support for importing and exporting packages described using the |CPS|_
+  (CPS) was added.  This improves build system interoperability by allowing
+  expressive, feature-rich package descriptions to be exchanged in a format
+  other than CMake Language.
+
+  * The :command:`find_package` now searches for and can import CPS packages.
+
+  * The :command:`install` and :command:`export` commands gained a new
+    ``PACKAGE_INFO`` sub-command to generate CPS package descriptions.
+
+  * The :command:`project` command gained new ``COMPAT_VERSION`` and
+    ``SPDX_LICENSE`` options.  These values may be inherited when creating a
+    CPS package description.  See the :command:`install(PACKAGE_INFO)`
+    documentation for details.
+
+.. _CPS: https://cps-org.github.io/cps/
+.. |CPS| replace:: Common Package Specification
+
+Instrumentation
+---------------
+
+* :manual:`cmake-instrumentation(7)` was added to enable collection of
+  timing data, target information, and system diagnostic information during
+  the configure, generate, build, test, and install steps of a CMake project:
+
+  * Instrumentation data are :ref:`indexed <cmake-instrumentation Indexing>`
+    and provided to :ref:`callbacks <cmake-instrumentation Callbacks>` for
+    custom processing.
+
+  * Instrumentation data are included in submissions to CDash.
+
+  * Optionally,
+    :ref:`Google Trace Event Format <cmake-instrumentation Google Trace File>`
+    files may be generated to visualize instrumentation data.
+
+Presets
+-------
+
+* :manual:`cmake-presets(7)` files now support schema version ``11``.
+  The ``jobs`` field under test presets now supports an empty string, to
+  match the behavior of :option:`ctest --parallel` with the value omitted.
+* The ``jobs`` field under both build and test presets no longer accept
+  negative integer values, regardless of the schema version.
+
+File-Based API
+--------------
+
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 version field
+  has been updated to 2.10.
+
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 "target" object
+  gained a new ``interfaceSources`` array field, and the ``sourceGroups``
+  array items gained a new ``interfaceSourceIndexes`` array field.
+
+Platforms
+---------
+
+* ``HIP`` language code may now be compiled for SPIR-V targets,
+  e.g., via chipStar.  See the :variable:`CMAKE_HIP_PLATFORM` variable.
+
+Command-Line
+------------
+
+* :option:`cmake --version` now supports a ``=json-v1`` value to print
+  detailed version information in a JSON format.
+
+* :option:`cmake --build` now supports specifying a build directory and
+  preset together.  The build preset will be used with the explicit
+  build directory substituted.
+
+* The :option:`cmake -E` commands
+  :option:`md5sum <cmake-E md5sum>`,
+  :option:`sha1sum <cmake-E sha1sum>`,
+  :option:`sha224sum <cmake-E sha224sum>`,
+  :option:`sha256sum <cmake-E sha256sum>`,
+  :option:`sha384sum <cmake-E sha384sum>`, and
+  :option:`sha512sum <cmake-E sha512sum>`
+  now support reading from standard input by passing ``-``.
+
+* The :option:`cmake -E bin2c <cmake-E bin2c>` command-line tool was added.
+
+* The :option:`cmake -E tar <cmake-E tar>` command-line tool:
+
+  * Gained a ``--cmake-tar-compression-level`` flag to specify the
+    compression level.
+  * Gained a ``--cmake-tar-compression-method`` flag to specify the
+    compression method.
+  * Gained a ``--cmake-tar-threads`` flag to enable multithreaded operations.
+  * Now supports specifying compression method and level for ``7zip`` and
+    ``zip`` formats.
+  * Gained a ``--format=raw`` flag to disable compression.
+  * Gained a ``--lzma`` flag to specify ``LZMA`` compression.
+
+Commands
+--------
+
+* The :command:`cmake_instrumentation` command was added to make
+  project-level instrumentation queries.
+
+* The :command:`file(ARCHIVE_CREATE)` command:
+
+  * Gained a ``THREADS`` option to enable multithreaded operations.
+  * Now supports ``COMPRESSION`` method ``Deflate`` as an alias for ``GZip``.
+  * Now supports ``COMPRESSION`` method ``LZMA``.
+  * Now supports ``COMPRESSION`` method ``LZMA2`` as an alias for ``XZ``.
+  * Now supports ``COMPRESSION`` method ``PPMd`` for format ``7zip``.
+  * Now supports ``COMPRESSION`` and ``COMPRESSION_LEVEL`` options
+    for formats ``7zip`` and ``zip``.
+
+* The :command:`get_property` and :command:`set_property` commands
+  now support a ``FILE_SET`` scope for file set properties of a target.
+
+* The :command:`string(JSON)` command gained new ``GET_RAW`` and
+  ``STRING_ENCODE`` modes.
+
+* The :command:`source_group` command now supports
+  :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+* The :command:`cmake_host_system_information` command gained a
+  ``LOCALE_CHARSET`` query for the expected :manual:`cmake-language(7)`
+  script encoding.
+
+Variables
+---------
+
+* The :variable:`CMAKE_<LANG>_LINK_FLAGS` and
+  :variable:`CMAKE_<LANG>_LINK_FLAGS_<CONFIG>` variables were added
+  to support per-language link flags for all target types.
+  See policy :policy:`CMP0210`.
+
+* The :variable:`CMAKE_VERIFY_PRIVATE_HEADER_SETS` variable and corresponding
+  :prop_tgt:`VERIFY_PRIVATE_HEADER_SETS` target property were added to
+  enable build rules that verify all headers in private file sets can be used
+  on their own.
+
+Properties
+----------
+
+* A :prop_tgt:`<LANG>_PVS_STUDIO` target property and supporting
+  :variable:`CMAKE_<LANG>_PVS_STUDIO` variable were introduced to tell
+  :ref:`Makefile Generators` and :ref:`Ninja Generators` to run
+  ``pvs-studio-analyzer`` with the compiler for ``C`` and ``CXX`` languages.
+
+* When :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` is set to true on an executable
+  target, that target's interface file sets are verified regardless of its
+  :prop_tgt:`ENABLE_EXPORTS` property. See policy :policy:`CMP0209`.
+
+* The :prop_tgt:`PRIVATE_HEADER_SETS_TO_VERIFY` target property was added to
+  customize which private file sets to verify when the target's
+  :prop_tgt:`VERIFY_PRIVATE_HEADER_SETS` property is true.
+
+Modules
+-------
+
+* The :module:`FindCUDAToolkit` module now creates a ``CUDA::bin2c``
+  imported target for the :ref:`bin2c <FindCUDAToolkit_bin2c>` utility.
+
+* The :module:`FindLibXml2` module gained a ``LibXml2_USE_STATIC_LIBS`` hint
+  to select static libraries.
+
+* The :module:`FindRuby` module now provides imported targets.
+
+* The :module:`FindSQLite3` module now provides imported
+  targets with the ``SQLite3::`` prefix.
+
+* The :module:`UseJava` module's :command:`add_jar` command now accepts a new
+  ``INCLUDE_MODULES`` option that adds its arguments to the ``--module-path``
+  argument to the Java compiler. This allows building JAR files that use JPMS
+  modules in their build.
+
+Generator Expressions
+---------------------
+
+* :ref:`String Comparison <String Comparisons Generator Expressions>`
+  generator expressions were added.
+
+* :genex:`$<STRING:...>` generator expressions were added for
+  :ref:`query <String Queries Generator Expressions>`,
+  :ref:`generation <String Generating Generator Expressions>`, and
+  :ref:`transformation <String Transforming Generator Expressions>`
+  operations on strings.
+
+* The :genex:`$<FILE_SET_EXISTS>` and :genex:`$<FILE_SET_PROPERTY>` generator
+  expressions were added to query file set existence and properties.
+
+* The :genex:`$<SOURCE_EXISTS>` and :genex:`$<SOURCE_PROPERTY>` generator
+  expressions were added to query source file existence and properties.
+
+CTest
+-----
+
+* The :module:`CTestCoverageCollectGCOV` module:
+
+  * Now supports ``TARBALL_COMPRESSION`` method ``LZMA``.
+
+  * Now supports ``TARBALL_COMPRESSION`` method ``LZMA2``
+    as an alias for ``XZ``.
+
+  * Now supports ``FROM_EXT`` with file extensions corresponding to
+    ``LZMA`` and ``ZSTD`` compression.
+
+CPack
+-----
+
+* :module:`CPack` gained the :variable:`CPACK_COMPRESSION_LEVEL`
+  variable to control the compression level used when creating
+  packages.
+
+* The :cpack_gen:`CPack Archive Generator`:
+
+  * Now supports compression method specification for formats
+    ``7zip`` and ``zip``.
+
+  * Gained a :variable:`CPACK_ARCHIVE_COMPRESSION_LEVEL` option to
+    control the compression level used when creating archive packages.
+
+  * Gained :variable:`CPACK_ARCHIVE_UID` and :variable:`CPACK_ARCHIVE_GID`
+    options to specify the UID and GID of archive entries, respectively.
+    The defaults are UID ``0`` and GID ``0``.  See policy :policy:`CMP0206`.
+
+* The :cpack_gen:`CPack DEB Generator` gained a new
+  :variable:`CPACK_DEBIAN_COMPRESSION_LEVEL` variable to control the
+  compression level used when creating Debian packages.
+
+* The :cpack_gen:`CPack WIX Generator` now supports per-user installers
+  by setting :variable:`CPACK_WIX_INSTALL_SCOPE` to ``perUser``.
+
+Deprecated and Removed Features
+===============================
+
+* The :variable:`CMAKE_ENABLE_EXPORTS` variable is deprecated in favor of
+  the :variable:`CMAKE_EXECUTABLE_ENABLE_EXPORTS` and
+  :variable:`CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS` variables.
+
+* The :command:`export(EXPORT)` command no longer allows certain
+  arguments to be missing or empty.  See policy :policy:`CMP0208`.
+
+Other Changes
+=============
+
+* The :option:`cmake -E tar <cmake-E tar>` command-line tool
+  and the :command:`file(ARCHIVE_EXTRACT)` command now reject archive
+  entries whose paths are absolute or contain ``..`` path traversal
+  components.
+
+* The family of :option:`cmake --trace` and related commands now print "end"
+  commands for control structures: :command:`endblock`, :command:`endforeach`,
+  :command:`endfunction`, :command:`endif`, :command:`endmacro`, and
+  :command:`endwhile`.
+
+* The :command:`file(CREATE_LINK)` command's ``COPY_ON_ERROR`` option,
+  when used with a directory, now copies directory content.
+  See policy :policy:`CMP0205`.
+
+* The :command:`file(GET_RUNTIME_DEPENDENCIES)`
+  and :command:`install(RUNTIME_DEPENDENCY_SET)` commands now normalize
+  paths before matching filters.  See policy :policy:`CMP0207`.
+
+* The precompiled Linux ``aarch64`` binaries provided on
+  `cmake.org <https://cmake.org/download/>`_ now require GLIBC 2.28 or higher.
+
+* The precompiled macOS binary provided on ``cmake.org`` for macOS 10.13+
+  now requires macOS 12 or newer for the :manual:`cmake-gui(1)` application.
+  The command-line tools still run on macOS 10.13.
+
+* The precompiled Windows binaries provided on
+  `cmake.org <https://cmake.org/download/>`_ now require Windows 10 or higher.
+
+Updates
+=======
+
+Changes made since CMake 4.3.0 include the following.
+
+4.3.1, 4.3.2
+------------
+
+* These versions made no changes to documented features or interfaces.
+  Some implementation updates were made to support ecosystem changes
+  and/or fix regressions.
diff --git a/Help/release/index.rst b/Help/release/index.rst
index 54190ee..c525705 100644
--- a/Help/release/index.rst
+++ b/Help/release/index.rst
@@ -13,6 +13,7 @@
 .. toctree::
    :maxdepth: 1
 
+   4.3 <4.3>
    4.2 <4.2>
    4.1 <4.1>
    4.0 <4.0>
diff --git a/Help/variable/CMAKE_ENABLE_EXPORTS.rst b/Help/variable/CMAKE_ENABLE_EXPORTS.rst
index da23342..efde96d 100644
--- a/Help/variable/CMAKE_ENABLE_EXPORTS.rst
+++ b/Help/variable/CMAKE_ENABLE_EXPORTS.rst
@@ -3,13 +3,16 @@
 
 .. versionadded:: 3.4
 
+.. deprecated:: 4.3
+  This variable has been deprecated in favor of the
+  :variable:`CMAKE_EXECUTABLE_ENABLE_EXPORTS` and
+  :variable:`CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS` variables,
+  which have been available since CMake 3.27.
+  It is provided for backward compatibility with older CMake code,
+  but should not be used in new projects.
+
 Specify whether executables export symbols for loadable modules.
 
 This variable is used to initialize the :prop_tgt:`ENABLE_EXPORTS` target
 property for executable targets when they are created by calls to the
 :command:`add_executable` command.  See the property documentation for details.
-
-This variable has been superseded by the
-:variable:`CMAKE_EXECUTABLE_ENABLE_EXPORTS` variable.  It is provided for
-backward compatibility with older CMake code, but should not be used in new
-projects.
diff --git a/Help/variable/CMAKE_EXECUTABLE_ENABLE_EXPORTS.rst b/Help/variable/CMAKE_EXECUTABLE_ENABLE_EXPORTS.rst
index aa6dda2..5168555 100644
--- a/Help/variable/CMAKE_EXECUTABLE_ENABLE_EXPORTS.rst
+++ b/Help/variable/CMAKE_EXECUTABLE_ENABLE_EXPORTS.rst
@@ -9,4 +9,9 @@
 property for executable targets when they are created by calls to the
 :command:`add_executable` command.  See the property documentation for details.
 
-This variable supersede the :variable:`CMAKE_ENABLE_EXPORTS` variable.
+This variable supersedes the :variable:`CMAKE_ENABLE_EXPORTS` variable.
+
+See Also
+^^^^^^^^
+
+* The :variable:`CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS` variable.
diff --git a/Help/variable/CMAKE_EXE_LINKER_FLAGS.rst b/Help/variable/CMAKE_EXE_LINKER_FLAGS.rst
index 0bb08ce..4e746ea 100644
--- a/Help/variable/CMAKE_EXE_LINKER_FLAGS.rst
+++ b/Help/variable/CMAKE_EXE_LINKER_FLAGS.rst
@@ -3,6 +3,12 @@
 
 Linker flags to be used to create executables.
 
-These flags will be used by the linker when creating an executable.
+These flags will be used by the linker when creating an executable for all
+build configurations.
 
 .. include:: ../variable/include/LINKER_FLAGS.rst
+
+See Also
+^^^^^^^^
+
+* :variable:`CMAKE_EXE_LINKER_FLAGS_<CONFIG>`
diff --git a/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG.rst b/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG.rst
index 30aad20..7dac9e9 100644
--- a/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG.rst
+++ b/Help/variable/CMAKE_EXE_LINKER_FLAGS_CONFIG.rst
@@ -3,7 +3,12 @@
 
 Flags to be used when linking an executable.
 
-Same as ``CMAKE_C_FLAGS_*`` but used by the linker when creating
-executables.
+These flags will be used by the linker when creating an executable for the
+``<CONFIG>`` configuration.
 
 .. include:: ../variable/include/LINKER_FLAGS.rst
+
+See Also
+^^^^^^^^
+
+* :variable:`CMAKE_EXE_LINKER_FLAGS`
diff --git a/Help/variable/CMAKE_HIP_ARCHITECTURES.rst b/Help/variable/CMAKE_HIP_ARCHITECTURES.rst
index 3f17983..96876b8 100644
--- a/Help/variable/CMAKE_HIP_ARCHITECTURES.rst
+++ b/Help/variable/CMAKE_HIP_ARCHITECTURES.rst
@@ -12,5 +12,9 @@
   Uses architectures reported by ``rocm_agent_enumerator``, if available,
   and otherwise to a default chosen by the compiler.
 
+``spirv``
+  Defaults to ``OFF``. The HIP package (e.g., chipStar) handles targeting
+  via its own configuration.
+
 This variable is used to initialize the :prop_tgt:`HIP_ARCHITECTURES` property
 on all targets. See the target property for additional information.
diff --git a/Help/variable/CMAKE_HIP_PLATFORM.rst b/Help/variable/CMAKE_HIP_PLATFORM.rst
index 5e3a2b7..82e1a03 100644
--- a/Help/variable/CMAKE_HIP_PLATFORM.rst
+++ b/Help/variable/CMAKE_HIP_PLATFORM.rst
@@ -13,6 +13,11 @@
 ``nvidia``
   NVIDIA GPUs
 
+``spirv``
+  .. versionadded:: 4.3
+
+  SPIR-V target (e.g., chipStar)
+
 If not specified, a default is computed via ``hipconfig --platform``.
 
 :variable:`CMAKE_HIP_ARCHITECTURES` entries are interpreted with
diff --git a/Help/variable/CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO.rst b/Help/variable/CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO.rst
new file mode 100644
index 0000000..9ddd449
--- /dev/null
+++ b/Help/variable/CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO.rst
@@ -0,0 +1,124 @@
+CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO
+-------------------------------------
+
+.. versionadded:: 4.3
+
+.. note::
+
+   This variable is meaningful only when experimental support has been enabled
+   by the ``CMAKE_EXPERIMENTAL_FIXME`` gate.
+
+A list of directives instructing CMake to install |CPS| package information
+when exported target information is installed via :command:`install(EXPORT)`.
+The value is treated as a list, with each directive having the form::
+
+  <export-name>:<package-name>[/[l][a<appendix-name>][/<destination>]]
+
+Slashes are used to separate different components of the directive.
+
+Note that this feature is intended for package distributors, and should
+**only** be used when editing a project's CMake script is not feasible.
+Developers should use :command:`install(PACKAGE_INFO)` directly.
+
+Additionally, because ``CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO`` functions by
+emulating a call to :command:`install(PACKAGE_INFO)`, using it with a project
+that is already calling :command:`install(PACKAGE_INFO)` directly may result
+in conflicting installation directives, which will usually cause the project's
+configure step to fail.
+
+The meaning of the values is as follows:
+
+``<export-name>``
+  Name of the export for which package information should be installed.
+
+``<package-name>``
+  Name of the package for which to generate package information.  This is also
+  the name that users would use in a :command:`find_package` call.
+
+``l``
+  Optional.  Specifies that the name of the package information file on disk
+  should be lower case.  See the ``LOWER_CASE_FILE`` option of
+  :command:`install(PACKAGE_INFO)`.
+
+``a<appendix-name>``
+  Optional.  Specifies that an appendix ``<appendix-name>`` should be created
+  rather than a root package description.  See the ``APPENDIX`` option of
+  :command:`install(PACKAGE_INFO)`.  Note that additional information
+  (see below) cannot be added to appendices.
+
+``<destination>``
+  Optional.  Specifies the destination to which the package information file
+  should be installed.  See the ``DESTINATION`` option of
+  :command:`install(PACKAGE_INFO)`.  Note that the default is a
+  platform-specific location that is appropriate for |CPS| files in most
+  instances, *not* the ``DESTINATION`` of the :command:`install(EXPORT)`
+  which the directive matched.
+
+For non-appendices, CMake will also infer additional information from several
+CMake variables of the form ``<export-name>_EXPORT_PACKAGE_INFO_<var>``.  The
+values of these are first processed as if by :command:`string(CONFIGURE)` with
+the ``@ONLY`` option.  These are optional, and their effect is equivalent to
+passing their value to the ``<var>`` option of the
+:command:`install(PACKAGE_INFO)` command.
+
+The additional variables are:
+
+  * ``<export-name>_EXPORT_PACKAGE_INFO_VERSION``
+  * ``<export-name>_EXPORT_PACKAGE_INFO_COMPAT_VERSION``
+  * ``<export-name>_EXPORT_PACKAGE_INFO_VERSION_SCHEMA``
+  * ``<export-name>_EXPORT_PACKAGE_INFO_LICENSE``
+  * ``<export-name>_EXPORT_PACKAGE_INFO_DEFAULT_LICENSE``
+  * ``<export-name>_EXPORT_PACKAGE_INFO_DEFAULT_CONFIGURATIONS``
+
+Ideally, the version should be set to ``@PROJECT_VERSION@``.  However,
+some projects may not use the ``VERSION`` option of the :command:`project`
+command.
+
+Example
+^^^^^^^
+
+Consider the following (simplified) project:
+
+.. code-block:: cmake
+
+  project(Example VERSION 1.2.3 SPDX_LICENSE "BSD-3-Clause")
+
+  add_library(foo ...)
+  add_library(bar ...)
+
+  install(TARGETS foo EXPORT required-targets)
+  install(TARGETS bar EXPORT optional-targets)
+
+  install(EXPORT required-targets FILE example-targets.cmake ...)
+  install(EXPORT optional-targets FILE example-optional-targets.cmake ...)
+
+In this example, let ``example-targets.cmake`` be a file which is always
+installed, and ``example-optional-targets.cmake`` be a file which is
+optionally installed (e.g. is distributed as part of a separate package which
+depends on the 'base' package).
+
+Now, imagine we are a distributor that wants to make |CPS| package information
+files available to our users, but we do not want to modify the project's build
+files.  We can do this by passing the following arguments to CMake:
+
+.. code-block::
+
+  -DCMAKE_EXPERIMENTAL_FIXME=<elided>
+  -DCMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO=\
+    required-targets:Example/l;\
+    optional-targets:Example/laoptional
+  -Drequired-targets_EXPORT_PACKAGE_INFO_VERSION=@Example_VERSION@
+  -Drequired-targets_EXPORT_PACKAGE_INFO_LICENSE=@Example_SPDX_LICENSE@
+
+(Whitespace and line continuation characters, added for readability, should
+be removed in real usage. Arguments may need to be quoted to prevent being
+reinterpreted by the command shell.)
+
+This will cause CMake to also create and install the files ``example.cps`` and
+``example-optional.cps`` which describe the ``Example`` package.  We could
+also specify the version and license information using substitutions provided
+by the package build system (e.g. rpm, dpkg) if the project does not provide
+this information via the :command:`project` command.
+
+.. _CPS: https://cps-org.github.io/cps/
+.. |CPS| replace:: Common Package Specification
diff --git a/Help/variable/CMAKE_INSTALL_PREFIX.rst b/Help/variable/CMAKE_INSTALL_PREFIX.rst
index ce7cb8b..340bc35 100644
--- a/Help/variable/CMAKE_INSTALL_PREFIX.rst
+++ b/Help/variable/CMAKE_INSTALL_PREFIX.rst
@@ -45,3 +45,21 @@
 .. code-block:: shell
 
   cmake --install . --prefix /my/install/prefix
+
+.. note::
+
+  When the project is using the :module:`GNUInstallDirs` module, there are
+  some :ref:`special cases <GNUInstallDirs special cases>` that are
+  evaluated based on the value of the :variable:`CMAKE_INSTALL_PREFIX`
+  variable during the configuration phase.  The results persist even
+  if an alternative :option:`--prefix <cmake--install --prefix>` option
+  is used during installation.
+
+See Also
+^^^^^^^^
+
+* The :option:`--install-prefix <cmake --install-prefix>` option.
+* The :genex:`$<INSTALL_PREFIX>` generator expression.
+* The :ref:`installDir <CMakePresets installDir>` field in CMake configure
+  presets.
+* The :variable:`CPACK_PACKAGING_INSTALL_PREFIX` variable.
diff --git a/Help/variable/CMAKE_LANG_LINK_FLAGS.rst b/Help/variable/CMAKE_LANG_LINK_FLAGS.rst
new file mode 100644
index 0000000..9e2c45c
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_LINK_FLAGS.rst
@@ -0,0 +1,38 @@
+CMAKE_<LANG>_LINK_FLAGS
+-----------------------
+
+.. versionadded:: 4.3
+
+Language-wide flags for language ``<LANG>`` used when linking for all
+configurations. These flags will be passed to all invocations of the compiler
+which drive linking.
+
+The flags in this variable will obey the following behavior with respect to
+ordering of flags from other variables.
+
+* They will be passed after those added by :variable:`CMAKE_<LANG>_FLAGS` and
+  :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>`.
+* They will be passed after those added by :variable:`CMAKE_EXE_LINKER_FLAGS`,
+  :variable:`CMAKE_EXE_LINKER_FLAGS_<CONFIG>`,
+  :variable:`CMAKE_SHARED_LINKER_FLAGS`,
+  :variable:`CMAKE_SHARED_LINKER_FLAGS_<CONFIG>`,
+  :variable:`CMAKE_MODULE_LINKER_FLAGS`,
+  and :variable:`CMAKE_MODULE_LINKER_FLAGS_<CONFIG>` depending on the given
+  target type.
+* They will be passed before those added by
+  :variable:`CMAKE_<LANG>_LINK_FLAGS_<CONFIG>`.
+* They will be passed before those added by commands such
+  as :command:`add_link_options` and :command:`target_link_options`.
+
+Use of this variable is enabled when policy :policy:`CMP0210` is ``NEW``.
+
+.. include:: ../command/include/LINK_LIBRARIES_LINKER.rst
+
+This support implies to parse and re-quote the content of the variable.
+
+See Also
+^^^^^^^^
+
+* :variable:`CMAKE_<LANG>_LINK_FLAGS_<CONFIG>`
+* :variable:`CMAKE_<LANG>_FLAGS`
+* :policy:`CMP0210`
diff --git a/Help/variable/CMAKE_LANG_LINK_FLAGS_CONFIG.rst b/Help/variable/CMAKE_LANG_LINK_FLAGS_CONFIG.rst
new file mode 100644
index 0000000..c0c517b
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_LINK_FLAGS_CONFIG.rst
@@ -0,0 +1,23 @@
+CMAKE_<LANG>_LINK_FLAGS_<CONFIG>
+--------------------------------
+
+.. versionadded:: 4.3
+
+Language-wide flags for language ``<LANG>`` used when linking for the
+``<CONFIG>`` configuration. These flags will be passed to all invocations of
+the compiler which drive linking.
+
+See :variable:`CMAKE_<LANG>_LINK_FLAGS` for the ordering of these flags with
+respect to other variables. Notably, flags in
+``CMAKE_<LANG>_LINK_FLAGS_<CONFIG>`` are passed after those in
+:variable:`CMAKE_<LANG>_LINK_FLAGS`.
+
+.. include:: ../command/include/LINK_LIBRARIES_LINKER.rst
+
+This support implies to parse and re-quote the content of the variable.
+
+See Also
+^^^^^^^^
+
+* :variable:`CMAKE_<LANG>_LINK_FLAGS`
+* :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>`
diff --git a/Help/variable/CMAKE_LANG_PVS_STUDIO.rst b/Help/variable/CMAKE_LANG_PVS_STUDIO.rst
new file mode 100644
index 0000000..5128080
--- /dev/null
+++ b/Help/variable/CMAKE_LANG_PVS_STUDIO.rst
@@ -0,0 +1,15 @@
+CMAKE_<LANG>_PVS_STUDIO
+-----------------------
+
+.. versionadded:: 4.3
+
+Default value for :prop_tgt:`<LANG>_PVS_STUDIO` target property
+when ``<LANG>`` is ``C`` or ``CXX``.
+
+This variable is used to initialize the property on each target as it is
+created.  For example:
+
+.. code-block:: cmake
+
+  set(CMAKE_CXX_PVS_STUDIO pvs-studio-analyzer analyze -a "GA\;OP")
+  add_executable(foo foo.cxx)
diff --git a/Help/variable/CMAKE_MODULE_LINKER_FLAGS.rst b/Help/variable/CMAKE_MODULE_LINKER_FLAGS.rst
index e74b6ee..5e7797f 100644
--- a/Help/variable/CMAKE_MODULE_LINKER_FLAGS.rst
+++ b/Help/variable/CMAKE_MODULE_LINKER_FLAGS.rst
@@ -3,6 +3,12 @@
 
 Linker flags to be used to create modules.
 
-These flags will be used by the linker when creating a module.
+These flags will be used by the linker when creating a module for all build
+configurations.
 
 .. include:: ../variable/include/LINKER_FLAGS.rst
+
+See Also
+^^^^^^^^
+
+* :variable:`CMAKE_MODULE_LINKER_FLAGS_<CONFIG>`
diff --git a/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG.rst b/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG.rst
index 693565a..864c45b 100644
--- a/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG.rst
+++ b/Help/variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG.rst
@@ -3,6 +3,12 @@
 
 Flags to be used when linking a module.
 
-Same as ``CMAKE_C_FLAGS_*`` but used by the linker when creating modules.
+These flags will be used by the linker when creating a module for the
+``<CONFIG>`` configuration.
 
 .. include:: ../variable/include/LINKER_FLAGS.rst
+
+See Also
+^^^^^^^^
+
+* :variable:`CMAKE_MODULE_LINKER_FLAGS`
diff --git a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
index 3a9605f..1197560 100644
--- a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
+++ b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
@@ -40,6 +40,8 @@
   policy :policy:`CMP0133`.
 * ``CMAKE_POLICY_WARNING_CMP0172`` controls the warning for
   policy :policy:`CMP0172`.
+* ``CMAKE_POLICY_WARNING_CMP0206`` controls the warning for
+  policy :policy:`CMP0206`.
 
 This variable should not be set by a project in CMake code.  Project
 developers running CMake may set this variable in their cache to
diff --git a/Help/variable/CMAKE_PROJECT_COMPAT_VERSION.rst b/Help/variable/CMAKE_PROJECT_COMPAT_VERSION.rst
index e32d381..1b5e96a 100644
--- a/Help/variable/CMAKE_PROJECT_COMPAT_VERSION.rst
+++ b/Help/variable/CMAKE_PROJECT_COMPAT_VERSION.rst
@@ -1,24 +1,20 @@
 CMAKE_PROJECT_COMPAT_VERSION
 ----------------------------
 
-.. versionadded:: 4.1
-
-.. note::
-
-  Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+.. versionadded:: 4.3
 
 The compatibility version of the top level project.
 
-This variable holds the compatibility version of the project as specified in the
-top level CMakeLists.txt file by a :command:`project` command.  In the event
-that the top level CMakeLists.txt contains multiple :command:`project` calls,
-the most recently called one from that top level CMakeLists.txt will determine
-the value that ``CMAKE_PROJECT_COMPAT_VERSION`` contains.  For example, consider
-the following top level CMakeLists.txt:
+This variable holds the compatibility version of the project as specified in
+the top level CMakeLists.txt file by a :command:`project` command.  In the
+event that the top level CMakeLists.txt contains multiple :command:`project`
+calls, the most recently called one from that top level CMakeLists.txt will
+determine the value that ``CMAKE_PROJECT_COMPAT_VERSION`` contains.  For
+example, consider the following top level CMakeLists.txt:
 
 .. code-block:: cmake
 
-  cmake_minimum_required(VERSION 4.1)
+  cmake_minimum_required(VERSION 4.3)
   project(First VERSION 9.0 COMPAT_VERSION 1.2.3)
   project(Second VERSION 9.0 COMPAT_VERSION 3.4.5)
   add_subdirectory(sub)
@@ -36,6 +32,6 @@
 
   CMAKE_PROJECT_COMPAT_VERSION = 3.4.5
 
-To obtain the version from the most recent call to :command:`project` in
-the current directory scope or above, see the :variable:`PROJECT_COMPAT_VERSION`
-variable.
+To obtain the version from the most recent call to :command:`project`
+in the current directory scope or above, see the
+:variable:`PROJECT_COMPAT_VERSION` variable.
diff --git a/Help/variable/CMAKE_PROJECT_SPDX_LICENSE.rst b/Help/variable/CMAKE_PROJECT_SPDX_LICENSE.rst
index 0cbde7c..3164b7e 100644
--- a/Help/variable/CMAKE_PROJECT_SPDX_LICENSE.rst
+++ b/Help/variable/CMAKE_PROJECT_SPDX_LICENSE.rst
@@ -1,11 +1,7 @@
 CMAKE_PROJECT_SPDX_LICENSE
 --------------------------
 
-.. versionadded:: 4.2
-
-.. note::
-
-  Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+.. versionadded:: 4.3
 
 The license(s) of the top level project.
 
@@ -18,7 +14,7 @@
 
 .. code-block:: cmake
 
-  cmake_minimum_required(VERSION 4.2)
+  cmake_minimum_required(VERSION 4.3)
   project(First SPDX_LICENSE "BSD-3-Clause")
   project(Second SPDX_LICENSE "BSD-3-Clause AND CC-BY-SA-4.0")
   add_subdirectory(sub)
diff --git a/Help/variable/CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS.rst b/Help/variable/CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS.rst
index 3e2c6df..07c99e2 100644
--- a/Help/variable/CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS.rst
+++ b/Help/variable/CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS.rst
@@ -8,3 +8,8 @@
 This variable is used to initialize the :prop_tgt:`ENABLE_EXPORTS` target
 property for shared library targets when they are created by calls to the
 :command:`add_library` command.  See the property documentation for details.
+
+See Also
+^^^^^^^^
+
+* The :variable:`CMAKE_EXECUTABLE_ENABLE_EXPORTS` variable.
diff --git a/Help/variable/CMAKE_SHARED_LINKER_FLAGS.rst b/Help/variable/CMAKE_SHARED_LINKER_FLAGS.rst
index 93c84ee..5a81879 100644
--- a/Help/variable/CMAKE_SHARED_LINKER_FLAGS.rst
+++ b/Help/variable/CMAKE_SHARED_LINKER_FLAGS.rst
@@ -3,6 +3,12 @@
 
 Linker flags to be used to create shared libraries.
 
-These flags will be used by the linker when creating a shared library.
+These flags will be used by the linker when creating a shared library for all
+build configurations.
 
 .. include:: ../variable/include/LINKER_FLAGS.rst
+
+See Also
+^^^^^^^^
+
+* :variable:`CMAKE_SHARED_LINKER_FLAGS_<CONFIG>`
diff --git a/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.rst b/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.rst
index d0eb4fd..51b276b 100644
--- a/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.rst
+++ b/Help/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.rst
@@ -3,7 +3,12 @@
 
 Flags to be used when linking a shared library.
 
-Same as ``CMAKE_C_FLAGS_*`` but used by the linker when creating shared
-libraries.
+These flags will be used by the linker when creating a shared library for the
+``<CONFIG>`` configuration.
 
 .. include:: ../variable/include/LINKER_FLAGS.rst
+
+See Also
+^^^^^^^^
+
+* :variable:`CMAKE_SHARED_LINKER_FLAGS`
diff --git a/Help/variable/CMAKE_VERIFY_INTERFACE_HEADER_SETS.rst b/Help/variable/CMAKE_VERIFY_INTERFACE_HEADER_SETS.rst
index 3fb8817..f0302ba 100644
--- a/Help/variable/CMAKE_VERIFY_INTERFACE_HEADER_SETS.rst
+++ b/Help/variable/CMAKE_VERIFY_INTERFACE_HEADER_SETS.rst
@@ -3,37 +3,8 @@
 
 .. versionadded:: 3.24
 
-This variable is used to initialize the
-:prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` property of targets when they are
-created.  Setting it to true enables header set verification.
-
-Projects should not normally set this variable, it is intended as a developer
-control to be set on the :manual:`cmake(1)` command line or other
-equivalent methods.  The developer must have the ability to enable or
-disable header set verification according to the capabilities of their own
-machine and compiler.
-
-Verification of a dependency's header sets is not typically of interest
-to developers.  Therefore, :command:`FetchContent_MakeAvailable` explicitly
-sets ``CMAKE_VERIFY_INTERFACE_HEADER_SETS`` to false for the duration of its
-call, but restores its original value before returning.  If a project brings
-a dependency directly into the main build (e.g. calling
-:command:`add_subdirectory` on a vendored project from a git submodule), it
-should also do likewise.  For example:
-
-.. code:: cmake
-
-  # Save original setting so we can restore it later
-  set(want_header_set_verification ${CMAKE_VERIFY_INTERFACE_HEADER_SETS})
-
-  # Include the vendored dependency with header set verification disabled
-  set(CMAKE_VERIFY_INTERFACE_HEADER_SETS OFF)
-  add_subdirectory(...)   # Vendored sources, e.g. from git submodules
-
-  # Add the project's own sources. Restore the developer's original choice
-  # for whether to enable header set verification.
-  set(CMAKE_VERIFY_INTERFACE_HEADER_SETS ${want_header_set_verification})
-  add_subdirectory(src)
-
-By default, this variable is not set, which will result in header set
-verification being disabled.
+.. |VERIFY_XXX_HEADER_SETS| replace:: :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS`
+.. |CMAKE_VERIFY_XXX_HEADER_SETS| replace:: ``CMAKE_VERIFY_INTERFACE_HEADER_SETS``
+.. |COMPLEMENTARY_CMAKE_VERIFY_XXX_HEADER_SETS| replace:: :variable:`CMAKE_VERIFY_PRIVATE_HEADER_SETS`
+.. |xxx| replace:: interface
+.. include:: include/CMAKE_VERIFY_XXX_HEADER_SETS.rst
diff --git a/Help/variable/CMAKE_VERIFY_PRIVATE_HEADER_SETS.rst b/Help/variable/CMAKE_VERIFY_PRIVATE_HEADER_SETS.rst
new file mode 100644
index 0000000..3dd15fa
--- /dev/null
+++ b/Help/variable/CMAKE_VERIFY_PRIVATE_HEADER_SETS.rst
@@ -0,0 +1,10 @@
+CMAKE_VERIFY_PRIVATE_HEADER_SETS
+--------------------------------
+
+.. versionadded:: 4.3
+
+.. |VERIFY_XXX_HEADER_SETS| replace:: :prop_tgt:`VERIFY_PRIVATE_HEADER_SETS`
+.. |CMAKE_VERIFY_XXX_HEADER_SETS| replace:: ``CMAKE_VERIFY_PRIVATE_HEADER_SETS``
+.. |COMPLEMENTARY_CMAKE_VERIFY_XXX_HEADER_SETS| replace:: :variable:`CMAKE_VERIFY_INTERFACE_HEADER_SETS`
+.. |xxx| replace:: private
+.. include:: include/CMAKE_VERIFY_XXX_HEADER_SETS.rst
diff --git a/Help/variable/CTEST_BINARY_DIRECTORY.rst b/Help/variable/CTEST_BINARY_DIRECTORY.rst
index 8413e37..ec30f2d 100644
--- a/Help/variable/CTEST_BINARY_DIRECTORY.rst
+++ b/Help/variable/CTEST_BINARY_DIRECTORY.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``BuildDirectory`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_BUILD_COMMAND.rst b/Help/variable/CTEST_BUILD_COMMAND.rst
index 31c44e2..e4110c7 100644
--- a/Help/variable/CTEST_BUILD_COMMAND.rst
+++ b/Help/variable/CTEST_BUILD_COMMAND.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``MakeCommand`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_BUILD_NAME.rst b/Help/variable/CTEST_BUILD_NAME.rst
index 3d08397..d6b0636 100644
--- a/Help/variable/CTEST_BUILD_NAME.rst
+++ b/Help/variable/CTEST_BUILD_NAME.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``BuildName`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_BZR_COMMAND.rst b/Help/variable/CTEST_BZR_COMMAND.rst
index 0c05d1a..8927886 100644
--- a/Help/variable/CTEST_BZR_COMMAND.rst
+++ b/Help/variable/CTEST_BZR_COMMAND.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``BZRCommand`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_BZR_UPDATE_OPTIONS.rst b/Help/variable/CTEST_BZR_UPDATE_OPTIONS.rst
index 4dd5e5b..475dab2 100644
--- a/Help/variable/CTEST_BZR_UPDATE_OPTIONS.rst
+++ b/Help/variable/CTEST_BZR_UPDATE_OPTIONS.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``BZRUpdateOptions`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_CHANGE_ID.rst b/Help/variable/CTEST_CHANGE_ID.rst
index a6d15f7..5202020 100644
--- a/Help/variable/CTEST_CHANGE_ID.rst
+++ b/Help/variable/CTEST_CHANGE_ID.rst
@@ -4,7 +4,7 @@
 .. versionadded:: 3.4
 
 Specify the CTest ``ChangeId`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
 
 This setting allows CTest to pass arbitrary information about this
 build up to CDash.  One use of this feature is to allow CDash to
diff --git a/Help/variable/CTEST_CHECKOUT_COMMAND.rst b/Help/variable/CTEST_CHECKOUT_COMMAND.rst
index 852c28e..2203d6b 100644
--- a/Help/variable/CTEST_CHECKOUT_COMMAND.rst
+++ b/Help/variable/CTEST_CHECKOUT_COMMAND.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Tell the :command:`ctest_start` command how to checkout or initialize
-the source directory in a :manual:`ctest(1)` dashboard client script.
+the source directory in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_CONFIGURATION_TYPE.rst b/Help/variable/CTEST_CONFIGURATION_TYPE.rst
index 932f81d..6ae4a34 100644
--- a/Help/variable/CTEST_CONFIGURATION_TYPE.rst
+++ b/Help/variable/CTEST_CONFIGURATION_TYPE.rst
@@ -4,7 +4,7 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``DefaultCTestConfigurationType`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
 
 If the configuration type is set via :option:`-C \<cfg\> <ctest -C>` from the command line
 then this variable is populated accordingly.
diff --git a/Help/variable/CTEST_CONFIGURE_COMMAND.rst b/Help/variable/CTEST_CONFIGURE_COMMAND.rst
index 992ef47..90c50f4 100644
--- a/Help/variable/CTEST_CONFIGURE_COMMAND.rst
+++ b/Help/variable/CTEST_CONFIGURE_COMMAND.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``ConfigureCommand`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_COVERAGE_COMMAND.rst b/Help/variable/CTEST_COVERAGE_COMMAND.rst
index 3df2262..8168b33 100644
--- a/Help/variable/CTEST_COVERAGE_COMMAND.rst
+++ b/Help/variable/CTEST_COVERAGE_COMMAND.rst
@@ -4,7 +4,7 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``CoverageCommand`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
 
 Cobertura
 '''''''''
diff --git a/Help/variable/CTEST_COVERAGE_EXTRA_FLAGS.rst b/Help/variable/CTEST_COVERAGE_EXTRA_FLAGS.rst
index 39d9b5d..bae5c79 100644
--- a/Help/variable/CTEST_COVERAGE_EXTRA_FLAGS.rst
+++ b/Help/variable/CTEST_COVERAGE_EXTRA_FLAGS.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``CoverageExtraFlags`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_CURL_OPTIONS.rst b/Help/variable/CTEST_CURL_OPTIONS.rst
index 45e84ed..07557e9 100644
--- a/Help/variable/CTEST_CURL_OPTIONS.rst
+++ b/Help/variable/CTEST_CURL_OPTIONS.rst
@@ -8,4 +8,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``CurlOptions`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_CVS_COMMAND.rst b/Help/variable/CTEST_CVS_COMMAND.rst
index 7932070..797a4e7 100644
--- a/Help/variable/CTEST_CVS_COMMAND.rst
+++ b/Help/variable/CTEST_CVS_COMMAND.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``CVSCommand`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_CVS_UPDATE_OPTIONS.rst b/Help/variable/CTEST_CVS_UPDATE_OPTIONS.rst
index 359e708..6d9288a 100644
--- a/Help/variable/CTEST_CVS_UPDATE_OPTIONS.rst
+++ b/Help/variable/CTEST_CVS_UPDATE_OPTIONS.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``CVSUpdateOptions`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_DROP_LOCATION.rst b/Help/variable/CTEST_DROP_LOCATION.rst
index f66793b..3955193 100644
--- a/Help/variable/CTEST_DROP_LOCATION.rst
+++ b/Help/variable/CTEST_DROP_LOCATION.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``DropLocation`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_DROP_METHOD.rst b/Help/variable/CTEST_DROP_METHOD.rst
index 3a84658..6a0d0a7 100644
--- a/Help/variable/CTEST_DROP_METHOD.rst
+++ b/Help/variable/CTEST_DROP_METHOD.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``DropMethod`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_DROP_SITE.rst b/Help/variable/CTEST_DROP_SITE.rst
index 9c871e3..be64d72 100644
--- a/Help/variable/CTEST_DROP_SITE.rst
+++ b/Help/variable/CTEST_DROP_SITE.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``DropSite`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_DROP_SITE_CDASH.rst b/Help/variable/CTEST_DROP_SITE_CDASH.rst
index dcdb286..7d09a36 100644
--- a/Help/variable/CTEST_DROP_SITE_CDASH.rst
+++ b/Help/variable/CTEST_DROP_SITE_CDASH.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``IsCDash`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_DROP_SITE_PASSWORD.rst b/Help/variable/CTEST_DROP_SITE_PASSWORD.rst
index 8259651..b2f684e 100644
--- a/Help/variable/CTEST_DROP_SITE_PASSWORD.rst
+++ b/Help/variable/CTEST_DROP_SITE_PASSWORD.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``DropSitePassword`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_DROP_SITE_USER.rst b/Help/variable/CTEST_DROP_SITE_USER.rst
index 8d2e3a3..07f115e 100644
--- a/Help/variable/CTEST_DROP_SITE_USER.rst
+++ b/Help/variable/CTEST_DROP_SITE_USER.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``DropSiteUser`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_EXTRA_SUBMIT_FILES.rst b/Help/variable/CTEST_EXTRA_SUBMIT_FILES.rst
index 21f801f..a721ecf 100644
--- a/Help/variable/CTEST_EXTRA_SUBMIT_FILES.rst
+++ b/Help/variable/CTEST_EXTRA_SUBMIT_FILES.rst
@@ -2,4 +2,4 @@
 ------------------------
 
 Specify files for :command:`ctest_submit(PARTS ExtraFiles)` to submit
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_GIT_COMMAND.rst b/Help/variable/CTEST_GIT_COMMAND.rst
index eb9b440..01ffca7 100644
--- a/Help/variable/CTEST_GIT_COMMAND.rst
+++ b/Help/variable/CTEST_GIT_COMMAND.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``GITCommand`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_GIT_INIT_SUBMODULES.rst b/Help/variable/CTEST_GIT_INIT_SUBMODULES.rst
index 529bfc7..6e4b9c1 100644
--- a/Help/variable/CTEST_GIT_INIT_SUBMODULES.rst
+++ b/Help/variable/CTEST_GIT_INIT_SUBMODULES.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.6
 
 Specify the CTest ``GITInitSubmodules`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_GIT_UPDATE_CUSTOM.rst b/Help/variable/CTEST_GIT_UPDATE_CUSTOM.rst
index 82a8a6a..1ae1099 100644
--- a/Help/variable/CTEST_GIT_UPDATE_CUSTOM.rst
+++ b/Help/variable/CTEST_GIT_UPDATE_CUSTOM.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``GITUpdateCustom`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_GIT_UPDATE_OPTIONS.rst b/Help/variable/CTEST_GIT_UPDATE_OPTIONS.rst
index 1568239..a063ba3 100644
--- a/Help/variable/CTEST_GIT_UPDATE_OPTIONS.rst
+++ b/Help/variable/CTEST_GIT_UPDATE_OPTIONS.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``GITUpdateOptions`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_HG_COMMAND.rst b/Help/variable/CTEST_HG_COMMAND.rst
index 3372fe4..426cfd5 100644
--- a/Help/variable/CTEST_HG_COMMAND.rst
+++ b/Help/variable/CTEST_HG_COMMAND.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``HGCommand`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_HG_UPDATE_OPTIONS.rst b/Help/variable/CTEST_HG_UPDATE_OPTIONS.rst
index 85c6b03..751b300 100644
--- a/Help/variable/CTEST_HG_UPDATE_OPTIONS.rst
+++ b/Help/variable/CTEST_HG_UPDATE_OPTIONS.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``HGUpdateOptions`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_LABELS_FOR_SUBPROJECTS.rst b/Help/variable/CTEST_LABELS_FOR_SUBPROJECTS.rst
index dd6d125..4c1ec4b 100644
--- a/Help/variable/CTEST_LABELS_FOR_SUBPROJECTS.rst
+++ b/Help/variable/CTEST_LABELS_FOR_SUBPROJECTS.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.10
 
 Specify the CTest ``LabelsForSubprojects`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_MEMORYCHECK_COMMAND.rst b/Help/variable/CTEST_MEMORYCHECK_COMMAND.rst
index 25f1bd9..1c86357 100644
--- a/Help/variable/CTEST_MEMORYCHECK_COMMAND.rst
+++ b/Help/variable/CTEST_MEMORYCHECK_COMMAND.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``MemoryCheckCommand`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_MEMORYCHECK_COMMAND_OPTIONS.rst b/Help/variable/CTEST_MEMORYCHECK_COMMAND_OPTIONS.rst
index 51830d5..f2c91e3 100644
--- a/Help/variable/CTEST_MEMORYCHECK_COMMAND_OPTIONS.rst
+++ b/Help/variable/CTEST_MEMORYCHECK_COMMAND_OPTIONS.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``MemoryCheckCommandOptions`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_MEMORYCHECK_SANITIZER_OPTIONS.rst b/Help/variable/CTEST_MEMORYCHECK_SANITIZER_OPTIONS.rst
index b6fee2e..d9f3eea 100644
--- a/Help/variable/CTEST_MEMORYCHECK_SANITIZER_OPTIONS.rst
+++ b/Help/variable/CTEST_MEMORYCHECK_SANITIZER_OPTIONS.rst
@@ -4,7 +4,7 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``MemoryCheckSanitizerOptions`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
 
 CTest prepends correct sanitizer options ``*_OPTIONS``
 environment variable to executed command. CTests adds
diff --git a/Help/variable/CTEST_MEMORYCHECK_SUPPRESSIONS_FILE.rst b/Help/variable/CTEST_MEMORYCHECK_SUPPRESSIONS_FILE.rst
index a61a3ef..fe54eb9 100644
--- a/Help/variable/CTEST_MEMORYCHECK_SUPPRESSIONS_FILE.rst
+++ b/Help/variable/CTEST_MEMORYCHECK_SUPPRESSIONS_FILE.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``MemoryCheckSuppressionFile`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_MEMORYCHECK_TYPE.rst b/Help/variable/CTEST_MEMORYCHECK_TYPE.rst
index 80353a4..d412e79 100644
--- a/Help/variable/CTEST_MEMORYCHECK_TYPE.rst
+++ b/Help/variable/CTEST_MEMORYCHECK_TYPE.rst
@@ -4,7 +4,7 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``MemoryCheckType`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
 Valid values are ``Valgrind``, ``Purify``, ``BoundsChecker``, ``DrMemory``,
 ``CudaSanitizer``, ``ThreadSanitizer``, ``AddressSanitizer``, ``LeakSanitizer``,
 ``MemorySanitizer`` and ``UndefinedBehaviorSanitizer``.
diff --git a/Help/variable/CTEST_NIGHTLY_START_TIME.rst b/Help/variable/CTEST_NIGHTLY_START_TIME.rst
index 2d707d5..3ccf50a 100644
--- a/Help/variable/CTEST_NIGHTLY_START_TIME.rst
+++ b/Help/variable/CTEST_NIGHTLY_START_TIME.rst
@@ -4,7 +4,7 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``NightlyStartTime`` setting in a :manual:`ctest(1)`
-dashboard client script.
+:ref:`Dashboard Client` script.
 
 Note that this variable must always be set for a nightly build in a
 dashboard script. It is needed so that nightly builds can be properly grouped
diff --git a/Help/variable/CTEST_NOTES_FILES.rst b/Help/variable/CTEST_NOTES_FILES.rst
index 301b78a..cc66345 100644
--- a/Help/variable/CTEST_NOTES_FILES.rst
+++ b/Help/variable/CTEST_NOTES_FILES.rst
@@ -2,4 +2,4 @@
 -----------------
 
 Specify files for :command:`ctest_submit(PARTS Notes)` to submit
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_P4_CLIENT.rst b/Help/variable/CTEST_P4_CLIENT.rst
index 0778c5b..63c1739 100644
--- a/Help/variable/CTEST_P4_CLIENT.rst
+++ b/Help/variable/CTEST_P4_CLIENT.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``P4Client`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_P4_COMMAND.rst b/Help/variable/CTEST_P4_COMMAND.rst
index 5cc2a81..61cd4a1 100644
--- a/Help/variable/CTEST_P4_COMMAND.rst
+++ b/Help/variable/CTEST_P4_COMMAND.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``P4Command`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_P4_OPTIONS.rst b/Help/variable/CTEST_P4_OPTIONS.rst
index 01b6534..b4889f8 100644
--- a/Help/variable/CTEST_P4_OPTIONS.rst
+++ b/Help/variable/CTEST_P4_OPTIONS.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``P4Options`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_P4_UPDATE_OPTIONS.rst b/Help/variable/CTEST_P4_UPDATE_OPTIONS.rst
index 365aa3f..5dec345 100644
--- a/Help/variable/CTEST_P4_UPDATE_OPTIONS.rst
+++ b/Help/variable/CTEST_P4_UPDATE_OPTIONS.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``P4UpdateOptions`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_RESOURCE_SPEC_FILE.rst b/Help/variable/CTEST_RESOURCE_SPEC_FILE.rst
index 8e9bf01..294e138 100644
--- a/Help/variable/CTEST_RESOURCE_SPEC_FILE.rst
+++ b/Help/variable/CTEST_RESOURCE_SPEC_FILE.rst
@@ -4,7 +4,7 @@
 .. versionadded:: 3.18
 
 Specify the CTest ``ResourceSpecFile`` setting in a :manual:`ctest(1)`
-dashboard client script.
+:ref:`Dashboard Client` script.
 
 This can also be used to specify the resource spec file from a CMake build. If
 no ``RESOURCE_SPEC_FILE`` is passed to :command:`ctest_test`, and
diff --git a/Help/variable/CTEST_SITE.rst b/Help/variable/CTEST_SITE.rst
index 526e6ed..7875b30 100644
--- a/Help/variable/CTEST_SITE.rst
+++ b/Help/variable/CTEST_SITE.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``Site`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_SOURCE_DIRECTORY.rst b/Help/variable/CTEST_SOURCE_DIRECTORY.rst
index 4c6ac54..84fd1f8 100644
--- a/Help/variable/CTEST_SOURCE_DIRECTORY.rst
+++ b/Help/variable/CTEST_SOURCE_DIRECTORY.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``SourceDirectory`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_SUBMIT_INACTIVITY_TIMEOUT.rst b/Help/variable/CTEST_SUBMIT_INACTIVITY_TIMEOUT.rst
index 175885a..cdc4ff4 100644
--- a/Help/variable/CTEST_SUBMIT_INACTIVITY_TIMEOUT.rst
+++ b/Help/variable/CTEST_SUBMIT_INACTIVITY_TIMEOUT.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.23
 
 Specify the CTest ``SubmitInactivityTimeout`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_SUBMIT_URL.rst b/Help/variable/CTEST_SUBMIT_URL.rst
index b6e7f68..3147b4a 100644
--- a/Help/variable/CTEST_SUBMIT_URL.rst
+++ b/Help/variable/CTEST_SUBMIT_URL.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.14
 
 Specify the CTest ``SubmitURL`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_SVN_COMMAND.rst b/Help/variable/CTEST_SVN_COMMAND.rst
index e97acd0..8d8b263 100644
--- a/Help/variable/CTEST_SVN_COMMAND.rst
+++ b/Help/variable/CTEST_SVN_COMMAND.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``SVNCommand`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_SVN_OPTIONS.rst b/Help/variable/CTEST_SVN_OPTIONS.rst
index 5326e20..3d111cc 100644
--- a/Help/variable/CTEST_SVN_OPTIONS.rst
+++ b/Help/variable/CTEST_SVN_OPTIONS.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``SVNOptions`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_SVN_UPDATE_OPTIONS.rst b/Help/variable/CTEST_SVN_UPDATE_OPTIONS.rst
index 24e0bbf..0830c2f 100644
--- a/Help/variable/CTEST_SVN_UPDATE_OPTIONS.rst
+++ b/Help/variable/CTEST_SVN_UPDATE_OPTIONS.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``SVNUpdateOptions`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_TEST_LOAD.rst b/Help/variable/CTEST_TEST_LOAD.rst
index b6a9d62..fed4042 100644
--- a/Help/variable/CTEST_TEST_LOAD.rst
+++ b/Help/variable/CTEST_TEST_LOAD.rst
@@ -4,6 +4,6 @@
 .. versionadded:: 3.4
 
 Specify the ``TestLoad`` setting in the :ref:`CTest Test Step`
-of a :manual:`ctest(1)` dashboard client script.  This sets the
+of a :manual:`ctest(1)` :ref:`Dashboard Client` script.  This sets the
 default value for the ``TEST_LOAD`` option of the :command:`ctest_test`
 command.
diff --git a/Help/variable/CTEST_TEST_TIMEOUT.rst b/Help/variable/CTEST_TEST_TIMEOUT.rst
index 61d9191..f6a1daa 100644
--- a/Help/variable/CTEST_TEST_TIMEOUT.rst
+++ b/Help/variable/CTEST_TEST_TIMEOUT.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``TimeOut`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_UPDATE_COMMAND.rst b/Help/variable/CTEST_UPDATE_COMMAND.rst
index c4ed645..1084065 100644
--- a/Help/variable/CTEST_UPDATE_COMMAND.rst
+++ b/Help/variable/CTEST_UPDATE_COMMAND.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``UpdateCommand`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_UPDATE_OPTIONS.rst b/Help/variable/CTEST_UPDATE_OPTIONS.rst
index 96c4b6c..ef2dad3 100644
--- a/Help/variable/CTEST_UPDATE_OPTIONS.rst
+++ b/Help/variable/CTEST_UPDATE_OPTIONS.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``UpdateOptions`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_UPDATE_VERSION_ONLY.rst b/Help/variable/CTEST_UPDATE_VERSION_ONLY.rst
index f7c863c..c778338 100644
--- a/Help/variable/CTEST_UPDATE_VERSION_ONLY.rst
+++ b/Help/variable/CTEST_UPDATE_VERSION_ONLY.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest :ref:`UpdateVersionOnly <UpdateVersionOnly>` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_UPDATE_VERSION_OVERRIDE.rst b/Help/variable/CTEST_UPDATE_VERSION_OVERRIDE.rst
index 87918cb..9f4ecc3 100644
--- a/Help/variable/CTEST_UPDATE_VERSION_OVERRIDE.rst
+++ b/Help/variable/CTEST_UPDATE_VERSION_OVERRIDE.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.15
 
 Specify the CTest :ref:`UpdateVersionOverride <UpdateVersionOverride>` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/CTEST_USE_LAUNCHERS.rst b/Help/variable/CTEST_USE_LAUNCHERS.rst
index 728cdc5..3326bad 100644
--- a/Help/variable/CTEST_USE_LAUNCHERS.rst
+++ b/Help/variable/CTEST_USE_LAUNCHERS.rst
@@ -4,4 +4,4 @@
 .. versionadded:: 3.1
 
 Specify the CTest ``UseLaunchers`` setting
-in a :manual:`ctest(1)` dashboard client script.
+in a :manual:`ctest(1)` :ref:`Dashboard Client` script.
diff --git a/Help/variable/PROJECT-NAME_COMPAT_VERSION.rst b/Help/variable/PROJECT-NAME_COMPAT_VERSION.rst
index 29c24b8..5bcd8d5 100644
--- a/Help/variable/PROJECT-NAME_COMPAT_VERSION.rst
+++ b/Help/variable/PROJECT-NAME_COMPAT_VERSION.rst
@@ -1,11 +1,7 @@
 <PROJECT-NAME>_COMPAT_VERSION
 -----------------------------
 
-.. versionadded:: 4.1
-
-.. note::
-
-  Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+.. versionadded:: 4.3
 
 Value given to the ``COMPAT_VERSION`` option of the most recent call to the
 :command:`project` command with project name ``<PROJECT-NAME>``, if any.
diff --git a/Help/variable/PROJECT-NAME_SPDX_LICENSE.rst b/Help/variable/PROJECT-NAME_SPDX_LICENSE.rst
index 06c395d..0febd48 100644
--- a/Help/variable/PROJECT-NAME_SPDX_LICENSE.rst
+++ b/Help/variable/PROJECT-NAME_SPDX_LICENSE.rst
@@ -1,11 +1,7 @@
 <PROJECT-NAME>_SPDX_LICENSE
 ---------------------------
 
-.. versionadded:: 4.2
-
-.. note::
-
-  Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+.. versionadded:: 4.3
 
 Value given to the ``SPDX_LICENSE`` option of the most recent call to the
 :command:`project` command with project name ``<PROJECT-NAME>``, if any.
diff --git a/Help/variable/PROJECT_COMPAT_VERSION.rst b/Help/variable/PROJECT_COMPAT_VERSION.rst
index cab800c..94bea94 100644
--- a/Help/variable/PROJECT_COMPAT_VERSION.rst
+++ b/Help/variable/PROJECT_COMPAT_VERSION.rst
@@ -1,11 +1,7 @@
 PROJECT_COMPAT_VERSION
 ----------------------
 
-.. versionadded:: 4.1
-
-.. note::
-
-  Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+.. versionadded:: 4.3
 
 Value given to the ``COMPAT_VERSION`` option of the most recent call to the
 :command:`project` command, if any. To obtain the compatibility version of the
diff --git a/Help/variable/PROJECT_SPDX_LICENSE.rst b/Help/variable/PROJECT_SPDX_LICENSE.rst
index 4f62e94..947e753 100644
--- a/Help/variable/PROJECT_SPDX_LICENSE.rst
+++ b/Help/variable/PROJECT_SPDX_LICENSE.rst
@@ -1,11 +1,7 @@
 PROJECT_SPDX_LICENSE
 --------------------
 
-.. versionadded:: 4.2
-
-.. note::
-
-  Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+.. versionadded:: 4.3
 
 Value given to the ``SPDX_LICENSE`` option of the most recent call to the
 :command:`project` command, if any. To obtain the compatibility version of the
diff --git a/Help/variable/include/CMAKE_VERIFY_XXX_HEADER_SETS.rst b/Help/variable/include/CMAKE_VERIFY_XXX_HEADER_SETS.rst
new file mode 100644
index 0000000..9a274d3
--- /dev/null
+++ b/Help/variable/include/CMAKE_VERIFY_XXX_HEADER_SETS.rst
@@ -0,0 +1,39 @@
+This variable is used to initialize the |VERIFY_XXX_HEADER_SETS| property of
+targets when they are created.  Setting it to true enables |xxx| header set
+verification.
+
+Projects should not normally set this variable, it is intended as a developer
+control to be set on the :manual:`cmake(1)` command line or other
+equivalent methods.  The developer must have the ability to enable or
+disable header set verification according to the capabilities of their own
+machine and compiler.
+
+Verification of a dependency's header sets is not typically of interest to
+developers.  Therefore, :command:`FetchContent_MakeAvailable` explicitly sets
+|CMAKE_VERIFY_XXX_HEADER_SETS| and |COMPLEMENTARY_CMAKE_VERIFY_XXX_HEADER_SETS|
+to false for the duration of its call, but restores their original values
+before returning.  If a project brings a dependency directly into the main
+build (e.g. calling :command:`add_subdirectory` on a vendored project from a
+git submodule), it should also do likewise.  For example:
+
+.. code:: cmake
+
+  # Save original setting so we can restore it later
+  set(want_interface_header_set_verification ${CMAKE_VERIFY_INTERFACE_HEADER_SETS})
+  set(want_private_header_set_verification ${CMAKE_VERIFY_PRIVATE_HEADER_SETS})
+
+  # Include the vendored dependency with header set verification disabled
+  set(CMAKE_VERIFY_INTERFACE_HEADER_SETS OFF)
+  set(CMAKE_VERIFY_PRIVATE_HEADER_SETS OFF)
+  add_subdirectory(...)   # Vendored sources, e.g. from git submodules
+
+  # Add the project's own sources. Restore the developer's original choice
+  # for whether to enable header set verification.
+  set(CMAKE_VERIFY_INTERFACE_HEADER_SETS ${want_interface_header_set_verification})
+  set(CMAKE_VERIFY_PRIVATE_HEADER_SETS ${want_private_header_set_verification})
+  add_subdirectory(src)
+
+By default, this variable is not set, which will result in |xxx| header set
+verification being disabled.
+
+See also |COMPLEMENTARY_CMAKE_VERIFY_XXX_HEADER_SETS|.
diff --git a/LICENSE.rst b/LICENSE.rst
index 782e365..3ddcf87 100644
--- a/LICENSE.rst
+++ b/LICENSE.rst
@@ -1,4 +1,4 @@
-Copyright 2000-2025 Kitware, Inc. and `Contributors <CONTRIBUTORS.rst>`_
+Copyright 2000-2026 Kitware, Inc. and `Contributors <CONTRIBUTORS.rst>`_
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
diff --git a/Modules/CMakeCCompiler.cmake.in b/Modules/CMakeCCompiler.cmake.in
index 1ccc7f5..96e5c60 100644
--- a/Modules/CMakeCCompiler.cmake.in
+++ b/Modules/CMakeCCompiler.cmake.in
@@ -22,6 +22,7 @@
 set(CMAKE_C_COMPILER_ARCHITECTURE_ID "@CMAKE_C_COMPILER_ARCHITECTURE_ID@")
 @_SET_CMAKE_C_COMPILER_SYSROOT@
 @SET_MSVC_C_ARCHITECTURE_ID@
+@SET_CMAKE_C_MSVC_I18N_DIR@
 @SET_CMAKE_XCODE_ARCHS@
 set(CMAKE_AR "@CMAKE_AR@")
 set(CMAKE_C_COMPILER_AR "@CMAKE_C_COMPILER_AR@")
diff --git a/Modules/CMakeCXXCompiler.cmake.in b/Modules/CMakeCXXCompiler.cmake.in
index 8e2e3d6..9e1db3b 100644
--- a/Modules/CMakeCXXCompiler.cmake.in
+++ b/Modules/CMakeCXXCompiler.cmake.in
@@ -24,6 +24,7 @@
 set(CMAKE_CXX_COMPILER_ARCHITECTURE_ID "@CMAKE_CXX_COMPILER_ARCHITECTURE_ID@")
 @_SET_CMAKE_CXX_COMPILER_SYSROOT@
 @SET_MSVC_CXX_ARCHITECTURE_ID@
+@SET_CMAKE_CXX_MSVC_I18N_DIR@
 @SET_CMAKE_XCODE_ARCHS@
 set(CMAKE_AR "@CMAKE_AR@")
 set(CMAKE_CXX_COMPILER_AR "@CMAKE_CXX_COMPILER_AR@")
@@ -96,5 +97,6 @@
 set(CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES@")
 set(CMAKE_CXX_COMPILER_CLANG_RESOURCE_DIR "@CMAKE_CXX_COMPILER_CLANG_RESOURCE_DIR@")
 
-set(CMAKE_CXX_COMPILER_IMPORT_STD "")
-@CMAKE_CXX_IMPORT_STD@
+set(CMAKE_CXX_COMPILER_IMPORT_STD "@CMAKE_CXX_COMPILER_IMPORT_STD@")
+set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE  "@CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE@")
+set(CMAKE_CXX_STDLIB_MODULES_JSON "@CMAKE_CXX_STDLIB_MODULES_JSON@")
diff --git a/Modules/CMakeDetermineASMCompiler.cmake b/Modules/CMakeDetermineASMCompiler.cmake
index 5f72d2f..46f42e0 100644
--- a/Modules/CMakeDetermineASMCompiler.cmake
+++ b/Modules/CMakeDetermineASMCompiler.cmake
@@ -16,7 +16,7 @@
       set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ARG1 "${CMAKE_ASM${ASM_DIALECT}_FLAGS_ENV_INIT}" CACHE STRING "Arguments to ASM${ASM_DIALECT} compiler")
     endif()
     if(NOT EXISTS ${CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT})
-      message(FATAL_ERROR "Could not find compiler set in environment variable ASM${ASM_DIALECT}:\n$ENV{ASM${ASM_DIALECT}}.")
+      message(FATAL_ERROR "Could not find the compiler specified in the environment variable ASM${ASM_DIALECT}:\n$ENV{ASM${ASM_DIALECT}}.")
     endif()
   endif()
 
diff --git a/Modules/CMakeDetermineCCompiler.cmake b/Modules/CMakeDetermineCCompiler.cmake
index fbe5166..9723fb6 100644
--- a/Modules/CMakeDetermineCCompiler.cmake
+++ b/Modules/CMakeDetermineCCompiler.cmake
@@ -45,7 +45,7 @@
         set(CMAKE_C_COMPILER_ARG1 "${CMAKE_C_FLAGS_ENV_INIT}" CACHE STRING "Arguments to C compiler")
       endif()
       if(NOT EXISTS ${CMAKE_C_COMPILER_INIT})
-        message(FATAL_ERROR "Could not find compiler set in environment variable CC:\n$ENV{CC}.")
+        message(FATAL_ERROR "Could not find the compiler specified in the environment variable CC:\n$ENV{CC}.")
       endif()
     endif()
 
@@ -214,6 +214,11 @@
     "set(MSVC_C_ARCHITECTURE_ID ${MSVC_C_ARCHITECTURE_ID})")
 endif()
 
+if(CMAKE_C_MSVC_I18N_DIR)
+  set(SET_CMAKE_C_MSVC_I18N_DIR
+    "set(CMAKE_C_MSVC_I18N_DIR ${CMAKE_C_MSVC_I18N_DIR})")
+endif()
+
 if(CMAKE_C_XCODE_ARCHS)
   set(SET_CMAKE_XCODE_ARCHS
     "set(CMAKE_XCODE_ARCHS \"${CMAKE_C_XCODE_ARCHS}\")")
diff --git a/Modules/CMakeDetermineCUDACompiler.cmake b/Modules/CMakeDetermineCUDACompiler.cmake
index 44456d6..e70742b 100644
--- a/Modules/CMakeDetermineCUDACompiler.cmake
+++ b/Modules/CMakeDetermineCUDACompiler.cmake
@@ -26,7 +26,7 @@
         set(CMAKE_CUDA_COMPILER_ARG1 "${CMAKE_CUDA_FLAGS_ENV_INIT}" CACHE STRING "Arguments to CUDA compiler")
       endif()
       if(NOT EXISTS ${CMAKE_CUDA_COMPILER_INIT})
-        message(FATAL_ERROR "Could not find compiler set in environment variable CUDACXX:\n$ENV{CUDACXX}.\n${CMAKE_CUDA_COMPILER_INIT}")
+        message(FATAL_ERROR "Could not find the compiler specified in the environment variable CUDACXX:\n$ENV{CUDACXX}.\n${CMAKE_CUDA_COMPILER_INIT}")
       endif()
     endif()
 
@@ -48,7 +48,7 @@
   if(NOT $ENV{CUDAHOSTCXX} STREQUAL "")
     get_filename_component(CMAKE_CUDA_HOST_COMPILER $ENV{CUDAHOSTCXX} PROGRAM)
     if(NOT EXISTS ${CMAKE_CUDA_HOST_COMPILER})
-      message(FATAL_ERROR "Could not find compiler set in environment variable CUDAHOSTCXX:\n$ENV{CUDAHOSTCXX}.\n${CMAKE_CUDA_HOST_COMPILER}")
+      message(FATAL_ERROR "Could not find the compiler specified in the environment variable CUDAHOSTCXX:\n$ENV{CUDAHOSTCXX}.\n${CMAKE_CUDA_HOST_COMPILER}")
     endif()
   elseif(CMAKE_CUDA_HOST_COMPILER)
     # We get here if CMAKE_CUDA_HOST_COMPILER was specified by the user or toolchain file.
@@ -64,7 +64,7 @@
       unset(_CMAKE_CUDA_HOST_COMPILER_PATH)
     endif()
     if(NOT EXISTS "${CMAKE_CUDA_HOST_COMPILER}")
-      message(FATAL_ERROR "Could not find compiler set in variable CMAKE_CUDA_HOST_COMPILER:\n  ${CMAKE_CUDA_HOST_COMPILER}")
+      message(FATAL_ERROR "Could not find the compiler specified in the variable CMAKE_CUDA_HOST_COMPILER:\n  ${CMAKE_CUDA_HOST_COMPILER}")
     endif()
     # If the value was cached, update the cache entry with our modifications.
     get_property(_CMAKE_CUDA_HOST_COMPILER_CACHED CACHE CMAKE_CUDA_HOST_COMPILER PROPERTY TYPE)
diff --git a/Modules/CMakeDetermineCXXCompiler.cmake b/Modules/CMakeDetermineCXXCompiler.cmake
index 5331681..5c5d441 100644
--- a/Modules/CMakeDetermineCXXCompiler.cmake
+++ b/Modules/CMakeDetermineCXXCompiler.cmake
@@ -44,7 +44,7 @@
         set(CMAKE_CXX_COMPILER_ARG1 "${CMAKE_CXX_FLAGS_ENV_INIT}" CACHE STRING "Arguments to CXX compiler")
       endif()
       if(NOT EXISTS ${CMAKE_CXX_COMPILER_INIT})
-        message(FATAL_ERROR "Could not find compiler set in environment variable CXX:\n$ENV{CXX}.\n${CMAKE_CXX_COMPILER_INIT}")
+        message(FATAL_ERROR "Could not find the compiler specified in the environment variable CXX:\n$ENV{CXX}.\n${CMAKE_CXX_COMPILER_INIT}")
       endif()
     endif()
 
@@ -220,6 +220,11 @@
     "set(MSVC_CXX_ARCHITECTURE_ID ${MSVC_CXX_ARCHITECTURE_ID})")
 endif()
 
+if(CMAKE_CXX_MSVC_I18N_DIR)
+  set(SET_CMAKE_CXX_MSVC_I18N_DIR
+    "set(CMAKE_CXX_MSVC_I18N_DIR ${CMAKE_CXX_MSVC_I18N_DIR})")
+endif()
+
 if(CMAKE_CXX_XCODE_ARCHS)
   set(SET_CMAKE_XCODE_ARCHS
     "set(CMAKE_XCODE_ARCHS \"${CMAKE_CXX_XCODE_ARCHS}\")")
diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake
index d431f04..0518128 100644
--- a/Modules/CMakeDetermineCompilerId.cmake
+++ b/Modules/CMakeDetermineCompilerId.cmake
@@ -256,6 +256,12 @@
     set(CMAKE_${lang}_CL_SHOWINCLUDES_PREFIX "")
   endif()
 
+  if(CMAKE_GENERATOR MATCHES "^FASTBuild"
+      AND CMAKE_${lang}_COMPILER_ID STREQUAL "MSVC")
+    cmake_determine_msvc_i18n_dir(${lang})
+    set(CMAKE_${lang}_MSVC_I18N_DIR ${CMAKE_${lang}_MSVC_I18N_DIR} PARENT_SCOPE)
+  endif()
+
   if(CMAKE_EFFECTIVE_SYSTEM_NAME STREQUAL "Apple" AND CMAKE_${lang}_COMPILER_ID MATCHES "Clang$")
     cmake_path(GET src EXTENSION LAST_ONLY ext)
     set(apple_sdk_dir "${CMAKE_${lang}_COMPILER_ID_DIR}")
@@ -1340,3 +1346,40 @@
   endif()
   message(CONFIGURE_LOG "Detecting ${lang} compiler /showIncludes prefix:\n${msg}\n")
 endfunction()
+
+function(CMAKE_DETERMINE_MSVC_I18N_DIR lang)
+  # The FASTBuild generator needs the full path to clui.dll:
+  cmake_path(GET CMAKE_${lang}_COMPILER PARENT_PATH cldir)
+
+  # if the VSLANG env.var is set, prefer that.
+  # If that doesn't exist, try 1033, the US version.
+  # Otherwise, search for any clui.dll, and use the first one that is found.
+  if(DEFINED ENV{VSLANG})
+    if(EXISTS "${cldir}/$ENV{VSLANG}/clui.dll")
+      set(MSVC_I18N_DIR "$ENV{VSLANG}")
+    else()
+      message(WARNING "The environment variable VSLANG is set to $ENV{VSLANG}, but could not find ${cldir}/$ENV{VSLANG}/clui.dll")
+    endif()
+  endif()
+
+  if (NOT MSVC_I18N_DIR)
+    if(EXISTS "${cldir}/1033/clui.dll")
+      set(MSVC_I18N_DIR "1033")
+    endif()
+  endif()
+
+  if(NOT MSVC_I18N_DIR)
+    file(GLOB_RECURSE cluis "${cldir}/*/clui.dll")
+    list(GET cluis 0 firstClui)
+    if (firstClui)
+      cmake_path(GET firstClui PARENT_PATH cluiParentPath)
+      cmake_path(GET cluiParentPath FILENAME MSVC_I18N_DIR)
+    endif()
+  endif()
+
+  if(MSVC_I18N_DIR)
+    set(CMAKE_${lang}_MSVC_I18N_DIR ${MSVC_I18N_DIR} PARENT_SCOPE )
+  else()
+    message(FATAL_ERROR "Could not find clui.dll !")
+  endif()
+endfunction()
diff --git a/Modules/CMakeDetermineCompilerSupport.cmake b/Modules/CMakeDetermineCompilerSupport.cmake
index c22bf07..512a1c4 100644
--- a/Modules/CMakeDetermineCompilerSupport.cmake
+++ b/Modules/CMakeDetermineCompilerSupport.cmake
@@ -105,18 +105,21 @@
       )
     endif()
 
-    # Create targets for use with `import std;` here.
-    set(CMAKE_CXX_IMPORT_STD "")
-    foreach (_cmake_import_std_version IN ITEMS 23 26)
-      if (CMAKE_CXX${_cmake_import_std_version}_COMPILE_FEATURES)
-        set(_cmake_cxx_import_std "")
-        cmake_create_cxx_import_std("${_cmake_import_std_version}" _cmake_cxx_import_std)
-        if (_cmake_cxx_import_std)
-          string(APPEND CMAKE_CXX_IMPORT_STD "### Imported target for C++${_cmake_import_std_version} standard library\n")
-          string(APPEND CMAKE_CXX_IMPORT_STD "${_cmake_cxx_import_std}\n\n")
-        endif ()
-      endif ()
-    endforeach ()
+    # Find the module metadata for import std
+    set(CMAKE_CXX_COMPILER_IMPORT_STD "")
+    cmake_cxx_find_modules_json()
+    foreach(_cmake_import_std_version IN ITEMS 23 26)
+      if(CMAKE_CXX${_cmake_import_std_version}_COMPILE_FEATURES)
+        # Modules JSON covers all versions, otherwise rely on toolchain targets
+        if(CMAKE_CXX_STDLIB_MODULES_JSON OR (TARGET "__CMAKE:CXX${_cmake_import_std_version}"))
+          list(APPEND CMAKE_CXX_COMPILER_IMPORT_STD ${_cmake_import_std_version})
+        endif()
+      endif()
+    endforeach()
+
+    set(CMAKE_CXX_COMPILER_IMPORT_STD ${CMAKE_CXX_COMPILER_IMPORT_STD} PARENT_SCOPE)
+    set(CMAKE_CXX_STDLIB_MODULES_JSON ${CMAKE_CXX_STDLIB_MODULES_JSON} PARENT_SCOPE)
+    set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "${CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE}" PARENT_SCOPE)
 
     set(CMAKE_CXX_COMPILE_FEATURES ${CMAKE_CXX_COMPILE_FEATURES} PARENT_SCOPE)
     set(CMAKE_CXX98_COMPILE_FEATURES ${CMAKE_CXX98_COMPILE_FEATURES} PARENT_SCOPE)
@@ -126,7 +129,6 @@
     set(CMAKE_CXX20_COMPILE_FEATURES ${CMAKE_CXX20_COMPILE_FEATURES} PARENT_SCOPE)
     set(CMAKE_CXX23_COMPILE_FEATURES ${CMAKE_CXX23_COMPILE_FEATURES} PARENT_SCOPE)
     set(CMAKE_CXX26_COMPILE_FEATURES ${CMAKE_CXX26_COMPILE_FEATURES} PARENT_SCOPE)
-    set(CMAKE_CXX_IMPORT_STD ${CMAKE_CXX_IMPORT_STD} PARENT_SCOPE)
 
     message(CHECK_PASS "done")
 
diff --git a/Modules/CMakeDetermineFortranCompiler.cmake b/Modules/CMakeDetermineFortranCompiler.cmake
index f7727a9..dc39577 100644
--- a/Modules/CMakeDetermineFortranCompiler.cmake
+++ b/Modules/CMakeDetermineFortranCompiler.cmake
@@ -30,7 +30,7 @@
       endif()
       if(EXISTS ${CMAKE_Fortran_COMPILER_INIT})
       else()
-        message(FATAL_ERROR "Could not find compiler set in environment variable FC:\n$ENV{FC}.")
+        message(FATAL_ERROR "Could not find the compiler specified in the environment variable FC:\n$ENV{FC}.")
       endif()
     endif()
 
diff --git a/Modules/CMakeDetermineHIPCompiler.cmake b/Modules/CMakeDetermineHIPCompiler.cmake
index 13ec392..c3a1649 100644
--- a/Modules/CMakeDetermineHIPCompiler.cmake
+++ b/Modules/CMakeDetermineHIPCompiler.cmake
@@ -17,15 +17,17 @@
     )
   if(_CMAKE_HIPCONFIG_RESULT EQUAL 0 AND _CMAKE_HIPCONFIG_PLATFORM MATCHES "^(nvidia|nvcc)$")
     set(CMAKE_HIP_PLATFORM "nvidia" CACHE STRING "HIP platform" FORCE)
+  elseif(_CMAKE_HIPCONFIG_RESULT EQUAL 0 AND _CMAKE_HIPCONFIG_PLATFORM MATCHES "^(spirv)$")
+    set(CMAKE_HIP_PLATFORM "spirv" CACHE STRING "HIP platform" FORCE)
   else()
     set(CMAKE_HIP_PLATFORM "amd" CACHE STRING "HIP platform" FORCE)
   endif()
 endif()
-if(NOT CMAKE_HIP_PLATFORM MATCHES "^(amd|nvidia)$")
+if(NOT CMAKE_HIP_PLATFORM MATCHES "^(amd|nvidia|spirv)$")
   message(FATAL_ERROR
     "The CMAKE_HIP_PLATFORM has unsupported value:\n"
     " '${CMAKE_HIP_PLATFORM}'\n"
-    "It must be 'amd' or 'nvidia'."
+    "It must be 'amd', 'nvidia', or 'spirv'."
     )
 endif()
 
@@ -46,7 +48,7 @@
       set(CMAKE_HIP_COMPILER_ARG1 "${CMAKE_HIP_FLAGS_ENV_INIT}" CACHE STRING "Arguments to CXX compiler")
     endif()
     if(NOT EXISTS ${CMAKE_HIP_COMPILER_INIT})
-      message(FATAL_ERROR "Could not find compiler set in environment variable HIPCXX:\n$ENV{HIPCXX}.\n${CMAKE_HIP_COMPILER_INIT}")
+      message(FATAL_ERROR "Could not find the compiler specified in the environment variable HIPCXX:\n$ENV{HIPCXX}.\n${CMAKE_HIP_COMPILER_INIT}")
     endif()
   endif()
 
@@ -54,10 +56,10 @@
   if(NOT CMAKE_HIP_COMPILER_INIT)
     if(CMAKE_HIP_PLATFORM STREQUAL "nvidia")
       set(CMAKE_HIP_COMPILER_LIST nvcc)
-    elseif(CMAKE_HIP_PLATFORM STREQUAL "amd")
+    elseif(CMAKE_HIP_PLATFORM STREQUAL "amd" OR CMAKE_HIP_PLATFORM STREQUAL "spirv")
       set(CMAKE_HIP_COMPILER_LIST clang++)
 
-      # Look for the Clang coming with ROCm to support HIP.
+      # Look for the Clang coming with ROCm or chipStar to support HIP.
       execute_process(COMMAND hipconfig --hipclangpath
         OUTPUT_VARIABLE _CMAKE_HIPCONFIG_CLANGPATH
         RESULT_VARIABLE _CMAKE_HIPCONFIG_RESULT
@@ -111,7 +113,7 @@
     if(NOT CMAKE_HIP_HOST_COMPILER AND NOT $ENV{HIPHOSTCXX} STREQUAL "")
       get_filename_component(CMAKE_HIP_HOST_COMPILER $ENV{HIPHOSTCXX} PROGRAM)
       if(NOT EXISTS "${CMAKE_HIP_HOST_COMPILER}")
-        message(FATAL_ERROR "Could not find compiler set in environment variable HIPHOSTCXX:\n$ENV{HIPHOSTCXX}.\n${CMAKE_HIP_HOST_COMPILER}")
+        message(FATAL_ERROR "Could not find the compiler specified in the environment variable HIPHOSTCXX:\n$ENV{HIPHOSTCXX}.\n${CMAKE_HIP_HOST_COMPILER}")
       endif()
     elseif(CMAKE_HIP_HOST_COMPILER)
       # We get here if CMAKE_HIP_HOST_COMPILER was specified by the user or toolchain file.
@@ -127,7 +129,7 @@
         unset(_CMAKE_HIP_HOST_COMPILER_PATH)
       endif()
       if(NOT EXISTS "${CMAKE_HIP_HOST_COMPILER}")
-        message(FATAL_ERROR "Could not find compiler set in variable CMAKE_HIP_HOST_COMPILER:\n  ${CMAKE_HIP_HOST_COMPILER}")
+        message(FATAL_ERROR "Could not find the compiler specified in the variable CMAKE_HIP_HOST_COMPILER:\n  ${CMAKE_HIP_HOST_COMPILER}")
       endif()
       # If the value was cached, update the cache entry with our modifications.
       get_property(_CMAKE_HIP_HOST_COMPILER_CACHED CACHE CMAKE_HIP_HOST_COMPILER PROPERTY TYPE)
@@ -140,7 +142,13 @@
   endif()
 
   if(CMAKE_HIP_COMPILER_ID STREQUAL "Clang")
-    list(APPEND CMAKE_HIP_COMPILER_ID_TEST_FLAGS_FIRST "-v")
+    # For spirv platform (chipStar), set special flags for compiler identification
+    include(Internal/CMakeChipStarHIP)
+    if(CMAKE_HIP_PLATFORM STREQUAL "spirv")
+      _cmake_chipstar_set_compiler_id_flags()
+    else()
+      list(APPEND CMAKE_HIP_COMPILER_ID_TEST_FLAGS_FIRST "-v")
+    endif()
   elseif(CMAKE_HIP_COMPILER_ID STREQUAL "NVIDIA")
     # Tell nvcc to treat .hip files as CUDA sources.
     list(APPEND CMAKE_HIP_COMPILER_ID_TEST_FLAGS_FIRST "-x cu -v")
@@ -194,11 +202,18 @@
   endif()
 endif()
 if(NOT CMAKE_HIP_COMPILER_ROCM_ROOT)
-  message(FATAL_ERROR "Failed to find ROCm root directory.")
+  # For spirv platform (chipStar), fall back to HIP_PATH environment variable
+  if(CMAKE_HIP_PLATFORM STREQUAL "spirv" AND DEFINED ENV{HIP_PATH} AND IS_DIRECTORY "$ENV{HIP_PATH}")
+    set(CMAKE_HIP_COMPILER_ROCM_ROOT "$ENV{HIP_PATH}")
+    file(TO_CMAKE_PATH "${CMAKE_HIP_COMPILER_ROCM_ROOT}" CMAKE_HIP_COMPILER_ROCM_ROOT)
+  else()
+    message(FATAL_ERROR "Failed to find HIP root directory.")
+  endif()
 endif()
 
-if(CMAKE_HIP_PLATFORM STREQUAL "amd")
-  # For this platform we need the hip-lang cmake package.
+
+if(CMAKE_HIP_PLATFORM STREQUAL "amd" OR CMAKE_HIP_PLATFORM STREQUAL "spirv")
+  # For amd and spirv platforms we need the hip-lang cmake package.
 
   # Normally implicit link information is not detected until ABI detection,
   # but we need to populate CMAKE_HIP_LIBRARY_ARCHITECTURE to find hip-lang.
@@ -227,6 +242,8 @@
       )
     if(CMAKE_HIP_LIBRARY_ARCHITECTURE)
       list(APPEND _CMAKE_HIP_COMPILER_ROCM_LIB_DIRS "${CMAKE_HIP_COMPILER_ROCM_ROOT}/lib/${CMAKE_HIP_LIBRARY_ARCHITECTURE}")
+    elseif(CMAKE_LIBRARY_ARCHITECTURE)
+      list(APPEND _CMAKE_HIP_COMPILER_ROCM_LIB_DIRS "${CMAKE_HIP_COMPILER_ROCM_ROOT}/lib/${CMAKE_LIBRARY_ARCHITECTURE}")
     endif()
     foreach(dir IN LISTS _CMAKE_HIP_COMPILER_ROCM_LIB_DIRS)
       if(EXISTS "${dir}/cmake/hip-lang/hip-lang-config.cmake")
@@ -309,6 +326,9 @@
     endif()
   endif()
   unset(CMAKE_HIP_ARCHITECTURES_DEFAULT)
+elseif(NOT DEFINED CMAKE_HIP_ARCHITECTURES AND CMAKE_HIP_PLATFORM STREQUAL "spirv")
+  # chipStar handles targeting via hip package
+  set(CMAKE_HIP_ARCHITECTURES "OFF" CACHE STRING "HIP architectures")
 elseif(NOT DEFINED CMAKE_HIP_ARCHITECTURES)
   # Use 'rocm_agent_enumerator' to get the current GPU architecture.
   set(_CMAKE_HIP_ARCHITECTURES)
diff --git a/Modules/CMakeDetermineISPCCompiler.cmake b/Modules/CMakeDetermineISPCCompiler.cmake
index 9b7866c..29e97fd 100644
--- a/Modules/CMakeDetermineISPCCompiler.cmake
+++ b/Modules/CMakeDetermineISPCCompiler.cmake
@@ -29,7 +29,7 @@
       set(CMAKE_ISPC_COMPILER_ARG1 "${CMAKE_ISPC_FLAGS_ENV_INIT}" CACHE STRING "First argument to ISPC compiler")
     endif()
     if(NOT EXISTS ${CMAKE_ISPC_COMPILER_INIT})
-      message(FATAL_ERROR "Could not find compiler set in environment variable ISPC:\n$ENV{ISPC}.")
+      message(FATAL_ERROR "Could not find the compiler specified in the environment variable ISPC:\n$ENV{ISPC}.")
     endif()
   endif()
 
diff --git a/Modules/CMakeDetermineJavaCompiler.cmake b/Modules/CMakeDetermineJavaCompiler.cmake
index b20a255..f66402e 100644
--- a/Modules/CMakeDetermineJavaCompiler.cmake
+++ b/Modules/CMakeDetermineJavaCompiler.cmake
@@ -14,21 +14,21 @@
       set(CMAKE_Java_COMPILER_ARG1 "${CMAKE_Java_FLAGS_ENV_INIT}" CACHE STRING "Arguments to Java compiler")
     endif()
     if(NOT EXISTS ${CMAKE_Java_COMPILER_INIT})
-      message(SEND_ERROR "Could not find compiler set in environment variable JAVA_COMPILER:\n$ENV{JAVA_COMPILER}.")
+      message(SEND_ERROR "Could not find the compiler specified in the environment variable JAVA_COMPILER:\n$ENV{JAVA_COMPILER}.")
     endif()
   endif()
 
   if(NOT $ENV{JAVA_RUNTIME} STREQUAL "")
     get_filename_component(CMAKE_Java_RUNTIME_INIT $ENV{JAVA_RUNTIME} PROGRAM PROGRAM_ARGS CMAKE_Java_FLAGS_ENV_INIT)
     if(NOT EXISTS ${CMAKE_Java_RUNTIME_INIT})
-      message(SEND_ERROR "Could not find compiler set in environment variable JAVA_RUNTIME:\n$ENV{JAVA_RUNTIME}.")
+      message(SEND_ERROR "Could not find the compiler specified in the environment variable JAVA_RUNTIME:\n$ENV{JAVA_RUNTIME}.")
     endif()
   endif()
 
   if(NOT $ENV{JAVA_ARCHIVE} STREQUAL "")
     get_filename_component(CMAKE_Java_ARCHIVE_INIT $ENV{JAVA_ARCHIVE} PROGRAM PROGRAM_ARGS CMAKE_Java_FLAGS_ENV_INIT)
     if(NOT EXISTS ${CMAKE_Java_ARCHIVE_INIT})
-      message(SEND_ERROR "Could not find compiler set in environment variable JAVA_ARCHIVE:\n$ENV{JAVA_ARCHIVE}.")
+      message(SEND_ERROR "Could not find the compiler specified in the environment variable JAVA_ARCHIVE:\n$ENV{JAVA_ARCHIVE}.")
     endif()
   endif()
 
diff --git a/Modules/CMakeDetermineOBJCCompiler.cmake b/Modules/CMakeDetermineOBJCCompiler.cmake
index 75b3900..f8d334a 100644
--- a/Modules/CMakeDetermineOBJCCompiler.cmake
+++ b/Modules/CMakeDetermineOBJCCompiler.cmake
@@ -40,7 +40,7 @@
           set(CMAKE_OBJC_COMPILER_ARG1 "${CMAKE_OBJC_FLAGS_ENV_INIT}" CACHE STRING "Arguments to Objective-C compiler")
         endif()
         if(NOT EXISTS ${CMAKE_OBJC_COMPILER_INIT})
-          message(FATAL_ERROR "Could not find compiler set in environment variable ${var}:\n  $ENV{${var}}")
+          message(FATAL_ERROR "Could not find the compiler specified in the environment variable ${var}:\n  $ENV{${var}}")
         endif()
         break()
       endif()
diff --git a/Modules/CMakeDetermineOBJCXXCompiler.cmake b/Modules/CMakeDetermineOBJCXXCompiler.cmake
index 8036da2..0c03eea 100644
--- a/Modules/CMakeDetermineOBJCXXCompiler.cmake
+++ b/Modules/CMakeDetermineOBJCXXCompiler.cmake
@@ -42,7 +42,7 @@
           set(CMAKE_OBJCXX_COMPILER_ARG1 "${CMAKE_OBJCXX_FLAGS_ENV_INIT}" CACHE STRING "Arguments to Objective-C++ compiler")
         endif()
         if(NOT EXISTS ${CMAKE_OBJCXX_COMPILER_INIT})
-          message(FATAL_ERROR "Could not find compiler set in environment variable ${var}:\n  $ENV{${var}}")
+          message(FATAL_ERROR "Could not find the compiler specified in the environment variable ${var}:\n  $ENV{${var}}")
         endif()
         break()
       endif()
diff --git a/Modules/CMakeDetermineRCCompiler.cmake b/Modules/CMakeDetermineRCCompiler.cmake
index 354fef4..5de8599 100644
--- a/Modules/CMakeDetermineRCCompiler.cmake
+++ b/Modules/CMakeDetermineRCCompiler.cmake
@@ -17,7 +17,7 @@
     endif()
     if(EXISTS ${CMAKE_RC_COMPILER_INIT})
     else()
-      message(FATAL_ERROR "Could not find compiler set in environment variable RC:\n$ENV{RC}.")
+      message(FATAL_ERROR "Could not find the compiler specified in the environment variable RC:\n$ENV{RC}.")
     endif()
   endif()
 
diff --git a/Modules/CMakeDetermineRustCompiler.cmake b/Modules/CMakeDetermineRustCompiler.cmake
new file mode 100644
index 0000000..43441b0
--- /dev/null
+++ b/Modules/CMakeDetermineRustCompiler.cmake
@@ -0,0 +1,49 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
+
+if(NOT "${CMAKE_GENERATOR}" MATCHES "^Ninja")
+  message(FATAL_ERROR "Rust language not supported by \"${CMAKE_GENERATOR}\" generator")
+endif()
+
+set(CMAKE_Rust_COMPILER_INIT "rustc")
+set(CMAKE_Rust_COMPILER_HINTS "$ENV{HOME}/.cargo/bin")
+
+_cmake_find_compiler(Rust)
+
+get_filename_component(RUSTC_REAL "${CMAKE_Rust_COMPILER}" REALPATH)
+get_filename_component(RUSTC_FILENAME "${RUSTC_REAL}" NAME)
+
+# When rustup is used for installing rust, rustc will just be a symlink to rustup. In such cases,
+# we need to query rustup for underlying rustc path.
+if(RUSTC_FILENAME STREQUAL "rustup")
+  get_filename_component(RUSTC_DIR "${CMAKE_Rust_COMPILER}" DIRECTORY)
+  set(RUSTUP_PATH "${RUSTC_DIR}/rustup")
+
+  # Fix RUSTUP_HOME in ctest.
+  if(RUSTC_FILENAME STREQUAL "rustup" AND NOT "$ENV{CTEST_REAL_HOME}" STREQUAL "" AND "$ENV{RUSTUP_HOME}" STREQUAL "")
+    set(ENV{RUSTUP_HOME} "$ENV{CTEST_REAL_HOME}/.rustup")
+  endif()
+
+  execute_process(
+    COMMAND ${RUSTUP_PATH} which rustc
+    OUTPUT_VARIABLE REAL_RUSTC
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+  )
+
+  if("${REAL_RUSTC}" STREQUAL "")
+    message(FATAL_ERROR "Failed to find path to real rustc")
+  endif()
+
+  set_property(CACHE CMAKE_Rust_COMPILER PROPERTY VALUE "${REAL_RUSTC}")
+endif()
+
+if(CMAKE_Rust_COMPILER)
+  set(CMAKE_Rust_COMPILER_WORKS TRUE)
+endif()
+
+configure_file(
+  "${CMAKE_ROOT}/Modules/CMakeRustCompiler.cmake.in"
+  "${CMAKE_PLATFORM_INFO_DIR}/CMakeRustCompiler.cmake"
+  @ONLY)
diff --git a/Modules/CMakeDetermineSwiftCompiler.cmake b/Modules/CMakeDetermineSwiftCompiler.cmake
index 6d46e78..e9285b6 100644
--- a/Modules/CMakeDetermineSwiftCompiler.cmake
+++ b/Modules/CMakeDetermineSwiftCompiler.cmake
@@ -37,7 +37,7 @@
           STRING "Arguments to the Swift compiler")
       endif()
       if(NOT EXISTS ${CMAKE_Swift_COMPILER_INIT})
-        message(FATAL_ERROR "Could not find compiler set in environment variable SWIFTC\n$ENV{SWIFTC}.\n${CMAKE_Swift_COMPILER_INIT}")
+        message(FATAL_ERROR "Could not find the compiler specified in the environment variable SWIFTC\n$ENV{SWIFTC}.\n${CMAKE_Swift_COMPILER_INIT}")
       endif()
     endif()
 
diff --git a/Modules/CMakeHIPInformation.cmake b/Modules/CMakeHIPInformation.cmake
index 9162129..e8d0232 100644
--- a/Modules/CMakeHIPInformation.cmake
+++ b/Modules/CMakeHIPInformation.cmake
@@ -69,6 +69,13 @@
 # CMAKE_HIP_COMPILE_OBJECT
 # CMAKE_HIP_LINK_EXECUTABLE
 
+# For spirv platform (chipStar), set compile and link commands
+if(CMAKE_HIP_PLATFORM STREQUAL "spirv")
+  include(Internal/CMakeChipStarHIP)
+  _cmake_chipstar_set_compiler_flags()
+  _cmake_chipstar_set_link_commands()
+endif()
+
 # create a shared library
 if(NOT CMAKE_HIP_CREATE_SHARED_LIBRARY)
   set(CMAKE_HIP_CREATE_SHARED_LIBRARY
diff --git a/Modules/CMakeRustCompiler.cmake.in b/Modules/CMakeRustCompiler.cmake.in
new file mode 100644
index 0000000..deb19ba
--- /dev/null
+++ b/Modules/CMakeRustCompiler.cmake.in
@@ -0,0 +1,5 @@
+set(CMAKE_Rust_COMPILER "@CMAKE_Rust_COMPILER@")
+set(CMAKE_Rust_COMPILER_ENV_VAR "RUSTC")
+set(CMAKE_Rust_SOURCE_FILE_EXTENSIONS rs)
+set(CMAKE_Rust_COMPILER_LOADED 1)
+set(CMAKE_Rust_COMPILER_WORKS @CMAKE_Rust_COMPILER_WORKS@)
diff --git a/Modules/CMakeRustInformation.cmake b/Modules/CMakeRustInformation.cmake
new file mode 100644
index 0000000..2224d01
--- /dev/null
+++ b/Modules/CMakeRustInformation.cmake
@@ -0,0 +1,41 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+include(CMakeLanguageInformation)
+
+if(UNIX)
+  set(CMAKE_Rust_OUTPUT_EXTENSION .o)
+else()
+  set(CMAKE_Rust_OUTPUT_EXTENSION .obj)
+endif()
+
+set(CMAKE_Rust_LIBRARY_PATH_FLAG "-L ")
+set(CMAKE_Rust_LINK_LIBRARY_FILE_FLAG "-C link-arg=")
+set(CMAKE_EXECUTABLE_RUNTIME_Rust_FLAG "-C link-arg=-Wl,-rpath,")
+set(CMAKE_EXECUTABLE_RUNTIME_Rust_FLAG_SEP ",")
+
+set(CMAKE_Rust_FLAGS_DEBUG_INIT "-C opt-level=0 -g")
+set(CMAKE_Rust_FLAGS_RELEASE_INIT "-O")
+set(CMAKE_Rust_FLAGS_RELWITHDEBINFO_INIT "-O -g")
+set(CMAKE_Rust_FLAGS_MINSIZEREL_INIT "-C opt-level=z")
+
+cmake_initialize_per_config_variable(CMAKE_Rust_FLAGS "Flags used by the Rust compiler")
+
+if(NOT CMAKE_Rust_CREATE_STATIC_LIBRARY)
+  set(CMAKE_Rust_CREATE_STATIC_LIBRARY "${CMAKE_Rust_COMPILER} <LANGUAGE_COMPILE_FLAGS> --crate-type=staticlib <RUST_SOURCES> -o <TARGET> -C link-args=\"<RUST_OBJECT_DEPS>\"")
+endif()
+
+if(NOT CMAKE_Rust_CREATE_SHARED_LIBRARY)
+  set(CMAKE_Rust_CREATE_SHARED_LIBRARY "${CMAKE_Rust_COMPILER} <LANGUAGE_COMPILE_FLAGS> --crate-type=cdylib <RUST_SOURCES> -o <TARGET> <LINK_FLAGS> <LINK_LIBRARIES> -C link-args=\"<RUST_OBJECT_DEPS>\"")
+endif()
+
+# Deadcode warnings are not useful when generating object files.
+if(NOT CMAKE_Rust_COMPILE_OBJECT)
+  set(CMAKE_Rust_COMPILE_OBJECT "${CMAKE_Rust_COMPILER} <FLAGS> -A dead_code --crate-type=lib --emit=obj=<OBJECT>,dep-info=<DEP_FILE> <SOURCE>")
+endif()
+
+if(NOT CMAKE_Rust_LINK_EXECUTABLE)
+  set(CMAKE_Rust_LINK_EXECUTABLE "${CMAKE_Rust_COMPILER} <FLAGS> --crate-type=bin <RUST_SOURCES> -o <TARGET> <LINK_FLAGS> <LINK_LIBRARIES> -C link-args=\"<RUST_OBJECT_DEPS>\"")
+endif()
+
+set(CMAKE_Rust_INFORMATION_LOADED 1)
diff --git a/Modules/CMakeTestHIPCompiler.cmake b/Modules/CMakeTestHIPCompiler.cmake
index 60b2121..ed1df10 100644
--- a/Modules/CMakeTestHIPCompiler.cmake
+++ b/Modules/CMakeTestHIPCompiler.cmake
@@ -11,7 +11,7 @@
 
 set(__CMAKE_HIP_FLAGS "${CMAKE_HIP_FLAGS}")
 
-if(CMAKE_HIP_COMPILER_ID STREQUAL "Clang")
+if(CMAKE_HIP_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_HIP_PLATFORM STREQUAL "spirv")
   string(APPEND CMAKE_HIP_FLAGS " --cuda-host-only")
 endif()
 
diff --git a/Modules/CMakeTestRustCompiler.cmake b/Modules/CMakeTestRustCompiler.cmake
new file mode 100644
index 0000000..8e3e819
--- /dev/null
+++ b/Modules/CMakeTestRustCompiler.cmake
@@ -0,0 +1,9 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+configure_file(
+  "${CMAKE_ROOT}/Modules/CMakeRustCompiler.cmake.in"
+  "${CMAKE_PLATFORM_INFO_DIR}/CMakeRustCompiler.cmake"
+  @ONLY)
+
+include(${CMAKE_PLATFORM_INFO_DIR}/CMakeRustCompiler.cmake)
diff --git a/Modules/CPack.cmake b/Modules/CPack.cmake
index 0be4846..b8e7049 100644
--- a/Modules/CPack.cmake
+++ b/Modules/CPack.cmake
@@ -338,6 +338,24 @@
 
   Other compression methods ignore this value and use only one thread.
 
+.. variable:: CPACK_COMPRESSION_LEVEL
+
+  .. versionadded:: 4.3
+
+  Select the compression level to use when it's applicable,
+  such as compressing the installer package.
+
+  Some compression methods used by CPack generators such as Debian or Archive
+  may take advantage of different compression levels. The accepted values
+  are in the range ``0`` to ``9``. If you select the ``zstd`` compression method,
+  you can select the compression level between ``0`` and ``19``, except the ``zip``
+  archive format.
+
+  By default ``CPACK_COMPRESSION_LEVEL`` is set to ``0``, which selects the default
+  compression level. It is selected automatically by the archive library backend and
+  not directly set by CMake itself. The default compression level
+  may vary between archive formats, platforms, etc.
+
 Variables for Source Package Generators
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -554,16 +572,15 @@
 function(cpack_encode_variables)
   set(commands "")
   get_cmake_property(res VARIABLES)
-  foreach(var ${res})
-    if(var MATCHES "^CPACK")
-      if(CPACK_VERBATIM_VARIABLES)
-        _cpack_escape_for_cmake(value "${${var}}")
-      else()
-        set(value "${${var}}")
-      endif()
-
-      string(APPEND commands "\nset(${var} \"${value}\")")
+  list(FILTER res INCLUDE REGEX "^CPACK")
+  foreach(var IN LISTS res)
+    if(CPACK_VERBATIM_VARIABLES)
+      _cpack_escape_for_cmake(value "${${var}}")
+    else()
+      set(value "${${var}}")
     endif()
+
+    string(APPEND commands "\nset(${var} \"${value}\")")
   endforeach()
 
   set(_CPACK_OTHER_VARIABLES_ "${commands}" PARENT_SCOPE)
@@ -936,6 +953,24 @@
 endif()
 unset(_CPack_CMP0161)
 
+# Archive specific variables
+if(NOT DEFINED CPACK_ARCHIVE_UID AND NOT DEFINED CPACK_ARCHIVE_GID)
+  cmake_policy(GET CMP0206 _CPack_CMP0206)
+  if(NOT "x${_CPack_CMP0206}x" STREQUAL "xNEWx")
+    if(NOT "x${_CPack_CMP0206}x" STREQUAL "xOLDx" AND CMAKE_POLICY_WARNING_CMP0206)
+      cmake_policy(GET_WARNING CMP0206 _CMP0206_warning)
+      message(AUTHOR_WARNING
+        "${_CMP0206_warning}\n"
+        "For compatibility, CMake will set archive UID/GID to -1/-1."
+        )
+      unset(_CMP0206_warning)
+    endif()
+    _cpack_set_default(CPACK_ARCHIVE_UID "-1")
+    _cpack_set_default(CPACK_ARCHIVE_GID "-1")
+  endif()
+  unset(_CPack_CMP0206)
+endif()
+
 # set sysroot so SDK tools can be used
 if(CMAKE_OSX_SYSROOT)
   _cpack_set_default(CPACK_OSX_SYSROOT "${_CMAKE_OSX_SYSROOT_PATH}")
diff --git a/Modules/CPackIFWConfigureFile.cmake b/Modules/CPackIFWConfigureFile.cmake
index f92fc10..bed78f9 100644
--- a/Modules/CPackIFWConfigureFile.cmake
+++ b/Modules/CPackIFWConfigureFile.cmake
@@ -7,8 +7,8 @@
 
 .. versionadded:: 3.8
 
-This module defines :command:`configure_file` similar command to
-configure file templates prepared in QtIFW/SDK/Creator style.
+This module provides a command similar to :command:`configure_file` for
+configuring file templates prepared in QtIFW/SDK/Creator style.
 
 Load this module in a CMake project with:
 
@@ -19,21 +19,100 @@
 Commands
 ^^^^^^^^
 
-The module defines the following commands:
+This module provides the following command:
 
 .. command:: cpack_ifw_configure_file
 
-  Copy a file to another location and modify its contents.
+  Copies a file template to output file and substitutes variable values
+  referenced as ``%{VAR}`` or ``%VAR%`` from the input file template
+  content:
 
   .. code-block:: cmake
 
     cpack_ifw_configure_file(<input> <output>)
 
-  Copies an ``<input>`` file to an ``<output>`` file and substitutes variable
-  values referenced as ``%{VAR}`` or ``%VAR%`` in the input file content.
+  ``<input>``
+    Input file template.  If given as a relative path, it is interpreted as
+    relative to the current source directory
+    (:variable:`CMAKE_CURRENT_SOURCE_DIR`).
+
+  ``<output>``
+    Output file.  If given as a relative path, it is interpreted as relative
+    to the current binary directory (:variable:`CMAKE_CURRENT_BINARY_DIR`).
+
+  Qt Installer Framework (QtIFW) uses ``@`` characters for embedding
+  predefined variables (``TargetDir``, ``StartMenuDir``, etc.) in Qt
+  installer scripts:
+
+  .. code-block:: javascript
+    :caption: ``example.qs``
+
+    component.addOperation(
+      "CreateShortcut",
+      "@TargetDir@/example.com.html",
+      "@StartMenuDir@/Example Web Site.lnk"
+    );
+
+  The purpose of this command is to preserve the QtIFW predefined variables
+  containing the ``@`` characters (``@VAR@``), and instead use the ``%``
+  characters for template placeholders (``%VAR%``, ``%{VAR}``) in
+  Qt/IFW/SDK/Creator templates.  The :command:`configure_file` command
+  would otherwise replace all variable references containing the ``@``
+  characters.
+
   Each variable reference will be replaced with the current value of the
   variable, or the empty string if the variable is not defined.
 
+Examples
+^^^^^^^^
+
+In the following example this module is used to create an IFW component
+script from a given template file ``qt.tools.foo.qs.in``, where
+``%FOO_DOC_DIR%`` variable reference will be replaced by the values of
+the ``FOO_DOC_DIR`` CMake variable.
+
+.. code-block:: cmake
+  :caption: ``CMakeLists.txt``
+
+  cmake_minimum_required(VERSION 3.8)
+
+  project(Foo)
+
+  # ...
+
+  include(CPackIFWConfigureFile)
+
+  set(FOO_DOC_DIR "doc/foo")
+
+  cpack_ifw_configure_file(qt.tools.foo.qs.in qt.tools.foo.qs)
+
+.. code-block:: javascript
+  :caption: ``qt.tools.foo.qs.in``
+
+  function Component()
+  {
+  }
+
+  Component.prototype.createOperations = function()
+  {
+    if (installer.value("os") === "win") {
+      component.addOperation(
+        "CreateShortcut",
+        "@TargetDir@/%FOO_DOC_DIR%/example.com.html",
+        "@StartMenuDir@/Example Web Site.lnk"
+      );
+    }
+
+    component.createOperations();
+  }
+
+  // ...
+
+See Also
+^^^^^^^^
+
+* The :cpack_gen:`CPack IFW Generator`.
+* The :module:`CPackIFW` module.
 #]=======================================================================]
 
 if(NOT DEFINED CPackIFWConfigureFile_CMake_INCLUDED)
diff --git a/Modules/CTest.cmake b/Modules/CTest.cmake
index 06d11bb..66f6cda 100644
--- a/Modules/CTest.cmake
+++ b/Modules/CTest.cmake
@@ -7,7 +7,7 @@
 
 Configure a project for testing with CTest/CDash
 
-Include this module in the top CMakeLists.txt file of a project to
+Include this module in the top ``CMakeLists.txt`` file of a project to
 enable testing with CTest and dashboard submissions to CDash:
 
 .. code-block:: cmake
@@ -41,8 +41,8 @@
   set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC")
   set(CTEST_SUBMIT_URL "http://my.cdash.org/submit.php?project=MyProject")
 
-(the CDash server can provide the file to a project administrator who
-configures ``MyProject``).  Settings in the config file are shared by
+The CDash server can provide the file to a project administrator who
+configures ``MyProject``.  Settings in the config file are shared by
 both this ``CTest`` module and the :manual:`ctest(1)` command-line
 :ref:`Dashboard Client` mode (:option:`ctest -S`).
 
diff --git a/Modules/CTestCoverageCollectGCOV.cmake b/Modules/CTestCoverageCollectGCOV.cmake
index 4c1211f..f36c022 100644
--- a/Modules/CTestCoverageCollectGCOV.cmake
+++ b/Modules/CTestCoverageCollectGCOV.cmake
@@ -65,14 +65,53 @@
 
     Specify a compression algorithm for the
     ``TARBALL`` data file.  Using this option reduces the size of the data file
-    before it is submitted to CDash.  ``<compression>`` must be one of ``GZIP``,
-    ``BZIP2``, ``XZ``, ``ZSTD``, ``FROM_EXT``, or an expression that CMake
-    evaluates as ``FALSE``.  The default value is ``BZIP2``.
+    before it is submitted to CDash.
+    ``<compression>`` should be one of the following:
+
+    * ``GZIP``
+    * ``BZIP2``
+    * ``LZMA``
+
+      .. versionadded:: 4.3
+
+    * ``LZMA2``
+
+      .. versionadded:: 4.3
+
+      This is an alias for ``XZ``.
+
+    * ``XZ``
+    * ``ZSTD``
+    * ``FROM_EXT``
+    * An expression that CMake evaluates as ``FALSE``
+
+    The default value is ``BZIP2``.
 
     If ``FROM_EXT`` is specified, the resulting file will be compressed based on
     the file extension of the ``<tar-file>`` (i.e. ``.tar.gz`` will use ``GZIP``
-    compression). File extensions that will produce compressed output include
-    ``.tar.gz``, ``.tgz``, ``.tar.bzip2``, ``.tbz``, ``.tar.xz``, and ``.txz``.
+    compression). File extensions that will produce compressed output include:
+
+    * ``.tar.gz``
+    * ``.tgz``
+    * ``.tar.bzip2``
+    * ``.tbz``
+    * ``.tar.xz``
+    * ``.txz``
+    * ``.tar.lzma``
+
+      .. versionadded:: 4.3
+
+    * ``.tlzma``
+
+      .. versionadded:: 4.3
+
+    * ``.tar.zst``
+
+      .. versionadded:: 4.3
+
+    * ``.tzst``
+
+      .. versionadded:: 4.3
 
   ``SOURCE <source-dir>``
     Specify the top-level source directory for the build.
@@ -152,12 +191,12 @@
   else()
     set(gcov_command "${GCOV_GCOV_COMMAND}")
   endif()
+  set(supported_compressions "GZIP" "BZIP2" "LZMA" "LZMA2" "XZ" "ZSTD" "FROM_EXT")
   if(NOT DEFINED GCOV_TARBALL_COMPRESSION)
     set(GCOV_TARBALL_COMPRESSION "BZIP2")
   elseif( GCOV_TARBALL_COMPRESSION AND
-      NOT GCOV_TARBALL_COMPRESSION MATCHES "^(GZIP|BZIP2|XZ|ZSTD|FROM_EXT)$")
-    message(FATAL_ERROR "TARBALL_COMPRESSION must be one of OFF, GZIP, "
-      "BZIP2, XZ, ZSTD, or FROM_EXT for ctest_coverage_collect_gcov")
+      NOT GCOV_TARBALL_COMPRESSION IN_LIST supported_compressions)
+    message(FATAL_ERROR "TARBALL_COMPRESSION must be OFF or one of ${supported_compressions} for ctest_coverage_collect_gcov")
   endif()
   # run gcov on each gcda file in the binary tree
   set(gcda_files)
@@ -341,6 +380,7 @@
   # Prepare tar command line arguments
 
   set(tar_opts "")
+  set(zstd_tar_opt "")
   # Select data compression mode
   if( GCOV_TARBALL_COMPRESSION STREQUAL "FROM_EXT")
     if( GCOV_TARBALL MATCHES [[\.(tgz|tar.gz)$]] )
@@ -349,15 +389,21 @@
       string(APPEND tar_opts "J")
     elseif( GCOV_TARBALL MATCHES [[\.(tbz|tar.bz)$]] )
       string(APPEND tar_opts "j")
+    elseif( GCOV_TARBALL MATCHES [[\.(tlzma|tar.lzma)$]] )
+      set(zstd_tar_opt "--lzma")
+    elseif( GCOV_TARBALL MATCHES [[\.(tzst|tar.zst)$]] )
+      set(zstd_tar_opt "--zstd")
     endif()
   elseif(GCOV_TARBALL_COMPRESSION STREQUAL "GZIP")
     string(APPEND tar_opts "z")
-  elseif(GCOV_TARBALL_COMPRESSION STREQUAL "XZ")
+  elseif((GCOV_TARBALL_COMPRESSION STREQUAL "XZ") OR (GCOV_TARBALL_COMPRESSION STREQUAL "LZMA2"))
     string(APPEND tar_opts "J")
   elseif(GCOV_TARBALL_COMPRESSION STREQUAL "BZIP2")
     string(APPEND tar_opts "j")
   elseif(GCOV_TARBALL_COMPRESSION STREQUAL "ZSTD")
     set(zstd_tar_opt "--zstd")
+  elseif(GCOV_TARBALL_COMPRESSION STREQUAL "LZMA")
+    set(zstd_tar_opt "--lzma")
   endif()
   # Verbosity options
   if(NOT GCOV_QUIET AND NOT tar_opts MATCHES v)
diff --git a/Modules/CheckCSourceCompiles.cmake b/Modules/CheckCSourceCompiles.cmake
index 8367206..4681ef0 100644
--- a/Modules/CheckCSourceCompiles.cmake
+++ b/Modules/CheckCSourceCompiles.cmake
@@ -77,7 +77,7 @@
 
   include(CheckCSourceCompiles)
 
-  check_c_source_compiles("
+  check_c_source_compiles([[
     #include <emmintrin.h>
     int main(void)
     {
@@ -85,7 +85,7 @@
       (void)a;
       return 0;
     }
-  " PROJECT_HAVE_SSE2_INTRINSICS)
+  ]] PROJECT_HAVE_SSE2_INTRINSICS)
 
 See Also
 ^^^^^^^^
diff --git a/Modules/CheckCSourceRuns.cmake b/Modules/CheckCSourceRuns.cmake
index f1188a3..e4e27c3 100644
--- a/Modules/CheckCSourceRuns.cmake
+++ b/Modules/CheckCSourceRuns.cmake
@@ -65,12 +65,12 @@
 
   include(CheckCSourceRuns)
 
-  check_c_source_runs("
+  check_c_source_runs([[
     #include <stdlib.h>
     #include <stdnoreturn.h>
     noreturn void f(){ exit(0); }
     int main(void) { f(); return 1; }
-  " HAVE_NORETURN)
+  ]] HAVE_NORETURN)
 
 See Also
 ^^^^^^^^
diff --git a/Modules/CheckCXXSourceCompiles.cmake b/Modules/CheckCXXSourceCompiles.cmake
index 2da6ef2..134782a 100644
--- a/Modules/CheckCXXSourceCompiles.cmake
+++ b/Modules/CheckCXXSourceCompiles.cmake
@@ -79,13 +79,13 @@
 
   include(CheckCXXSourceCompiles)
 
-  check_cxx_source_compiles("
+  check_cxx_source_compiles([[
     int main()
     {
       auto lambda = []() { return 42; };
       return lambda();
     }
-  " HAVE_CXX11_LAMBDAS)
+  ]] HAVE_CXX11_LAMBDAS)
 
 See Also
 ^^^^^^^^
diff --git a/Modules/CheckSourceCompiles.cmake b/Modules/CheckSourceCompiles.cmake
index 96246da..7984296 100644
--- a/Modules/CheckSourceCompiles.cmake
+++ b/Modules/CheckSourceCompiles.cmake
@@ -111,13 +111,13 @@
 
   include(CheckSourceCompiles)
 
-  check_source_compiles(CXX "
+  check_source_compiles(CXX [[
     int main()
     {
       auto lambda = []() { return 42; };
       return lambda();
     }
-  " HAVE_CXX11_LAMBDAS)
+  ]] HAVE_CXX11_LAMBDAS)
 
 Example: Checking Code With Bracket Argument
 """"""""""""""""""""""""""""""""""""""""""""
@@ -179,7 +179,7 @@
     cmake_push_check_state(RESET)
       set(CMAKE_REQUIRED_LIBRARIES PostgreSQL::PostgreSQL)
 
-      check_source_compiles(C "
+      check_source_compiles(C [[
         #include <libpq-fe.h>
         int main(void)
         {
@@ -187,7 +187,7 @@
           (void)e;
           return 0;
         }
-      " HAVE_PQERRORS_SQLSTATE)
+      ]] HAVE_PQERRORS_SQLSTATE)
     cmake_pop_check_state()
   endif()
 
diff --git a/Modules/CheckSourceRuns.cmake b/Modules/CheckSourceRuns.cmake
index 0874a1f..97e1eb5 100644
--- a/Modules/CheckSourceRuns.cmake
+++ b/Modules/CheckSourceRuns.cmake
@@ -96,12 +96,12 @@
 
   include(CheckSourceRuns)
 
-  check_source_runs(C "
+  check_source_runs(C [[
     #include <stdlib.h>
     #include <stdnoreturn.h>
     noreturn void f(){ exit(0); }
     int main(void) { f(); return 1; }
-  " HAVE_NORETURN)
+  ]] HAVE_NORETURN)
 
 Example: Checking Fortran Code
 """"""""""""""""""""""""""""""
@@ -112,12 +112,12 @@
 
   include(CheckSourceRuns)
 
-  check_source_runs(Fortran "
+  check_source_runs(Fortran [[
     program test
     real :: x[*]
     call co_sum(x)
     end program
-  " HAVE_COARRAY)
+  ]] HAVE_COARRAY)
 
 Example: Checking C++ Code With Bracket Argument
 """"""""""""""""""""""""""""""""""""""""""""""""
@@ -171,7 +171,7 @@
       set(CMAKE_REQUIRED_LIBRARIES gnu)
     endif()
 
-    check_source_runs(C "
+    check_source_runs(C [[
       #include <sched.h>
       int main(void)
       {
@@ -180,7 +180,7 @@
         }
         return 0;
       }
-    " HAVE_SCHED_GETCPU)
+    ]] HAVE_SCHED_GETCPU)
   cmake_pop_check_state()
 
 See Also
diff --git a/Modules/Compiler/ARMClang.cmake b/Modules/Compiler/ARMClang.cmake
index 89a523b..2f0ee91 100644
--- a/Modules/Compiler/ARMClang.cmake
+++ b/Modules/Compiler/ARMClang.cmake
@@ -121,7 +121,12 @@
     list(TRANSFORM CMAKE_LINKER_CPU_LIST TOLOWER)
     __armclang_check_processor("${CMAKE_SYSTEM_PROCESSOR}" "${CMAKE_LINKER_CPU_LIST}" _CMAKE_CHECK_LINK_CPU_RESULT)
     if(_CMAKE_CHECK_LINK_CPU_RESULT)
-      string(APPEND CMAKE_${lang}_LINK_FLAGS " --cpu=${CMAKE_SYSTEM_PROCESSOR}")
+      string(APPEND CMAKE_EXECUTABLE_CREATE_${lang}_FLAGS " --cpu=${CMAKE_SYSTEM_PROCESSOR}")
+      cmake_policy(GET CMP0210 _CMP0210)
+      if (NOT _CMP0210 STREQUAL "NEW")
+        string(APPEND CMAKE_${lang}_LINK_FLAGS " --cpu=${CMAKE_SYSTEM_PROCESSOR}")
+      endif()
+      unset(_CMP0210)
     endif()
 
   endif()
diff --git a/Modules/Compiler/AppleClang-CXX.cmake b/Modules/Compiler/AppleClang-CXX.cmake
index 8a6c855..bd92cbb 100644
--- a/Modules/Compiler/AppleClang-CXX.cmake
+++ b/Modules/Compiler/AppleClang-CXX.cmake
@@ -63,7 +63,13 @@
   set(CMAKE_CXX_STANDARD_LATEST 20)
 endif()
 
-if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0)
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0)
+  set(CMAKE_CXX23_STANDARD_COMPILE_OPTION "-std=c++23")
+  set(CMAKE_CXX23_EXTENSION_COMPILE_OPTION "-std=gnu++23")
+  set(CMAKE_CXX26_STANDARD_COMPILE_OPTION "-std=c++26")
+  set(CMAKE_CXX26_EXTENSION_COMPILE_OPTION "-std=gnu++26")
+  set(CMAKE_CXX_STANDARD_LATEST 26)
+elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0)
   set(CMAKE_CXX23_STANDARD_COMPILE_OPTION "-std=c++2b")
   set(CMAKE_CXX23_EXTENSION_COMPILE_OPTION "-std=gnu++2b")
   set(CMAKE_CXX_STANDARD_LATEST 23)
diff --git a/Modules/Compiler/CMakeCommonCompilerMacros.cmake b/Modules/Compiler/CMakeCommonCompilerMacros.cmake
index 067aa6f..a97fe0f 100644
--- a/Modules/Compiler/CMakeCommonCompilerMacros.cmake
+++ b/Modules/Compiler/CMakeCommonCompilerMacros.cmake
@@ -202,43 +202,21 @@
   _has_compiler_features_hip(98)
 endmacro()
 
-function(cmake_create_cxx_import_std std variable)
-  set(_cmake_supported_import_std_features
-    # Compilers support `import std` in C++20 as an extension. Skip
-    # for now.
-    # 20
-    23
-    26)
-  list(FIND _cmake_supported_import_std_features "${std}" _cmake_supported_import_std_idx)
-  if (_cmake_supported_import_std_idx EQUAL "-1")
-    set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Unsupported C++ standard: C++${std}\")\n"
-      PARENT_SCOPE)
-    return ()
-  endif ()
-  # If the target exists, skip. A toolchain file may have provided it.
-  if (TARGET "__CMAKE::CXX${std}")
-    return ()
-  endif ()
+function(cmake_cxx_find_modules_json)
   # The generator must support imported C++ modules.
   if (NOT CMAKE_GENERATOR MATCHES "Ninja")
-    set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Unsupported generator: ${CMAKE_GENERATOR}\")\n"
-      PARENT_SCOPE)
+    set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "Unsupported generator: ${CMAKE_GENERATOR}" PARENT_SCOPE)
     return ()
   endif ()
+
   # Check if the compiler understands how to `import std;`.
   include("${CMAKE_ROOT}/Modules/Compiler/${CMAKE_CXX_COMPILER_ID}-CXX-CXXImportStd.cmake" OPTIONAL RESULT_VARIABLE _cmake_import_std_res)
   if (NOT _cmake_import_std_res)
-    set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Toolchain does not support discovering `import std` support\")\n"
-      PARENT_SCOPE)
+    set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "Toolchain does not support discovering module metadata" PARENT_SCOPE)
     return ()
   endif ()
-  if (NOT COMMAND _cmake_cxx_import_std)
-    set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Toolchain does not provide `import std` discovery command\")\n"
-      PARENT_SCOPE)
+  if (NOT COMMAND _cmake_cxx_find_modules_json)
+    set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "Toolchain does not provide module metadata discovery command" PARENT_SCOPE)
     return ()
   endif ()
 
@@ -249,19 +227,11 @@
     "CxxImportStd"
     _cmake_supported_import_std_experimental)
   if (NOT _cmake_supported_import_std_experimental)
-    set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Experimental `import std` support not enabled when detecting toolchain; it must be set before `CXX` is enabled (usually a `project()` call)\")\n"
-      PARENT_SCOPE)
+    set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "Experimental `import std` support not enabled when detecting toolchain; it must be set before `CXX` is enabled (usually a `project()` call)" PARENT_SCOPE)
     return ()
   endif ()
 
-  _cmake_cxx_import_std("${std}" target_definition)
-  string(CONCAT guarded_target_definition
-    "if (NOT TARGET \"__CMAKE::CXX${std}\")\n"
-    "${target_definition}"
-    "endif ()\n"
-    "if (TARGET \"__CMAKE::CXX${std}\")\n"
-    "  list(APPEND CMAKE_CXX_COMPILER_IMPORT_STD \"${std}\")\n"
-    "endif ()\n")
-  set("${variable}" "${guarded_target_definition}" PARENT_SCOPE)
+  _cmake_cxx_find_modules_json()
+  set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "${CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE}" PARENT_SCOPE)
+  set(CMAKE_CXX_STDLIB_MODULES_JSON "${CMAKE_CXX_STDLIB_MODULES_JSON}" PARENT_SCOPE)
 endfunction()
diff --git a/Modules/Compiler/Clang-C.cmake b/Modules/Compiler/Clang-C.cmake
index 24b7157..b7359b2 100644
--- a/Modules/Compiler/Clang-C.cmake
+++ b/Modules/Compiler/Clang-C.cmake
@@ -5,11 +5,6 @@
   set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TC)
   set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
   set(CMAKE_C_INCLUDE_WHAT_YOU_USE_DRIVER_MODE "cl")
-  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
-      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
-      AND CMAKE_DEPFILE_FLAGS_C)
-    set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
-  endif()
 elseif("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
   set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
   if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
diff --git a/Modules/Compiler/Clang-CXX-CXXImportStd.cmake b/Modules/Compiler/Clang-CXX-CXXImportStd.cmake
index 9061e00..9b66b56 100644
--- a/Modules/Compiler/Clang-CXX-CXXImportStd.cmake
+++ b/Modules/Compiler/Clang-CXX-CXXImportStd.cmake
@@ -1,18 +1,14 @@
-function (_cmake_cxx_import_std std variable)
+function (_cmake_cxx_find_modules_json)
   if (CMAKE_CXX_STANDARD_LIBRARY STREQUAL "libc++")
     set(_clang_modules_json_impl "libc++")
   elseif (CMAKE_CXX_STANDARD_LIBRARY STREQUAL "libstdc++")
     set(_clang_modules_json_impl "libstdc++")
   else ()
-    set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Only `libc++` and `libstdc++` are supported\")\n"
-      PARENT_SCOPE)
+    set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "Only `libc++` and `libstdc++` are supported" PARENT_SCOPE)
     return ()
   endif ()
 
-  if (CMAKE_CXX_STDLIB_MODULES_JSON)
-    set(_clang_libcxx_modules_json_file "${CMAKE_CXX_STDLIB_MODULES_JSON}")
-  else ()
+  if (NOT CMAKE_CXX_STDLIB_MODULES_JSON)
     execute_process(
       COMMAND
         "${CMAKE_CXX_COMPILER}"
@@ -24,19 +20,11 @@
       OUTPUT_STRIP_TRAILING_WHITESPACE
       ERROR_STRIP_TRAILING_WHITESPACE)
     if (_clang_libcxx_modules_json_file_res)
-      set("${variable}"
-        "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Could not find `${_clang_modules_json_impl}.modules.json` resource\")\n"
-        PARENT_SCOPE)
+      set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "Could not find `${_clang_modules_json_impl}.modules.json` resource" PARENT_SCOPE)
       return ()
     endif ()
-  endif ()
-
-  # Without this file, we do not have modules installed.
-  if (NOT EXISTS "${_clang_libcxx_modules_json_file}")
-    set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`${_clang_modules_json_impl}.modules.json` resource does not exist\")\n"
-      PARENT_SCOPE)
-    return ()
+    cmake_path(CONVERT "${_clang_libcxx_modules_json_file}" TO_CMAKE_PATH_LIST CMAKE_CXX_STDLIB_MODULES_JSON NORMALIZE)
+    set(CMAKE_CXX_STDLIB_MODULES_JSON "${CMAKE_CXX_STDLIB_MODULES_JSON}" PARENT_SCOPE)
   endif ()
 
   if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "18.1.2" AND
@@ -44,145 +32,7 @@
     # The original PR had a key spelling mismatch internally. Do not support it
     # and instead require a release known to have the fix.
     # https://github.com/llvm/llvm-project/pull/83036
-    set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"LLVM 18.1.2 is required for `${_clang_modules_json_impl}.modules.json` format fix\")\n"
-      PARENT_SCOPE)
+    set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "LLVM 18.1.2 is required for `${_clang_modules_json_impl}.modules.json` format fix" PARENT_SCOPE)
     return ()
   endif ()
-
-  file(READ "${_clang_libcxx_modules_json_file}" _clang_libcxx_modules_json)
-  string(JSON _clang_modules_json_version GET "${_clang_libcxx_modules_json}" "version")
-  string(JSON _clang_modules_json_revision GET "${_clang_libcxx_modules_json}" "revision")
-  # Require version 1.
-  if (NOT _clang_modules_json_version EQUAL "1")
-    set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`libc++.modules.json` version ${_clang_modules_json_version}.${_clang_modules_json_revision} is not recognized\")\n"
-      PARENT_SCOPE)
-    return ()
-  endif ()
-
-  string(JSON _clang_modules_json_nmodules LENGTH "${_clang_libcxx_modules_json}" "modules")
-  # Don't declare the target without any modules.
-  if (NOT _clang_modules_json_nmodules)
-    set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`libc++.modules.json` does not list any available modules\")\n"
-      PARENT_SCOPE)
-    return ()
-  endif ()
-
-  # Declare the target.
-  set(_clang_libcxx_target "")
-  # Clang 18 does not provide the module initializer for the `std` modules.
-  # Create a static library to hold these. Hope that Clang 19 can provide this,
-  # but never run the code.
-  string(APPEND _clang_libcxx_target
-    "add_library(__cmake_cxx${std} STATIC)\n")
-  string(APPEND _clang_libcxx_target
-    "target_sources(__cmake_cxx${std} INTERFACE \"$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,STATIC_LIBRARY>:$<TARGET_OBJECTS:__cmake_cxx${std}>>\")\n")
-  string(APPEND _clang_libcxx_target
-    "set_property(TARGET __cmake_cxx${std} PROPERTY EXCLUDE_FROM_ALL 1)\n")
-  string(APPEND _clang_libcxx_target
-    "set_property(TARGET __cmake_cxx${std} PROPERTY CXX_SCAN_FOR_MODULES 1)\n")
-  string(APPEND _clang_libcxx_target
-    "set_property(TARGET __cmake_cxx${std} PROPERTY CXX_MODULE_STD 0)\n")
-  string(APPEND _clang_libcxx_target
-    "target_compile_features(__cmake_cxx${std} PUBLIC cxx_std_${std})\n")
-
-  set(_clang_modules_is_stdlib 0)
-  set(_clang_modules_include_dirs_list "")
-  set(_clang_modules_module_paths "")
-  get_filename_component(_clang_modules_dir "${_clang_libcxx_modules_json_file}" DIRECTORY)
-
-  # Add module sources.
-  math(EXPR _clang_modules_json_nmodules_range "${_clang_modules_json_nmodules} - 1")
-  foreach (_clang_modules_json_modules_idx RANGE 0 "${_clang_modules_json_nmodules_range}")
-    string(JSON _clang_modules_json_module GET "${_clang_libcxx_modules_json}" "modules" "${_clang_modules_json_modules_idx}")
-
-    string(JSON _clang_modules_json_module_source GET "${_clang_modules_json_module}" "source-path")
-    string(JSON _clang_modules_json_module_is_stdlib GET "${_clang_modules_json_module}" "is-std-library")
-    string(JSON _clang_modules_json_module_local_arguments ERROR_VARIABLE _clang_modules_json_module_local_arguments_error GET "${_clang_modules_json_module}" "local-arguments")
-    string(JSON _clang_modules_json_module_nsystem_include_directories ERROR_VARIABLE _clang_modules_json_module_nsystem_include_directories_error LENGTH "${_clang_modules_json_module_local_arguments}" "system-include-directories")
-
-    if (_clang_modules_json_module_local_arguments_error)
-      set(_clang_modules_json_module_local_arguments "")
-    endif ()
-    if (_clang_modules_json_module_nsystem_include_directories_error)
-      set(_clang_modules_json_module_nsystem_include_directories 0)
-    endif ()
-    if (NOT IS_ABSOLUTE "${_clang_modules_json_module_source}")
-      string(PREPEND _clang_modules_json_module_source "${_clang_modules_dir}/")
-    endif ()
-    list(APPEND _clang_modules_module_paths
-      "${_clang_modules_json_module_source}")
-
-    if (_clang_modules_json_module_is_stdlib)
-      set(_clang_modules_is_stdlib 1)
-    endif ()
-
-    if (_clang_modules_json_module_nsystem_include_directories)
-      math(EXPR _clang_modules_json_module_nsystem_include_directories_range "${_clang_modules_json_module_nsystem_include_directories} - 1")
-      foreach (_clang_modules_json_modules_system_include_directories_idx RANGE 0 "${_clang_modules_json_module_nsystem_include_directories_range}")
-        string(JSON _clang_modules_json_module_system_include_directory GET "${_clang_modules_json_module_local_arguments}" "system-include-directories" "${_clang_modules_json_modules_system_include_directories_idx}")
-
-        if (NOT IS_ABSOLUTE "${_clang_modules_json_module_system_include_directory}")
-          string(PREPEND _clang_modules_json_module_system_include_directory "${_clang_modules_dir}/")
-        endif ()
-        list(APPEND _clang_modules_include_dirs_list
-          "${_clang_modules_json_module_system_include_directory}")
-      endforeach ()
-    endif ()
-  endforeach ()
-
-  # Split the paths into basedirs and module paths.
-  set(_clang_modules_base_dirs_list "")
-  set(_clang_modules_files "")
-  foreach (_clang_modules_module_path IN LISTS _clang_modules_module_paths)
-    get_filename_component(_clang_module_dir "${_clang_modules_module_path}" DIRECTORY)
-
-    list(APPEND _clang_modules_base_dirs_list
-      "${_clang_module_dir}")
-    string(APPEND _clang_modules_files
-      " \"${_clang_modules_module_path}\"")
-  endforeach ()
-  list(REMOVE_DUPLICATES _clang_modules_base_dirs_list)
-  set(_clang_modules_base_dirs "")
-  foreach (_clang_modules_base_dir IN LISTS _clang_modules_base_dirs_list)
-    string(APPEND _clang_modules_base_dirs
-      " \"${_clang_modules_base_dir}\"")
-  endforeach ()
-
-  # If we have a standard library module, suppress warnings about reserved
-  # module names.
-  if (_clang_modules_is_stdlib)
-    string(APPEND _clang_libcxx_target
-      "target_compile_options(__cmake_cxx${std} PRIVATE -Wno-reserved-module-identifier)\n")
-  endif ()
-
-  # Set up include directories.
-  list(REMOVE_DUPLICATES _clang_modules_include_dirs_list)
-  set(_clang_modules_include_dirs "")
-  foreach (_clang_modules_include_dir IN LISTS _clang_modules_include_dirs_list)
-    string(APPEND _clang_modules_include_dirs
-      " \"${_clang_modules_include_dir}\"")
-  endforeach ()
-  string(APPEND _clang_libcxx_target
-    "target_include_directories(__cmake_cxx${std} PRIVATE ${_clang_modules_include_dirs})\n")
-
-  # Create the file set for the modules.
-  string(APPEND _clang_libcxx_target
-    "target_sources(__cmake_cxx${std}
-  PUBLIC
-  FILE_SET std TYPE CXX_MODULES
-    BASE_DIRS ${_clang_modules_base_dirs}
-    FILES ${_clang_modules_files})\n")
-
-  # Wrap the `__cmake_cxx${std}` target in a check.
-  string(PREPEND _clang_libcxx_target
-    "if (NOT TARGET \"__cmake_cxx${std}\")\n")
-  string(APPEND _clang_libcxx_target
-    "endif ()\n")
-  string(APPEND _clang_libcxx_target
-    "add_library(__CMAKE::CXX${std} ALIAS __cmake_cxx${std})\n")
-
-  set("${variable}" "${_clang_libcxx_target}" PARENT_SCOPE)
 endfunction ()
diff --git a/Modules/Compiler/Clang-CXX.cmake b/Modules/Compiler/Clang-CXX.cmake
index 87a4cdd..205c5f7 100644
--- a/Modules/Compiler/Clang-CXX.cmake
+++ b/Modules/Compiler/Clang-CXX.cmake
@@ -18,11 +18,6 @@
 if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
   set(CMAKE_CXX_CLANG_TIDY_DRIVER_MODE "cl")
   set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE_DRIVER_MODE "cl")
-  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
-      AND CMAKE_GENERATOR MATCHES "Makefiles"
-      AND CMAKE_DEPFILE_FLAGS_CXX)
-    set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
-  endif()
 endif()
 
 if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)
@@ -61,6 +56,7 @@
     unset(_clang_scan_deps_mv)
     set(CMAKE_CXX_MODULE_MAP_FORMAT "clang")
     set(CMAKE_CXX_MODULE_MAP_FLAG "@<MODULE_MAP_FILE>")
-    set(CMAKE_CXX_MODULE_BMI_ONLY_FLAG "--precompile")
+    set(CMAKE_CXX_COMPILE_BMI
+      "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> --precompile <SOURCE>")
   endif()
 endif()
diff --git a/Modules/Compiler/GNU-CXX-CXXImportStd.cmake b/Modules/Compiler/GNU-CXX-CXXImportStd.cmake
index 834e999..c8bd960 100644
--- a/Modules/Compiler/GNU-CXX-CXXImportStd.cmake
+++ b/Modules/Compiler/GNU-CXX-CXXImportStd.cmake
@@ -1,14 +1,10 @@
-function (_cmake_cxx_import_std std variable)
+function (_cmake_cxx_find_modules_json)
   if (NOT CMAKE_CXX_STANDARD_LIBRARY STREQUAL "libstdc++")
-    set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Only `libstdc++` is supported\")\n"
-      PARENT_SCOPE)
+    set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "Only `libstdc++` is supported" PARENT_SCOPE)
     return ()
   endif ()
 
-  if (CMAKE_CXX_STDLIB_MODULES_JSON)
-    set(_gnu_libstdcxx_modules_json_file "${CMAKE_CXX_STDLIB_MODULES_JSON}")
-  else ()
+  if (NOT CMAKE_CXX_STDLIB_MODULES_JSON)
     execute_process(
       COMMAND
         "${CMAKE_CXX_COMPILER}"
@@ -20,119 +16,9 @@
       OUTPUT_STRIP_TRAILING_WHITESPACE
       ERROR_STRIP_TRAILING_WHITESPACE)
     if (_gnu_libstdcxx_modules_json_file_res)
-      set("${variable}"
-        "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Could not find `libstdc++.modules.json` resource\")\n"
-        PARENT_SCOPE)
+      set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "Could not find `libstdc++.modules.json` resource" PARENT_SCOPE)
       return ()
     endif ()
+    set(CMAKE_CXX_STDLIB_MODULES_JSON "${_gnu_libstdcxx_modules_json_file}" PARENT_SCOPE)
   endif ()
-
-  # Without this file, we do not have modules installed.
-  if (NOT EXISTS "${_gnu_libstdcxx_modules_json_file}")
-    set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`libstdc++.modules.json` resource does not exist\")\n"
-      PARENT_SCOPE)
-    return ()
-  endif ()
-
-  file(READ "${_gnu_libstdcxx_modules_json_file}" _gnu_libstdcxx_modules_json)
-  string(JSON _gnu_modules_json_version GET "${_gnu_libstdcxx_modules_json}" "version")
-  string(JSON _gnu_modules_json_revision GET "${_gnu_libstdcxx_modules_json}" "revision")
-  # Require version 1.
-  if (NOT _gnu_modules_json_version EQUAL "1")
-    set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`libstdc++.modules.json` version ${_gnu_modules_json_version}.${_gnu_modules_json_revision} is not recognized\")\n"
-      PARENT_SCOPE)
-    return ()
-  endif ()
-
-  string(JSON _gnu_modules_json_nmodules LENGTH "${_gnu_libstdcxx_modules_json}" "modules")
-  # Don't declare the target without any modules.
-  if (NOT _gnu_modules_json_nmodules)
-    set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`libstdc++.modules.json` does not list any available modules\")\n"
-      PARENT_SCOPE)
-    return ()
-  endif ()
-
-  # Declare the target.
-  set(_gnu_libstdcxx_target "")
-  string(APPEND _gnu_libstdcxx_target
-    "add_library(__CMAKE::CXX${std} IMPORTED INTERFACE)\n")
-  string(APPEND _gnu_libstdcxx_target
-    "target_compile_features(__CMAKE::CXX${std} INTERFACE cxx_std_${std})\n")
-
-  set(_gnu_modules_is_stdlib 0)
-  set(_gnu_modules_include_dirs_list "")
-  set(_gnu_modules_module_paths "")
-  get_filename_component(_gnu_modules_dir "${_gnu_libstdcxx_modules_json_file}" DIRECTORY)
-
-  # Add module sources.
-  math(EXPR _gnu_modules_json_nmodules_range "${_gnu_modules_json_nmodules} - 1")
-  foreach (_gnu_modules_json_modules_idx RANGE 0 "${_gnu_modules_json_nmodules_range}")
-    string(JSON _gnu_modules_json_module GET "${_gnu_libstdcxx_modules_json}" "modules" "${_gnu_modules_json_modules_idx}")
-
-    string(JSON _gnu_modules_json_module_source GET "${_gnu_modules_json_module}" "source-path")
-    string(JSON _gnu_modules_json_module_is_stdlib GET "${_gnu_modules_json_module}" "is-std-library")
-    string(JSON _gnu_modules_json_module_local_arguments ERROR_VARIABLE _gnu_modules_json_module_local_arguments_error GET "${_gnu_modules_json_module}" "local-arguments")
-    string(JSON _gnu_modules_json_module_nsystem_include_directories ERROR_VARIABLE _gnu_modules_json_module_nsystem_include_directories_error LENGTH "${_gnu_modules_json_module_local_arguments}" "system-include-directories")
-
-    if (_gnu_modules_json_module_local_arguments_error STREQUAL "NOTFOUND")
-      set(_gnu_modules_json_module_local_arguments "")
-    endif ()
-    if (_gnu_modules_json_module_nsystem_include_directories_error STREQUAL "NOTFOUND")
-      set(_gnu_modules_json_module_nsystem_include_directories 0)
-    endif ()
-
-    if (NOT IS_ABSOLUTE "${_gnu_modules_json_module_source}")
-      string(PREPEND _gnu_modules_json_module_source "${_gnu_modules_dir}/")
-    endif ()
-    list(APPEND _gnu_modules_module_paths
-      "${_gnu_modules_json_module_source}")
-
-    if (_gnu_modules_json_module_is_stdlib)
-      set(_gnu_modules_is_stdlib 1)
-    endif ()
-
-    if (_gnu_modules_json_module_nsystem_include_directories)
-      math(EXPR _gnu_modules_json_module_nsystem_include_directories_range "${_gnu_modules_json_module_nsystem_include_directories} - 1")
-      foreach (_gnu_modules_json_modules_system_include_directories_idx RANGE 0 "${_gnu_modules_json_module_nsystem_include_directories_range}")
-        string(JSON _gnu_modules_json_module_system_include_directory GET "${_gnu_modules_json_module_local_arguments}" "system-include-directories" "${_gnu_modules_json_modules_system_include_directories_idx}")
-
-        if (NOT IS_ABSOLUTE "${_gnu_modules_json_module_system_include_directory}")
-          string(PREPEND _gnu_modules_json_module_system_include_directory "${_gnu_modules_dir}/")
-        endif ()
-        list(APPEND _gnu_modules_include_dirs_list
-          "${_gnu_modules_json_module_system_include_directory}")
-      endforeach ()
-    endif ()
-  endforeach ()
-
-  # Split the paths into basedirs and module paths.
-  set(_gnu_modules_base_dirs_list "")
-  set(_gnu_modules_files "")
-  foreach (_gnu_modules_module_path IN LISTS _gnu_modules_module_paths)
-    get_filename_component(_gnu_module_dir "${_gnu_modules_module_path}" DIRECTORY)
-
-    list(APPEND _gnu_modules_base_dirs_list
-      "${_gnu_module_dir}")
-    string(APPEND _gnu_modules_files
-      " \"${_gnu_modules_module_path}\"")
-  endforeach ()
-  list(REMOVE_DUPLICATES _gnu_modules_base_dirs_list)
-  set(_gnu_modules_base_dirs "")
-  foreach (_gnu_modules_base_dir IN LISTS _gnu_modules_base_dirs_list)
-    string(APPEND _gnu_modules_base_dirs
-      " \"${_gnu_modules_base_dir}\"")
-  endforeach ()
-
-  # Create the file set for the modules.
-  string(APPEND _gnu_libstdcxx_target
-    "target_sources(__CMAKE::CXX${std}
-  INTERFACE
-  FILE_SET std TYPE CXX_MODULES
-    BASE_DIRS ${_gnu_modules_base_dirs}
-    FILES ${_gnu_modules_files})\n")
-
-  set("${variable}" "${_gnu_libstdcxx_target}" PARENT_SCOPE)
 endfunction ()
diff --git a/Modules/Compiler/MSVC-CXX-CXXImportStd.cmake b/Modules/Compiler/MSVC-CXX-CXXImportStd.cmake
index ff01263..b7bd525 100644
--- a/Modules/Compiler/MSVC-CXX-CXXImportStd.cmake
+++ b/Modules/Compiler/MSVC-CXX-CXXImportStd.cmake
@@ -1,119 +1,104 @@
-function (_cmake_cxx_import_std std variable)
+function (_cmake_cxx_find_modules_json)
   if (CMAKE_CXX_STDLIB_MODULES_JSON)
-    set(_msvc_modules_json_file "${CMAKE_CXX_STDLIB_MODULES_JSON}")
-  else ()
-    find_file(_msvc_modules_json_file
-      NAME modules.json
-      HINTS
-        "$ENV{VCToolsInstallDir}/modules"
-      PATHS
-        "$ENV{INCLUDE}"
-        "${CMAKE_CXX_COMPILER}/../../.."
-        "${CMAKE_CXX_COMPILER}/../.."    # msvc-wine layout
-      PATH_SUFFIXES
-        ../modules
-      NO_CACHE)
-    # Without this file, we do not have modules installed.
-    if (NOT EXISTS "${_msvc_modules_json_file}")
-      set("${variable}"
-        "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"Could not find `modules.json` resource\")\n"
-        PARENT_SCOPE)
-      return ()
-    endif ()
+    return ()
+  endif ()
+
+  find_file(_msvc_modules_json_file
+    NAME modules.json
+    HINTS
+      "$ENV{VCToolsInstallDir}/modules"
+    PATHS
+      "$ENV{INCLUDE}"
+      "${CMAKE_CXX_COMPILER}/../../.."
+      "${CMAKE_CXX_COMPILER}/../.."    # msvc-wine layout
+    PATH_SUFFIXES
+      ../modules
+    NO_CACHE)
+
+  # Without this file, we do not have modules installed.
+  if (NOT EXISTS "${_msvc_modules_json_file}")
+    set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "Could not find `modules.json` resource" PARENT_SCOPE)
+    return ()
   endif ()
 
   file(READ "${_msvc_modules_json_file}" _msvc_modules_json)
+  string(JSON _msvc_json_modules ERROR_VARIABLE _msvc_json_err GET "${_msvc_modules_json}" "modules")
+
+  # This is probably a conforming module metadata file, use it as is
+  if (_msvc_json_modules)
+    set(CMAKE_CXX_STDLIB_MODULES_JSON "${_msvc_modules_json_file}" PARENT_SCOPE)
+    return ()
+  endif ()
+
+  # Otherwise it's a Microsoft STL-style modules.json, check if we recognize it
   string(JSON _msvc_json_version GET "${_msvc_modules_json}" "version")
   string(JSON _msvc_json_revision GET "${_msvc_modules_json}" "revision")
   # Require version 1.
   if (NOT _msvc_json_version EQUAL "1")
-    set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`modules.json` version ${_msvc_json_version}.${_msvc_json_revision} is not recognized\")\n"
-      PARENT_SCOPE)
+    set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "`modules.json` version ${_msvc_json_version}.${_msvc_json_revision} is not recognized" PARENT_SCOPE)
     return ()
   endif ()
 
   string(JSON _msvc_json_library GET "${_msvc_modules_json}" "library")
   # Bail if we don't understand the library.
   if (NOT _msvc_json_library STREQUAL "microsoft/STL")
-    set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`modules.json` library `${_msvc_json_library}` is not recognized\")\n"
-      PARENT_SCOPE)
+    set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "`modules.json` library `${_msvc_json_library}` is not recognized" PARENT_SCOPE)
     return ()
   endif ()
 
-  string(JSON _msvc_json_nmodules LENGTH "${_msvc_modules_json}" "module-sources")
-  # Don't declare the target without any modules.
-  if (NOT _msvc_json_nmodules)
-    set("${variable}"
-      "set(CMAKE_CXX${std}_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE \"`modules.json` does not list any available modules\")\n"
-      PARENT_SCOPE)
+  string(JSON _msvc_json_sources_len LENGTH "${_msvc_modules_json}" "module-sources")
+  # Bail if there aren't any sources
+  if (NOT _msvc_json_sources_len)
+    set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "`modules.json` does not list any available sources" PARENT_SCOPE)
     return ()
   endif ()
 
-  # Declare the target.
-  set(_msvc_std_target "")
-  string(APPEND _msvc_std_target
-    "add_library(__cmake_cxx${std} STATIC)\n")
-  string(APPEND _msvc_std_target
-    "target_sources(__cmake_cxx${std} INTERFACE \"$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,STATIC_LIBRARY>:$<TARGET_OBJECTS:__cmake_cxx${std}>>\")\n")
-  string(APPEND _msvc_std_target
-    "set_property(TARGET __cmake_cxx${std} PROPERTY EXCLUDE_FROM_ALL 1)\n")
-  string(APPEND _msvc_std_target
-    "set_property(TARGET __cmake_cxx${std} PROPERTY CXX_SCAN_FOR_MODULES 1)\n")
-  string(APPEND _msvc_std_target
-    "set_property(TARGET __cmake_cxx${std} PROPERTY CXX_MODULE_STD 0)\n")
-  string(APPEND _msvc_std_target
-    "target_compile_features(__cmake_cxx${std} PUBLIC cxx_std_${std})\n")
+  set(_msvc_module_metadata [=[{
+    "version": 1,
+    "revision": 1,
+    "modules": []
+  }]=])
 
-  set(_msvc_modules_module_paths "")
-  get_filename_component(_msvc_modules_dir "${_msvc_modules_json_file}" DIRECTORY)
+  cmake_path(GET _msvc_modules_json_file PARENT_PATH _msvc_base_dir)
+  math(EXPR _msvc_json_sources_len "${_msvc_json_sources_len}-1")
+  foreach (idx RANGE ${_msvc_json_sources_len})
+    string(JSON _msvc_source GET "${_msvc_modules_json}" "module-sources" ${idx})
 
-  # Add module sources.
-  math(EXPR _msvc_modules_json_nmodules_range "${_msvc_json_nmodules} - 1")
-  foreach (_msvc_modules_json_modules_idx RANGE 0 "${_msvc_modules_json_nmodules_range}")
-    string(JSON _msvc_modules_json_module_source GET "${_msvc_modules_json}" "module-sources" "${_msvc_modules_json_modules_idx}")
-
-    if (NOT IS_ABSOLUTE "${_msvc_modules_json_module_source}")
-      string(PREPEND _msvc_modules_json_module_source "${_msvc_modules_dir}/")
+    set(_msvc_path ${_msvc_source})
+    cmake_path(IS_RELATIVE _msvc_path _msvc_is_rel)
+    if (_msvc_is_rel)
+      cmake_path(ABSOLUTE_PATH _msvc_path BASE_DIRECTORY "${_msvc_base_dir}")
     endif ()
-    list(APPEND _msvc_modules_module_paths
-      "${_msvc_modules_json_module_source}")
-  endforeach ()
 
-  # Split the paths into basedirs and module paths.
-  set(_msvc_modules_base_dirs_list "")
-  set(_msvc_modules_files "")
-  foreach (_msvc_modules_module_path IN LISTS _msvc_modules_module_paths)
-    get_filename_component(_msvc_module_dir "${_msvc_modules_module_path}" DIRECTORY)
+    if (_msvc_source MATCHES "std.ixx")
+      string(JSON _msvc_module_metadata
+        SET "${_msvc_module_metadata}" "modules" ${idx}
+        "{
+            \"logical-name\": \"std\",
+            \"source-path\": \"${_msvc_path}\",
+            \"is-std-library\": true
+        }"
+      )
+    elseif (_msvc_source MATCHES "std.compat.ixx")
+      string(JSON _msvc_module_metadata
+        SET "${_msvc_module_metadata}" "modules" ${idx}
+        "{
+            \"logical-name\": \"std.compat\",
+            \"source-path\": \"${_msvc_path}\",
+            \"is-std-library\": true
+        }"
+      )
+    endif ()
+  endforeach()
 
-    list(APPEND _msvc_modules_base_dirs_list
-      "${_msvc_module_dir}")
-    string(APPEND _msvc_modules_files
-      " \"${_msvc_modules_module_path}\"")
-  endforeach ()
-  list(REMOVE_DUPLICATES _msvc_modules_base_dirs_list)
-  set(_msvc_modules_base_dirs "")
-  foreach (_msvc_modules_base_dir IN LISTS _msvc_modules_base_dirs_list)
-    string(APPEND _msvc_modules_base_dirs
-      " \"${_msvc_modules_base_dir}\"")
-  endforeach ()
+  string(JSON _msvc_module_metadata_modules_len LENGTH ${_msvc_module_metadata} "modules")
 
-  # Create the file set for the modules.
-  string(APPEND _msvc_std_target
-    "target_sources(__cmake_cxx${std}
-  PUBLIC
-  FILE_SET std TYPE CXX_MODULES
-    BASE_DIRS ${_msvc_modules_base_dirs}
-    FILES ${_msvc_modules_files})\n")
+  # Bail if we didn't recognize any of the modules
+  if (NOT _msvc_module_metadata_modules_len)
+    set(CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE "`modules.json` did not contain any recognized sources (std.ixx, std.compat.ixx)" PARENT_SCOPE)
+    return ()
+  endif ()
 
-  # Wrap the `__cmake_cxx${std}` target in a check.
-  string(PREPEND _msvc_std_target
-    "if (NOT TARGET \"__cmake_cxx${std}\")\n")
-  string(APPEND _msvc_std_target
-    "endif ()\n")
-  string(APPEND _msvc_std_target
-    "add_library(__CMAKE::CXX${std} ALIAS __cmake_cxx${std})\n")
-
-  set("${variable}" "${_msvc_std_target}" PARENT_SCOPE)
+  file(WRITE "${CMAKE_PLATFORM_INFO_DIR}/msvcstl.modules.json" "${_msvc_module_metadata}")
+  set(CMAKE_CXX_STDLIB_MODULES_JSON "${CMAKE_PLATFORM_INFO_DIR}/msvcstl.modules.json" PARENT_SCOPE)
 endfunction ()
diff --git a/Modules/FetchContent.cmake b/Modules/FetchContent.cmake
index 4c1068e..80152f6 100644
--- a/Modules/FetchContent.cmake
+++ b/Modules/FetchContent.cmake
@@ -397,17 +397,20 @@
     FetchContent_Declare(other ...)
     FetchContent_MakeAvailable(uses_other other)
 
-  Note that :variable:`CMAKE_VERIFY_INTERFACE_HEADER_SETS` is explicitly set
-  to false upon entry to ``FetchContent_MakeAvailable()``, and is restored to
-  its original value before the command returns.  Developers typically only
+  Note that :variable:`CMAKE_VERIFY_INTERFACE_HEADER_SETS` and
+  :variable:`CMAKE_VERIFY_PRIVATE_HEADER_SETS` are explicitly set to false
+  upon entry to ``FetchContent_MakeAvailable()``, and are restored to their
+  original values before the command returns.  Developers typically only
   want to verify header sets from the main project, not those from any
   dependencies.  This local manipulation of the
-  :variable:`CMAKE_VERIFY_INTERFACE_HEADER_SETS` variable provides that
+  :variable:`CMAKE_VERIFY_INTERFACE_HEADER_SETS` and
+  :variable:`CMAKE_VERIFY_PRIVATE_HEADER_SETS` variables provides that
   intuitive behavior.  You can use variables like
   :variable:`CMAKE_PROJECT_INCLUDE` or
   :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE` to turn verification back
   on for all or some dependencies.  You can also set the
-  :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` property of individual targets.
+  :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` and
+  :prop_tgt:`VERIFY_PRIVATE_HEADER_SETS` properties of individual targets.
 
 .. command:: FetchContent_Populate
 
@@ -2240,12 +2243,14 @@
 # calls will be available to the caller.
 macro(FetchContent_MakeAvailable)
 
-  # We must append an item, even if the variable is unset, so prefix its value.
-  # We will strip that prefix when we pop the value at the end of the macro.
+  # We must append these, even if the variables are unset, so prefix the values.
+  # We will strip that prefix when we pop the values at the end of the macro.
   list(APPEND __cmake_fcCurrentVarsStack
     "__fcprefix__${CMAKE_VERIFY_INTERFACE_HEADER_SETS}"
+    "__fcprefix__${CMAKE_VERIFY_PRIVATE_HEADER_SETS}"
   )
   set(CMAKE_VERIFY_INTERFACE_HEADER_SETS FALSE)
+  set(CMAKE_VERIFY_PRIVATE_HEADER_SETS FALSE)
 
   get_property(__cmake_providerCommand GLOBAL PROPERTY
     __FETCHCONTENT_MAKEAVAILABLE_SERIAL_PROVIDER
@@ -2453,18 +2458,30 @@
   endforeach()
 
   # Prefix will be "__fcprefix__"
-  list(POP_BACK __cmake_fcCurrentVarsStack __cmake_original_verify_setting)
-  string(SUBSTRING "${__cmake_original_verify_setting}"
-    12 -1 __cmake_original_verify_setting
+  list(POP_BACK __cmake_fcCurrentVarsStack
+    __cmake_original_verify_private_setting
+    __cmake_original_verify_interface_setting
   )
-  set(CMAKE_VERIFY_INTERFACE_HEADER_SETS ${__cmake_original_verify_setting})
+  string(SUBSTRING "${__cmake_original_verify_private_setting}"
+    12 -1 __cmake_original_verify_private_setting
+  )
+  string(SUBSTRING "${__cmake_original_verify_interface_setting}"
+    12 -1 __cmake_original_verify_interface_setting
+  )
+  set(CMAKE_VERIFY_PRIVATE_HEADER_SETS
+    ${__cmake_original_verify_private_setting}
+  )
+  set(CMAKE_VERIFY_INTERFACE_HEADER_SETS
+    ${__cmake_original_verify_interface_setting}
+  )
 
   # clear local variables to prevent leaking into the caller's scope
   unset(__cmake_contentName)
   unset(__cmake_contentNameLower)
   unset(__cmake_contentNameUpper)
   unset(__cmake_providerCommand)
-  unset(__cmake_original_verify_setting)
+  unset(__cmake_original_verify_interface_setting)
+  unset(__cmake_original_verify_private_setting)
 
 endmacro()
 
diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake
index 1a7e806..17e2735 100644
--- a/Modules/FindCUDAToolkit.cmake
+++ b/Modules/FindCUDAToolkit.cmake
@@ -524,6 +524,19 @@
 
 **Note**: direct usage of this target by consumers should not be necessary.
 
+.. _`FindCUDAToolkit_bin2c`:
+
+bin2c
+"""""
+
+.. versionadded:: 4.3
+
+A utility that converts binary files to C files containing byte arrays.
+
+Target Created:
+
+- ``CUDA::bin2c``
+
 Result Variables
 ^^^^^^^^^^^^^^^^
 
@@ -693,7 +706,7 @@
         if(NOT $ENV{CUDAHOSTCXX} STREQUAL "")
           get_filename_component(CUDAToolkit_CUDA_HOST_COMPILER $ENV{CUDAHOSTCXX} PROGRAM)
           if(NOT EXISTS ${CUDAToolkit_CUDA_HOST_COMPILER})
-            message(FATAL_ERROR "Could not find compiler set in environment variable CUDAHOSTCXX:\n$ENV{CUDAHOSTCXX}.\n${CUDAToolkit_CUDA_HOST_COMPILER}")
+            message(FATAL_ERROR "Could not find the compiler specified in the environment variable CUDAHOSTCXX:\n$ENV{CUDAHOSTCXX}.\n${CUDAToolkit_CUDA_HOST_COMPILER}")
           endif()
         elseif(CUDAToolkit_CUDA_HOST_COMPILER)
           # We get here if CUDAToolkit_CUDA_HOST_COMPILER was specified by the user or toolchain file.
@@ -709,7 +722,7 @@
             unset(_CUDAToolkit_CUDA_HOST_COMPILER_PATH)
           endif()
           if(NOT EXISTS "${CUDAToolkit_CUDA_HOST_COMPILER}")
-            message(FATAL_ERROR "Could not find compiler set in variable CUDAToolkit_CUDA_HOST_COMPILER:\n  ${CUDAToolkit_CUDA_HOST_COMPILER}")
+            message(FATAL_ERROR "Could not find the compiler specified in the variable CUDAToolkit_CUDA_HOST_COMPILER:\n  ${CUDAToolkit_CUDA_HOST_COMPILER}")
           endif()
           # If the value was cached, update the cache entry with our modifications.
           get_property(_CUDAToolkit_CUDA_HOST_COMPILER_CACHED CACHE CUDAToolkit_CUDA_HOST_COMPILER PROPERTY TYPE)
@@ -1302,7 +1315,7 @@
 
   if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 12.0.0)
     _CUDAToolkit_find_and_add_import_lib(nvJitLink)
-    _CUDAToolkit_find_and_add_import_lib(nvJitLink_static DEPS cudart_static_deps)
+    _CUDAToolkit_find_and_add_import_lib(nvJitLink_static DEPS cudart_static_deps nvptxcompiler_static)
   endif()
 
   if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 12.4.0)
@@ -1486,6 +1499,16 @@
   endif()
 
   _CUDAToolkit_find_and_add_import_lib(OpenCL)
+
+  find_program(CUDA_bin2c_EXECUTABLE
+    NAMES bin2c
+    HINTS ${CUDAToolkit_BIN_DIR}
+    NO_DEFAULT_PATH
+  )
+  if(NOT TARGET CUDA::bin2c AND CUDA_bin2c_EXECUTABLE)
+    add_executable(CUDA::bin2c IMPORTED)
+    set_property(TARGET CUDA::bin2c PROPERTY IMPORTED_LOCATION "${CUDA_bin2c_EXECUTABLE}")
+  endif()
 endif()
 
 if(_CUDAToolkit_Pop_ROOT_PATH)
diff --git a/Modules/FindCurses.cmake b/Modules/FindCurses.cmake
index de79bbb..c93cb86 100644
--- a/Modules/FindCurses.cmake
+++ b/Modules/FindCurses.cmake
@@ -57,7 +57,7 @@
 This module accepts the following variables:
 
 ``CURSES_NEED_NCURSES``
-  Set this variable to ``TRUE`` before calling ``find_package(Curses)`` if the
+  Set this variable to ``TRUE`` before calling ``find_package(Curses)`` if
   the ncurses implementation functionality is specifically required.
 
 ``CURSES_NEED_WIDE``
diff --git a/Modules/FindGLEW.cmake b/Modules/FindGLEW.cmake
index 644b332..6169553 100644
--- a/Modules/FindGLEW.cmake
+++ b/Modules/FindGLEW.cmake
@@ -189,17 +189,17 @@
 
 
 function(__glew_set_find_library_suffix shared_or_static)
-  if((UNIX AND NOT APPLE) AND "${shared_or_static}" MATCHES "SHARED")
+  if((UNIX AND NOT APPLE AND NOT CYGWIN) AND "${shared_or_static}" MATCHES "SHARED")
     set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" PARENT_SCOPE)
-  elseif((UNIX AND NOT APPLE) AND "${shared_or_static}" MATCHES "STATIC")
+  elseif((UNIX AND NOT APPLE AND NOT CYGWIN) AND "${shared_or_static}" MATCHES "STATIC")
     set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" PARENT_SCOPE)
   elseif(APPLE AND "${shared_or_static}" MATCHES "SHARED")
     set(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib;.so" PARENT_SCOPE)
   elseif(APPLE AND "${shared_or_static}" MATCHES "STATIC")
     set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" PARENT_SCOPE)
-  elseif(WIN32 AND MINGW AND "${shared_or_static}" MATCHES "SHARED")
+  elseif((WIN32 AND MINGW OR CYGWIN) AND "${shared_or_static}" MATCHES "SHARED")
     set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll.a" PARENT_SCOPE)
-  elseif(WIN32 AND MINGW AND "${shared_or_static}" MATCHES "STATIC")
+  elseif((WIN32 AND MINGW OR CYGWIN) AND "${shared_or_static}" MATCHES "STATIC")
     set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" PARENT_SCOPE)
   elseif(WIN32 AND "${shared_or_static}" MATCHES "SHARED")
     set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" PARENT_SCOPE)
diff --git a/Modules/FindHDF5.cmake b/Modules/FindHDF5.cmake
index 380b9fa..0a15557 100644
--- a/Modules/FindHDF5.cmake
+++ b/Modules/FindHDF5.cmake
@@ -683,7 +683,16 @@
         if(HDF5_FIND_DEBUG)
             message(STATUS "Found HDF5 at ${HDF5_DIR} via NO_MODULE. Now trying to extract locations etc.")
         endif()
-        set(HDF5_IS_PARALLEL ${HDF5_ENABLE_PARALLEL})
+        # Extract information from imported targets
+        if (DEFINED HDF5_ENABLE_PARALLEL)
+          # Versions of <2.0.0 use `HDF5_ENABLE_PARALLEL`
+          set(HDF5_IS_PARALLEL ${HDF5_ENABLE_PARALLEL})
+        elseif(DEFINED HDF5_PROVIDES_PARALLEL)
+          # Versions of >=2.0.0 use `HDF5_PROVIDES_PARALLEL`
+          set(HDF5_IS_PARALLEL ${HDF5_PROVIDES_PARALLEL})
+        else()
+          set(HDF5_IS_PARALLEL NONE)
+        endif()
         set(HDF5_INCLUDE_DIRS ${HDF5_INCLUDE_DIR})
         set(HDF5_LIBRARIES)
         if (NOT TARGET hdf5 AND NOT TARGET hdf5-static AND NOT TARGET hdf5-shared)
diff --git a/Modules/FindLATEX.cmake b/Modules/FindLATEX.cmake
index 4400a05..7db4fc6 100644
--- a/Modules/FindLATEX.cmake
+++ b/Modules/FindLATEX.cmake
@@ -55,7 +55,7 @@
   Finds the DVIPDF converter.
 
 ``PS2PDF``
-  Finds the the PS2PDF converter.
+  Finds the PS2PDF converter.
 
 ``PDFTOPS``
   Finds the PDF-to-PostScript converter.
diff --git a/Modules/FindLibLZMA.cmake b/Modules/FindLibLZMA.cmake
index 4a39d2c..95d2692 100644
--- a/Modules/FindLibLZMA.cmake
+++ b/Modules/FindLibLZMA.cmake
@@ -6,7 +6,7 @@
 -----------
 
 Finds the liblzma, a data compression library that implements the LZMA
-(Lempel–Ziv–Markov chain algorithm):
+(Lempel-Ziv-Markov chain algorithm):
 
 .. code-block:: cmake
 
diff --git a/Modules/FindLibXml2.cmake b/Modules/FindLibXml2.cmake
index 67d20e4..05d198b 100644
--- a/Modules/FindLibXml2.cmake
+++ b/Modules/FindLibXml2.cmake
@@ -53,6 +53,14 @@
 ``LIBXML2_DEFINITIONS``
   The compiler switches required for using libxml2.
 
+Other Variables
+^^^^^^^^^^^^^^^
+
+``LibXml2_USE_STATIC_LIBS``
+  .. versionadded:: 4.3
+
+  Set to ``TRUE`` to use static libraries.  Default is ``FALSE``.
+
 Cache Variables
 ^^^^^^^^^^^^^^^
 
@@ -120,12 +128,27 @@
   set(LIBXML2_LIBRARY ${LIBXML2_LIBRARIES})
 endif()
 
+# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
+if(LibXml2_USE_STATIC_LIBS)
+  set(_libxml2_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+  if(WIN32)
+    list(INSERT CMAKE_FIND_LIBRARY_SUFFIXES 0 .lib .a)
+  else()
+    set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
+  endif()
+endif()
+
 find_library(LIBXML2_LIBRARY NAMES xml2 libxml2 libxml2_a
    HINTS
    ${PC_LIBXML_LIBDIR}
    ${PC_LIBXML_LIBRARY_DIRS}
    )
 
+# Restore the original find library ordering
+if(LibXml2_USE_STATIC_LIBS)
+  set(CMAKE_FIND_LIBRARY_SUFFIXES ${_libxml2_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
+endif()
+
 find_program(LIBXML2_XMLLINT_EXECUTABLE xmllint)
 # for backwards compat. with KDE 4.0.x:
 set(XMLLINT_EXECUTABLE "${LIBXML2_XMLLINT_EXECUTABLE}")
diff --git a/Modules/FindLua.cmake b/Modules/FindLua.cmake
index 33fd8fd..d37ad81 100644
--- a/Modules/FindLua.cmake
+++ b/Modules/FindLua.cmake
@@ -16,6 +16,9 @@
 .. versionadded:: 3.18
   Support for Lua 5.4.
 
+.. versionadded:: 4.3
+  Support for Lua 5.5.
+
 When working with Lua, its library headers are intended to be included in
 project source code as:
 
@@ -144,7 +147,7 @@
 
 # this is a function only to have all the variables inside go away automatically
 function(_lua_get_versions)
-    set(LUA_VERSIONS5 5.4 5.3 5.2 5.1 5.0)
+    set(LUA_VERSIONS5 5.5 5.4 5.3 5.2 5.1 5.0)
 
     if (Lua_FIND_VERSION_EXACT)
         if (Lua_FIND_VERSION_COUNT GREATER 1)
@@ -214,11 +217,11 @@
   file(STRINGS "${_hdr_file}" lua_version_strings
        REGEX "^#define[ \t]+LUA_(RELEASE[ \t]+\"Lua [0-9]|VERSION([ \t]+\"Lua [0-9]|_[MR])).*")
 
-  string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MAJOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" Lua_VERSION_MAJOR ";${lua_version_strings};")
+  string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MAJOR(_N)?[ \t]+\"?([0-9])\"?[ \t]*;.*" "\\2" Lua_VERSION_MAJOR ";${lua_version_strings};")
 
   if (Lua_VERSION_MAJOR MATCHES "^[0-9]+$")
-    string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MINOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" Lua_VERSION_MINOR ";${lua_version_strings};")
-    string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_RELEASE[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" Lua_VERSION_PATCH ";${lua_version_strings};")
+    string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MINOR(_N)?[ \t]+\"?([0-9])\"?[ \t]*;.*" "\\2" Lua_VERSION_MINOR ";${lua_version_strings};")
+    string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_RELEASE(_N)?[ \t]+\"?([0-9])\"?[ \t]*;.*" "\\2" Lua_VERSION_PATCH ";${lua_version_strings};")
     set(Lua_VERSION "${Lua_VERSION_MAJOR}.${Lua_VERSION_MINOR}.${Lua_VERSION_PATCH}")
   else ()
     string(REGEX REPLACE ".*;#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" Lua_VERSION ";${lua_version_strings};")
diff --git a/Modules/FindMatlab.cmake b/Modules/FindMatlab.cmake
index 8acc6f3..231700a 100644
--- a/Modules/FindMatlab.cmake
+++ b/Modules/FindMatlab.cmake
@@ -5,308 +5,767 @@
 FindMatlab
 ----------
 
-Finds Matlab or Matlab Compiler Runtime (MCR) and provides Matlab tools,
+Finds MATLAB or MATLAB Compiler Runtime (MCR) and provides its tools,
 libraries and compilers to CMake:
 
 .. code-block:: cmake
 
-  find_package(Matlab [<version>] [COMPONENTS <components>...] [...])
+  find_package(Matlab [<version>] [COMPONENTS <components>...] [REGISTRY_VIEW <view>] [...])
 
-This package primary purpose is to find the libraries associated with Matlab
-or the MCR in order to be able to build Matlab extensions (mex files). It
-can also be used:
+The primary purpose of this module is to find the libraries associated with
+MATLAB or the MCR in order to be able to build MATLAB extensions (MEX files).
+It can also be used:
 
-* to run specific commands in Matlab in case Matlab is available
-* for declaring Matlab unit test
-* to retrieve various information from Matlab (mex extensions, versions and
+* to run specific commands in MATLAB in case MATLAB is available
+* for declaring MATLAB unit tests
+* to retrieve various information from MATLAB (MEX extensions, versions and
   release queries, ...)
 
 .. versionadded:: 3.12
-  Added Matlab Compiler Runtime (MCR) support.
-
-The module supports the following components:
-
-* ``ENG_LIBRARY`` and ``MAT_LIBRARY``: respectively the ``ENG`` and ``MAT``
-  libraries of Matlab
-* ``MAIN_PROGRAM`` the Matlab binary program. Note that this component is not
-  available on the MCR version, and will yield an error if the MCR is found
-  instead of the regular Matlab installation.
-* ``MEX_COMPILER`` the MEX compiler.
-* ``MCC_COMPILER`` the MCC compiler, included with the Matlab Compiler add-on.
-* ``SIMULINK`` the Simulink environment.
-
-.. versionadded:: 3.7
-  Added the ``MAT_LIBRARY`` component.
-
-.. versionadded:: 3.13
-  Added the ``ENGINE_LIBRARY``, ``DATAARRAY_LIBRARY`` and ``MCC_COMPILER``
-  components.
-
-.. versionchanged:: 3.14
-  Removed the ``MX_LIBRARY``, ``ENGINE_LIBRARY`` and ``DATAARRAY_LIBRARY``
-  components.  These libraries are found unconditionally.
+  MATLAB Compiler Runtime (MCR) support.
 
 .. versionadded:: 3.30
-  Added support for specifying a version range to :command:`find_package` and
-  added support for specifying ``REGISTRY_VIEW`` to :command:`find_package`,
+  Support for specifying a version range to :command:`find_package`,
+  support for specifying ``REGISTRY_VIEW`` argument to
+  :command:`find_package`,
   :command:`matlab_extract_all_installed_versions_from_registry` and
-  :command:`matlab_get_all_valid_matlab_roots_from_registry`. The default
-  behavior remained unchanged, by using the registry view ``TARGET``.
+  :command:`matlab_get_all_valid_matlab_roots_from_registry` commands.
+  The default behavior remained unchanged, by using the registry view
+  ``TARGET``.
 
 .. note::
 
-  The version given to the :command:`find_package` directive is the Matlab
-  **version**, which should not be confused with the Matlab *release* name
-  (e.g. `R2023b`).
-  The :command:`matlab_get_version_from_release_name` and
-  :command:`matlab_get_release_name_from_version` provide a mapping
-  between the release name and the version.
+  The version given to the :command:`find_package` argument is the MATLAB
+  *version*, which should not be confused with the MATLAB *release name*
+  (e.g. ``R2023b``).  The :command:`matlab_get_version_from_release_name`
+  and :command:`matlab_get_release_name_from_version` commands provide a
+  mapping between the release name and the version.
 
-The variable :variable:`Matlab_ROOT_DIR` may be specified in order to give
-the path of the desired Matlab version. Otherwise, the behavior is platform
-specific:
+Components
+^^^^^^^^^^
 
-* Windows: The installed versions of Matlab/MCR are retrieved from the
-  Windows registry. The ``REGISTRY_VIEW`` argument may optionally be specified
-  to manually control whether 32bit or 64bit versions shall be searched for.
-* macOS: The installed versions of Matlab/MCR are given by the MATLAB
-  default installation paths under ``$HOME/Applications`` and ``/Applications``.
-  If no such application is found, it falls back to the one that might be
-  accessible from the ``PATH``.
-* Unix: The desired Matlab should be accessible from the ``PATH``. This does
-  not work for MCR installation and :variable:`Matlab_ROOT_DIR` should be
-  specified on this platform.
+This module supports optional components which can be specified using the
+:command:`find_package` command:
 
-Additional information is provided when :variable:`MATLAB_FIND_DEBUG` is set.
-When a Matlab/MCR installation is found automatically and the ``MATLAB_VERSION``
-is not given, the version is queried from Matlab directly (on Windows this
-may pop up a Matlab window) or from the MCR installation.
+.. code-block:: cmake
 
-The mapping of the release names and the version of Matlab is performed by
-defining pairs (name, version).  The variable
-:variable:`MATLAB_ADDITIONAL_VERSIONS` may be provided before the call to
-the :command:`find_package` in order to handle additional versions.
+  find_package(Matlab [COMPONENTS <components>...])
 
-A Matlab scripts can be added to the set of tests using the
-:command:`matlab_add_unit_test`. By default, the Matlab unit test framework
-will be used (>= 2013a) to run this script, but regular ``.m`` files
-returning an exit code can be used as well (0 indicating a success).
+Supported components include:
 
-Module Input Variables
-^^^^^^^^^^^^^^^^^^^^^^
+``ENG_LIBRARY``
+  .. versionadded:: 3.3
 
-Users or projects may set the following variables to configure the module
-behavior:
+  Finds the ``ENG`` library of MATLAB.
 
-:variable:`Matlab_ROOT <<PackageName>_ROOT>`
-  .. versionadded:: 3.25
+``MAT_LIBRARY``
+  .. versionadded:: 3.7
 
-  Default value for :variable:`Matlab_ROOT_DIR`, the root of the Matlab
-  installation.
+  Finds the ``MAT`` library of MATLAB.
 
-:variable:`Matlab_ROOT_DIR`
-  The root of the Matlab installation.
+``MAIN_PROGRAM``
+  .. versionadded:: 3.3
 
-:variable:`MATLAB_FIND_DEBUG`
-  outputs debug information
+  Finds the MATLAB binary program.  Note that this component is not
+  available on the MCR version, and will yield an error if the MCR is found
+  instead of the regular MATLAB installation.
 
-:variable:`MATLAB_ADDITIONAL_VERSIONS`
-  additional versions of Matlab for the automatic retrieval of the installed
-  versions.
+``MEX_COMPILER``
+  .. versionadded:: 3.3
+
+  Finds the MEX compiler.
+
+``MCC_COMPILER``
+  .. versionadded:: 3.13
+
+  Finds the MCC compiler, included with the MATLAB Compiler add-on.
+
+``SIMULINK``
+  .. versionadded:: 3.3
+
+  Finds the Simulink environment.
+
+Implicitly Found Components
+"""""""""""""""""""""""""""
+
+The following components are always found unconditionally, without needing
+to be specified explicitly:
+
+``MX_LIBRARY``
+  .. versionchanged:: 3.14
+    This component has been removed and is now always found unconditionally.
+
+  .. versionadded:: 3.3
+
+  Finds the MATLAB mx library.
+
+``ENGINE_LIBRARY``
+  .. versionchanged:: 3.14
+    This component has been removed and is now always found unconditionally.
+
+  .. versionadded:: 3.13
+
+  Finds the MATLAB engine library.
+
+``DATAARRAY_LIBRARY``
+  .. versionchanged:: 3.14
+    This component has been removed and is now always found unconditionally.
+
+  .. versionadded:: 3.13
+
+  Finds the C++ MATLAB data array library.
+
+If no components are specified, the module looks for the ``MX_LIBRARY``,
+``ENGINE_LIBRARY``, and ``DATAARRAY_LIBRARY`` by default.
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
-.. versionadded:: 3.22
-
-This module defines the following :prop_tgt:`IMPORTED` targets:
+This module provides the following :ref:`Imported Targets`:
 
 ``Matlab::mex``
-  The ``mex`` library, always available for MATLAB installations. Available for
-  MCR installations if provided by MCR.
+  .. versionadded:: 3.22
+
+  Target encapsulating the ``mex`` library usage requirements, always
+  available for MATLAB installations.  Available for MCR installations if
+  provided by MCR.
 
 ``Matlab::mx``
-  The mx library of Matlab (arrays), always available for MATLAB installations.
-  Available for MCR installations if provided by MCR.
+  .. versionadded:: 3.22
+
+  Target encapsulating the usage requirements of the mx library of MATLAB
+  (arrays), always available for MATLAB installations.  Available for MCR
+  installations if provided by MCR.
 
 ``Matlab::eng``
-  Matlab engine library. Available only if the ``ENG_LIBRARY`` component
-  is requested.
+  .. versionadded:: 3.22
+
+  Target encapsulating the MATLAB engine library usage requirements.
+  Available only if the ``ENG_LIBRARY`` component is requested.
 
 ``Matlab::mat``
-  Matlab matrix library. Available only if the ``MAT_LIBRARY`` component
-  is requested.
+  .. versionadded:: 3.22
+
+  Target encapsulating the MATLAB matrix library usage requirements.
+  Available only if the ``MAT_LIBRARY`` component is requested.
 
 ``Matlab::MatlabEngine``
-  Matlab C++ engine library, always available for MATLAB R2018a and newer.
-  Available for MCR installations if provided by MCR.
+  .. versionadded:: 3.22
+
+  Target encapsulating the MATLAB C++ engine library usage requirements,
+  always available for MATLAB R2018a and newer.  Available for MCR
+  installations if provided by MCR.
 
 ``Matlab::MatlabDataArray``
-  Matlab C++ data array library, always available for MATLAB R2018a and newer.
-  Available for MCR installations if provided by MCR.
+  .. versionadded:: 3.22
 
-Variables defined by the module
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  Target encapsulating the MATLAB C++ data array library usage requirements,
+  always available for MATLAB R2018a and newer.  Available for MCR
+  installations if provided by MCR.
 
-Result variables
-""""""""""""""""
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
 
 ``Matlab_FOUND``
   .. versionadded:: 3.3
 
-  Boolean indicating whether the (requested version of) Matlab installation
-  was found.  All variables below are defined if Matlab is found.
+  Boolean indicating whether the (requested version of) MATLAB installation
+  was found.  All variables below are defined if MATLAB is found.
 
 ``Matlab_VERSION``
   .. versionadded:: 3.27
 
-  the numerical version (e.g. 23.2.0) of Matlab found. Not to be confused with
-  Matlab release name (e.g. R2023b) that can be obtained with
-  :command:`matlab_get_release_name_from_version`.
+  The numerical version (e.g. ``23.2.0``) of MATLAB found.  Not to be
+  confused with MATLAB release name (e.g. ``R2023b``) that can be obtained
+  with :command:`matlab_get_release_name_from_version`.
+
+  When a MATLAB/MCR installation is found automatically and the
+  ``Matlab_VERSION`` is not given, the version is queried from MATLAB
+  directly (on Windows this may pop up a MATLAB window) or from the MCR
+  installation.
+
 ``Matlab_ROOT_DIR``
-  the final root of the Matlab installation determined by the FindMatlab
-  module.
+  .. versionadded:: 3.3
+
+  The final root of the MATLAB installation determined by this module.
+
 ``Matlab_MAIN_PROGRAM``
-  the Matlab binary program. Available only if the component ``MAIN_PROGRAM``
-  is given in the :command:`find_package` directive.
+  .. versionadded:: 3.3
+
+  The MATLAB binary program.  Available only if the component ``MAIN_PROGRAM``
+  is given in the :command:`find_package` argument.
+
 ``Matlab_INCLUDE_DIRS``
- the path of the Matlab libraries headers
+  .. versionadded:: 3.3
+
+  The path of the MATLAB libraries headers.
+
 ``Matlab_MEX_LIBRARY``
-  library for mex, always available for MATLAB installations. Available for MCR
-  installations if provided by MCR.
+  Library for MEX, always available for MATLAB installations.  Available
+  for MCR installations if provided by MCR.
+
 ``Matlab_MX_LIBRARY``
-  mx library of Matlab (arrays), always available for MATLAB installations.
-  Available for MCR installations if provided by MCR.
+  The mx library of MATLAB (arrays), always available for MATLAB
+  installations.  Available for MCR installations if provided by MCR.
+
 ``Matlab_ENG_LIBRARY``
-  Matlab engine library. Available only if the component ``ENG_LIBRARY``
+  MATLAB engine library.  Available only if the component ``ENG_LIBRARY``
   is requested.
+
 ``Matlab_MAT_LIBRARY``
-  Matlab matrix library. Available only if the component ``MAT_LIBRARY``
+  .. versionadded:: 3.7
+
+  Matlab matrix library.  Available only if the component ``MAT_LIBRARY``
   is requested.
+
 ``Matlab_ENGINE_LIBRARY``
   .. versionadded:: 3.13
 
   Matlab C++ engine library, always available for MATLAB R2018a and newer.
   Available for MCR installations if provided by MCR.
+
 ``Matlab_DATAARRAY_LIBRARY``
   .. versionadded:: 3.13
 
-  Matlab C++ data array library, always available for MATLAB R2018a and newer.
-  Available for MCR installations if provided by MCR.
+  Matlab C++ data array library, always available for MATLAB R2018a and
+  newer.  Available for MCR installations if provided by MCR.
+
 ``Matlab_LIBRARIES``
-  the whole set of libraries of Matlab
+  The whole set of libraries of MATLAB.
+
 ``Matlab_MEX_COMPILER``
-  the mex compiler of Matlab. Currently not used.
-  Available only if the component ``MEX_COMPILER`` is requested.
+  .. versionadded:: 3.3
+
+  The MEX compiler of MATLAB.  Currently not used.  Available only if the
+  component ``MEX_COMPILER`` is requested.
+
 ``Matlab_MCC_COMPILER``
   .. versionadded:: 3.13
 
-  the mcc compiler of Matlab. Included with the Matlab Compiler add-on.
+  The mcc compiler of MATLAB.  Included with the MATLAB Compiler add-on.
   Available only if the component ``MCC_COMPILER`` is requested.
 
-Cached variables
-""""""""""""""""
+Cache Variables
+^^^^^^^^^^^^^^^
+
+The following cache variables may also be set:
 
 ``Matlab_MEX_EXTENSION``
-  the extension of the mex files for the current platform (given by Matlab).
+  .. versionadded:: 3.3
+
+  The extension of the MEX files for the current platform (given by MATLAB).
+
 ``Matlab_ROOT_DIR``
-  the location of the root of the Matlab installation found. If this value
+  .. versionadded:: 3.3
+
+  The location of the root of the MATLAB installation found.  If this value
   is changed by the user, the result variables are recomputed.
 
-Provided commands
-^^^^^^^^^^^^^^^^^
+Input Variables
+^^^^^^^^^^^^^^^
 
-:command:`matlab_get_version_from_release_name`
-  returns the version from the Matlab release name
-:command:`matlab_get_release_name_from_version`
-  returns the release name from the Matlab version
-:command:`matlab_add_mex`
-  adds a target compiling a MEX file.
-:command:`matlab_add_unit_test`
-  adds a Matlab unit test file as a test to the project.
-:command:`matlab_extract_all_installed_versions_from_registry`
-  parses the registry for all Matlab versions. Available on Windows only.
-  The part of the registry parsed is dependent on the host processor
-:command:`matlab_get_all_valid_matlab_roots_from_registry`
-  returns all the possible Matlab or MCR paths, according to a previously
-  given list. Only the existing/accessible paths are kept. This is mainly
-  useful for the searching all possible Matlab installation.
-:command:`matlab_get_mex_suffix`
-  returns the suffix to be used for the mex files
-  (platform/architecture dependent)
-:command:`matlab_get_version_from_matlab_run`
-  returns the version of Matlab/MCR, given the full directory of the Matlab/MCR
-  installation path.
+Users or projects may set the following variables to configure the module
+behavior before calling ``find_package(Matlab)``:
 
+:variable:`Matlab_ROOT <<PackageName>_ROOT>`
+  .. versionadded:: 3.25
 
-Known issues
-^^^^^^^^^^^^
+  Default value for the ``Matlab_ROOT_DIR`` variable, the root of the
+  MATLAB installation.
 
-**Symbol clash in a MEX target**
-  By default, every symbols inside a MEX
-  file defined with the command :command:`matlab_add_mex` have hidden
-  visibility, except for the entry point. This is the default behavior of
-  the MEX compiler, which lowers the risk of symbol collision between the
-  libraries shipped with Matlab, and the libraries to which the MEX file is
-  linking to. This is also the default on Windows platforms.
+``Matlab_ROOT_DIR``
+  .. versionadded:: 3.3
 
-  However, this is not sufficient in certain case, where for instance your
-  MEX file is linking against libraries that are already loaded by Matlab,
-  even if those libraries have different SONAMES.
-  A possible solution is to hide the symbols of the libraries to which the
-  MEX target is linking to. This can be achieved in GNU GCC compilers with
-  the linker option ``-Wl,--exclude-libs,ALL``.
+  The root folder of the MATLAB installation.  If set before the call to
+  :command:`find_package`, the module will look for the components in that
+  path.  If not set, then an automatic search of MATLAB will be performed.
+  If set, it should point to a valid version of MATLAB.
 
-**Tests using GPU resources**
-  in case your MEX file is using the GPU and
-  in order to be able to run unit tests on this MEX file, the GPU resources
-  should be properly released by Matlab. A possible solution is to make
-  Matlab aware of the use of the GPU resources in the session, which can be
-  performed by a command such as ``D = gpuDevice()`` at the beginning of
-  the test script (or via a fixture).
+  This variable may be specified in order to give the path of the desired
+  MATLAB version.  Otherwise, the behavior is platform specific:
 
+  * Windows: The installed versions of MATLAB/MCR are retrieved from the
+    Windows registry.  The ``REGISTRY_VIEW`` argument may optionally be
+    specified to manually control whether 32bit or 64bit versions shall be
+    searched for.
+  * macOS: The installed versions of MATLAB/MCR are given by the MATLAB
+    default installation paths under ``$HOME/Applications`` and
+    ``/Applications``.  If no such application is found, it falls back to
+    the one that might be accessible from the ``PATH``.
+  * Unix: The desired MATLAB should be accessible from the ``PATH``.  This
+    does not work for MCR installation and ``Matlab_ROOT_DIR`` should be
+    specified on this platform.
 
-Reference
-^^^^^^^^^
+``MATLAB_FIND_DEBUG``
+  .. versionadded:: 3.3
 
-.. variable:: Matlab_ROOT_DIR
+  If set to a boolean true, additional debug information is outputted to
+  the console, such as the lookup of MATLAB and the intermediate
+  configuration steps.
 
-   The root folder of the Matlab installation. If set before the call to
-   :command:`find_package`, the module will look for the components in that
-   path. If not set, then an automatic search of Matlab
-   will be performed. If set, it should point to a valid version of Matlab.
+``MATLAB_ADDITIONAL_VERSIONS``
+  .. versionadded:: 3.3
 
-.. variable:: MATLAB_FIND_DEBUG
+  If set, it specifies additional versions of MATLAB for the automatic
+  retrieval of the installed versions that may be handled and looked for.
 
-   If set, the lookup of Matlab and the intermediate configuration steps are
-   outputted to the console.
-
-.. variable:: MATLAB_ADDITIONAL_VERSIONS
-
-  If set, specifies additional versions of Matlab that may be looked for.
-  The variable should be a list of strings, organized by pairs of release
-  name and versions, such as follows:
+  The mapping of the release names and the version of MATLAB is performed
+  by defining pairs (name, version).  The variable should be a list of
+  strings, organized by pairs of release name and versions, such as
+  follows:
 
   .. code-block:: cmake
 
-    set(MATLAB_ADDITIONAL_VERSIONS
+    set(
+      MATLAB_ADDITIONAL_VERSIONS
         "release_name1=corresponding_version1"
         "release_name2=corresponding_version2"
-        ...
-        )
+        # ...
+    )
+
+    find_package(Matlab)
 
   Example:
 
   .. code-block:: cmake
 
-    set(MATLAB_ADDITIONAL_VERSIONS
+    set(
+      MATLAB_ADDITIONAL_VERSIONS
         "R2013b=8.2"
         "R2013a=8.1"
-        "R2012b=8.0")
+        "R2012b=8.0"
+        # ...
+    )
 
-  The order of entries in this list matters when several versions of
-  Matlab are installed. The priority is set according to the ordering in
-  this list.
+    find_package(Matlab)
+
+  The order of entries in this list matters when several versions of MATLAB
+  are installed.  The priority is set according to the ordering in this
+  list.
+
+Commands
+^^^^^^^^
+
+This module provides the following commands:
+
+* :command:`matlab_get_version_from_release_name`
+* :command:`matlab_get_release_name_from_version`
+* :command:`matlab_get_version_from_matlab_run`
+* :command:`matlab_extract_all_installed_versions_from_registry`
+* :command:`matlab_get_all_valid_matlab_roots_from_registry`
+* :command:`matlab_add_mex`
+* :command:`matlab_get_mex_suffix`
+* :command:`matlab_add_unit_test`
+
+.. command:: matlab_get_version_from_release_name
+
+  .. versionadded:: 3.3
+
+  Returns the version of MATLAB from a release name:
+
+  .. code-block:: cmake
+
+    matlab_get_version_from_release_name(<release-name> <version-var>)
+
+  The arguments are:
+
+  ``<release-name>``
+    Input release name string (e.g. ``R2023b``).
+
+  ``<version-var>``
+    The name of the variable in which to store the version of MATLAB.  The
+    output result is e.g. ``23.2.0``.
+
+  .. note::
+
+    This command provides correct versions mappings for MATLAB but not MCR.
+
+.. command:: matlab_get_release_name_from_version
+
+  .. versionadded:: 3.3
+
+  Returns the release name from the version of MATLAB:
+
+  .. code-block:: cmake
+
+    matlab_get_release_name_from_version(<version> <release-name-var>)
+
+  The arguments are:
+
+  ``<version>``
+    Input MATLAB version string (e.g. ``23.2.0``).
+
+  ``<release-name-var>``
+    The name of the variable in which to store the MATLAB release name.  The
+    output result is e.g. ``R2023b``.
+
+  .. note::
+
+    This command provides correct version mappings for MATLAB but not MCR.
+
+.. command:: matlab_get_version_from_matlab_run
+
+  .. versionadded:: 3.3
+
+  Runs the specified MATLAB program and extracts the version of MATLAB/MCR,
+  given the full directory of the MATLAB/MCR installation path:
+
+  .. code-block:: cmake
+
+    matlab_get_version_from_matlab_run(<matlab-binary> <matlab-versions-var>)
+
+  The arguments are:
+
+  ``<matlab-binary>``
+    The path to the ``matlab`` binary executable.
+
+  ``<matlab-versions-var>``
+    The name of the variable in which a list of extracted MATLAB versions
+    are stored.
+
+  If the path provided for the MATLAB installation points to an MCR
+  installation, the version is extracted from the installed files.
+
+.. command:: matlab_extract_all_installed_versions_from_registry
+
+  .. versionadded:: 3.3
+
+  Parses the Windows registry and finds all installed MATLAB versions:
+
+  .. signature::
+    matlab_extract_all_installed_versions_from_registry(<versions-var>
+      [REGISTRY_VIEW <view>])
+    :target: matlab_extract_all_installed_versions_from_registry-keyword
+
+  The arguments are:
+
+  ``<versions-var>``
+    The name of the variable in which to store the list of all MATLAB
+    versions found.
+
+  ``REGISTRY_VIEW <view>``
+    .. versionadded:: 3.30
+
+    Optional registry view argument that provides a more precise interface
+    on how to interact with the Windows Registry.  The argument is passed
+    (or omitted) to :command:`cmake_host_system_information` without
+    further checks or modification.  For example, ``<view>`` value can be
+    one of ``64``, ``32``, ``64_32``, ``32_64``, ``HOST``, ``TARGET``,
+    ``BOTH``.
+
+  The old signature is:
+
+  .. signature::
+    matlab_extract_all_installed_versions_from_registry(<win64> <versions-var>)
+    :target: matlab_extract_all_installed_versions_from_registry-positional
+
+  The arguments are:
+
+  ``<win64>``
+    Boolean whether to search for the 64-bit version of MATLAB.  If set
+    to boolean true, 64-bit registry view will be searched.  If set to
+    boolean false, 32-bit registry view will be searched.  For finer
+    control, use the above signature.
+
+  ``<versions-var>``
+    The name of the variable in which to store the list of all MATLAB
+    versions found.
+
+  This command is available on Windows only.  The part of the registry
+  parsed is dependent on the host processor.
+
+  The returned list contains all versions under
+  ``HKLM\SOFTWARE\Mathworks\MATLAB``,
+  ``HKLM\SOFTWARE\Mathworks\MATLAB Runtime`` and
+  ``HKLM\SOFTWARE\Mathworks\MATLAB Compiler Runtime`` or an empty list in
+  case an error occurred (or nothing found).
+
+  .. note::
+
+    Only the versions are provided.  No check is made over the existence of
+    the installation referenced in the registry.
+
+.. command:: matlab_get_all_valid_matlab_roots_from_registry
+
+  .. versionadded:: 3.3
+
+  Returns all the possible MATLAB or MCR paths, according to a previously
+  given list:
+
+  .. code-block:: cmake
+
+    matlab_get_all_valid_matlab_roots_from_registry(
+      <matlab-versions>
+      <matlab-roots-var>
+      [REGISTRY_VIEW <view>]
+    )
+
+  This command populates the MATLAB root with valid versions of MATLAB or
+  MATLAB Runtime (MCR) and is mainly useful for the searching of all
+  possible MATLAB installations.  Only the existing/accessible paths are
+  kept.
+
+  The arguments are:
+
+  ``<matlab-versions>``
+    A :ref:`semicolon-separated list <CMake Language Lists>` of each of the
+    MATLAB or MCR installations.  Specify it as a single string value.
+
+  ``<matlab-roots-var>``
+    The name of the variable in which to store a list of locations of each
+    of the MATLAB or MCR installations.
+
+    The value of this variable is organized in triplets
+    ``(type,version_number,matlab_root_path)``, where ``type`` indicates
+    either ``MATLAB`` or ``MCR``.
+
+  ``REGISTRY_VIEW <view>``
+    .. versionadded:: 3.30
+
+    Optional registry view argument that provides a more precise interface
+    on how to interact with the Windows Registry.  The argument is passed
+    (or omitted) to :command:`cmake_host_system_information` without
+    further checks or modification.  For example, ``<view>`` value can be
+    one of ``64``, ``32``, ``64_32``, ``32_64``, ``HOST``, ``TARGET``,
+    ``BOTH``.
+
+.. command:: matlab_add_mex
+
+  .. versionadded:: 3.3
+
+  Adds a target that compiles MATLAB MEX target file:
+
+  .. code-block:: cmake
+
+    matlab_add_mex(
+      NAME <name>
+      [EXECUTABLE | MODULE | SHARED]
+      SRC <sources>...
+      [OUTPUT_NAME <output-name>]
+      [DOCUMENTATION <file>]
+      [LINK_TO <targets>...]
+      [R2017b | R2018a]
+      [EXCLUDE_FROM_ALL]
+      [NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES]
+      [...]
+    )
+
+  This commands compiles the given sources with the current tool-chain in
+  order to produce a MEX file.  The final name of the produced output may
+  be specified, as well as additional link libraries, and a documentation
+  entry for the MEX file.  Remaining arguments of the call are passed to
+  the :command:`add_library` or :command:`add_executable` command.
+
+  The arguments are:
+
+  ``NAME <name>``
+    The name of the target.
+
+  ``SRC <sources>...``
+    One or more source files to be compiled.
+
+  ``LINK_TO <targets>...``
+    A list of additional link dependencies.  The target links to ``libmex``
+    and ``libmx`` by default, unless the
+    ``NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES`` option is passed.
+
+  ``OUTPUT_NAME <output-name>``
+    If given, overrides the default name.  The default name is the name of
+    the target without any prefix and with ``Matlab_MEX_EXTENSION`` suffix.
+
+  ``DOCUMENTATION <file>``
+    If given, the ``<file>`` will be considered as being the documentation
+    file for the MEX file.  This file is copied into the same folder without
+    any processing, with the same name as the final MEX file, and with
+    extension ``.m``.  In that case, typing ``help <name>`` in MATLAB
+    prints the documentation contained in this file.
+
+    The documentation file is not processed and should be in the following
+    format:
+
+    .. code-block:: matlab
+
+      % This is the documentation
+      function ret = mex_target_output_name(input1)
+
+  ``R2017b`` or ``R2018a``
+    .. versionadded:: 3.14
+
+    May be given to specify the version of the C API
+    to use: ``R2017b`` specifies the traditional (separate complex) C API,
+    and corresponds to the ``-R2017b`` flag for the ``mex`` command.
+    ``R2018a`` specifies the new interleaved complex C API, and corresponds
+    to the ``-R2018a`` flag for the ``mex`` command.  Ignored for MATLAB
+    versions prior to R2018a.  Defaults to ``R2017b``.
+
+  ``MODULE`` or ``SHARED``
+    .. versionadded:: 3.7
+
+    May be given to specify the type of library to be created.
+
+  ``EXECUTABLE``
+    .. versionadded:: 3.7
+
+    May be given to create an executable instead of a library.  If no type
+    is given explicitly, the default type is ``SHARED``.
+
+  ``EXCLUDE_FROM_ALL``
+    This option has the same meaning as the :prop_tgt:`EXCLUDE_FROM_ALL`
+    target property and is forwarded to the :command:`add_library`, or
+    :command:`add_executable` command.
+
+  ``NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES``
+    .. versionadded:: 3.24
+
+    This option permits to disable the automatic linking of MATLAB
+    libraries, so that only the libraries that are actually required can be
+    linked via the ``LINK_TO`` option.
+
+.. command:: matlab_get_mex_suffix
+
+  .. versionadded:: 3.3
+
+  Returns the extension to be used for the MEX files (the suffix):
+
+  .. code-block:: cmake
+
+    matlab_get_mex_suffix(<matlab-root> <mex-suffix-var>)
+
+  The arguments are:
+
+  ``<matlab-root>``
+    The root of MATLAB/MCR installation.  For example, the value of the
+    ``Matlab_ROOT_DIR`` variable.
+
+  ``<mex-suffix-var>``
+    The name of the variable in which the suffix will be returned.
+
+  This command is platform and architecture dependent.  It should not be
+  called before the appropriate MATLAB root has been found.
+
+.. command:: matlab_add_unit_test
+
+  .. versionadded:: 3.3
+
+  Adds a MATLAB unit test file to the project's test set of CMake/CTest:
+
+  .. code-block:: cmake
+
+    matlab_add_unit_test(
+      NAME <name>
+      UNITTEST_FILE <matlab-file-containing-unittest.m>
+      [CUSTOM_TEST_COMMAND <matlab-command-to-run-as-test>]
+      [UNITTEST_PRECOMMAND <matlab-command-to-run>]
+      [TIMEOUT <timeout>]
+      [ADDITIONAL_PATH <paths>...]
+      [MATLAB_ADDITIONAL_STARTUP_OPTIONS <options>...]
+      [TEST_ARGS <args>...]
+      [NO_UNITTEST_FRAMEWORK]
+      [WORKING_DIRECTORY <dir>]
+    )
+
+  By default, the MATLAB unit test framework will be used (>= 2013a) to run
+  the added MATLAB script, but regular ``.m`` files returning an exit code
+  can be used as well (0 indicating a success).
+
+  This command requires the component ``MAIN_PROGRAM`` and hence is not
+  available for an MCR installation.
+
+  The unit test uses the MATLAB unittest framework (default, available
+  starting MATLAB 2013b+) except if the option ``NO_UNITTEST_FRAMEWORK``
+  is given.
+
+  The command expects one MATLAB test script file to be given.
+  In the case ``NO_UNITTEST_FRAMEWORK`` is given, the unittest script file
+  should contain the script to be run, plus an exit command with the exit
+  value.  This exit value will be passed to the ctest framework (0 success,
+  non 0 failure).  Additional arguments accepted by :command:`add_test` can
+  be passed through ``TEST_ARGS`` (e.g. ``CONFIGURATIONS <config> ...``).
+
+  The arguments are:
+
+  ``NAME <name>``
+    The name of the unittest in ctest.
+
+  ``UNITTEST_FILE <matlab-file-containing-unittest.m>``
+    The MATLAB unittest file.  Its path will be automatically added to the
+    MATLAB path.
+
+  ``CUSTOM_TEST_COMMAND <matlab-command-to-run-as-test>``
+    MATLAB script command to run as the test.
+    If this is not set, then the following is run:
+    ``runtests('matlab_file_name'), exit(max([ans(1,:).Failed]))`` where
+    ``matlab_file_name`` is the ``UNITTEST_FILE`` without the extension.
+
+  ``UNITTEST_PRECOMMAND <matlab-command-to-run>``
+    MATLAB script command to be ran before the file
+    containing the test (e.g. GPU device initialization based on CMake
+    variables).
+
+  ``TIMEOUT <timeout>``
+    The test timeout in seconds.  Defaults to 180 seconds as the
+    MATLAB unit test may hang.
+
+  ``ADDITIONAL_PATH <paths>...``
+    A list of paths to add to the MATLAB path prior to running the unit
+    test.
+
+  ``MATLAB_ADDITIONAL_STARTUP_OPTIONS <options>``
+    A list of additional option in order to run MATLAB from the command
+    line.  The ``-nosplash``, ``-nodesktop``, and ``-nodisplay`` options
+    are always added automatically.
+
+  ``TEST_ARGS <args>...``
+    Additional options provided to the add_test command.  These
+    options are added to the default options (e.g. ``CONFIGURATIONS Release``).
+
+  ``NO_UNITTEST_FRAMEWORK``
+    When set, indicates that the test should not
+    use the unittest framework of MATLAB (available for versions >= R2013a).
+
+  ``WORKING_DIRECTORY <dir>``
+    This will be the working directory for the test.  If specified it will
+    also be the output directory used for the log file of the test run.
+    If not specified the temporary directory ``${CMAKE_BINARY_DIR}/Matlab``
+    will be used as the working directory and the log location.
+
+Known Issues
+^^^^^^^^^^^^
+
+**Symbol clash in a MEX target**
+  By default, every symbol inside a MEX
+  file defined with the command :command:`matlab_add_mex` have hidden
+  visibility, except for the entry point.  This is the default behavior of
+  the MEX compiler, which lowers the risk of symbol collision between the
+  libraries shipped with MATLAB, and the libraries to which the MEX file is
+  linking to.  This is also the default on Windows platforms.
+
+  However, this is not sufficient in certain case, where for instance the
+  MEX file is linking against libraries that are already loaded by MATLAB,
+  even if those libraries have different SONAMES.
+  A possible solution is to hide the symbols of the libraries to which the
+  MEX target is linking to.  This can be achieved in GNU GCC compilers with
+  the linker option ``-Wl,--exclude-libs,ALL``.
+
+**Tests using GPU resources**
+  In case the MEX file is using the GPU and in order to be able to run unit
+  tests on this MEX file, the GPU resources should be properly released by
+  MATLAB.  A possible solution is to make MATLAB aware of the use of the
+  GPU resources in the session, which can be performed by a command, such
+  as ``D = gpuDevice()``, at the beginning of the test script (or via a
+  fixture).
+
+Examples
+^^^^^^^^
+
+Finding MATLAB and linking imported target to a project target:
+
+.. code-block:: cmake
+
+  find_package(Matlab)
+  target_link_libraries(example PRIVATE Matlab::mx)
 #]=======================================================================]
 
 cmake_policy(PUSH)
@@ -370,23 +829,7 @@
 
 file(MAKE_DIRECTORY "${_matlab_temporary_folder}")
 
-#[=======================================================================[.rst:
-.. command:: matlab_get_version_from_release_name
-
-  .. code-block:: cmake
-
-    matlab_get_version_from_release_name(release version)
-
-  * Input: ``release`` is the release name (e.g. R2023b)
-  * Output: ``version`` is the version of Matlab (e.g. 23.2.0)
-
-  Returns the version of Matlab from a release name
-
-  .. note::
-
-    This command provides correct versions mappings for Matlab but not MCR.
-
-#]=======================================================================]
+# Public.
 macro(matlab_get_version_from_release_name release_name version_name)
 
   string(REGEX MATCHALL "${release_name}=([0-9]+\\.[0-9]+)" _matched ${MATLAB_VERSIONS_MAPPING})
@@ -401,24 +844,7 @@
 
 endmacro()
 
-
-#[=======================================================================[.rst:
-.. command:: matlab_get_release_name_from_version
-
-  .. code-block:: cmake
-
-    matlab_get_release_name_from_version(version release_name)
-
-  * Input: ``version`` is the version of Matlab (e.g. 23.2.0)
-  * Output: ``release_name`` is the release name (R2023b)
-
-  Returns the release name from the version of Matlab
-
-  .. note::
-
-    This command provides correct version mappings for Matlab but not MCR.
-
-#]=======================================================================]
+# Public.
 function(matlab_get_release_name_from_version version release_name)
 
   # only the major.minor version is used
@@ -435,7 +861,6 @@
 
 endfunction()
 
-
 # extracts all the supported release names (R2022b...) of Matlab
 # internal use
 macro(matlab_get_supported_releases list_releases)
@@ -451,8 +876,6 @@
   unset(_var)
 endmacro()
 
-
-
 # extracts all the supported versions of Matlab
 # internal use
 macro(matlab_get_supported_versions list_versions)
@@ -468,47 +891,7 @@
   unset(_var)
 endmacro()
 
-
-#[=======================================================================[.rst:
-.. command:: matlab_extract_all_installed_versions_from_registry
-
-  This function parses the Windows registry and finds the Matlab versions that
-  are installed. The found versions are stored in a given ``<versions-var>``.
-
-  .. signature::
-    matlab_extract_all_installed_versions_from_registry(<versions-var>
-      [REGISTRY_VIEW view])
-    :target: matlab_extract_all_installed_versions_from_registry-keyword
-
-    .. versionadded:: 3.30
-
-    * Output: ``<versions-var>`` is a list of all the versions of Matlab found
-    * Input: ``REGISTRY_VIEW`` Optional registry view to use for registry
-      interaction. The argument is passed (or omitted) to
-      :command:`cmake_host_system_information` without further checks or
-      modification.
-
-  .. signature::
-    matlab_extract_all_installed_versions_from_registry(<win64> <versions-var>)
-    :target: matlab_extract_all_installed_versions_from_registry-positional
-
-    * Input: ``win64`` is a boolean to search for the 64 bit version of
-      Matlab. Set to ``ON`` to use the 64bit registry view or ``OFF`` to use the
-      32bit registry view. If finer control is needed, see signature above.
-    * Output: ``<versions-var>`` is a list of all the versions of Matlab found
-
-  The returned list contains all versions under
-  ``HKLM\SOFTWARE\Mathworks\MATLAB``,
-  ``HKLM\SOFTWARE\Mathworks\MATLAB Runtime`` and
-  ``HKLM\SOFTWARE\Mathworks\MATLAB Compiler Runtime`` or an empty list in
-  case an error occurred (or nothing found).
-
-  .. note::
-
-    Only the versions are provided. No check is made over the existence of the
-    installation referenced in the registry,
-
-#]=======================================================================]
+# Public.
 function(matlab_extract_all_installed_versions_from_registry win64_or_matlab_versions)
 
   if(NOT CMAKE_HOST_WIN32)
@@ -562,8 +945,6 @@
 
 endfunction()
 
-
-
 # (internal)
 macro(extract_matlab_versions_from_registry_brute_force matlab_versions)
   # get the supported versions
@@ -579,32 +960,7 @@
   set(${matlab_versions} ${matlab_supported_versions})
 endmacro()
 
-
-#[=======================================================================[.rst:
-.. command:: matlab_get_all_valid_matlab_roots_from_registry
-
-  Populates the Matlab root with valid versions of Matlab or
-  Matlab Runtime (MCR).
-  The returned matlab_roots is organized in triplets
-  ``(type,version_number,matlab_root_path)``, where ``type``
-  indicates either ``MATLAB`` or ``MCR``.
-
-  .. code-block:: cmake
-
-    matlab_get_all_valid_matlab_roots_from_registry(matlab_versions matlab_roots [REGISTRY_VIEW view])
-
-  * Input: ``matlab_versions`` of each of the Matlab or MCR installations
-  * Output: ``matlab_roots`` location of each of the Matlab or MCR installations
-  * Input: ``REGISTRY_VIEW`` Optional registry view to use for registry
-    interaction. The argument is passed (or omitted) to
-    :command:`cmake_host_system_information` without further checks or
-    modification.
-
-  .. versionadded:: 3.30
-    The optional ``REGISTRY_VIEW`` argument was added to provide a more precise
-    interface on how to interact with the Windows Registry.
-
-#]=======================================================================]
+# Public.
 function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_roots)
 
   # The matlab_versions comes either from
@@ -672,20 +1028,7 @@
   set(${matlab_roots} ${_matlab_roots_list} PARENT_SCOPE)
 endfunction()
 
-#[=======================================================================[.rst:
-.. command:: matlab_get_mex_suffix
-
-  Returns the extension of the mex files (the suffixes).
-  This function should not be called before the appropriate Matlab root has
-  been found.
-
-  .. code-block:: cmake
-
-    matlab_get_mex_suffix(matlab_root mex_suffix)
-
-  * Input: ``matlab_root`` root of Matlab/MCR install e.g. ``Matlab_ROOT_DIR``
-  * Output: ``mex_suffix`` variable name in which the suffix will be returned.
-#]=======================================================================]
+# Public.
 function(matlab_get_mex_suffix matlab_root mex_suffix)
 
   # find_program does not consider script suffix .bat for Matlab mexext.bat on Windows
@@ -761,21 +1104,7 @@
   set(${mex_suffix} ${_matlab_mex_extension} PARENT_SCOPE)
 endfunction()
 
-
-#[=======================================================================[.rst:
-.. command:: matlab_get_version_from_matlab_run
-
-  This function runs Matlab program specified on arguments and extracts its
-  version. If the path provided for the Matlab installation points to an MCR
-  installation, the version is extracted from the installed files.
-
-  .. code-block:: cmake
-
-    matlab_get_version_from_matlab_run(matlab_binary_path matlab_list_versions)
-
-  * Input: ``matlab_binary_path`` path of the `matlab` binary executable
-  * Output: ``matlab_list_versions`` the version extracted from Matlab
-#]=======================================================================]
+# Public.
 function(matlab_get_version_from_matlab_run matlab_binary_program matlab_list_versions)
 
   set(${matlab_list_versions} "" PARENT_SCOPE)
@@ -926,77 +1255,7 @@
 
 endfunction()
 
-#[=======================================================================[.rst:
-.. command:: matlab_add_unit_test
-
-  Adds a Matlab unit test to the test set of cmake/ctest.
-  This command requires the component ``MAIN_PROGRAM`` and hence is not
-  available for an MCR installation.
-
-  The unit test uses the Matlab unittest framework (default, available
-  starting Matlab 2013b+) except if the option ``NO_UNITTEST_FRAMEWORK``
-  is given.
-
-  The function expects one Matlab test script file to be given.
-  In the case ``NO_UNITTEST_FRAMEWORK`` is given, the unittest script file
-  should contain the script to be run, plus an exit command with the exit
-  value. This exit value will be passed to the ctest framework (0 success,
-  non 0 failure). Additional arguments accepted by :command:`add_test` can be
-  passed through ``TEST_ARGS`` (eg. ``CONFIGURATION <config> ...``).
-
-  .. code-block:: cmake
-
-    matlab_add_unit_test(
-        NAME <name>
-        UNITTEST_FILE matlab_file_containing_unittest.m
-        [CUSTOM_TEST_COMMAND matlab_command_to_run_as_test]
-        [UNITTEST_PRECOMMAND matlab_command_to_run]
-        [TIMEOUT timeout]
-        [ADDITIONAL_PATH path1 [path2 ...]]
-        [MATLAB_ADDITIONAL_STARTUP_OPTIONS option1 [option2 ...]]
-        [TEST_ARGS arg1 [arg2 ...]]
-        [NO_UNITTEST_FRAMEWORK]
-        )
-
-  Function Parameters:
-
-  ``NAME``
-    name of the unittest in ctest.
-  ``UNITTEST_FILE``
-    the matlab unittest file. Its path will be automatically
-    added to the Matlab path.
-  ``CUSTOM_TEST_COMMAND``
-    Matlab script command to run as the test.
-    If this is not set, then the following is run:
-    ``runtests('matlab_file_name'), exit(max([ans(1,:).Failed]))``
-    where ``matlab_file_name`` is the ``UNITTEST_FILE`` without the extension.
-  ``UNITTEST_PRECOMMAND``
-    Matlab script command to be ran before the file
-    containing the test (eg. GPU device initialization based on CMake
-    variables).
-  ``TIMEOUT``
-    the test timeout in seconds. Defaults to 180 seconds as the
-    Matlab unit test may hang.
-  ``ADDITIONAL_PATH``
-    a list of paths to add to the Matlab path prior to
-    running the unit test.
-  ``MATLAB_ADDITIONAL_STARTUP_OPTIONS``
-    a list of additional option in order
-    to run Matlab from the command line.
-    ``-nosplash -nodesktop -nodisplay`` are always added.
-  ``TEST_ARGS``
-    Additional options provided to the add_test command. These
-    options are added to the default options (eg. "CONFIGURATIONS Release")
-  ``NO_UNITTEST_FRAMEWORK``
-    when set, indicates that the test should not
-    use the unittest framework of Matlab (available for versions >= R2013a).
-  ``WORKING_DIRECTORY``
-    This will be the working directory for the test. If specified it will
-    also be the output directory used for the log file of the test run.
-    If not specified the temporary directory ``${CMAKE_BINARY_DIR}/Matlab`` will
-    be used as the working directory and the log location.
-
-#]=======================================================================]
+# Public.
 function(matlab_add_unit_test)
 
   if(NOT Matlab_MAIN_PROGRAM)
@@ -1049,93 +1308,7 @@
            )
 endfunction()
 
-
-#[=======================================================================[.rst:
-.. command:: matlab_add_mex
-
-  Adds a Matlab MEX target.
-  This commands compiles the given sources with the current tool-chain in
-  order to produce a MEX file. The final name of the produced output may be
-  specified, as well as additional link libraries, and a documentation entry
-  for the MEX file. Remaining arguments of the call are passed to the
-  :command:`add_library` or :command:`add_executable` command.
-
-  .. code-block:: cmake
-
-     matlab_add_mex(
-         NAME <name>
-         [EXECUTABLE | MODULE | SHARED]
-         SRC src1 [src2 ...]
-         [OUTPUT_NAME output_name]
-         [DOCUMENTATION file.txt]
-         [LINK_TO target1 target2 ...]
-         [R2017b | R2018a]
-         [EXCLUDE_FROM_ALL]
-         [NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES]
-         [...]
-     )
-
-  Function Parameters:
-
-  ``NAME``
-    name of the target.
-  ``SRC``
-    list of source files.
-  ``LINK_TO``
-    a list of additional link dependencies.  The target links to ``libmex``
-    and ``libmx`` by default, unless the
-    ``NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES`` option is passed.
-  ``OUTPUT_NAME``
-    if given, overrides the default name. The default name is
-    the name of the target without any prefix and
-    with ``Matlab_MEX_EXTENSION`` suffix.
-  ``DOCUMENTATION``
-    if given, the file ``file.txt`` will be considered as
-    being the documentation file for the MEX file. This file is copied into
-    the same folder without any processing, with the same name as the final
-    mex file, and with extension `.m`. In that case, typing ``help <name>``
-    in Matlab prints the documentation contained in this file.
-  ``R2017b`` or ``R2018a``
-    .. versionadded:: 3.14
-
-    May be given to specify the version of the C API
-    to use: ``R2017b`` specifies the traditional (separate complex) C API,
-    and corresponds to the ``-R2017b`` flag for the `mex` command. ``R2018a``
-    specifies the new interleaved complex C API, and corresponds to the
-    ``-R2018a`` flag for the `mex` command. Ignored if MATLAB version prior
-    to R2018a. Defaults to ``R2017b``.
-
-  ``MODULE`` or ``SHARED``
-    .. versionadded:: 3.7
-
-    May be given to specify the type of library to be
-    created.
-
-  ``EXECUTABLE``
-    .. versionadded:: 3.7
-
-    May be given to create an executable instead of
-    a library. If no type is given explicitly, the type is ``SHARED``.
-  ``EXCLUDE_FROM_ALL``
-    This option has the same meaning as for :prop_tgt:`EXCLUDE_FROM_ALL` and
-    is forwarded to :command:`add_library` or :command:`add_executable`
-    commands.
-  ``NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES``
-    .. versionadded:: 3.24
-
-    This option permits to disable the automatic linking of MATLAB
-    libraries, so that only the libraries that are actually required can be
-    linked via the ``LINK_TO`` option.
-
-  The documentation file is not processed and should be in the following
-  format:
-
-  ::
-
-    % This is the documentation
-    function ret = mex_target_output_name(input1)
-
-#]=======================================================================]
+# Public.
 function(matlab_add_mex)
 
   set(options EXECUTABLE MODULE SHARED R2017b R2018a EXCLUDE_FROM_ALL NO_IMPLICIT_LINK_TO_MATLAB_LIBRARIES)
@@ -1331,7 +1504,6 @@
 
 endfunction()
 
-
 # (internal)
 # Used to get the version of matlab, using caching. This basically transforms the
 # output of the root list, with possible unknown version, to a version
@@ -1477,7 +1649,6 @@
 
 endfunction()
 
-
 function(_Matlab_VersionInfoXML matlab_root _version)
 
   set(_ver "unknown")
@@ -1496,7 +1667,6 @@
 
 endfunction()
 
-
 # Utility function for finding Matlab or MCR on Win32
 function(_Matlab_find_instances_win32 matlab_roots)
   # On WIN32, we look for Matlab installation in the registry
@@ -1819,7 +1989,6 @@
 endif()
 
 
-
 set(MATLAB_INCLUDE_DIR_TO_LOOK ${Matlab_ROOT_DIR}/extern/include)
 if(CMAKE_SIZEOF_VOID_P EQUAL 4)
   set(_matlab_current_suffix ${_matlab_bin_suffix_32bits})
@@ -1851,8 +2020,6 @@
   message(STATUS "[MATLAB] _matlab_lib_prefix_for_search = ${_matlab_lib_prefix_for_search} | _matlab_lib_dir_for_search = ${_matlab_lib_dir_for_search}")
 endif()
 
-
-
 # internal
 # This small stub around find_library is to prevent any pollution of CMAKE_FIND_LIBRARY_PREFIXES in the global scope.
 # This is the function to be used below instead of the find_library directives.
diff --git a/Modules/FindOpenGL.cmake b/Modules/FindOpenGL.cmake
index da01072..6362edf 100644
--- a/Modules/FindOpenGL.cmake
+++ b/Modules/FindOpenGL.cmake
@@ -96,7 +96,7 @@
 ``OpenGL::GLX``
   .. versionadded:: 3.10
 
-  Target encapsulating the usage requirements of the OpenGL Extension to the
+  Target encapsulating the usage requirements of the OpenGL Extension to
   the X Window System (GLX), available if OpenGL and GLX are found.
 
 ``OpenGL::EGL``
@@ -240,7 +240,9 @@
       correspond to GLVND libraries).
 
   ``LEGACY``
-    Prefer to use the legacy libGL library, if available.
+    Prefer to use the legacy libGL library, if available. This makes
+    ``OPENGL_opengl_LIBRARY`` and ``OPENGL_glx_LIBRARY``
+    point to ``OPENGL_gl_LIBRARY``.
 
 .. _`Linux Specific`:
 
@@ -255,12 +257,10 @@
 ``OpenGL::GLX`` or ``OpenGL::EGL``.
 
 Projects may use the ``OpenGL::GL`` target (or ``OPENGL_LIBRARIES`` variable)
-to use legacy GL interfaces.  These will use the legacy GL library located
-by ``OPENGL_gl_LIBRARY``, if available.  If ``OPENGL_gl_LIBRARY`` is empty or
-not found and GLVND is available, the ``OpenGL::GL`` target will use GLVND
-``OpenGL::OpenGL`` and ``OpenGL::GLX`` (and the ``OPENGL_LIBRARIES``
-variable will use the corresponding libraries).  Thus, for non-EGL-based
-Linux targets, the ``OpenGL::GL`` target is most portable.
+to use legacy GL interfaces.  Depending on ``OpenGL_GL_PREFERENCE``, these
+will either use the legacy GL library or the GLVND ``OpenGL::OpenGL`` and
+``OpenGL::GLX``.  Thus, for non-EGL-based Linux targets,
+the ``OpenGL::GL`` target is most portable.
 
 The ``OpenGL_GL_PREFERENCE`` variable may be set to specify the preferred way
 to provide legacy GL interfaces in case multiple choices are available.
@@ -529,6 +529,12 @@
     list(APPEND _OpenGL_CACHE_VARS OPENGL_gl_LIBRARY)
   endif()
 
+  # When preferring legacy, linking OpenGL and GLX should behave the same as linking legacy GL.
+  if(OpenGL_GL_PREFERENCE STREQUAL "LEGACY")
+    set(OpenGL_glx_LIBRARY "${OPENGL_gl_LIBRARY}")
+    set(OpenGL_opengl_LIBRARY "${OPENGL_gl_LIBRARY}")
+  endif()
+
   if(_OpenGL_GL_POLICY_WARN AND OPENGL_gl_LIBRARY AND OPENGL_opengl_LIBRARY AND OPENGL_glx_LIBRARY)
     cmake_policy(GET_WARNING CMP0072 _cmp0072_warning)
     message(AUTHOR_WARNING
diff --git a/Modules/FindOpenMP.cmake b/Modules/FindOpenMP.cmake
index 19adf40..6ef1152 100644
--- a/Modules/FindOpenMP.cmake
+++ b/Modules/FindOpenMP.cmake
@@ -760,7 +760,7 @@
         set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
           INTERFACE_COMPILE_OPTIONS "$<$<COMPILE_LANGUAGE:${LANG}>:SHELL:${OpenMP_${LANG}_FLAGS}>")
         if(CMAKE_${LANG}_COMPILER_ID STREQUAL "Fujitsu"
-          OR ${CMAKE_${LANG}_COMPILER_ID} STREQUAL "IntelLLVM"
+          OR CMAKE_${LANG}_COMPILER_ID STREQUAL "IntelLLVM"
           OR CMAKE_${LANG}_COMPILER_ID MATCHES "^(Cray|CrayClang)$")
           set_property(TARGET OpenMP::OpenMP_${LANG} PROPERTY
             INTERFACE_LINK_OPTIONS "SHELL:${OpenMP_${LANG}_FLAGS}")
diff --git a/Modules/FindOpenThreads.cmake b/Modules/FindOpenThreads.cmake
index 5e01ac2..0d3df43 100644
--- a/Modules/FindOpenThreads.cmake
+++ b/Modules/FindOpenThreads.cmake
@@ -123,7 +123,7 @@
 )
 
 find_library(OPENTHREADS_LIBRARY_RELEASE
-    NAMES OpenThreads OpenThreadsWin32
+    NAMES OpenThreads OpenThreadsWin32 OpenThreadsrd
     HINTS
         ENV OPENTHREADS_LIBRARY_DIR
         ENV OPENTHREADS_DIR
diff --git a/Modules/FindPNG.cmake b/Modules/FindPNG.cmake
index f7d5eb9..47540f7 100644
--- a/Modules/FindPNG.cmake
+++ b/Modules/FindPNG.cmake
@@ -105,7 +105,7 @@
 find_package(ZLIB ${_FIND_ZLIB_ARG})
 
 if(ZLIB_FOUND)
-  set(_PNG_VERSION_SUFFIXES 17 16 15 14 12)
+  set(_PNG_VERSION_SUFFIXES 18 17 16 15 14 12)
 
   list(APPEND _PNG_INCLUDE_PATH_SUFFIXES include/libpng)
   foreach(v IN LISTS _PNG_VERSION_SUFFIXES)
diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake
index 2d34332..6029be0 100644
--- a/Modules/FindPython/Support.cmake
+++ b/Modules/FindPython/Support.cmake
@@ -588,7 +588,22 @@
   if ("Interpreter" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS AND _${_PYTHON_PREFIX}_EXECUTABLE
       AND (_${_PYTHON_PREFIX}_CROSSCOMPILING OR NOT CMAKE_CROSSCOMPILING))
     if (NAME STREQUAL "PREFIX")
-      execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n   import sysconfig\n   sys.stdout.write(';'.join([sysconfig.get_config_var('base') or '', sysconfig.get_config_var('installed_base') or '']))\nexcept Exception:\n   from distutils import sysconfig\n   sys.stdout.write(';'.join([sysconfig.PREFIX,sysconfig.EXEC_PREFIX,sysconfig.BASE_EXEC_PREFIX]))"
+      execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c [==[
+import sys
+try:
+    import sysconfig
+    sys.stdout.write(';'.join([
+        sysconfig.get_config_var('base') or '',
+        sysconfig.get_config_var('installed_base') or '',
+    ]))
+except Exception:
+    from distutils import sysconfig
+    sys.stdout.write(';'.join([
+        sysconfig.PREFIX,
+        sysconfig.EXEC_PREFIX,
+        sysconfig.BASE_EXEC_PREFIX,
+    ]))
+]==]
                        RESULT_VARIABLE _result
                        OUTPUT_VARIABLE _values
                        ERROR_QUIET
@@ -605,7 +620,23 @@
         set (_scheme "posix_prefix")
       endif()
       execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
-                               "import sys\ntry:\n   import sysconfig\n   sys.stdout.write(';'.join([sysconfig.get_path('platinclude'),sysconfig.get_path('platinclude','${_scheme}'),sysconfig.get_path('include'),sysconfig.get_path('include','${_scheme}')]))\nexcept Exception:\n   from distutils import sysconfig\n   sys.stdout.write(';'.join([sysconfig.get_python_inc(plat_specific=True),sysconfig.get_python_inc(plat_specific=False)]))"
+                               [==[
+import sys
+try:
+    import sysconfig
+    sys.stdout.write(';'.join([
+        sysconfig.get_path('platinclude'),
+        sysconfig.get_path('platinclude', sys.argv[1]),
+        sysconfig.get_path('include'),
+        sysconfig.get_path('include', sys.argv[1]),
+    ]))
+except Exception:
+    from distutils import sysconfig
+    sys.stdout.write(';'.join([
+        sysconfig.get_python_inc(plat_specific=True),
+        sysconfig.get_python_inc(plat_specific=False),
+    ]))
+]==] "${_scheme}"
                        RESULT_VARIABLE _result
                        OUTPUT_VARIABLE _values
                        ERROR_QUIET
@@ -618,7 +649,15 @@
     elseif (NAME STREQUAL "SOABI")
       # first step: compute SOABI form EXT_SUFFIX config variable
       execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
-                               "import sys\ntry:\n   import sysconfig\n   sys.stdout.write(sysconfig.get_config_var('EXT_SUFFIX') or '')\nexcept Exception:\n   from distutils import sysconfig;sys.stdout.write(sysconfig.get_config_var('EXT_SUFFIX') or '')"
+                               [==[
+import sys
+try:
+    import sysconfig
+    sys.stdout.write(sysconfig.get_config_var('EXT_SUFFIX') or '')
+except Exception:
+    from distutils import sysconfig
+    sys.stdout.write(sysconfig.get_config_var('EXT_SUFFIX') or '')
+]==]
                        RESULT_VARIABLE _result
                        OUTPUT_VARIABLE _values
                        ERROR_QUIET
@@ -639,7 +678,21 @@
       # second step: use SOABI or SO config variables as fallback
       if (NOT _values)
         execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
-          "import sys\ntry:\n   import sysconfig\n   sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('SO') or '']))\nexcept Exception:\n   from distutils import sysconfig;sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('SO') or '']))"
+          [==[
+import sys
+try:
+    import sysconfig
+    sys.stdout.write(';'.join([
+        sysconfig.get_config_var('SOABI') or '',
+        sysconfig.get_config_var('SO') or '',
+    ]))
+except Exception:
+    from distutils import sysconfig
+    sys.stdout.write(';'.join([
+        sysconfig.get_config_var('SOABI') or '',
+        sysconfig.get_config_var('SO') or '',
+    ]))
+]==]
           RESULT_VARIABLE _result
           OUTPUT_VARIABLE _soabi
           ERROR_QUIET
@@ -664,7 +717,12 @@
         endif()
       endif()
     elseif (NAME STREQUAL "SOSABI")
-      execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\nimport re\nimport importlib.machinery\nsys.stdout.write(next(filter(lambda x: re.search('^\\.abi', x), importlib.machinery.EXTENSION_SUFFIXES)))"
+      execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c [==[
+import sys
+import re
+import importlib.machinery
+sys.stdout.write(next(filter(lambda x: re.search('^\\.abi', x), importlib.machinery.EXTENSION_SUFFIXES)))
+]==]
                        RESULT_VARIABLE _result
                        OUTPUT_VARIABLE _values
                        ERROR_QUIET
@@ -677,7 +735,14 @@
     elseif (NAME STREQUAL "ABIFLAGS" AND WIN32)
       # config var ABIFLAGS does not exist for version < 3.14, check GIL specific variable
       execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
-                               "import sys\nimport sysconfig\ntry:\n   sys.stdout.write(sysconfig.get_config_var('ABIFLAGS'))\nexcept Exception:\n   sys.stdout.write('t' if sysconfig.get_config_var('Py_GIL_DISABLED') == 1 else '<none>')"
+                               [==[
+import sys
+import sysconfig
+try:
+    sys.stdout.write(sysconfig.get_config_var('ABIFLAGS'))
+except Exception:
+    sys.stdout.write('t' if sysconfig.get_config_var('Py_GIL_DISABLED') == 1 else '<none>')
+]==]
                      RESULT_VARIABLE _result
                      OUTPUT_VARIABLE _values
                      ERROR_QUIET
@@ -692,7 +757,15 @@
         set (config_flag "LIBPL")
       endif()
       execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
-                               "import sys\ntry:\n   import sysconfig\n   sys.stdout.write(sysconfig.get_config_var('${config_flag}'))\nexcept Exception:\n   from distutils import sysconfig\n   sys.stdout.write(sysconfig.get_config_var('${config_flag}'))"
+                               [=[
+import sys
+try:
+    import sysconfig
+    sys.stdout.write(sysconfig.get_config_var(sys.argv[1]))
+except Exception:
+    from distutils import sysconfig
+    sys.stdout.write(sysconfig.get_config_var(sys.argv[1]))
+]=] "${config_flag}"
                        RESULT_VARIABLE _result
                        OUTPUT_VARIABLE _values
                        ERROR_QUIET
@@ -1061,7 +1134,7 @@
       AND (_${_PYTHON_PREFIX}_CROSSCOMPILING OR NOT CMAKE_CROSSCOMPILING))
     # In this case, interpreter must have same architecture as environment
     execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
-                             "import sys, struct; sys.stdout.write(str(struct.calcsize(\"P\")))"
+                             "import sys, struct; sys.stdout.write(str(struct.calcsize('P')))"
                      RESULT_VARIABLE result
                      OUTPUT_VARIABLE size
                      ERROR_QUIET
@@ -1082,7 +1155,7 @@
 
     if (WIN32)
       # In this case, check if the interpreter is compatible with the target processor architecture
-      if (NOT CMAKE_GENERATOR_PLATFORM AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM" OR CMAKE_GENERATOR_PLATFORM MATCHES "ARM")
+      if (_$_PYTHON_PREFIX}_ARCHITECTURE_ID MATCHES "ARM")
         set(target_arm TRUE)
       else()
         set(target_arm FALSE)
@@ -1139,7 +1212,11 @@
 
   # retrieve python environment version from compiler
   set (working_dir "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir")
-  file (WRITE "${working_dir}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]])); sys.stdout.flush()\n")
+  file (WRITE "${working_dir}/version.py" [==[
+import sys
+sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))
+sys.stdout.flush()
+]==])
   execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_COMPILER}"
                            ${_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS}
                            /target:exe /embed /standalone "${working_dir}/version.py"
@@ -1621,6 +1698,35 @@
   endif()
 endif()
 
+# Define what is the current architecture
+unset(_${_PYTHON_PREFIX}_ARCHITECTURE_ID)
+block (SCOPE_FOR VARIABLES PROPAGATE _${_PYTHON_PREFIX}_ARCHITECTURE_ID)
+  while(TRUE)
+    ## First, try to use the variables CMAKE_<LANG>_COMPILER_ARCHITECTURE_ID which is
+    ## the most reliable way, especially on Windows, to get the current architecture
+    get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES)
+    foreach (lang IN LISTS languages)
+      if (CMAKE_${lang}_COMPILER_ARCHITECTURE_ID)
+        list(GET CMAKE_${lang}_COMPILER_ARCHITECTURE_ID 0 _${_PYTHON_PREFIX}_ARCHITECTURE_ID)
+        break()
+      endif()
+    endforeach()
+    if (_${_PYTHON_PREFIX}_ARCHITECTURE_ID)
+      break()
+    endif()
+    ## Second, try to use the CMAKE_VS_PLATFORM_NAME for Visual Studio generators
+    if (CMAKE_GENERATOR MATCHES "Visual Studio")
+      set (_${_PYTHON_PREFIX}_ARCHITECTURE_ID "${CMAKE_VS_PLATFORM_NAME}")
+      if (_${_PYTHON_PREFIX}_ARCHITECTURE_ID)
+        break()
+      endif()
+    endif()
+    ## Finally, use the CMAKE_SYSTEM_PROCESSOR variable
+    set (_${_PYTHON_PREFIX}_ARCHITECTURE_ID "${CMAKE_SYSTEM_PROCESSOR}")
+    break()
+  endwhile()
+endblock()
+
 # Python and Anaconda distributions: define which architectures can be used
 unset (_${_PYTHON_PREFIX}_REGISTRY_VIEW)
 if (CMAKE_SIZEOF_VOID_P)
@@ -1630,8 +1736,7 @@
       OR "Development.Embed" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS)
     # In this case, search only for 64bit or 32bit
     set (_${_PYTHON_PREFIX}_REGISTRY_VIEW REGISTRY_VIEW ${_${_PYTHON_PREFIX}_ARCH})
-    if (WIN32 AND (NOT CMAKE_GENERATOR_PLATFORM AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM"
-                   OR CMAKE_GENERATOR_PLATFORM MATCHES "ARM"))
+    if (WIN32 AND _${_PYTHON_PREFIX}_ARCHITECTURE_ID MATCHES "ARM")
       # search exclusively ARM architecture: 64bit or 32bit
       if (_${_PYTHON_PREFIX}_ARCH EQUAL 64)
         set (_${_PYTHON_PREFIX}_ARCH ARM64)
@@ -1641,13 +1746,13 @@
     endif()
   else()
     if (_${_PYTHON_PREFIX}_ARCH EQUAL "32")
-      if (CMAKE_SYSTEM_PROCESSOR MATCHES "ARM")
+      if (_${_PYTHON_PREFIX}_ARCHITECTURE_ID MATCHES "ARM")
         # search first ARM architectures: 32bit and then 64bit
         list (PREPEND _${_PYTHON_PREFIX}_ARCH ARM ARM64)
       endif()
       list (APPEND _${_PYTHON_PREFIX}_ARCH 64)
     else()
-      if (CMAKE_SYSTEM_PROCESSOR MATCHES "ARM")
+      if (_${_PYTHON_PREFIX}_ARCHITECTURE_ID MATCHES "ARM")
         # search first ARM architectures: 64bit and then 32bit
         list (PREPEND _${_PYTHON_PREFIX}_ARCH ARM64 ARM)
       endif()
@@ -1657,7 +1762,7 @@
 else()
   # architecture unknown, search for both 64bit and 32bit
   set (_${_PYTHON_PREFIX}_ARCH 64 32)
-  if (CMAKE_SYSTEM_PROCESSOR MATCHES "ARM")
+  if (_${_PYTHON_PREFIX}_ARCHITECTURE_ID MATCHES "ARM")
     list (PREPEND _${_PYTHON_PREFIX}_ARCH ARM64 ARM)
   endif()
 endif()
@@ -2394,11 +2499,32 @@
 
         # retrieve various package installation directories
         execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
-                                 "import sys\nif sys.version_info >= (3,10):\n   import sysconfig\n   sys.stdout.write(';'.join([sysconfig.get_path('stdlib'),sysconfig.get_path('platstdlib'),sysconfig.get_path('purelib'),sysconfig.get_path('platlib')]))\nelse:\n   from distutils import sysconfig\n   sys.stdout.write(';'.join([sysconfig.get_python_lib(plat_specific=False,standard_lib=True),sysconfig.get_python_lib(plat_specific=True,standard_lib=True),sysconfig.get_python_lib(plat_specific=False,standard_lib=False),sysconfig.get_python_lib(plat_specific=True,standard_lib=False)]))"
+                                 [==[
+import sys
+if sys.version_info >= (3, 10):
+    import sysconfig
+    sys.stdout.write(';'.join([
+        sysconfig.get_path('stdlib'),
+        sysconfig.get_path('platstdlib'),
+        sysconfig.get_path('purelib'),
+        sysconfig.get_path('platlib'),
+    ]))
+else:
+    from distutils import sysconfig
+    sys.stdout.write(';'.join([
+        sysconfig.get_python_lib(plat_specific=False, standard_lib=True),
+        sysconfig.get_python_lib(plat_specific=True, standard_lib=True),
+        sysconfig.get_python_lib(plat_specific=False, standard_lib=False),
+        sysconfig.get_python_lib(plat_specific=True, standard_lib=False),
+    ]))
+]==]
                          RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
                          OUTPUT_VARIABLE _${_PYTHON_PREFIX}_LIBPATHS
                          ERROR_QUIET)
         if (NOT _${_PYTHON_PREFIX}_RESULT)
+          if (WIN32)
+            cmake_path (CONVERT "${_${_PYTHON_PREFIX}_LIBPATHS}" TO_CMAKE_PATH_LIST _${_PYTHON_PREFIX}_LIBPATHS)
+          endif()
           list (GET _${_PYTHON_PREFIX}_LIBPATHS 0 ${_PYTHON_PREFIX}_STDLIB)
           list (GET _${_PYTHON_PREFIX}_LIBPATHS 1 ${_PYTHON_PREFIX}_STDARCH)
           list (GET _${_PYTHON_PREFIX}_LIBPATHS 2 ${_PYTHON_PREFIX}_SITELIB)
@@ -2740,7 +2866,11 @@
     # retrieve python environment version from compiler
     _python_get_launcher (_${_PYTHON_PREFIX}_COMPILER_LAUNCHER COMPILER)
     set (_${_PYTHON_PREFIX}_VERSION_DIR "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir")
-    file (WRITE "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]])); sys.stdout.flush()\n")
+    file (WRITE "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.py" [==[
+import sys
+sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))
+sys.stdout.flush()
+]==])
     execute_process (COMMAND ${_${_PYTHON_PREFIX}_COMPILER_LAUNCHER} "${_${_PYTHON_PREFIX}_COMPILER}"
                              ${_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS}
                              /target:exe /embed /standalone "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.py"
@@ -4077,18 +4207,25 @@
     endif()
   endif()
 
-  # Workaround Intel MKL library outputting a message in stdout, which cause
-  # incorrect detection of numpy.get_include() and numpy.__version__
-  # See https://github.com/numpy/numpy/issues/23775 and
-  # https://gitlab.kitware.com/cmake/cmake/-/issues/26240
-  if(NOT DEFINED ENV{MKL_ENABLE_INSTRUCTIONS})
-    set(_${_PYTHON_PREFIX}_UNSET_ENV_VAR_MKL_ENABLE_INSTRUCTIONS YES)
-    set(ENV{MKL_ENABLE_INSTRUCTIONS} "SSE4_2")
+  # Work around Intel MKL message to stdout on macOS:
+  #   https://github.com/numpy/numpy/issues/23775
+  if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+    if(NOT DEFINED ENV{MKL_ENABLE_INSTRUCTIONS})
+      set(_${_PYTHON_PREFIX}_UNSET_ENV_VAR_MKL_ENABLE_INSTRUCTIONS YES)
+      set(ENV{MKL_ENABLE_INSTRUCTIONS} "SSE4_2")
+    endif()
   endif()
 
   if (NOT _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)
     execute_process(COMMAND ${${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
-                            "import sys\ntry: import numpy; sys.stdout.write(numpy.get_include())\nexcept:pass\n"
+                            [==[
+import sys
+try:
+    import numpy
+    sys.stdout.write(numpy.get_include())
+except Exception:
+    pass
+]==]
                     RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
                     OUTPUT_VARIABLE _${_PYTHON_PREFIX}_NumPy_PATH
                     ERROR_QUIET
@@ -4111,7 +4248,14 @@
 
   if (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)
     execute_process (COMMAND ${${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
-                             "import sys\ntry: import numpy; sys.stdout.write(numpy.__version__)\nexcept:pass\n"
+                             [==[
+import sys
+try:
+    import numpy
+    sys.stdout.write(numpy.__version__)
+except Exception:
+    pass
+]==]
                      RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
                      OUTPUT_VARIABLE _${_PYTHON_PREFIX}_NumPy_VERSION)
     if (NOT _${_PYTHON_PREFIX}_RESULT)
diff --git a/Modules/FindRuby.cmake b/Modules/FindRuby.cmake
index 0ede27a..863f70a 100644
--- a/Modules/FindRuby.cmake
+++ b/Modules/FindRuby.cmake
@@ -9,12 +9,50 @@
 
 .. code-block:: cmake
 
-  find_package(Ruby [<version>] [...])
+  find_package(Ruby [<version>] [COMPONENTS <components>...] [...])
 
 Ruby is a general-purpose programming language.  This module supports Ruby
-1.8 through 3.4.  Virtual environments, such as RVM or RBENV, are also
+2.0 through 4.0.  Virtual environments, such as RVM or RBENV, are also
 supported.
 
+Components
+^^^^^^^^^^
+
+.. versionadded:: 4.3
+
+This module supports the following components:
+
+``Interpreter``
+  The Ruby interpreter executable.
+
+``Development``
+  Headers and libraries needed to build Ruby extensions or embed Ruby.
+
+If no components are specified, both ``Interpreter`` and ``Development``
+are searched for.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 4.3
+
+This module defines the following :prop_tgt:`IMPORTED` targets:
+
+``Ruby::Interpreter``
+  Ruby interpreter. Target defined if component ``Interpreter`` is found.
+
+``Ruby::Ruby``
+  Ruby library for embedding Ruby in C/C++ applications.
+  Target defined if component ``Development`` is found.
+
+``Ruby::Module``
+  Ruby library for building Ruby extension modules.
+  Target defined if component ``Development`` is found.
+  Use this target when creating native extensions that will be
+  loaded into Ruby via ``require``. On most platforms, extension
+  modules do not link directly to libruby. Includes appropriate
+  symbol visibility settings.
+
 Result Variables
 ^^^^^^^^^^^^^^^^
 
@@ -71,7 +109,7 @@
   Virtual environments may be provided by:
 
   ``rvm``
-    Requires that the ``MY_RUBY_HOME`` environment environment is defined.
+    Requires that the ``MY_RUBY_HOME`` environment is defined.
 
   ``rbenv``
     Requires that ``rbenv`` is installed in ``~/.rbenv/bin``
@@ -137,13 +175,17 @@
 set(_Ruby_POSSIBLE_EXECUTABLE_NAMES ruby)
 
 # If the user has not specified a Ruby version, create a list of Ruby versions
-# to check going from 1.8 to 3.4
+# to search (newest to oldest). Based on https://www.ruby-lang.org/en/downloads/releases/
 if (NOT Ruby_FIND_VERSION_EXACT)
-  foreach (_ruby_version RANGE 34 18 -1)
+  set(_Ruby_SUPPORTED_VERSIONS 40 34 33 32)
+  set(_Ruby_UNSUPPORTED_VERSIONS 31 30 27 26 25 24 23 22 21 20)
+  foreach (_ruby_version IN LISTS _Ruby_SUPPORTED_VERSIONS _Ruby_UNSUPPORTED_VERSIONS)
     string(SUBSTRING "${_ruby_version}" 0 1 _ruby_major_version)
     string(SUBSTRING "${_ruby_version}" 1 1 _ruby_minor_version)
     # Append both rubyX.Y and rubyXY (eg: ruby3.4 ruby34)
-    list(APPEND _Ruby_POSSIBLE_EXECUTABLE_NAMES ruby${_ruby_major_version}.${_ruby_minor_version} ruby${_ruby_major_version}${_ruby_minor_version})
+    list(APPEND _Ruby_POSSIBLE_EXECUTABLE_NAMES
+         ruby${_ruby_major_version}.${_ruby_minor_version}
+         ruby${_ruby_major_version}${_ruby_minor_version})
   endforeach ()
 endif ()
 
@@ -190,19 +232,11 @@
 
 # Query Ruby RBConfig module for the specified variable (_RUBY_CONFIG_VAR)
 function(_RUBY_CONFIG_VAR RBVAR OUTVAR)
-  execute_process(COMMAND ${Ruby_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['${RBVAR}']"
+  execute_process(COMMAND "${Ruby_EXECUTABLE}" -r rbconfig -e "print RbConfig::CONFIG['${RBVAR}']"
                   RESULT_VARIABLE _Ruby_SUCCESS
                   OUTPUT_VARIABLE _Ruby_OUTPUT
                   ERROR_QUIET)
 
-  # Config was deprecated in Ruby 1.9 and then removed in Ruby 2 - so this is for ancient code
-  if (_Ruby_SUCCESS OR _Ruby_OUTPUT STREQUAL "")
-    execute_process(COMMAND ${Ruby_EXECUTABLE} -r rbconfig -e "print Config::CONFIG['${RBVAR}']"
-                    RESULT_VARIABLE _Ruby_SUCCESS
-                    OUTPUT_VARIABLE _Ruby_OUTPUT
-                    ERROR_QUIET)
-  endif ()
-
   set(${OUTVAR} "${_Ruby_OUTPUT}" PARENT_SCOPE)
 endfunction()
 
@@ -262,6 +296,54 @@
   endif ()
 endfunction()
 
+# Check Ruby installed via Homebrew on macOS
+function(_RUBY_CHECK_BREW)
+  # Try to locate brew in common locations and in PATH
+  find_program(_BREW_EXECUTABLE
+          NAMES brew
+          NAMES_PER_DIR
+          PATHS
+          /opt/homebrew/bin      # Apple Silicon default
+          /usr/local/bin         # Intel default
+          ENV PATH
+          NO_CACHE
+  )
+
+  if (NOT _BREW_EXECUTABLE)
+    return()
+  endif ()
+
+  message(DEBUG "Found brew at: ${_BREW_EXECUTABLE}")
+
+  # Query Homebrew for the prefix of the 'ruby' formula.
+  # If Ruby is not installed via Homebrew, this will fail.
+  execute_process(
+          COMMAND "${_BREW_EXECUTABLE}" --prefix ruby
+          RESULT_VARIABLE _Ruby_BREW_RESULT
+          OUTPUT_VARIABLE _Ruby_BREW_DIR
+          ERROR_QUIET
+          OUTPUT_STRIP_TRAILING_WHITESPACE
+  )
+  message(DEBUG "Ruby BREW is: ${_Ruby_BREW_DIR}")
+
+  if (NOT _Ruby_BREW_RESULT EQUAL 0 OR _Ruby_BREW_DIR STREQUAL "")
+    # No 'ruby' formula installed in Homebrew
+    return()
+  endif ()
+
+  find_program(Ruby_EXECUTABLE
+          NAMES ${_Ruby_POSSIBLE_EXECUTABLE_NAMES}
+          NAMES_PER_DIR
+          PATHS "${_Ruby_BREW_DIR}/bin"
+          VALIDATOR _RUBY_VALIDATE_INTERPRETER
+          NO_DEFAULT_PATH
+  )
+
+  if (Ruby_EXECUTABLE)
+    set(Ruby_ENV "BREW" CACHE INTERNAL "Ruby environment")
+  endif ()
+endfunction()
+
 # Check system installed Ruby
 function(_RUBY_CHECK_SYSTEM)
   find_program(Ruby_EXECUTABLE
@@ -284,6 +366,11 @@
   endif ()
 endif ()
 
+# Check for Homebrew Ruby (non-virtualenv, common on MacOS)
+if (NOT Ruby_EXECUTABLE AND NOT Ruby_FIND_VIRTUALENV STREQUAL "ONLY")
+  _RUBY_CHECK_BREW()
+endif ()
+
 # Fallback to system installed Ruby
 if (NOT Ruby_EXECUTABLE AND NOT Ruby_FIND_VIRTUALENV STREQUAL "ONLY")
   _RUBY_CHECK_SYSTEM()
@@ -297,20 +384,30 @@
   _RUBY_CONFIG_VAR("MINOR" Ruby_VERSION_MINOR)
   _RUBY_CONFIG_VAR("TEENY" Ruby_VERSION_PATCH)
 
-  # query the different directories
+  # Ruby extensions information
+  _RUBY_CONFIG_VAR("arch" Ruby_ARCH) # x86_64-linux, arm64-darwin, x64-mswin64_140, etc
+  # Extension directory where so/bundle files are stored
   _RUBY_CONFIG_VAR("archdir" Ruby_ARCH_DIR)
-  _RUBY_CONFIG_VAR("arch" Ruby_ARCH)
+  # Extension suffix
+  _RUBY_CONFIG_VAR("DLEXT" _Ruby_DLEXT) # so, bundle, *not* dll
+
+  # Headers
   _RUBY_CONFIG_VAR("rubyhdrdir" Ruby_HDR_DIR)
   _RUBY_CONFIG_VAR("rubyarchhdrdir" Ruby_ARCHHDR_DIR)
-  _RUBY_CONFIG_VAR("libdir" _Ruby_POSSIBLE_LIB_DIR)
+
+  # Ruby library information
+  _RUBY_CONFIG_VAR("libdir" _Ruby_POSSIBLE_LIB_DIR) # /usr/lib64
+  _RUBY_CONFIG_VAR("RUBY_SO_NAME" _Ruby_SO_NAME) # ruby, x64-vcruntime140-ruby340, etc.
+
+  # Ruby directory for ruby files (*.rb). TODO - not relevant should be removed
   _RUBY_CONFIG_VAR("rubylibdir" Ruby_RUBY_LIB_DIR)
 
-  # site_ruby
+  # site_ruby - TODO - not relevant and should be removed
   _RUBY_CONFIG_VAR("sitearchdir" Ruby_SITEARCH_DIR)
   _RUBY_CONFIG_VAR("sitelibdir" Ruby_SITELIB_DIR)
 
-  # vendor_ruby available ?
-  execute_process(COMMAND ${Ruby_EXECUTABLE} -r vendor-specific -e "print 'true'"
+  # vendor_ruby - TODO - Not relevant and should be removed.
+  execute_process(COMMAND "${Ruby_EXECUTABLE}" -r vendor-specific -e "print 'true'"
                   OUTPUT_VARIABLE Ruby_HAS_VENDOR_RUBY ERROR_QUIET)
 
   if (Ruby_HAS_VENDOR_RUBY)
@@ -320,19 +417,21 @@
 
   # save the results in the cache so we don't have to run ruby the next time again
   set(_Ruby_EXECUTABLE_LAST_QUERIED "${Ruby_EXECUTABLE}" CACHE INTERNAL "The ruby executable last queried for version and path info")
-  set(Ruby_VERSION_MAJOR ${Ruby_VERSION_MAJOR} CACHE PATH "The Ruby major version" FORCE)
-  set(Ruby_VERSION_MINOR ${Ruby_VERSION_MINOR} CACHE PATH "The Ruby minor version" FORCE)
-  set(Ruby_VERSION_PATCH ${Ruby_VERSION_PATCH} CACHE PATH "The Ruby patch version" FORCE)
-  set(Ruby_ARCH_DIR ${Ruby_ARCH_DIR} CACHE PATH "The Ruby arch dir" FORCE)
-  set(Ruby_HDR_DIR ${Ruby_HDR_DIR} CACHE PATH "The Ruby header dir (1.9+)" FORCE)
-  set(Ruby_ARCHHDR_DIR ${Ruby_ARCHHDR_DIR} CACHE PATH "The Ruby arch header dir (2.0+)" FORCE)
-  set(_Ruby_POSSIBLE_LIB_DIR ${_Ruby_POSSIBLE_LIB_DIR} CACHE PATH "The Ruby lib dir" FORCE)
-  set(Ruby_RUBY_LIB_DIR ${Ruby_RUBY_LIB_DIR} CACHE PATH "The Ruby ruby-lib dir" FORCE)
-  set(Ruby_SITEARCH_DIR ${Ruby_SITEARCH_DIR} CACHE PATH "The Ruby site arch dir" FORCE)
-  set(Ruby_SITELIB_DIR ${Ruby_SITELIB_DIR} CACHE PATH "The Ruby site lib dir" FORCE)
+  set(Ruby_VERSION_MAJOR ${Ruby_VERSION_MAJOR} CACHE STRING "The Ruby major version" FORCE)
+  set(Ruby_VERSION_MINOR ${Ruby_VERSION_MINOR} CACHE STRING "The Ruby minor version" FORCE)
+  set(Ruby_VERSION_PATCH ${Ruby_VERSION_PATCH} CACHE STRING "The Ruby patch version" FORCE)
+  set(Ruby_ARCH_DIR ${Ruby_ARCH_DIR} CACHE INTERNAL "The Ruby arch dir" FORCE)
+  set(Ruby_HDR_DIR ${Ruby_HDR_DIR} CACHE INTERNAL "The Ruby header dir (1.9+)" FORCE)
+  set(Ruby_ARCHHDR_DIR ${Ruby_ARCHHDR_DIR} CACHE INTERNAL "The Ruby arch header dir (2.0+)" FORCE)
+  set(_Ruby_POSSIBLE_LIB_DIR ${_Ruby_POSSIBLE_LIB_DIR} CACHE INTERNAL "The Ruby lib dir" FORCE)
+  set(Ruby_RUBY_LIB_DIR ${Ruby_RUBY_LIB_DIR} CACHE INTERNAL "The Ruby ruby-lib dir" FORCE)
+  set(_Ruby_SO_NAME ${_Ruby_SO_NAME} CACHE STRING "The Ruby shared library name" FORCE)
+  set(_Ruby_DLEXT ${_Ruby_DLEXT} CACHE STRING "Ruby extensions extension" FORCE)
+  set(Ruby_SITEARCH_DIR ${Ruby_SITEARCH_DIR} CACHE INTERNAL "The Ruby site arch dir" FORCE)
+  set(Ruby_SITELIB_DIR ${Ruby_SITELIB_DIR} CACHE INTERNAL "The Ruby site lib dir" FORCE)
   set(Ruby_HAS_VENDOR_RUBY ${Ruby_HAS_VENDOR_RUBY} CACHE BOOL "Vendor Ruby is available" FORCE)
-  set(Ruby_VENDORARCH_DIR ${Ruby_VENDORARCH_DIR} CACHE PATH "The Ruby vendor arch dir" FORCE)
-  set(Ruby_VENDORLIB_DIR ${Ruby_VENDORLIB_DIR} CACHE PATH "The Ruby vendor lib dir" FORCE)
+  set(Ruby_VENDORARCH_DIR ${Ruby_VENDORARCH_DIR} CACHE INTERNAL "The Ruby vendor arch dir" FORCE)
+  set(Ruby_VENDORLIB_DIR ${Ruby_VENDORLIB_DIR} CACHE INTERNAL "The Ruby vendor lib dir" FORCE)
 
   mark_as_advanced(
       Ruby_ARCH_DIR
@@ -341,6 +440,8 @@
       Ruby_ARCHHDR_DIR
       _Ruby_POSSIBLE_LIB_DIR
       Ruby_RUBY_LIB_DIR
+      _Ruby_SO_NAME
+      _Ruby_DLEXT
       Ruby_SITEARCH_DIR
       Ruby_SITELIB_DIR
       Ruby_HAS_VENDOR_RUBY
@@ -352,30 +453,6 @@
   )
 endif ()
 
-# In case Ruby_EXECUTABLE could not be executed (e.g. cross compiling)
-# try to detect which version we found. This is not too good.
-if (Ruby_EXECUTABLE AND NOT Ruby_VERSION_MAJOR)
-  # by default assume 1.8.0
-  set(Ruby_VERSION_MAJOR 1)
-  set(Ruby_VERSION_MINOR 8)
-  set(Ruby_VERSION_PATCH 0)
-  # check whether we found 1.9.x
-  if (${Ruby_EXECUTABLE} MATCHES "ruby1\\.?9")
-    set(Ruby_VERSION_MAJOR 1)
-    set(Ruby_VERSION_MINOR 9)
-  endif ()
-  # check whether we found 2.[0-7].x
-  if (${Ruby_EXECUTABLE} MATCHES "ruby2")
-    set(Ruby_VERSION_MAJOR 2)
-    string(REGEX_REPLACE ${Ruby_EXECUTABLE} "ruby2\\.?([0-7])" "\\1" Ruby_VERSION_MINOR)
-  endif ()
-  # check whether we found 3.[0-1].x
-  if (${Ruby_EXECUTABLE} MATCHES "ruby3")
-    set(Ruby_VERSION_MAJOR 3)
-    string(REGEX_REPLACE ${Ruby_EXECUTABLE} "ruby3\\.?([0-1])" "\\1" Ruby_VERSION_MINOR)
-  endif ()
-endif ()
-
 if (Ruby_VERSION_MAJOR)
   set(Ruby_VERSION "${Ruby_VERSION_MAJOR}.${Ruby_VERSION_MINOR}.${Ruby_VERSION_PATCH}")
   set(_Ruby_VERSION_NODOT "${Ruby_VERSION_MAJOR}${Ruby_VERSION_MINOR}${Ruby_VERSION_PATCH}")
@@ -384,75 +461,34 @@
   set(_Ruby_VERSION_SHORT_NODOT "${Ruby_VERSION_MAJOR}${Ruby_VERSION_MINOR}")
 endif ()
 
-# FIXME: Currently we require both the interpreter and development components to be found
-# in order to use either.  See issue #20474.
+# Save CMAKE_FIND_FRAMEWORK
+set(_Ruby_CMAKE_FIND_FRAMEWORK_ORIGINAL ${CMAKE_FIND_FRAMEWORK})
+
+# Avoid finding the ancient Ruby framework included in macOS.
+set(CMAKE_FIND_FRAMEWORK LAST)
+
 find_path(Ruby_INCLUDE_DIR
-          NAMES ruby.h
-          HINTS
-          ${Ruby_HDR_DIR}
-          ${Ruby_ARCH_DIR}
-          /usr/lib/ruby/${_Ruby_VERSION_SHORT}/i586-linux-gnu/
-)
+        NAMES ruby.h
+        HINTS ${Ruby_HDR_DIR})
 
-set(Ruby_INCLUDE_DIRS ${Ruby_INCLUDE_DIR})
+find_path(Ruby_CONFIG_INCLUDE_DIR
+        NAMES ruby/config.h config.h
+        HINTS ${Ruby_ARCHHDR_DIR})
 
-# if ruby > 1.8 is required or if ruby > 1.8 was found, search for the config.h dir
-if (Ruby_FIND_VERSION VERSION_GREATER_EQUAL "1.9" OR Ruby_VERSION VERSION_GREATER_EQUAL "1.9" OR Ruby_HDR_DIR)
-  find_path(Ruby_CONFIG_INCLUDE_DIR
-            NAMES ruby/config.h config.h
-            HINTS
-            ${Ruby_HDR_DIR}/${Ruby_ARCH}
-            ${Ruby_ARCH_DIR}
-            ${Ruby_ARCHHDR_DIR}
-  )
+set(Ruby_INCLUDE_DIRS ${Ruby_INCLUDE_DIR} ${Ruby_CONFIG_INCLUDE_DIR})
 
-  set(Ruby_INCLUDE_DIRS ${Ruby_INCLUDE_DIRS} ${Ruby_CONFIG_INCLUDE_DIR})
-endif ()
+find_library(Ruby_LIBRARY
+        NAMES "${_Ruby_SO_NAME}"
+        HINTS ${_Ruby_POSSIBLE_LIB_DIR})
 
-# Determine the list of possible names for the ruby library
-set(_Ruby_POSSIBLE_LIB_NAMES
-  ruby
-  ruby-static
-  ruby-${Ruby_VERSION}
-  ruby${_Ruby_VERSION_NODOT}
-  ruby${_Ruby_VERSION_NODOT_ZERO_PATCH}
-  ruby-${_Ruby_VERSION_SHORT}
-  ruby${_Ruby_VERSION_SHORT}
-  ruby${_Ruby_VERSION_SHORT_NODOT}
-)
-
-if (WIN32)
-  set(_Ruby_POSSIBLE_RUNTIMES "ucrt;msvcrt;vcruntime140;vcruntime140_1;vcruntime${MSVC_TOOLSET_VERSION}")
-  set(_Ruby_POSSIBLE_VERSION_SUFFIXES "${_Ruby_VERSION_NODOT};${_Ruby_VERSION_NODOT_ZERO_PATCH}")
-
-  if (CMAKE_SIZEOF_VOID_P EQUAL 8)
-    set(_Ruby_POSSIBLE_ARCH_PREFIXES "libx64-;x64-")
-  else ()
-    set(_Ruby_POSSIBLE_ARCH_PREFIXES "lib")
-  endif ()
-
-  foreach (_Ruby_RUNTIME ${_Ruby_POSSIBLE_RUNTIMES})
-    foreach (_Ruby_VERSION_SUFFIX ${_Ruby_POSSIBLE_VERSION_SUFFIXES})
-      foreach (_Ruby_ARCH_PREFIX ${_Ruby_POSSIBLE_ARCH_PREFIXES})
-        list(APPEND _Ruby_POSSIBLE_LIB_NAMES
-             "${_Ruby_ARCH_PREFIX}${_Ruby_RUNTIME}-ruby${_Ruby_VERSION_SUFFIX}"
-             "${_Ruby_ARCH_PREFIX}${_Ruby_RUNTIME}-ruby${_Ruby_VERSION_SUFFIX}-static")
-      endforeach ()
-    endforeach ()
-  endforeach ()
-endif ()
-
-find_library(Ruby_LIBRARY NAMES ${_Ruby_POSSIBLE_LIB_NAMES} HINTS ${_Ruby_POSSIBLE_LIB_DIR})
-
-set(_Ruby_REQUIRED_VARS Ruby_EXECUTABLE Ruby_INCLUDE_DIR Ruby_LIBRARY)
-if (_Ruby_VERSION_SHORT_NODOT GREATER 18)
-  list(APPEND _Ruby_REQUIRED_VARS Ruby_CONFIG_INCLUDE_DIR)
-endif ()
+# Restore CMAKE_FIND_FRAMEWORK
+set(CMAKE_FIND_FRAMEWORK ${_Ruby_CMAKE_FIND_FRAMEWORK_ORIGINAL})
 
 message(DEBUG "--------FindRuby.cmake debug------------")
 message(DEBUG "_Ruby_POSSIBLE_EXECUTABLE_NAMES: ${_Ruby_POSSIBLE_EXECUTABLE_NAMES}")
 message(DEBUG "_Ruby_POSSIBLE_LIB_DIR: ${_Ruby_POSSIBLE_LIB_DIR}")
-message(DEBUG "_Ruby_POSSIBLE_LIB_NAMES: ${_Ruby_POSSIBLE_LIB_NAMES}")
+message(DEBUG "_Ruby_SO_NAME: ${_Ruby_SO_NAME}")
+message(DEBUG "_Ruby_DLEXT: ${_Ruby_DLEXT}")
 message(DEBUG "Ruby_FIND_VIRTUALENV=${Ruby_FIND_VIRTUALENV}")
 message(DEBUG "Ruby_ENV: ${Ruby_ENV}")
 message(DEBUG "Found Ruby_VERSION: \"${Ruby_VERSION}\"")
@@ -462,14 +498,114 @@
 message(DEBUG "Ruby_CONFIG_INCLUDE_DIR: ${Ruby_CONFIG_INCLUDE_DIR}")
 message(DEBUG "Ruby_HDR_DIR: ${Ruby_HDR_DIR}")
 message(DEBUG "Ruby_ARCH_DIR: ${Ruby_ARCH_DIR}")
+message(DEBUG "Ruby_ARCHHDR_DIR: ${Ruby_ARCHHDR_DIR}")
 message(DEBUG "--------------------")
 
+# Components
+#
+# If the caller does not request components, preserve legacy behavior
+if (NOT Ruby_FIND_COMPONENTS)
+  set(Ruby_FIND_COMPONENTS Interpreter Development)
+endif ()
+
+set(_Ruby_WANT_INTERPRETER FALSE)
+set(_Ruby_WANT_DEVELOPMENT FALSE)
+set(_Ruby_REQUIRED_VARS "")
+
+foreach (component IN LISTS Ruby_FIND_COMPONENTS)
+  if (component STREQUAL "Interpreter")
+    set(_Ruby_WANT_INTERPRETER TRUE)
+    list(APPEND _Ruby_REQUIRED_VARS Ruby_EXECUTABLE)
+  elseif (component STREQUAL "Development")
+    set(_Ruby_WANT_DEVELOPMENT TRUE)
+    list(APPEND _Ruby_REQUIRED_VARS Ruby_INCLUDE_DIR Ruby_CONFIG_INCLUDE_DIR)
+    if (WIN32)
+      list(APPEND _Ruby_REQUIRED_VARS Ruby_LIBRARY)
+    endif ()
+  else ()
+    message(FATAL_ERROR
+            "FindRuby: Unsupported component '${component}'. Supported components are: Interpreter, Development")
+  endif ()
+endforeach ()
+
+# Set component found flags
+if (Ruby_EXECUTABLE)
+  set(Ruby_Interpreter_FOUND TRUE)
+else ()
+  set(Ruby_Interpreter_FOUND FALSE)
+endif ()
+
+if (Ruby_INCLUDE_DIR AND Ruby_CONFIG_INCLUDE_DIR AND (Ruby_LIBRARY OR NOT WIN32))
+  set(Ruby_Development_FOUND TRUE)
+else ()
+  set(Ruby_Development_FOUND FALSE)
+endif ()
+
 include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(Ruby REQUIRED_VARS ${_Ruby_REQUIRED_VARS}
-                                  VERSION_VAR Ruby_VERSION)
+find_package_handle_standard_args(Ruby
+                                  REQUIRED_VARS ${_Ruby_REQUIRED_VARS}
+                                  VERSION_VAR Ruby_VERSION
+                                  HANDLE_COMPONENTS)
 
 if (Ruby_FOUND)
-  set(Ruby_LIBRARIES ${Ruby_LIBRARY})
+  if (NOT TARGET Ruby::Interpreter)
+    add_executable(Ruby::Interpreter IMPORTED GLOBAL)
+    set_target_properties(Ruby::Interpreter PROPERTIES
+      IMPORTED_LOCATION "${Ruby_EXECUTABLE}"
+    )
+  endif ()
+
+  if (Ruby_Development_FOUND)
+    set(Ruby_LIBRARIES ${Ruby_LIBRARY})
+
+    if (Ruby_LIBRARY AND NOT TARGET Ruby::Ruby)
+      add_library(Ruby::Ruby UNKNOWN IMPORTED)
+      set_target_properties(Ruby::Ruby PROPERTIES
+        IMPORTED_LOCATION "${Ruby_LIBRARY}"
+        INTERFACE_INCLUDE_DIRECTORIES "${Ruby_INCLUDE_DIRS}"
+        # Custom property for extension suffix (with dot), e.g. ".so", ".bundle"
+        INTERFACE_RUBY_EXTENSION_SUFFIX ".${_Ruby_DLEXT}"
+      )
+    endif ()
+
+    # Ruby::Module - For building Ruby extension modules
+    if (NOT TARGET Ruby::Module)
+      if (WIN32)
+        add_library(Ruby::Module UNKNOWN IMPORTED)
+        set_target_properties(Ruby::Module PROPERTIES
+          IMPORTED_LOCATION "${Ruby_LIBRARY}"
+        )
+      else ()
+        add_library(Ruby::Module INTERFACE IMPORTED)
+      endif ()
+
+      set_target_properties(Ruby::Module PROPERTIES
+        INTERFACE_INCLUDE_DIRECTORIES "${Ruby_INCLUDE_DIRS}"
+        # Custom property for extension suffix (with dot), e.g. ".so", ".bundle"
+        INTERFACE_RUBY_EXTENSION_SUFFIX ".${_Ruby_DLEXT}"
+        INTERFACE_C_VISIBILITY_PRESET hidden
+        INTERFACE_CXX_VISIBILITY_PRESET hidden
+        INTERFACE_VISIBILITY_INLINES_HIDDEN ON
+      )
+
+      # macOS: allow unresolved Ruby API symbols; resolved when Ruby loads the bundle.
+      if (APPLE)
+        target_link_options(Ruby::Module INTERFACE
+          "LINKER:-undefined,dynamic_lookup"
+        )
+      endif ()
+
+      # Linux (and other ELF platforms):
+      # Normally undefined Ruby API symbols are allowed in shared objects and resolved at dlopen().
+      # But if the toolchain/preset adds -Wl,--no-undefined, linking will fail.
+      # This counteracts that.
+      if (UNIX AND NOT APPLE)
+        target_link_options(Ruby::Module INTERFACE
+          "LINKER:--unresolved-symbols=ignore-all"
+        )
+      endif ()
+    endif ()
+  endif ()
 endif ()
 
 mark_as_advanced(
diff --git a/Modules/FindSQLite3.cmake b/Modules/FindSQLite3.cmake
index ea859e6..f27a403 100644
--- a/Modules/FindSQLite3.cmake
+++ b/Modules/FindSQLite3.cmake
@@ -21,10 +21,27 @@
 
 This module provides the following :ref:`Imported Targets`:
 
-``SQLite::SQLite3``
+``SQLite3::SQLite3``
   Target encapsulating SQLite library usage requirements.  It is available only
   when SQLite is found.
 
+  .. versionadded:: 4.3
+
+``SQLite::SQLite3``
+  Deprecated.  Identical to ``SQLite3::SQLite3``.
+
+  If your project needs to support CMake < 4.3, consider adding the following
+  to your project after calling ``find_package(SQLite3 ...)``:
+
+  .. code-block:: cmake
+
+    if(NOT TARGET SQLite3::SQLite3) # CMake < 4.3
+      add_library(SQLite3::SQLite3 ALIAS SQLite::SQLite3)
+    endif()
+
+  This will allow your project to use the new name while still permitting it to
+  compile with older versions of CMake.
+
 Result Variables
 ^^^^^^^^^^^^^^^^
 
@@ -52,7 +69,7 @@
 .. code-block:: cmake
 
   find_package(SQLite3)
-  target_link_libraries(project_target PRIVATE SQLite::SQLite3)
+  target_link_libraries(project_target PRIVATE SQLite3::SQLite3)
 #]=======================================================================]
 
 cmake_policy(PUSH)
@@ -96,11 +113,18 @@
 if(SQLite3_FOUND)
     set(SQLite3_INCLUDE_DIRS ${SQLite3_INCLUDE_DIR})
     set(SQLite3_LIBRARIES ${SQLite3_LIBRARY})
+    if(NOT TARGET SQLite3::SQLite3)
+        add_library(SQLite3::SQLite3 UNKNOWN IMPORTED)
+        set_target_properties(SQLite3::SQLite3 PROPERTIES
+            IMPORTED_LOCATION             "${SQLite3_LIBRARY}"
+            INTERFACE_INCLUDE_DIRECTORIES "${SQLite3_INCLUDE_DIR}")
+    endif()
     if(NOT TARGET SQLite::SQLite3)
         add_library(SQLite::SQLite3 UNKNOWN IMPORTED)
         set_target_properties(SQLite::SQLite3 PROPERTIES
             IMPORTED_LOCATION             "${SQLite3_LIBRARY}"
-            INTERFACE_INCLUDE_DIRECTORIES "${SQLite3_INCLUDE_DIR}")
+            INTERFACE_INCLUDE_DIRECTORIES "${SQLite3_INCLUDE_DIR}"
+            DEPRECATION                   "The target name SQLite::SQLite3 is deprecated. Please use SQLite3::SQLite3 instead.")
     endif()
 endif()
 
diff --git a/Modules/FindTIFF.cmake b/Modules/FindTIFF.cmake
index c1fa789..c2f598a 100644
--- a/Modules/FindTIFF.cmake
+++ b/Modules/FindTIFF.cmake
@@ -45,7 +45,7 @@
 ``TIFF::CXX``
   .. versionadded:: 3.19
 
-  Target encapsulating the usage requirements for the the C++ wrapper library
+  Target encapsulating the usage requirements for the C++ wrapper library
   ``libtiffxx``, available only if TIFF is found.  This target provides CXX
   usage requirements only if the compiler is not MSVC.  It also has the
   ``TIFF::TIFF`` target linked in to simplify its usage.
diff --git a/Modules/FindVulkan.cmake b/Modules/FindVulkan.cmake
index 4bbcb27..2111893 100644
--- a/Modules/FindVulkan.cmake
+++ b/Modules/FindVulkan.cmake
@@ -331,62 +331,79 @@
 
 if(WIN32)
   set(_Vulkan_library_name vulkan-1)
-  set(_Vulkan_hint_include_search_paths
-    "$ENV{VULKAN_SDK}/include"
-  )
-  if(CMAKE_SIZEOF_VOID_P EQUAL 8)
-    set(_Vulkan_hint_executable_search_paths
-      "$ENV{VULKAN_SDK}/bin"
-    )
-    set(_Vulkan_hint_library_search_paths
-      "$ENV{VULKAN_SDK}/lib"
-      "$ENV{VULKAN_SDK}/bin"
-    )
-  else()
-    set(_Vulkan_hint_executable_search_paths
-      "$ENV{VULKAN_SDK}/bin32"
-      "$ENV{VULKAN_SDK}/bin"
-    )
-    set(_Vulkan_hint_library_search_paths
-      "$ENV{VULKAN_SDK}/lib32"
-      "$ENV{VULKAN_SDK}/bin32"
-      "$ENV{VULKAN_SDK}/lib"
-      "$ENV{VULKAN_SDK}/bin"
-    )
-  endif()
 else()
   set(_Vulkan_library_name vulkan)
+endif()
+set(_Vulkan_hint_include_search_paths "")
+set(_Vulkan_hint_executable_search_paths "")
+set(_Vulkan_hint_library_search_paths "")
+
+if(DEFINED ENV{VULKAN_SDK} AND IS_DIRECTORY "$ENV{VULKAN_SDK}")
   set(_Vulkan_hint_include_search_paths
     "$ENV{VULKAN_SDK}/include"
   )
   set(_Vulkan_hint_executable_search_paths
     "$ENV{VULKAN_SDK}/bin"
   )
-  set(_Vulkan_hint_library_search_paths
-    "$ENV{VULKAN_SDK}/lib"
-  )
-endif()
-if(APPLE AND DEFINED ENV{VULKAN_SDK})
-  cmake_path(SET _MoltenVK_path NORMALIZE "$ENV{VULKAN_SDK}/../MoltenVK")
-  if(EXISTS "${_MoltenVK_path}")
-    list(APPEND _Vulkan_hint_include_search_paths
-      "${_MoltenVK_path}/include"
-    )
-    if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
-      list(APPEND _Vulkan_hint_library_search_paths
-        "${_MoltenVK_path}/dylib/iOS"
-      )
-    elseif(CMAKE_SYSTEM_NAME STREQUAL "tvOS")
-      list(APPEND _Vulkan_hint_library_search_paths
-        "${_MoltenVK_path}/dylib/tvOS"
-      )
-    else()
-      list(APPEND _Vulkan_hint_library_search_paths
-        "${_MoltenVK_path}/dylib/macOS"
-      )
+  if(WIN32)
+    # Detect the target architecture from one of:
+    # - the C++ compiler,
+    # - the C compiler,
+    # - the VS generator,
+    # - the command-line environment,
+    # - fallback to CMAKE_SYSTEM_PROCESSOR.
+    if(CMAKE_CXX_COMPILER_LOADED AND CMAKE_CXX_COMPILER_ARCHITECTURE_ID)
+      set(_Vulkan_arch_name "${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}")
+    elseif(CMAKE_C_COMPILER_LOADED AND CMAKE_C_COMPILER_ARCHITECTURE_ID)
+      set(_Vulkan_arch_name "${CMAKE_C_COMPILER_ARCHITECTURE_ID}")
+    elseif(CMAKE_VS_PLATFORM_NAME)
+      set(_Vulkan_arch_name "${CMAKE_VS_PLATFORM_NAME}")
+    elseif(DEFINED ENV{VSCMD_ARG_TGT_ARCH})
+      set(_Vulkan_arch_name "$ENV{VSCMD_ARG_TGT_ARCH}")
+    elseif(CMAKE_SYSTEM_PROCESSOR)
+      set(_Vulkan_arch_name "${CMAKE_SYSTEM_PROCESSOR}")
     endif()
+    # The Vulkan SDK may provide arch-specific directories for cross-compiling.
+    if(_Vulkan_arch_name MATCHES "^(ARM64|arm64|aarch64)" AND IS_DIRECTORY "$ENV{VULKAN_SDK}/lib-arm64")
+      # On X64 hosts the Vulkan SDK provides `-arm64` dirs for cross-compiling to ARM64.
+      set(_Vulkan_arch_suffix "-arm64")
+    elseif(_Vulkan_arch_name MATCHES "^(X64|x64|x86_64)" AND IS_DIRECTORY "$ENV{VULKAN_SDK}/lib-x64")
+      # On ARM64 hosts the Vulkan SDK provides `-x64` dirs for cross-compiling to x64.
+      set(_Vulkan_arch_suffix "-x64")
+    else()
+      # Otherwise assume we are compiling for the host.
+      set(_Vulkan_arch_suffix "")
+    endif()
+    unset(_Vulkan_arch_name)
+  else()
+    set(_Vulkan_arch_suffix "")
   endif()
-  unset(_MoltenVK_path)
+  set(_Vulkan_hint_library_search_paths
+    "$ENV{VULKAN_SDK}/lib${_Vulkan_arch_suffix}"
+  )
+  unset(_Vulkan_arch_suffix)
+  if(APPLE)
+    cmake_path(SET _MoltenVK_path NORMALIZE "$ENV{VULKAN_SDK}/../MoltenVK")
+    if(IS_DIRECTORY "${_MoltenVK_path}")
+      list(APPEND _Vulkan_hint_include_search_paths
+        "${_MoltenVK_path}/include"
+      )
+      if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
+        list(APPEND _Vulkan_hint_library_search_paths
+          "${_MoltenVK_path}/dylib/iOS"
+        )
+      elseif(CMAKE_SYSTEM_NAME STREQUAL "tvOS")
+        list(APPEND _Vulkan_hint_library_search_paths
+          "${_MoltenVK_path}/dylib/tvOS"
+        )
+      else()
+        list(APPEND _Vulkan_hint_library_search_paths
+          "${_MoltenVK_path}/dylib/macOS"
+        )
+      endif()
+    endif()
+    unset(_MoltenVK_path)
+  endif()
 endif()
 
 find_path(Vulkan_INCLUDE_DIR
diff --git a/Modules/Findosg_functions.cmake b/Modules/Findosg_functions.cmake
index 8fdfaeb..6775f9c 100644
--- a/Modules/Findosg_functions.cmake
+++ b/Modules/Findosg_functions.cmake
@@ -43,7 +43,7 @@
   string(TOUPPER ${module} module_uc)
 
   find_library(${module_uc}_LIBRARY_RELEASE
-    NAMES ${library}
+    NAMES ${library} ${library}rd
     HINTS
       ENV ${module_uc}_DIR
       ENV OSG_DIR
diff --git a/Modules/GNUInstallDirs.cmake b/Modules/GNUInstallDirs.cmake
index f677c27..c2aa29a 100644
--- a/Modules/GNUInstallDirs.cmake
+++ b/Modules/GNUInstallDirs.cmake
@@ -86,6 +86,15 @@
 
   On Debian, this may be ``lib/<multiarch-tuple>`` when
   :variable:`CMAKE_INSTALL_PREFIX` is ``/usr``.
+
+  .. note::
+
+    When an alternative installation prefix is specified with the
+    :option:`--prefix <cmake--install --prefix>` option at install time,
+    the special case with multi-architecture tuple is evaluated based on
+    the configuration-time :variable:`CMAKE_INSTALL_PREFIX`, not on the
+    alternative prefix value.
+
 ``INCLUDEDIR``
   C header files (``include``)
 ``OLDINCLUDEDIR``
@@ -94,6 +103,12 @@
   read-only architecture-independent data root (``share``)
 ``DATADIR``
   read-only architecture-independent data (``DATAROOTDIR``)
+
+  The ``DATADIR`` and ``DATAROOTDIR`` are treated separately so that
+  ``DATADIR`` can be customized for project-specific data files, while
+  ``DATAROOTDIR`` remains unchanged for standard architecture-independent
+  locations ``INFODIR``, ``LOCALEDIR``, ``MANDIR``, and ``DOCDIR``.
+
 ``INFODIR``
   info documentation (``DATAROOTDIR/info``)
 ``LOCALEDIR``
@@ -168,6 +183,13 @@
     absolute paths ``/etc/opt/...``, ``/var/opt/...`` and
     ``/var/run/opt/...`` respectively. See policy :policy:`CMP0192`.
 
+.. note::
+
+  When an alternative installation prefix is specified with the
+  :option:`--prefix <cmake--install --prefix>` option at install time,
+  these special cases are evaluated based on the configuration-time
+  :variable:`CMAKE_INSTALL_PREFIX`, not on the alternative prefix value.
+
 .. _`Filesystem Hierarchy Standard`: https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html
 
 Commands
diff --git a/Modules/GoogleTest.cmake b/Modules/GoogleTest.cmake
index 2fded3f..992b71e 100644
--- a/Modules/GoogleTest.cmake
+++ b/Modules/GoogleTest.cmake
@@ -145,8 +145,8 @@
   ``exe``
     The path to the test executable or the name of a CMake target.
   ``args``
-    A ;-list of extra arguments to be passed to executable.  The entire
-    list must be passed as a single argument.  Enclose it in quotes,
+    A semicolon-separated list of extra arguments to be passed to executable.
+    The entire list must be passed as a single argument.  Enclose it in quotes,
     or pass ``""`` for no arguments.
   ``files...``
     A list of source files to search for tests and test fixtures.
@@ -332,7 +332,7 @@
 
 # Save project's policies
 block(SCOPE_FOR POLICIES)
-cmake_policy(VERSION 3.30)
+cmake_policy(VERSION 4.2)
 
 #------------------------------------------------------------------------------
 function(gtest_add_tests)
diff --git a/Modules/GoogleTestAddTests.cmake b/Modules/GoogleTestAddTests.cmake
index 940cea0..b12a336 100644
--- a/Modules/GoogleTestAddTests.cmake
+++ b/Modules/GoogleTestAddTests.cmake
@@ -1,8 +1,7 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file LICENSE.rst or https://cmake.org/licensing for details.
 
-cmake_minimum_required(VERSION 3.30)
-cmake_policy(SET CMP0174 NEW)   # TODO: Remove this when we can update the above to 3.31
+cmake_minimum_required(VERSION 4.2)
 
 function(add_command name test_name)
   set(args "")
@@ -383,6 +382,7 @@
       "Error running test executable.\n"
       "  Path: '${path}'\n"
       "  Working directory: '${arg_TEST_WORKING_DIR}'\n"
+      "  Timeout: '${arg_TEST_DISCOVERY_TIMEOUT}'\n"
       "  Result: ${result}\n"
       "  Output:\n"
       "    ${output}\n"
diff --git a/Modules/Internal/CMakeChipStarHIP.cmake b/Modules/Internal/CMakeChipStarHIP.cmake
new file mode 100644
index 0000000..1249220
--- /dev/null
+++ b/Modules/Internal/CMakeChipStarHIP.cmake
@@ -0,0 +1,54 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+# Helper functions for chipStar (spirv platform) HIP support
+
+# Set chipStar compile flags in CMAKE_HIP_COMPILE_OBJECT
+function(_cmake_chipstar_set_compiler_flags)
+  if(NOT CMAKE_HIP_PLATFORM STREQUAL "spirv" OR NOT CMAKE_HIP_COMPILER_ID STREQUAL "Clang")
+    return()
+  endif()
+  set(_hip_path "${CMAKE_HIP_COMPILER_ROCM_ROOT}")
+  set(_chipstar_flags "--offload=spirv64 --hip-path=\"${_hip_path}\" -nogpulib -nohipwrapperinc -include \"${_hip_path}/include/hip/spirv_fixups.h\"")
+  set(CMAKE_HIP_COMPILE_OBJECT
+    "<CMAKE_HIP_COMPILER> ${_chipstar_flags} <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -x hip -c <SOURCE>" PARENT_SCOPE)
+endfunction()
+
+# Set link commands for chipStar to include libCHIP.so
+# This makes CMake treat it as if the compiler driver links it implicitly
+function(_cmake_chipstar_set_link_commands)
+  if(NOT CMAKE_HIP_PLATFORM STREQUAL "spirv")
+    return()
+  endif()
+  set(_hip_path "${CMAKE_HIP_COMPILER_ROCM_ROOT}")
+  set(_chipstar_lib "${_hip_path}/lib/libCHIP.so")
+  # Set link command templates with libCHIP.so appended (quoted for paths with spaces)
+  set(CMAKE_HIP_LINK_EXECUTABLE
+    "<CMAKE_HIP_COMPILER> <FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> \"${_chipstar_lib}\"" PARENT_SCOPE)
+  set(CMAKE_HIP_CREATE_SHARED_LIBRARY
+    "<CMAKE_HIP_COMPILER> <CMAKE_SHARED_LIBRARY_HIP_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES> \"${_chipstar_lib}\"" PARENT_SCOPE)
+  set(CMAKE_HIP_CREATE_SHARED_MODULE
+    "<CMAKE_HIP_COMPILER> <CMAKE_SHARED_LIBRARY_HIP_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES> \"${_chipstar_lib}\"" PARENT_SCOPE)
+endfunction()
+
+
+
+# Set compiler ID test flags for chipStar (called before CMAKE_HIP_COMPILER_ROCM_ROOT is set)
+function(_cmake_chipstar_set_compiler_id_flags)
+  if(NOT CMAKE_HIP_PLATFORM STREQUAL "spirv")
+    return()
+  endif()
+  # At this point CMAKE_HIP_COMPILER_ROCM_ROOT isn't set yet, use HIP_PATH or hipconfig
+  set(_hip_path "$ENV{HIP_PATH}")
+  if(NOT IS_DIRECTORY "${_hip_path}")
+    execute_process(COMMAND hipconfig --rocmpath
+      OUTPUT_VARIABLE _hip_path OUTPUT_STRIP_TRAILING_WHITESPACE)
+  endif()
+  if(IS_DIRECTORY "${_hip_path}")
+    file(TO_CMAKE_PATH "${_hip_path}" _hip_path)
+    # All flags in one string so they're used together. -no-hip-rt prevents linking amdhip64.
+    list(APPEND CMAKE_HIP_COMPILER_ID_TEST_FLAGS_FIRST
+      "-v --offload=spirv64 --hip-path=\"${_hip_path}\" -nogpulib -nohipwrapperinc -no-hip-rt \"${_hip_path}/lib/libCHIP.so\" -include \"${_hip_path}/include/hip/spirv_fixups.h\"")
+    set(CMAKE_HIP_COMPILER_ID_TEST_FLAGS_FIRST "${CMAKE_HIP_COMPILER_ID_TEST_FLAGS_FIRST}" PARENT_SCOPE)
+  endif()
+endfunction()
diff --git a/Modules/Internal/CMakeNVCCParseImplicitInfo.cmake b/Modules/Internal/CMakeNVCCParseImplicitInfo.cmake
index 7369847..ea07a22 100644
--- a/Modules/Internal/CMakeNVCCParseImplicitInfo.cmake
+++ b/Modules/Internal/CMakeNVCCParseImplicitInfo.cmake
@@ -4,7 +4,11 @@
 macro(cmake_nvcc_parse_implicit_info lang lang_var_)
   set(_nvcc_log "")
   string(REPLACE "\r" "" _nvcc_output_orig "${CMAKE_${lang}_COMPILER_PRODUCED_OUTPUT}")
-  if(_nvcc_output_orig MATCHES "#\\\$ +PATH= *([^\n]*)\n")
+  if(_nvcc_output_orig MATCHES "#\\\$ +PATH= *([^\n]*)\n.*#\\\$ +PATH= *([^\n]*)\n")
+    set(_nvcc_path "${CMAKE_MATCH_2}")
+    string(APPEND _nvcc_log "  found 'PATH=' string: [${_nvcc_path}]\n")
+    string(REPLACE ":" ";" _nvcc_path "${_nvcc_path}")
+  elseif(_nvcc_output_orig MATCHES "#\\\$ +PATH= *([^\n]*)\n")
     set(_nvcc_path "${CMAKE_MATCH_1}")
     string(APPEND _nvcc_log "  found 'PATH=' string: [${_nvcc_path}]\n")
     string(REPLACE ":" ";" _nvcc_path "${_nvcc_path}")
@@ -13,7 +17,10 @@
     string(REPLACE "\n" "\n    " _nvcc_output_log "\n${_nvcc_output_orig}")
     string(APPEND _nvcc_log "  no 'PATH=' string found in nvcc output:${_nvcc_output_log}\n")
   endif()
-  if(_nvcc_output_orig MATCHES "#\\\$ +LIBRARIES= *([^\n]*)\n")
+  if(_nvcc_output_orig MATCHES "#\\\$ +LIBRARIES= *([^\n]*)\n.*#\\\$ +LIBRARIES= *([^\n]*)\n")
+    set(_nvcc_libraries "${CMAKE_MATCH_2}")
+    string(APPEND _nvcc_log "  found 'LIBRARIES=' string: [${_nvcc_libraries}]\n")
+  elseif(_nvcc_output_orig MATCHES "#\\\$ +LIBRARIES= *([^\n]*)\n")
     set(_nvcc_libraries "${CMAKE_MATCH_1}")
     string(APPEND _nvcc_log "  found 'LIBRARIES=' string: [${_nvcc_libraries}]\n")
   else()
@@ -21,7 +28,10 @@
     string(REPLACE "\n" "\n    " _nvcc_output_log "\n${_nvcc_output_orig}")
     string(APPEND _nvcc_log "  no 'LIBRARIES=' string found in nvcc output:${_nvcc_output_log}\n")
   endif()
-  if(_nvcc_output_orig MATCHES "#\\\$ +INCLUDES= *([^\n]*)\n")
+  if(_nvcc_output_orig MATCHES "#\\\$ +INCLUDES= *([^\n]*)\n.*#\\\$ +INCLUDES= *([^\n]*)\n")
+    set(_nvcc_includes "${CMAKE_MATCH_2}")
+    string(APPEND _nvcc_log "  found 'INCLUDES=' string: [${_nvcc_includes}]\n")
+  elseif(_nvcc_output_orig MATCHES "#\\\$ +INCLUDES= *([^\n]*)\n")
     set(_nvcc_includes "${CMAKE_MATCH_1}")
     string(APPEND _nvcc_log "  found 'INCLUDES=' string: [${_nvcc_includes}]\n")
   else()
@@ -29,7 +39,10 @@
     string(REPLACE "\n" "\n    " _nvcc_output_log "\n${_nvcc_output_orig}")
     string(APPEND _nvcc_log "  no 'INCLUDES=' string found in nvcc output:${_nvcc_output_log}\n")
   endif()
-  if(_nvcc_output_orig MATCHES "#\\\$ +SYSTEM_INCLUDES= *([^\n]*)\n")
+  if(_nvcc_output_orig MATCHES "#\\\$ +SYSTEM_INCLUDES= *([^\n]*)\n.*#\\\$ +SYSTEM_INCLUDES= *([^\n]*)\n")
+    set(_nvcc_system_includes "${CMAKE_MATCH_2}")
+    string(APPEND _nvcc_log "  found 'SYSTEM_INCLUDES=' string: [${_nvcc_system_includes}]\n")
+  elseif(_nvcc_output_orig MATCHES "#\\\$ +SYSTEM_INCLUDES= *([^\n]*)\n")
     set(_nvcc_system_includes "${CMAKE_MATCH_1}")
     string(APPEND _nvcc_log "  found 'SYSTEM_INCLUDES=' string: [${_nvcc_system_includes}]\n")
   else()
diff --git a/Modules/Internal/CPack/CPack.STGZ_Header.sh.in b/Modules/Internal/CPack/CPack.STGZ_Header.sh.in
index a857aa5..fece7ed 100755
--- a/Modules/Internal/CPack/CPack.STGZ_Header.sh.in
+++ b/Modules/Internal/CPack/CPack.STGZ_Header.sh.in
@@ -136,8 +136,16 @@
 use_new_tail_syntax="-n"
 tail $use_new_tail_syntax +1 "$0" > /dev/null 2> /dev/null || use_new_tail_syntax=""
 
-extractor="pax -r"
-command -v pax > /dev/null 2> /dev/null || extractor="tar xf -"
+if command -v pax > /dev/null 2> /dev/null; then
+  extractor="pax -r"
+else
+  # Avoid replacing directory symlinks with directories from the package.
+  if tar --help 2> /dev/null | grep "keep-directory-symlink" > /dev/null 2> /dev/null; then
+    extractor="tar --keep-directory-symlink -xf -"
+  else
+    extractor="tar xf -"
+  fi
+fi
 
 tail $use_new_tail_syntax +###CPACK_HEADER_LENGTH### "$0" | gunzip | (cd "${toplevel}" && ${extractor}) || cpack_echo_exit "Problem unpacking the @CPACK_PACKAGE_FILE_NAME@"
 
diff --git a/Modules/Internal/CPack/CPackDeb.cmake b/Modules/Internal/CPack/CPackDeb.cmake
index 873c7bc..046adc2 100644
--- a/Modules/Internal/CPack/CPackDeb.cmake
+++ b/Modules/Internal/CPack/CPackDeb.cmake
@@ -808,6 +808,13 @@
     string(REGEX REPLACE "\.deb$" "-dbgsym.ddeb" CPACK_DBGSYM_OUTPUT_FILE_NAME "${CPACK_OUTPUT_FILE_NAME}")
   endif()
 
+  if(NOT DEFINED CPACK_DEBIAN_COMPRESSION_LEVEL)
+    set(CPACK_DEBIAN_COMPRESSION_LEVEL "0")
+    if(DEFINED CPACK_COMPRESSION_LEVEL)
+      set(CPACK_DEBIAN_COMPRESSION_LEVEL "${CPACK_COMPRESSION_LEVEL}")
+    endif()
+  endif()
+
   # Print out some debug information if we were asked for that
   if(CPACK_DEBIAN_PACKAGE_DEBUG)
      message("CPackDeb:Debug: CPACK_TOPLEVEL_DIRECTORY          = '${CPACK_TOPLEVEL_DIRECTORY}'")
@@ -820,6 +827,7 @@
      message("CPackDeb:Debug: CPACK_TEMPORARY_PACKAGE_FILE_NAME = '${CPACK_TEMPORARY_PACKAGE_FILE_NAME}'")
      message("CPackDeb:Debug: CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION = '${CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION}'")
      message("CPackDeb:Debug: CPACK_DEBIAN_PACKAGE_SOURCE       = '${CPACK_DEBIAN_PACKAGE_SOURCE}'")
+     message("CPackDeb:Debug: CPACK_DEBIAN_COMPRESSION_LEVEL       = '${CPACK_DEBIAN_COMPRESSION_LEVEL}'")
   endif()
 
   # For debian source packages:
@@ -849,6 +857,7 @@
   set(GEN_CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}" PARENT_SCOPE)
   set(GEN_CPACK_DEBIAN_ARCHIVE_TYPE "${CPACK_DEBIAN_ARCHIVE_TYPE}" PARENT_SCOPE)
   set(GEN_CPACK_DEBIAN_COMPRESSION_TYPE "${CPACK_DEBIAN_COMPRESSION_TYPE}" PARENT_SCOPE)
+  set(GEN_CPACK_DEBIAN_COMPRESSION_LEVEL "${CPACK_DEBIAN_COMPRESSION_LEVEL}" PARENT_SCOPE)
   set(GEN_CPACK_DEBIAN_PACKAGE_RECOMMENDS "${CPACK_DEBIAN_PACKAGE_RECOMMENDS}" PARENT_SCOPE)
   set(GEN_CPACK_DEBIAN_PACKAGE_SUGGESTS "${CPACK_DEBIAN_PACKAGE_SUGGESTS}" PARENT_SCOPE)
   set(GEN_CPACK_DEBIAN_PACKAGE_HOMEPAGE "${CPACK_DEBIAN_PACKAGE_HOMEPAGE}" PARENT_SCOPE)
diff --git a/Modules/Internal/HeaderpadWorkaround.cmake b/Modules/Internal/HeaderpadWorkaround.cmake
index 0555ded..3fc6d28 100644
--- a/Modules/Internal/HeaderpadWorkaround.cmake
+++ b/Modules/Internal/HeaderpadWorkaround.cmake
@@ -48,6 +48,7 @@
   if(remove_headerpad)
     foreach(flag IN ITEMS
       CMAKE_${_LANG}_LINK_FLAGS
+      CMAKE_EXECUTABLE_CREATE_${_LANG}_FLAGS
       CMAKE_SHARED_LIBRARY_CREATE_${_LANG}_FLAGS
       CMAKE_SHARED_MODULE_CREATE_${_LANG}_FLAGS)
       string(REPLACE "-Wl,-headerpad_max_install_names" "" ${flag} "${${flag}}")
diff --git a/Modules/Platform/AIX-GNU.cmake b/Modules/Platform/AIX-GNU.cmake
index 91cf2d7..a03911d 100644
--- a/Modules/Platform/AIX-GNU.cmake
+++ b/Modules/Platform/AIX-GNU.cmake
@@ -16,7 +16,12 @@
   set(CMAKE_${lang}_USE_IMPLICIT_LINK_DIRECTORIES_IN_RUNTIME_PATH 1)
   set(CMAKE_${lang}_VERBOSE_LINK_FLAG "-Wl,-v")
 
-  set(CMAKE_${lang}_LINK_FLAGS "-Wl,-bnoipath")
+  set(CMAKE_EXECUTABLE_CREATE_${lang}_FLAGS "-Wl,-bnoipath")
+  cmake_policy(GET CMP0210 _CMP0210)
+  if (NOT _CMP0210 STREQUAL "NEW")
+    set(CMAKE_${lang}_LINK_FLAGS "${CMAKE_EXECUTABLE_CREATE_${lang}_FLAGS}")
+  endif()
+  unset(_CMP0210)
 
   if(CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 7 OR CMAKE_SYSTEM_VERSION VERSION_LESS 7.1)
     unset(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY)
diff --git a/Modules/Platform/AIX-XL.cmake b/Modules/Platform/AIX-XL.cmake
index 9dfd9e5..8e82649 100644
--- a/Modules/Platform/AIX-XL.cmake
+++ b/Modules/Platform/AIX-XL.cmake
@@ -16,7 +16,12 @@
   set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS " ")
   set(CMAKE_SHARED_MODULE_${lang}_FLAGS  " ")
 
-  set(CMAKE_${lang}_LINK_FLAGS "-Wl,-bnoipath")
+  set(CMAKE_EXECUTABLE_CREATE_${lang}_FLAGS "-Wl,-bnoipath")
+  cmake_policy(GET CMP0210 _CMP0210)
+  if (NOT _CMP0210 STREQUAL "NEW")
+    set(CMAKE_${lang}_LINK_FLAGS "${CMAKE_EXECUTABLE_CREATE_${lang}_FLAGS}")
+  endif()
+  unset(_CMP0210)
 
   set(_OBJECTS " <OBJECTS>")
   if(DEFINED CMAKE_XL_CreateExportList AND CMAKE_XL_CreateExportList STREQUAL "")
diff --git a/Modules/Platform/Darwin-Initialize.cmake b/Modules/Platform/Darwin-Initialize.cmake
index d518ac9..fe42de1 100644
--- a/Modules/Platform/Darwin-Initialize.cmake
+++ b/Modules/Platform/Darwin-Initialize.cmake
@@ -222,6 +222,10 @@
     set(_arch_sysroot "")
     foreach(sdk ${_sdks})
       list(FIND _sdk_archs_${sdk} ${arch} arch_index)
+      # arm64e is a superset of arm64; an SDK listing arm64e supports arm64 binaries.
+      if(arch_index EQUAL -1 AND arch STREQUAL "arm64")
+        list(FIND _sdk_archs_${sdk} "arm64e" arch_index)
+      endif()
       if(NOT arch_index EQUAL -1)
         set(_arch_sysroot ${_sdk_path_${sdk}})
         break()
diff --git a/Modules/Platform/Darwin.cmake b/Modules/Platform/Darwin.cmake
index 42c6b35..bd46732 100644
--- a/Modules/Platform/Darwin.cmake
+++ b/Modules/Platform/Darwin.cmake
@@ -26,18 +26,6 @@
 string(REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_SYSTEM_VERSION}")
 string(REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\2" DARWIN_MINOR_VERSION "${CMAKE_SYSTEM_VERSION}")
 
-# Do not use the "-Wl,-search_paths_first" flag with the OSX 10.2 compiler.
-# Done this way because it is too early to do a TRY_COMPILE.
-if(NOT DEFINED HAVE_FLAG_SEARCH_PATHS_FIRST)
-  set(HAVE_FLAG_SEARCH_PATHS_FIRST 0)
-  if("${DARWIN_MAJOR_VERSION}" GREATER 6)
-    set(HAVE_FLAG_SEARCH_PATHS_FIRST 1)
-  endif()
-endif()
-# More desirable, but does not work:
-  #include(CheckCXXCompilerFlag)
-  #check_cxx_compiler_flag("-Wl,-search_paths_first" HAVE_FLAG_SEARCH_PATHS_FIRST)
-
 set(CMAKE_SHARED_LIBRARY_PREFIX "lib")
 set(CMAKE_SHARED_LIBRARY_SUFFIX ".dylib")
 set(CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES ".tbd" ".so")
@@ -51,19 +39,21 @@
   set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
 endif()
 
+cmake_policy(GET CMP0210 _CMP0210)
 foreach(lang C CXX OBJC OBJCXX)
   set(CMAKE_${lang}_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
   set(CMAKE_${lang}_OSX_CURRENT_VERSION_FLAG "-current_version ")
-  set(CMAKE_${lang}_LINK_FLAGS "-Wl,-headerpad_max_install_names")
 
-  if(HAVE_FLAG_SEARCH_PATHS_FIRST)
-    set(CMAKE_${lang}_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_${lang}_LINK_FLAGS}")
+  set(CMAKE_EXECUTABLE_CREATE_${lang}_FLAGS "-Wl,-search_paths_first -Wl,-headerpad_max_install_names")
+  if (NOT _CMP0210 STREQUAL "NEW")
+    set(CMAKE_${lang}_LINK_FLAGS "${CMAKE_EXECUTABLE_CREATE_${lang}_FLAGS}")
   endif()
 
   set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-dynamiclib -Wl,-headerpad_max_install_names")
   set(CMAKE_SHARED_MODULE_CREATE_${lang}_FLAGS "-bundle -Wl,-headerpad_max_install_names")
   set(CMAKE_SHARED_MODULE_LOADER_${lang}_FLAG "-Wl,-bundle_loader,")
 endforeach()
+unset(_CMP0210)
 
 set(CMAKE_PLATFORM_HAS_INSTALLNAME 1)
 set(CMAKE_FIND_LIBRARY_SUFFIXES ".tbd" ".dylib" ".so" ".a")
diff --git a/Modules/Platform/HP-UX-GNU.cmake b/Modules/Platform/HP-UX-GNU.cmake
index 30e1327..7cb9332 100644
--- a/Modules/Platform/HP-UX-GNU.cmake
+++ b/Modules/Platform/HP-UX-GNU.cmake
@@ -15,6 +15,12 @@
   set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG_SEP ":")
   set(CMAKE_SHARED_LIBRARY_SONAME_${lang}_FLAG "-Wl,+h")
 
-  set(CMAKE_${lang}_LINK_FLAGS "-Wl,+s,+nodefaultrpath")
+  set(CMAKE_EXECUTABLE_CREATE_${lang}_FLAGS "-Wl,+s,+nodefaultrpath")
+  cmake_policy(GET CMP0210 _CMP0210)
+  if (NOT _CMP0210 STREQUAL "NEW")
+    set(CMAKE_${lang}_LINK_FLAGS "${CMAKE_EXECUTABLE_CREATE_${lang}_FLAGS}")
+  endif()
+  unset(_CMP0210)
+
   unset(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY)
 endmacro()
diff --git a/Modules/Platform/HP-UX-HP.cmake b/Modules/Platform/HP-UX-HP.cmake
index 11f5caa..f9f131d 100644
--- a/Modules/Platform/HP-UX-HP.cmake
+++ b/Modules/Platform/HP-UX-HP.cmake
@@ -19,5 +19,10 @@
 
   string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
 
-  set(CMAKE_${lang}_LINK_FLAGS "-Wl,+s,+nodefaultrpath")
+  set(CMAKE_EXECUTABLE_CREATE_${lang}_FLAGS "-Wl,+s,+nodefaultrpath")
+  cmake_policy(GET CMP0210 _CMP0210)
+  if (NOT _CMP0210 STREQUAL "NEW")
+    set(CMAKE_${lang}_LINK_FLAGS "${CMAKE_EXECUTABLE_CREATE_${lang}_FLAGS}")
+  endif()
+  unset(_CMP0210)
 endmacro()
diff --git a/Modules/Platform/Linux-IntelLLVM.cmake b/Modules/Platform/Linux-IntelLLVM.cmake
index fd7064f..4524b3b 100644
--- a/Modules/Platform/Linux-IntelLLVM.cmake
+++ b/Modules/Platform/Linux-IntelLLVM.cmake
@@ -11,7 +11,6 @@
 macro(__linux_compiler_intel_llvm lang)
   set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
   set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIE")
-  set(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER NO)
   set(_CMAKE_${lang}_PIE_MAY_BE_SUPPORTED_BY_LINKER YES)
   set(CMAKE_${lang}_LINK_OPTIONS_PIE ${CMAKE_${lang}_COMPILE_OPTIONS_PIE} "-pie")
   set(CMAKE_${lang}_LINK_OPTIONS_NO_PIE "-no-pie")
diff --git a/Modules/Platform/Windows-Clang-C.cmake b/Modules/Platform/Windows-Clang-C.cmake
index a90e4b7..a1c52d9 100644
--- a/Modules/Platform/Windows-Clang-C.cmake
+++ b/Modules/Platform/Windows-Clang-C.cmake
@@ -1,18 +1,10 @@
 include(Platform/Windows-Clang)
 __windows_compiler_clang(C)
 
-if("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
-  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
-      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
-      AND CMAKE_DEPFILE_FLAGS_C)
-    set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
-  endif()
-elseif("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
-  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
-      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
-      AND CMAKE_DEPFILE_FLAGS_C)
-    # dependencies are computed by the compiler itself
-    set(CMAKE_C_DEPFILE_FORMAT gcc)
-    set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
-  endif()
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+    AND CMAKE_DEPFILE_FLAGS_C)
+  # dependencies are computed by the compiler itself
+  set(CMAKE_C_DEPFILE_FORMAT gcc)
+  set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
 endif()
diff --git a/Modules/Platform/Windows-Clang-CXX.cmake b/Modules/Platform/Windows-Clang-CXX.cmake
index af2a48f..6624088 100644
--- a/Modules/Platform/Windows-Clang-CXX.cmake
+++ b/Modules/Platform/Windows-Clang-CXX.cmake
@@ -2,18 +2,10 @@
 set(_COMPILE_CXX_MSVC " -TP")
 __windows_compiler_clang(CXX)
 
-if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
-  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
-      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
-      AND CMAKE_DEPFILE_FLAGS_CXX)
-    set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
-  endif()
-elseif("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
-  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
-      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
-      AND CMAKE_DEPFILE_FLAGS_CXX)
-    # dependencies are computed by the compiler itself
-    set(CMAKE_CXX_DEPFILE_FORMAT gcc)
-    set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
-  endif()
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+    AND CMAKE_DEPFILE_FLAGS_CXX)
+  # dependencies are computed by the compiler itself
+  set(CMAKE_CXX_DEPFILE_FORMAT gcc)
+  set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
 endif()
diff --git a/Modules/Platform/Windows-Clang-HIP.cmake b/Modules/Platform/Windows-Clang-HIP.cmake
index 20879fa..bb80e59 100644
--- a/Modules/Platform/Windows-Clang-HIP.cmake
+++ b/Modules/Platform/Windows-Clang-HIP.cmake
@@ -1,19 +1,11 @@
 include(Platform/Windows-Clang)
-set(_COMPILE_HIP_MSVC " -TP")
+set(_COMPILE_HIP_MSVC " -x hip")
 __windows_compiler_clang(HIP)
 
-if("x${CMAKE_HIP_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
-  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
-      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
-      AND CMAKE_DEPFILE_FLAGS_HIP)
-    set(CMAKE_HIP_DEPENDS_USE_COMPILER TRUE)
-  endif()
-elseif("x${CMAKE_HIP_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
-  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
-      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
-      AND CMAKE_DEPFILE_FLAGS_HIP)
-    # dependencies are computed by the compiler itself
-    set(CMAKE_HIP_DEPFILE_FORMAT gcc)
-    set(CMAKE_HIP_DEPENDS_USE_COMPILER TRUE)
-  endif()
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+    AND CMAKE_DEPFILE_FLAGS_HIP)
+  # dependencies are computed by the compiler itself
+  set(CMAKE_HIP_DEPFILE_FORMAT gcc)
+  set(CMAKE_HIP_DEPENDS_USE_COMPILER TRUE)
 endif()
diff --git a/Modules/Platform/Windows-Clang-OBJC.cmake b/Modules/Platform/Windows-Clang-OBJC.cmake
index 7babb98..7e9a164 100644
--- a/Modules/Platform/Windows-Clang-OBJC.cmake
+++ b/Modules/Platform/Windows-Clang-OBJC.cmake
@@ -1,18 +1,10 @@
 include(Platform/Windows-Clang)
 __windows_compiler_clang(OBJC)
 
-if("x${CMAKE_OBJC_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
-  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
-      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
-      AND CMAKE_DEPFILE_FLAGS_OBJC)
-    set(CMAKE_OBJC_DEPENDS_USE_COMPILER TRUE)
-  endif()
-elseif("x${CMAKE_OBJC_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
-  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
-      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
-      AND CMAKE_DEPFILE_FLAGS_OBJC)
-    # dependencies are computed by the compiler itself
-    set(CMAKE_OBJC_DEPFILE_FORMAT gcc)
-    set(CMAKE_OBJC_DEPENDS_USE_COMPILER TRUE)
-  endif()
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+    AND CMAKE_DEPFILE_FLAGS_OBJC)
+  # dependencies are computed by the compiler itself
+  set(CMAKE_OBJC_DEPFILE_FORMAT gcc)
+  set(CMAKE_OBJC_DEPENDS_USE_COMPILER TRUE)
 endif()
diff --git a/Modules/Platform/Windows-Clang-OBJCXX.cmake b/Modules/Platform/Windows-Clang-OBJCXX.cmake
index 3bc1673..55b9070 100644
--- a/Modules/Platform/Windows-Clang-OBJCXX.cmake
+++ b/Modules/Platform/Windows-Clang-OBJCXX.cmake
@@ -1,18 +1,10 @@
 include(Platform/Windows-Clang)
 __windows_compiler_clang(OBJCXX)
 
-if("x${CMAKE_OBJCXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
-  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
-      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
-      AND CMAKE_DEPFILE_FLAGS_OBJCXX)
-    set(CMAKE_OBJCXX_DEPENDS_USE_COMPILER TRUE)
-  endif()
-elseif("x${CMAKE_OBJCXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
-  if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
-      AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
-      AND CMAKE_DEPFILE_FLAGS_OBJCXX)
-    # dependencies are computed by the compiler itself
-    set(CMAKE_OBJCXX_DEPFILE_FORMAT gcc)
-    set(CMAKE_OBJCXX_DEPENDS_USE_COMPILER TRUE)
-  endif()
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
+    AND CMAKE_DEPFILE_FLAGS_OBJCXX)
+  # dependencies are computed by the compiler itself
+  set(CMAKE_OBJCXX_DEPFILE_FORMAT gcc)
+  set(CMAKE_OBJCXX_DEPENDS_USE_COMPILER TRUE)
 endif()
diff --git a/Modules/Platform/Windows-Clang.cmake b/Modules/Platform/Windows-Clang.cmake
index 82e9d82..0c002dd 100644
--- a/Modules/Platform/Windows-Clang.cmake
+++ b/Modules/Platform/Windows-Clang.cmake
@@ -233,6 +233,11 @@
     macro(__windows_compiler_clang_base lang)
       set(_COMPILE_${lang} "${_COMPILE_${lang}_MSVC}")
       __windows_compiler_msvc(${lang})
+
+      # Prefer clang-cl's gcc-style depfile over cl-style /showIncludes
+      set(CMAKE_DEPFILE_FLAGS_${lang} "-clang:-MD -clang:-MT<DEP_TARGET> -clang:-MF<DEP_FILE>")
+      unset(CMAKE_${lang}_DEPFILE_FORMAT)
+
       unset(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_DEBUG_INFORMATION_FORMAT_EditAndContinue) # -ZI not supported by Clang
       set(CMAKE_${lang}_COMPILE_OPTIONS_WARNING_AS_ERROR "-WX")
       set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-imsvc")
diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake
index cacddd4..f7cc13f 100644
--- a/Modules/Platform/Windows-MSVC.cmake
+++ b/Modules/Platform/Windows-MSVC.cmake
@@ -50,6 +50,8 @@
     set(_compiler_version ${CMAKE_Fortran_SIMULATE_VERSION})
   elseif(CMAKE_CUDA_SIMULATE_VERSION)
     set(_compiler_version ${CMAKE_CUDA_SIMULATE_VERSION})
+  elseif(CMAKE_HIP_SIMULATE_VERSION)
+    set(_compiler_version ${CMAKE_HIP_SIMULATE_VERSION})
   elseif(CMAKE_C_COMPILER_VERSION)
     set(_compiler_version ${CMAKE_C_COMPILER_VERSION})
   else()
@@ -390,12 +392,21 @@
 endif()
 unset(__WINDOWS_MSVC_CMP0184)
 
+# Use manifest directly on the linker's command line.
+set(_CMAKE_FASTBUILD_MANIFESTS "")
+if(CMAKE_GENERATOR MATCHES "FASTBuild")
+  string(APPEND _CMAKE_FASTBUILD_MANIFESTS " <MANIFESTS>")
+endif()
+
 macro(__windows_compiler_msvc lang)
   if(NOT MSVC_VERSION LESS 1400 AND NOT CMAKE_GENERATOR MATCHES "FASTBuild")
     # for 2005 make sure the manifest is put in the dll with mt
     set(_CMAKE_VS_LINK_DLL "<CMAKE_COMMAND> -E vs_link_dll --msvc-ver=${MSVC_VERSION} --intdir=<OBJECT_DIR> --rc=<CMAKE_RC_COMPILER> --mt=<CMAKE_MT> --manifests <MANIFESTS> -- ")
     set(_CMAKE_VS_LINK_EXE "<CMAKE_COMMAND> -E vs_link_exe --msvc-ver=${MSVC_VERSION} --intdir=<OBJECT_DIR> --rc=<CMAKE_RC_COMPILER> --mt=<CMAKE_MT> --manifests <MANIFESTS> -- ")
   endif()
+  if (CMAKE_GENERATOR MATCHES "FASTBuild")
+    set(CMAKE_${lang}_LINKER_MANIFEST_FLAG " /MANIFEST:EMBED /MANIFESTINPUT:")
+  endif()
   set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "")
   if(CMAKE_SYSTEM_NAME STREQUAL "WindowsKernelModeDriver")
     set(CMAKE_${lang}_SHARED_LIBRARY_COMPILE_DEFINITIONS "")
@@ -405,7 +416,7 @@
     set(_DLL_DRIVER "/dll")
   endif()
   set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
-    "${_CMAKE_VS_LINK_DLL}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> ${_DLL_DRIVER} /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <LINK_FLAGS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
+    "${_CMAKE_VS_LINK_DLL}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> ${_DLL_DRIVER} /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <LINK_FLAGS> <LINK_LIBRARIES>${_CMAKE_FASTBUILD_MANIFESTS} ${CMAKE_END_TEMP_FILE}")
   unset(_DLL_DRIVER)
 
   set(CMAKE_${lang}_CREATE_SHARED_MODULE ${CMAKE_${lang}_CREATE_SHARED_LIBRARY})
@@ -421,7 +432,7 @@
   set(CMAKE_${lang}_LINK_DEF_FILE_FLAG "/DEF:")
   set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_OBJECTS 1)
   set(CMAKE_${lang}_LINK_EXECUTABLE
-    "${_CMAKE_VS_LINK_EXE}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}")
+    "${_CMAKE_VS_LINK_EXE}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <LINK_FLAGS> <LINK_LIBRARIES>${_CMAKE_FASTBUILD_MANIFESTS} ${CMAKE_END_TEMP_FILE}")
 
   if(CMAKE_SYSTEM_NAME STREQUAL "WindowsCE")
     set(CMAKE_${lang}_CREATE_WIN32_EXE "/entry:WinMainCRTStartup")
@@ -483,7 +494,8 @@
   endif()
 
   if("x${lang}" STREQUAL "xC" OR
-      "x${lang}" STREQUAL "xCXX")
+      "x${lang}" STREQUAL "xCXX" OR
+      "x${lang}" STREQUAL "xHIP")
     if(CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT)
       set(_MDd "")
       set(_MD "")
diff --git a/Modules/UseJava.cmake b/Modules/UseJava.cmake
index b79d8d2..4192169 100644
--- a/Modules/UseJava.cmake
+++ b/Modules/UseJava.cmake
@@ -53,6 +53,7 @@
             [SOURCES] <source1> [<source2>...] [<resource1>...]
             [RESOURCES NAMESPACE <ns1> <resource1>... [NAMESPACE <nsX> <resourceX>...]... ]
             [INCLUDE_JARS <jar1> [<jar2>...]]
+            [INCLUDE_MODULES <jar1> [<jar2>...]]
             [ENTRY_POINT <entry>]
             [VERSION <version>]
             [MANIFEST <manifest>]
@@ -109,6 +110,13 @@
     jar files listed as sources are ignored (as they have been since the first
     version of this module).
 
+  ``INCLUDE_MODULES``
+    .. versionadded:: 4.3
+
+    The list of jars are added to the module path when building the java sources
+    and also to the dependencies of the target. ``INCLUDE_MODULES`` also
+    accepts other target names created by ``add_jar()``.
+
   ``ENTRY_POINT``
     Defines an entry point in the jar file.
 
@@ -568,6 +576,9 @@
     generated docs. Same behavior as option ``-version`` of ``javadoc`` tool.
 #]=======================================================================]
 
+block(SCOPE_FOR POLICIES)
+cmake_policy(SET CMP0140 NEW) # For return(PROPAGATE ...)
+
 function (__java_copy_file src dest comment)
     add_custom_command(
         OUTPUT  ${dest}
@@ -665,11 +676,42 @@
     set(_UseJava_PATH_SEP ":")
 endif()
 
+function(__java_resolve_jar outvar_path path_or_tgt)
+    if (TARGET "${path_or_tgt}")
+        # Check if this is a target created by add_jar
+        get_target_property(jarpath "${path_or_tgt}" JAR_FILE)
+        set("${outvar_path}" "${jarpath}")
+        if (NOT jarpath) # Some other target that we do not know how to use as a JAR
+            message(SEND_ERROR "target ${path_or_tgt} is not a jar")
+        endif ()
+    else () # Interpreted as the path to an external JAR
+        set("${outvar_path}" "${path_or_tgt}")
+    endif ()
+    return(PROPAGATE "${outvar_path}")
+endfunction()
+
+# Helper that processes a list of add_jar-created targets or paths to external
+# JAR files and:
+# - appends each item (target name or JAR path) to the list in outvar_depsraw.
+# - appends the resolved JAR path to the list in outvar_depsresolved.
+# If any item cannot be resolved, because it is a target name that was not
+# created by add_jar, a SEND_ERROR message is raised.
+function(__java_build_deplists outvar_depsraw outvar_depsresolved jars_or_targets_lst)
+    foreach(item IN LISTS "${jars_or_targets_lst}")
+        __java_resolve_jar(res_path "${item}")
+        if (res_path) # We would get a falsy value in the error case
+            list(APPEND "${outvar_depsraw}" "${item}") # Keep the original name (possibly a target) here
+            list(APPEND "${outvar_depsresolved}" "${res_path}")
+        endif ()
+    endforeach()
+    return(PROPAGATE "${outvar_depsraw}" "${outvar_depsresolved}")
+endfunction()
+
 function(add_jar _TARGET_NAME)
 
     set(options)  # currently there are no zero value args (aka: options)
     set(oneValueArgs "ENTRY_POINT;MANIFEST;OUTPUT_DIR;;OUTPUT_NAME;VERSION" )
-    set(multiValueArgs "GENERATE_NATIVE_HEADERS;INCLUDE_JARS;RESOURCES;SOURCES" )
+    set(multiValueArgs "GENERATE_NATIVE_HEADERS;INCLUDE_JARS;INCLUDE_MODULES;RESOURCES;SOURCES" )
 
     cmake_parse_arguments(PARSE_ARGV 1 _add_jar
                     "${options}"
@@ -803,6 +845,7 @@
     set(_JAVA_COMPILE_FILELISTS)
     set(_JAVA_DEPENDS)
     set(_JAVA_COMPILE_DEPENDS)
+    set(_JAVA_COMPILE_MODDEPENDS)
     set(_JAVA_RESOURCE_FILES)
     set(_JAVA_RESOURCE_FILES_RELATIVE)
     foreach(_JAVA_SOURCE_FILE IN LISTS _JAVA_SOURCE_FILES)
@@ -838,7 +881,8 @@
             # Ignored for backward compatibility
 
         elseif (_JAVA_EXT STREQUAL "")
-            list(APPEND CMAKE_JAVA_INCLUDE_PATH ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}} ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}_CLASSPATH})
+            # XXX: this was not being used after setting!
+            # list(APPEND CMAKE_JAVA_INCLUDE_PATH ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}} ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}_CLASSPATH})
             list(APPEND _JAVA_DEPENDS ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}})
 
         else ()
@@ -857,24 +901,21 @@
                                         _JAVA_RESOURCE_FILES_RELATIVE)
     endif()
 
-    foreach(_JAVA_INCLUDE_JAR IN LISTS _add_jar_INCLUDE_JARS)
-        if (TARGET ${_JAVA_INCLUDE_JAR})
-            get_target_property(_JAVA_JAR_PATH ${_JAVA_INCLUDE_JAR} JAR_FILE)
-            if (_JAVA_JAR_PATH)
-                string(APPEND CMAKE_JAVA_INCLUDE_PATH_FINAL "${_UseJava_PATH_SEP}${_JAVA_JAR_PATH}")
-                list(APPEND CMAKE_JAVA_INCLUDE_PATH ${_JAVA_JAR_PATH})
-                list(APPEND _JAVA_DEPENDS ${_JAVA_INCLUDE_JAR})
-                list(APPEND _JAVA_COMPILE_DEPENDS ${_JAVA_JAR_PATH})
-            else ()
-                message(SEND_ERROR "add_jar: INCLUDE_JARS target ${_JAVA_INCLUDE_JAR} is not a jar")
-            endif ()
-        else ()
-            string(APPEND CMAKE_JAVA_INCLUDE_PATH_FINAL "${_UseJava_PATH_SEP}${_JAVA_INCLUDE_JAR}")
-            list(APPEND CMAKE_JAVA_INCLUDE_PATH "${_JAVA_INCLUDE_JAR}")
-            list(APPEND _JAVA_DEPENDS "${_JAVA_INCLUDE_JAR}")
-            list(APPEND _JAVA_COMPILE_DEPENDS "${_JAVA_INCLUDE_JAR}")
-        endif ()
-    endforeach()
+    # Build dependency lists and arguments for JARs in the classpath
+    __java_build_deplists(_JAVA_DEPENDS _JAVA_COMPILE_DEPENDS _add_jar_INCLUDE_JARS)
+    foreach (resolved_cp_item IN LISTS _JAVA_COMPILE_DEPENDS)
+        string(APPEND CMAKE_JAVA_INCLUDE_PATH_FINAL "${_UseJava_PATH_SEP}${resolved_cp_item}")
+    endforeach ()
+    # Build dependency lists and arguments for JARs in the modulepath
+    set(javac_mp_args)
+    if (_add_jar_INCLUDE_MODULES)
+        if (Java_VERSION VERSION_LESS 9)
+            message(SEND_ERROR "INCLUDE_MODULES requires Java 9+")
+        endif()
+        __java_build_deplists(_JAVA_DEPENDS _JAVA_COMPILE_MODDEPENDS _add_jar_INCLUDE_MODULES)
+        list(JOIN _JAVA_COMPILE_MODDEPENDS "${_UseJava_PATH_SEP}" javac_mp_args)
+        set(javac_mp_args "--module-path [[${javac_mp_args}]]")
+    endif()
 
     if (_JAVA_COMPILE_FILES OR _JAVA_COMPILE_FILELISTS)
         set (_JAVA_SOURCES_FILELISTS)
@@ -899,33 +940,41 @@
 
         cmake_language(GET_MESSAGE_LOG_LEVEL _LOG_LEVEL)
         # Compile the java files and create a list of class files
-        add_custom_command(
-            # NOTE: this command generates an artificial dependency file
-            OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
+        # NOTE: this command generates an artificial dependency file
+        set(stamp_file "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}")
+        add_custom_command(OUTPUT "${stamp_file}"
             COMMAND ${CMAKE_COMMAND}
                 -DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH}
                 -DCMAKE_JAR_CLASSES_PREFIX=${CMAKE_JAR_CLASSES_PREFIX}
                 -P ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/UseJava/ClearClassFiles.cmake
                 --log-level ${_LOG_LEVEL}
-            COMMAND ${Java_JAVAC_EXECUTABLE}
-                ${CMAKE_JAVA_COMPILE_FLAGS}
-                -classpath "${CMAKE_JAVA_INCLUDE_PATH_FINAL}"
-                -d ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
-                ${_GENERATE_NATIVE_HEADERS}
-                ${_JAVA_SOURCES_FILELISTS}
-            COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
-            DEPENDS ${_JAVA_COMPILE_FILES} ${_JAVA_COMPILE_FILELISTS} ${_JAVA_COMPILE_DEPENDS} ${_JAVA_SOURCES_FILE}
+            DEPENDS ${_JAVA_COMPILE_FILES} ${_JAVA_COMPILE_FILELISTS} ${_JAVA_COMPILE_DEPENDS} ${_JAVA_COMPILE_MODDEPENDS} ${_JAVA_SOURCES_FILE}
             WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
             COMMENT "Building Java objects for ${_TARGET_NAME}.jar"
             VERBATIM
         )
+        cmake_language(EVAL CODE "
+            add_custom_command(OUTPUT [[${stamp_file}]]
+                APPEND COMMAND [[${Java_JAVAC_EXECUTABLE}]]
+                    \${CMAKE_JAVA_COMPILE_FLAGS}
+                    -classpath [[${CMAKE_JAVA_INCLUDE_PATH_FINAL}]]
+                    ${javac_mp_args}
+                    -d [[${CMAKE_JAVA_CLASS_OUTPUT_PATH}]]
+                    \${_GENERATE_NATIVE_HEADERS}
+                    \${_JAVA_SOURCES_FILELISTS}
+            )
+        ")
+        add_custom_command(OUTPUT "${stamp_file}"
+            APPEND COMMAND ${CMAKE_COMMAND} -E touch "${stamp_file}"
+        )
+
         add_custom_command(
             OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
             COMMAND ${CMAKE_COMMAND}
                 -DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH}
                 -DCMAKE_JAR_CLASSES_PREFIX=${CMAKE_JAR_CLASSES_PREFIX}
                 -P ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/UseJava/ClassFilelist.cmake
-            DEPENDS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
+            DEPENDS "${stamp_file}"
             WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
             VERBATIM
         )
@@ -1725,3 +1774,5 @@
             DESTINATION ${_install_jar_exports_DESTINATION}
             ${_COMPONENT})
 endfunction()
+
+endblock()
diff --git a/Modules/UseJava/javaTargets.cmake.in b/Modules/UseJava/javaTargets.cmake.in
index 68643c4..7a88344 100644
--- a/Modules/UseJava/javaTargets.cmake.in
+++ b/Modules/UseJava/javaTargets.cmake.in
@@ -1,5 +1,5 @@
 cmake_policy(PUSH)
-cmake_policy(VERSION 2.8.12...4.0)
+cmake_policy(VERSION 2.8.12...4.1)
 
 #----------------------------------------------------------------
 # Generated CMake Java target import file.
diff --git a/Packaging/QtSDK/qt.tools.cmake.xx.qs.in b/Packaging/QtSDK/qt.tools.cmake.xx.qs.in
index b449581..42e49af 100644
--- a/Packaging/QtSDK/qt.tools.cmake.xx.qs.in
+++ b/Packaging/QtSDK/qt.tools.cmake.xx.qs.in
@@ -16,7 +16,7 @@
 Component.prototype.reactOnTargetDirChange = function(key, value)
 {
     if (key == "TargetDir") {
-        var path = value + "/%CMAKE_BIN_DIR%";
+        var path = value + "/%CMake_INSTALL_BIN_DIR%";
         installer.setValue("CMAKE%CMake_VERSION_MAJOR%%CMake_VERSION_MINOR%_BIN_DIR", path.replace(/\\/g, "/"));
     }
 }
diff --git a/Source/CMakeInstallDestinations.cmake b/Source/CMakeInstallDestinations.cmake
index e82bec3..c97e1f8 100644
--- a/Source/CMakeInstallDestinations.cmake
+++ b/Source/CMakeInstallDestinations.cmake
@@ -35,25 +35,36 @@
   )
 mark_as_advanced(CMake_INSTALL_INFIX)
 
+if(APPLE AND BUILD_QtDialog)
+  set(CMake_INSTALL_APP_DIR "CMake.app/Contents")
+  set(CMake_INSTALL_APP_DIR_SLASH "${CMake_INSTALL_APP_DIR}/")
+else()
+  set(CMake_INSTALL_APP_DIR ".")
+  set(CMake_INSTALL_APP_DIR_SLASH "")
+endif()
+
 foreach(v
-    CMAKE_BIN_DIR
-    CMAKE_DATA_DIR
-    CMAKE_DOC_DIR
-    CMAKE_INFO_DIR
-    CMAKE_MAN_DIR
-    CMAKE_XDGDATA_DIR
+    BIN
+    DATA
+    DOC
+    INFO
+    MAN
+    XDGDATA
     )
   # Populate the cache with empty values so we know when the user sets them.
-  set(${v} "" CACHE STRING "")
-  set_property(CACHE ${v} PROPERTY HELPSTRING
-    "Location under install prefix for ${${v}_DESC} (default \"${${v}_DEFAULT}\")"
+  set(CMAKE_${v}_DIR "" CACHE STRING "")
+  set_property(CACHE CMAKE_${v}_DIR PROPERTY HELPSTRING
+    "Location under install prefix for ${CMAKE_${v}_DIR_DESC} (default \"${CMAKE_${v}_DIR_DEFAULT}\")"
     )
-  set_property(CACHE ${v} PROPERTY ADVANCED 1)
+  set_property(CACHE CMAKE_${v}_DIR PROPERTY ADVANCED 1)
 
   # Use the default when the user did not set this variable.
-  if(NOT ${v})
-    set(${v} "${CMake_INSTALL_INFIX}${${v}_DEFAULT}")
+  if(NOT CMAKE_${v}_DIR)
+    set(CMAKE_${v}_DIR "${CMake_INSTALL_INFIX}${CMAKE_${v}_DIR_DEFAULT}")
   endif()
   # Remove leading slash to treat as relative to install prefix.
-  string(REGEX REPLACE "^/" "" ${v} "${${v}}")
+  string(REGEX REPLACE "^/" "" CMAKE_${v}_DIR "${CMAKE_${v}_DIR}")
+
+  # Install under a base path within the prefix.
+  set(CMake_INSTALL_${v}_DIR "${CMake_INSTALL_APP_DIR_SLASH}${CMAKE_${v}_DIR}")
 endforeach()
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 55879de..0be5788 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -115,6 +115,7 @@
   cmBinUtilsWindowsPELinker.h
   cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
   cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h
+  cmBuildArgs.h
   cmBuildDatabase.cxx
   cmBuildDatabase.h
   cmBuildOptions.h
@@ -135,6 +136,8 @@
   cmCMakePresetsGraphReadJSONPackagePresets.cxx
   cmCMakePresetsGraphReadJSONTestPresets.cxx
   cmCMakePresetsGraphReadJSONWorkflowPresets.cxx
+  cmCMakeString.hxx
+  cmCMakeString.cxx
   cmCommandLineArgument.h
   cmCommonTargetGenerator.cxx
   cmCommonTargetGenerator.h
@@ -165,6 +168,8 @@
   cmCustomCommandTypes.h
   cmCxxModuleMapper.cxx
   cmCxxModuleMapper.h
+  cmCxxModuleMetadata.cxx
+  cmCxxModuleMetadata.h
   cmCxxModuleUsageEffects.cxx
   cmCxxModuleUsageEffects.h
   cmDefinitions.cxx
@@ -201,6 +206,8 @@
   cmExportBuildFileGenerator.cxx
   cmExportBuildPackageInfoGenerator.h
   cmExportBuildPackageInfoGenerator.cxx
+  cmExportBuildSbomGenerator.h
+  cmExportBuildSbomGenerator.cxx
   cmExportCMakeConfigGenerator.h
   cmExportCMakeConfigGenerator.cxx
   cmExportFileGenerator.h
@@ -213,10 +220,14 @@
   cmExportInstallFileGenerator.cxx
   cmExportInstallPackageInfoGenerator.h
   cmExportInstallPackageInfoGenerator.cxx
+  cmExportInstallSbomGenerator.h
+  cmExportInstallSbomGenerator.cxx
   cmExportPackageInfoGenerator.h
   cmExportPackageInfoGenerator.cxx
   cmExportTryCompileFileGenerator.h
   cmExportTryCompileFileGenerator.cxx
+  cmExportSbomGenerator.h
+  cmExportSbomGenerator.cxx
   cmExportSet.h
   cmExportSet.cxx
   cmExternalMakefileProjectGenerator.cxx
@@ -342,6 +353,8 @@
   cmInstallRuntimeDependencySet.cxx
   cmInstallRuntimeDependencySetGenerator.h
   cmInstallRuntimeDependencySetGenerator.cxx
+  cmInstallSbomExportGenerator.h
+  cmInstallSbomExportGenerator.cxx
   cmInstallScriptGenerator.h
   cmInstallScriptGenerator.cxx
   cmInstallSubdirectoryGenerator.h
@@ -390,7 +403,6 @@
   cmRulePlaceholderExpander.cxx
   cmRulePlaceholderExpander.h
   cmLocalUnixMakefileGenerator3.cxx
-  cmLocale.h
   cmMakefile.cxx
   cmMakefile.h
   cmMakefileTargetGenerator.cxx
@@ -428,6 +440,8 @@
   cmProcessOutput.h
   cmProcessTools.cxx
   cmProcessTools.h
+  cmProjectInfoArguments.cxx
+  cmProjectInfoArguments.h
   cmValue.cxx
   cmValue.h
   cmProperty.h
@@ -507,6 +521,7 @@
   cmUVStreambuf.h
   cmVariableWatch.cxx
   cmVariableWatch.h
+  cmVersion_Dependencies.cxx
   cmVersion.cxx
   cmVersion.h
   cmWindowsRegistry.cxx
@@ -701,6 +716,10 @@
   cmRemoveDefinitionsCommand.h
   cmReturnCommand.cxx
   cmReturnCommand.h
+  cmSbomArguments.h
+  cmSbomArguments.cxx
+  cmSbomObject.h
+  cmSbomSerializer.h
   cmSearchPath.cxx
   cmSearchPath.h
   cmSeparateArgumentsCommand.cxx
@@ -721,9 +740,10 @@
   cmSiteNameCommand.h
   cmSourceGroupCommand.cxx
   cmSourceGroupCommand.h
-  cmSPDXSerializer.cxx
-  cmSPDXSerializer.h
-  cmSPDXTypes.def
+  cmSpdx.cxx
+  cmSpdx.h
+  cmSpdxSerializer.cxx
+  cmSpdxSerializer.h
   cmString.cxx
   cmString.hxx
   cmStringReplaceHelper.cxx
@@ -1412,7 +1432,7 @@
 
 foreach(_tool IN LISTS _tools)
   CMake_OPTIONAL_COMPONENT(${_tool})
-  install(TARGETS ${_tool} DESTINATION ${CMAKE_BIN_DIR} ${COMPONENT})
+  install(TARGETS ${_tool} DESTINATION ${CMake_INSTALL_BIN_DIR} ${COMPONENT})
 endforeach()
 
 # Unset temporary variables
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index d943c32..9c3b2b7 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 2)
-set(CMake_VERSION_PATCH 5)
+set(CMake_VERSION_MINOR 3)
+set(CMake_VERSION_PATCH 2)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
index 8b955aa..e440b84 100644
--- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx
+++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
@@ -27,6 +27,7 @@
 #include "cmWIXDirectoriesSourceWriter.h"
 #include "cmWIXFeaturesSourceWriter.h"
 #include "cmWIXFilesSourceWriter.h"
+#include "cmWIXInstallScope.h"
 #include "cmWIXRichTextFormatWriter.h"
 #include "cmWIXSourceWriter.h"
 
@@ -545,9 +546,20 @@
 
   this->WixSources.push_back(directoryDefinitionsFilename);
 
+  cmWIXInstallScope installScope = GetInstallScope();
+
+  std::string componentKeysRegistryPath =
+    GetOption("CPACK_WIX_COMPONENT_KEYS_REGISTRY_PATH");
+  if (componentKeysRegistryPath.empty()) {
+    componentKeysRegistryPath =
+      cmStrCat("Software\\", GetOption("CPACK_PACKAGE_VENDOR"), "\\",
+               GetOption("CPACK_PACKAGE_NAME"), "\\Components");
+  }
+  cmSystemTools::ReplaceString(componentKeysRegistryPath, "/", "\\");
+
   cmWIXDirectoriesSourceWriter directoryDefinitions(
     this->WixVersion, this->Logger, directoryDefinitionsFilename,
-    this->ComponentGuidType);
+    this->ComponentGuidType, installScope, componentKeysRegistryPath);
   InjectXmlNamespaces(directoryDefinitions);
   directoryDefinitions.BeginElement("Fragment");
 
@@ -565,15 +577,18 @@
   auto installationPrefixDirectory =
     directoryDefinitions.BeginInstallationPrefixDirectory(GetRootFolderId(),
                                                           installRoot);
+  cm::optional<std::string> removeFolderComponentId =
+    directoryDefinitions.EmitRemoveFolderComponentOnUserInstall(
+      "INSTALL_ROOT");
 
   std::string fileDefinitionsFilename =
     cmStrCat(this->CPackTopLevel, "/files.wxs");
 
   this->WixSources.push_back(fileDefinitionsFilename);
 
-  cmWIXFilesSourceWriter fileDefinitions(this->WixVersion, this->Logger,
-                                         fileDefinitionsFilename,
-                                         this->ComponentGuidType);
+  cmWIXFilesSourceWriter fileDefinitions(
+    this->WixVersion, this->Logger, fileDefinitionsFilename,
+    this->ComponentGuidType, installScope, componentKeysRegistryPath);
   InjectXmlNamespaces(fileDefinitions);
 
   fileDefinitions.BeginElement("Fragment");
@@ -622,6 +637,10 @@
       *package, GetOption("CPACK_WIX_UPGRADE_GUID"));
   }
 
+  if (removeFolderComponentId.has_value()) {
+    featureDefinitions.EmitComponentRef(*removeFolderComponentId);
+  }
+
   if (!CreateFeatureHierarchy(featureDefinitions)) {
     return false;
   }
@@ -728,6 +747,8 @@
   cmValue rootFolderId = GetOption("CPACK_WIX_ROOT_FOLDER_ID");
   if (rootFolderId) {
     result = *rootFolderId;
+  } else if (GetInstallScope() == cmWIXInstallScope::PER_USER) {
+    result = "LocalAppDataFolder";
   } else if (this->WixVersion >= 4) {
     result = "ProgramFiles6432Folder";
   } else {
@@ -1083,6 +1104,13 @@
       directoryDefinitions.AddAttribute("Name", fileName);
       this->Patch->ApplyFragment(subDirectoryId, directoryDefinitions);
 
+      cm::optional<std::string> removeFolderComponentId =
+        directoryDefinitions.EmitRemoveFolderComponentOnUserInstall(
+          subDirectoryId);
+      if (removeFolderComponentId.has_value()) {
+        featureDefinitions.EmitComponentRef(*removeFolderComponentId);
+      }
+
       AddDirectoryAndFileDefinitions(fullPath, subDirectoryId,
                                      directoryDefinitions, fileDefinitions,
                                      featureDefinitions, packageExecutables,
@@ -1374,3 +1402,24 @@
                                          ns.second);
   }
 }
+
+cmWIXInstallScope cmCPackWIXGenerator::GetInstallScope() const
+{
+  cmValue value = this->GetOption("CPACK_WIX_INSTALL_SCOPE");
+
+  if (value == "perUser"_s) {
+    return cmWIXInstallScope::PER_USER;
+  }
+  if (value == "perMachine"_s) {
+    return cmWIXInstallScope::PER_MACHINE;
+  }
+  if (value == "NONE"_s) {
+    return cmWIXInstallScope::NONE;
+  }
+
+  cmCPackLogger(
+    cmCPackLog::LOG_ERROR,
+    "Invalid CPACK_WIX_INSTALL_SCOPE value, defaulting to perMachine: "
+      << (value ? *value : "") << std::endl);
+  return cmWIXInstallScope::PER_MACHINE;
+}
diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.h b/Source/CPack/WiX/cmCPackWIXGenerator.h
index bfad0d4..0d59eeb 100644
--- a/Source/CPack/WiX/cmCPackWIXGenerator.h
+++ b/Source/CPack/WiX/cmCPackWIXGenerator.h
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "cmCPackGenerator.h"
+#include "cmWIXInstallScope.h"
 #include "cmWIXPatch.h"
 #include "cmWIXShortcut.h"
 
@@ -159,6 +160,8 @@
 
   void InjectXmlNamespaces(cmWIXSourceWriter& sourceWriter);
 
+  cmWIXInstallScope GetInstallScope() const;
+
   std::vector<std::string> WixSources;
   id_map_t PathToIdMap;
   ambiguity_map_t IdAmbiguityCounter;
diff --git a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx
index b6e3cd2..4cee0f1 100644
--- a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx
+++ b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx
@@ -6,9 +6,24 @@
 
 cmWIXDirectoriesSourceWriter::cmWIXDirectoriesSourceWriter(
   unsigned long wixVersion, cmCPackLog* logger, std::string const& filename,
-  GuidType componentGuidType)
+  GuidType componentGuidType, cmWIXInstallScope installScope,
+  std::string componentKeysRegistryPath)
   : cmWIXSourceWriter(wixVersion, logger, filename, componentGuidType)
+  , ComponentKeysRegistryPath(std::move(componentKeysRegistryPath))
 {
+  switch (installScope) {
+    case cmWIXInstallScope::PER_USER:
+      this->PerUserInstall = true;
+      break;
+    case cmWIXInstallScope::PER_MACHINE:
+    case cmWIXInstallScope::NONE:
+      this->PerUserInstall = false;
+      break;
+    default:
+      cmCPackLogger(cmCPackLog::LOG_ERROR,
+                    "Unhandled install scope value, this is a CPack Bug.");
+      break;
+  }
 }
 
 void cmWIXDirectoriesSourceWriter::EmitStartMenuFolder(
@@ -47,6 +62,43 @@
   EndElement_StandardDirectory();
 }
 
+cm::optional<std::string>
+cmWIXDirectoriesSourceWriter::EmitRemoveFolderComponentOnUserInstall(
+  std::string const& directoryId)
+{
+  if (!this->PerUserInstall) {
+    return {};
+  }
+
+  BeginElement("Component");
+
+  std::string componentId = directoryId + "_RemoveFolderComponent";
+  AddAttribute("Id", componentId);
+  AddAttribute("Guid", CreateGuidFromComponentId(componentId));
+
+  BeginElement("RemoveFolder");
+  AddAttribute("Id", directoryId + "_RemoveFolder");
+  AddAttribute("Directory", directoryId);
+  AddAttribute("On", "uninstall");
+  EndElement("RemoveFolder");
+
+  // Need a keyPath for the component
+  BeginElement("RegistryValue");
+
+  AddAttribute("Root", "HKCU");
+  AddAttribute("Key", this->ComponentKeysRegistryPath);
+  AddAttribute("Name", componentId);
+  AddAttribute("Type", "string");
+  AddAttribute("Value", "1");
+  AddAttribute("KeyPath", "yes");
+
+  EndElement("RegistryValue");
+
+  EndElement("Component");
+
+  return componentId;
+}
+
 cmWIXDirectoriesSourceWriter::InstallationPrefixDirectory
 cmWIXDirectoriesSourceWriter::BeginInstallationPrefixDirectory(
   std::string const& programFilesFolderId,
diff --git a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h
index 5aa194d..8ec5810 100644
--- a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h
+++ b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h
@@ -4,7 +4,10 @@
 
 #include <string>
 
+#include <cm/optional>
+
 #include "cmCPackGenerator.h"
+#include "cmWIXInstallScope.h"
 #include "cmWIXSourceWriter.h"
 
 /** \class cmWIXDirectoriesSourceWriter
@@ -15,7 +18,9 @@
 public:
   cmWIXDirectoriesSourceWriter(unsigned long wixVersion, cmCPackLog* logger,
                                std::string const& filename,
-                               GuidType componentGuidType);
+                               GuidType componentGuidType,
+                               cmWIXInstallScope installScope,
+                               std::string componentKeysRegistryPath);
 
   void EmitStartMenuFolder(std::string const& startMenuFolder);
 
@@ -23,6 +28,9 @@
 
   void EmitStartupFolder();
 
+  cm::optional<std::string> EmitRemoveFolderComponentOnUserInstall(
+    std::string const& directoryId);
+
   struct InstallationPrefixDirectory
   {
     bool HasStandardDirectory = false;
@@ -35,4 +43,8 @@
 
   void EndInstallationPrefixDirectory(
     InstallationPrefixDirectory installationPrefixDirectory);
+
+private:
+  bool PerUserInstall = false;
+  std::string ComponentKeysRegistryPath;
 };
diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx
index 550e029..9581d9f 100644
--- a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx
+++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx
@@ -19,12 +19,26 @@
 #  include "cmsys/Encoding.hxx"
 #endif
 
-cmWIXFilesSourceWriter::cmWIXFilesSourceWriter(unsigned long wixVersion,
-                                               cmCPackLog* logger,
-                                               std::string const& filename,
-                                               GuidType componentGuidType)
+cmWIXFilesSourceWriter::cmWIXFilesSourceWriter(
+  unsigned long wixVersion, cmCPackLog* logger, std::string const& filename,
+  GuidType componentGuidType, cmWIXInstallScope installScope,
+  std::string componentKeysRegistryPath)
   : cmWIXSourceWriter(wixVersion, logger, filename, componentGuidType)
+  , ComponentKeysRegistryPath(std::move(componentKeysRegistryPath))
 {
+  switch (installScope) {
+    case cmWIXInstallScope::PER_USER:
+      this->PerUserInstall = true;
+      break;
+    case cmWIXInstallScope::PER_MACHINE:
+    case cmWIXInstallScope::NONE:
+      this->PerUserInstall = false;
+      break;
+    default:
+      cmCPackLogger(cmCPackLog::LOG_ERROR,
+                    "Unhandled install scope value, this is a CPack Bug.");
+      break;
+  }
 }
 
 void cmWIXFilesSourceWriter::EmitShortcut(std::string const& id,
@@ -127,7 +141,11 @@
   std::string componentId = std::string("CM_C") + id;
   std::string fileId = std::string("CM_F") + id;
 
-  std::string guid = CreateGuidFromComponentId(componentId);
+  // Wix doesn't support automatic GUIDs for components which have both
+  // registry entries and files.
+  std::string guid = this->PerUserInstall
+    ? CreateCmakeGeneratedGuidFromComponentId(componentId)
+    : CreateGuidFromComponentId(componentId);
 
   BeginElement("DirectoryRef");
   AddAttribute("Id", directoryId);
@@ -150,6 +168,22 @@
   }
 
   patch.ApplyFragment(componentId, *this);
+
+  if (this->PerUserInstall) {
+    // For perUser installs, MSI requires using a registry entry as the key
+    // path for components.
+    BeginElement("RegistryValue");
+
+    AddAttribute("Root", "HKCU");
+    AddAttribute("Key", this->ComponentKeysRegistryPath);
+    AddAttribute("Name", fileId);
+    AddAttribute("Type", "string");
+    AddAttribute("Value", "1");
+    AddAttribute("KeyPath", "yes");
+
+    EndElement("RegistryValue");
+  }
+
   BeginElement("File");
   AddAttribute("Id", fileId);
 
@@ -164,7 +198,9 @@
 #endif
   AddAttribute("Source", sourcePath);
 
-  AddAttribute("KeyPath", "yes");
+  if (!this->PerUserInstall) {
+    AddAttribute("KeyPath", "yes");
+  }
 
   mode_t fileMode = 0;
   cmSystemTools::GetPermissions(filePath.c_str(), fileMode);
diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.h b/Source/CPack/WiX/cmWIXFilesSourceWriter.h
index fff7c4f..1d55067 100644
--- a/Source/CPack/WiX/cmWIXFilesSourceWriter.h
+++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.h
@@ -2,7 +2,10 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #pragma once
 
+#include <string>
+
 #include "cmCPackGenerator.h"
+#include "cmWIXInstallScope.h"
 #include "cmWIXPatch.h"
 #include "cmWIXShortcut.h"
 #include "cmWIXSourceWriter.h"
@@ -15,7 +18,9 @@
 public:
   cmWIXFilesSourceWriter(unsigned long wixVersion, cmCPackLog* logger,
                          std::string const& filename,
-                         GuidType componentGuidType);
+                         GuidType componentGuidType,
+                         cmWIXInstallScope installScope,
+                         std::string componentKeysRegistryPath);
 
   void EmitShortcut(std::string const& id, cmWIXShortcut const& shortcut,
                     std::string const& shortcutPrefix, size_t shortcutIndex);
@@ -37,4 +42,8 @@
                                 std::string const& filePath, cmWIXPatch& patch,
                                 cmInstalledFile const* installedFile,
                                 int diskId);
+
+private:
+  bool PerUserInstall = false;
+  std::string ComponentKeysRegistryPath;
 };
diff --git a/Source/CPack/WiX/cmWIXInstallScope.h b/Source/CPack/WiX/cmWIXInstallScope.h
new file mode 100644
index 0000000..6b69457
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXInstallScope.h
@@ -0,0 +1,10 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#pragma once
+
+enum class cmWIXInstallScope
+{
+  NONE,
+  PER_MACHINE,
+  PER_USER
+};
diff --git a/Source/CPack/WiX/cmWIXSourceWriter.cxx b/Source/CPack/WiX/cmWIXSourceWriter.cxx
index ed3cbe0..f2cb8b4 100644
--- a/Source/CPack/WiX/cmWIXSourceWriter.cxx
+++ b/Source/CPack/WiX/cmWIXSourceWriter.cxx
@@ -159,15 +159,21 @@
 {
   std::string guid = "*";
   if (this->ComponentGuidType == CMAKE_GENERATED_GUID) {
-    cmCryptoHash hasher(cmCryptoHash::AlgoMD5);
-    std::string md5 = hasher.HashString(componentId);
-    cmUuid uuid;
-    std::vector<unsigned char> ns;
-    guid = uuid.FromMd5(ns, md5);
+    guid = CreateCmakeGeneratedGuidFromComponentId(componentId);
   }
   return guid;
 }
 
+std::string cmWIXSourceWriter::CreateCmakeGeneratedGuidFromComponentId(
+  std::string const& componentId)
+{
+  cmCryptoHash hasher(cmCryptoHash::AlgoMD5);
+  std::string md5 = hasher.HashString(componentId);
+  cmUuid uuid;
+  std::vector<unsigned char> ns;
+  return uuid.FromMd5(ns, md5);
+}
+
 void cmWIXSourceWriter::WriteXMLDeclaration()
 {
   File << R"(<?xml version="1.0" encoding="UTF-8"?>)" << std::endl;
diff --git a/Source/CPack/WiX/cmWIXSourceWriter.h b/Source/CPack/WiX/cmWIXSourceWriter.h
index 5e1150d..8243275 100644
--- a/Source/CPack/WiX/cmWIXSourceWriter.h
+++ b/Source/CPack/WiX/cmWIXSourceWriter.h
@@ -5,6 +5,8 @@
 #include <string>
 #include <vector>
 
+#include <cm/optional>
+
 #include "cmsys/FStream.hxx"
 
 #include "cmCPackLog.h"
@@ -52,6 +54,12 @@
 
   std::string CreateGuidFromComponentId(std::string const& componentId);
 
+  // In most cases CreateGuidFromComponentId should be used instead, since it
+  // takes ComponentGuidType into consideration. This function always generates
+  // an explicit GUID.
+  static std::string CreateCmakeGeneratedGuidFromComponentId(
+    std::string const& componentId);
+
   static std::string EscapeAttributeValue(std::string const& value);
 
 protected:
diff --git a/Source/CPack/cmCPackAppImageGenerator.cxx b/Source/CPack/cmCPackAppImageGenerator.cxx
index c6d4d8a..03dffab 100644
--- a/Source/CPack/cmCPackAppImageGenerator.cxx
+++ b/Source/CPack/cmCPackAppImageGenerator.cxx
@@ -4,7 +4,6 @@
 #include "cmCPackAppImageGenerator.h"
 
 #include <algorithm>
-#include <cctype>
 #include <cstddef>
 #include <utility>
 #include <vector>
@@ -14,6 +13,7 @@
 #include <sys/types.h>
 
 #include "cmsys/FStream.hxx"
+#include "cmsys/String.h"
 
 #include "cmCPackLog.h"
 #include "cmELF.h"
@@ -340,11 +340,9 @@
 // Trim leading and trailing whitespace from a string
 std::string trim(std::string const& str)
 {
-  auto start = std::find_if_not(
-    str.begin(), str.end(), [](unsigned char c) { return std::isspace(c); });
-  auto end = std::find_if_not(str.rbegin(), str.rend(), [](unsigned char c) {
-               return std::isspace(c);
-             }).base();
+  auto start = std::find_if_not(str.begin(), str.end(), cmsysString_isspace);
+  auto end =
+    std::find_if_not(str.rbegin(), str.rend(), cmsysString_isspace).base();
   return (start < end) ? std::string(start, end) : std::string();
 }
 } // namespace
diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx
index ac09918..8ee5637 100644
--- a/Source/CPack/cmCPackArchiveGenerator.cxx
+++ b/Source/CPack/cmCPackArchiveGenerator.cxx
@@ -135,10 +135,51 @@
 
 cmCPackGenerator* cmCPackArchiveGenerator::Create7ZGenerator()
 {
+  return cmCPackArchiveGenerator::Create7ZLzmaGenerator();
+}
+
+cmCPackGenerator* cmCPackArchiveGenerator::Create7ZStoreGenerator()
+{
   return new cmCPackArchiveGenerator(cmArchiveWrite::CompressNone, "7zip",
                                      ".7z");
 }
 
+cmCPackGenerator* cmCPackArchiveGenerator::Create7ZDeflateGenerator()
+{
+  return new cmCPackArchiveGenerator(cmArchiveWrite::CompressGZip, "7zip",
+                                     ".7z");
+}
+
+cmCPackGenerator* cmCPackArchiveGenerator::Create7ZBzip2Generator()
+{
+  return new cmCPackArchiveGenerator(cmArchiveWrite::CompressBZip2, "7zip",
+                                     ".7z");
+}
+
+cmCPackGenerator* cmCPackArchiveGenerator::Create7ZLzmaGenerator()
+{
+  return new cmCPackArchiveGenerator(cmArchiveWrite::CompressLZMA, "7zip",
+                                     ".7z");
+}
+
+cmCPackGenerator* cmCPackArchiveGenerator::Create7ZLzma2Generator()
+{
+  return new cmCPackArchiveGenerator(cmArchiveWrite::CompressXZ, "7zip",
+                                     ".7z");
+}
+
+cmCPackGenerator* cmCPackArchiveGenerator::Create7ZZstdGenerator()
+{
+  return new cmCPackArchiveGenerator(cmArchiveWrite::CompressZstd, "7zip",
+                                     ".7z");
+}
+
+cmCPackGenerator* cmCPackArchiveGenerator::Create7ZPPMdGenerator()
+{
+  return new cmCPackArchiveGenerator(cmArchiveWrite::CompressPPMd, "7zip",
+                                     ".7z");
+}
+
 cmCPackGenerator* cmCPackArchiveGenerator::CreateTBZ2Generator()
 {
   return new cmCPackArchiveGenerator(cmArchiveWrite::CompressBZip2, "paxr",
@@ -177,10 +218,45 @@
 
 cmCPackGenerator* cmCPackArchiveGenerator::CreateZIPGenerator()
 {
+  return cmCPackArchiveGenerator::CreateZipDeflateGenerator();
+}
+
+cmCPackGenerator* cmCPackArchiveGenerator::CreateZipStoreGenerator()
+{
   return new cmCPackArchiveGenerator(cmArchiveWrite::CompressNone, "zip",
                                      ".zip");
 }
 
+cmCPackGenerator* cmCPackArchiveGenerator::CreateZipDeflateGenerator()
+{
+  return new cmCPackArchiveGenerator(cmArchiveWrite::CompressGZip, "zip",
+                                     ".zip");
+}
+
+cmCPackGenerator* cmCPackArchiveGenerator::CreateZipBzip2Generator()
+{
+  return new cmCPackArchiveGenerator(cmArchiveWrite::CompressBZip2, "zip",
+                                     ".zip");
+}
+
+cmCPackGenerator* cmCPackArchiveGenerator::CreateZipLzmaGenerator()
+{
+  return new cmCPackArchiveGenerator(cmArchiveWrite::CompressLZMA, "zip",
+                                     ".zip");
+}
+
+cmCPackGenerator* cmCPackArchiveGenerator::CreateZipLzma2Generator()
+{
+  return new cmCPackArchiveGenerator(cmArchiveWrite::CompressXZ, "zip",
+                                     ".zip");
+}
+
+cmCPackGenerator* cmCPackArchiveGenerator::CreateZipZstdGenerator()
+{
+  return new cmCPackArchiveGenerator(cmArchiveWrite::CompressZstd, "zip",
+                                     ".zip");
+}
+
 cmCPackArchiveGenerator::cmCPackArchiveGenerator(
   cmArchiveWrite::Compress compress, std::string format, std::string extension)
   : Compress(compress)
@@ -233,7 +309,7 @@
   cmValue newExtensionValue = this->GetOption("CPACK_ARCHIVE_FILE_EXTENSION");
   if (!newExtensionValue.IsEmpty()) {
     std::string newExtension = *newExtensionValue;
-    if (!cmHasLiteralPrefix(newExtension, ".")) {
+    if (!cmHasPrefix(newExtension, '.')) {
       newExtension = cmStrCat('.', newExtension);
     }
     cmCPackLogger(cmCPackLog::LOG_DEBUG,
@@ -316,8 +392,12 @@
                     << (filename) << ">." << std::endl);                      \
     return 0;                                                                 \
   }                                                                           \
-  cmArchiveWrite archive(gf, this->Compress, this->ArchiveFormat, 0,          \
+  cmArchiveWrite archive(gf, this->Compress, this->ArchiveFormat,             \
+                         this->GetCompressionLevel(),                         \
                          this->GetThreadCount());                             \
+  if (this->UID >= 0 && this->GID >= 0) {                                     \
+    archive.SetUIDAndGID(this->UID, this->GID);                               \
+  }                                                                           \
   do {                                                                        \
     if (!archive.Open()) {                                                    \
       cmCPackLogger(cmCPackLog::LOG_ERROR,                                    \
@@ -436,6 +516,19 @@
   cmCPackLogger(cmCPackLog::LOG_DEBUG,
                 "Toplevel: " << this->toplevel << std::endl);
 
+  if (cmValue UIDoption = this->GetOptionIfSet("CPACK_ARCHIVE_UID")) {
+    long u;
+    if (cmStrToLong(*UIDoption, &u)) {
+      this->UID = static_cast<int>(u);
+    }
+  }
+  if (cmValue GIDoption = this->GetOptionIfSet("CPACK_ARCHIVE_GID")) {
+    long g;
+    if (cmStrToLong(*GIDoption, &g)) {
+      this->GID = static_cast<int>(g);
+    }
+  }
+
   if (this->WantsComponentInstallation()) {
     // CASE 1 : COMPONENT ALL-IN-ONE package
     // If ALL COMPONENTS in ONE package has been requested
@@ -503,3 +596,17 @@
 
   return threads;
 }
+
+int cmCPackArchiveGenerator::GetCompressionLevel() const
+{
+  int level = 0;
+
+  // CPACK_ARCHIVE_COMPRESSION_LEVEL overrides CPACK_COMPRESSION_LEVEL
+  if (cmValue v = this->GetOptionIfSet("CPACK_ARCHIVE_COMPRESSION_LEVEL")) {
+    level = std::stoi(*v);
+  } else if (cmValue v2 = this->GetOptionIfSet("CPACK_COMPRESSION_LEVEL")) {
+    level = std::stoi(*v2);
+  }
+
+  return level;
+}
diff --git a/Source/CPack/cmCPackArchiveGenerator.h b/Source/CPack/cmCPackArchiveGenerator.h
index fb56842..22c8bba 100644
--- a/Source/CPack/cmCPackArchiveGenerator.h
+++ b/Source/CPack/cmCPackArchiveGenerator.h
@@ -24,6 +24,13 @@
   using Superclass = cmCPackGenerator;
 
   static cmCPackGenerator* Create7ZGenerator();
+  static cmCPackGenerator* Create7ZStoreGenerator();
+  static cmCPackGenerator* Create7ZDeflateGenerator();
+  static cmCPackGenerator* Create7ZBzip2Generator();
+  static cmCPackGenerator* Create7ZLzmaGenerator();
+  static cmCPackGenerator* Create7ZLzma2Generator();
+  static cmCPackGenerator* Create7ZZstdGenerator();
+  static cmCPackGenerator* Create7ZPPMdGenerator();
   static cmCPackGenerator* CreateTBZ2Generator();
   static cmCPackGenerator* CreateTGZGenerator();
   static cmCPackGenerator* CreateTXZGenerator();
@@ -31,6 +38,12 @@
   static cmCPackGenerator* CreateTZSTGenerator();
   static cmCPackGenerator* CreateTarGenerator();
   static cmCPackGenerator* CreateZIPGenerator();
+  static cmCPackGenerator* CreateZipStoreGenerator();
+  static cmCPackGenerator* CreateZipDeflateGenerator();
+  static cmCPackGenerator* CreateZipBzip2Generator();
+  static cmCPackGenerator* CreateZipLzmaGenerator();
+  static cmCPackGenerator* CreateZipLzma2Generator();
+  static cmCPackGenerator* CreateZipZstdGenerator();
 
   /**
    * Construct generator
@@ -92,9 +105,12 @@
   }
 
   int GetThreadCount() const;
+  int GetCompressionLevel() const;
 
 private:
   cmArchiveWrite::Compress Compress;
   std::string ArchiveFormat;
   std::string OutputExtension;
+  int UID = 0;
+  int GID = 0;
 };
diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx
index 1571bd1..523a293 100644
--- a/Source/CPack/cmCPackDebGenerator.cxx
+++ b/Source/CPack/cmCPackDebGenerator.cxx
@@ -32,8 +32,8 @@
 public:
   DebGenerator(cmCPackLog* logger, std::string outputName, std::string workDir,
                std::string topLevelDir, std::string temporaryDir,
-               cmValue debianCompressionType, cmValue numThreads,
-               cmValue debianArchiveType,
+               cmValue debianCompressionType, cmValue debianCompressionLevel,
+               cmValue numThreads, cmValue debianArchiveType,
                std::map<std::string, std::string> controlValues,
                bool genShLibs, std::string shLibsFilename, bool genPostInst,
                std::string postInst, bool genPostRm, std::string postRm,
@@ -69,16 +69,18 @@
   bool const PermissionStrictPolicy;
   std::vector<std::string> const PackageFiles;
   cmArchiveWrite::Compress TarCompressionType;
+  int CompressionLevel = 0;
 };
 
 DebGenerator::DebGenerator(
   cmCPackLog* logger, std::string outputName, std::string workDir,
   std::string topLevelDir, std::string temporaryDir,
-  cmValue debCompressionType, cmValue numThreads, cmValue debianArchiveType,
-  std::map<std::string, std::string> controlValues, bool genShLibs,
-  std::string shLibsFilename, bool genPostInst, std::string postInst,
-  bool genPostRm, std::string postRm, cmValue controlExtra,
-  bool permissionStrictPolicy, std::vector<std::string> packageFiles)
+  cmValue debCompressionType, cmValue debCompressionLevel, cmValue numThreads,
+  cmValue debianArchiveType, std::map<std::string, std::string> controlValues,
+  bool genShLibs, std::string shLibsFilename, bool genPostInst,
+  std::string postInst, bool genPostRm, std::string postRm,
+  cmValue controlExtra, bool permissionStrictPolicy,
+  std::vector<std::string> packageFiles)
   : Logger(logger)
   , OutputName(std::move(outputName))
   , WorkDir(std::move(workDir))
@@ -135,6 +137,19 @@
   } else {
     this->NumThreads = 1;
   }
+
+  if (debCompressionLevel) {
+    long compressionLevel;
+    if (!cmStrToLong(*debCompressionLevel, &compressionLevel)) {
+      compressionLevel = 0;
+      cmCPackLogger(cmCPackLog::LOG_ERROR,
+                    "Unrecognized compression level: " << debCompressionLevel
+                                                       << std::endl);
+    }
+    this->CompressionLevel = static_cast<int>(compressionLevel);
+  } else {
+    this->CompressionLevel = 0;
+  }
 }
 
 bool DebGenerator::generate() const
@@ -192,7 +207,7 @@
     return false;
   }
   cmArchiveWrite data_tar(fileStream_data_tar, this->TarCompressionType,
-                          this->DebianArchiveType, 0,
+                          this->DebianArchiveType, this->CompressionLevel,
                           static_cast<int>(this->NumThreads));
   if (!data_tar.Open()) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
@@ -324,7 +339,7 @@
     return false;
   }
   cmArchiveWrite control_tar(fileStream_control_tar, this->TarCompressionType,
-                             this->DebianArchiveType);
+                             this->DebianArchiveType, this->CompressionLevel);
   if (!control_tar.Open()) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "Error opening the archive \""
@@ -846,6 +861,7 @@
     this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
     this->GetOption("CPACK_TEMPORARY_DIRECTORY"),
     this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE"),
+    this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_LEVEL"),
     this->GetOption("CPACK_THREADS"),
     this->GetOption("GEN_CPACK_DEBIAN_ARCHIVE_TYPE"), controlValues, gen_shibs,
     shlibsfilename, this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTINST"), postinst,
@@ -901,6 +917,7 @@
     this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
     this->GetOption("CPACK_TEMPORARY_DIRECTORY"),
     this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE"),
+    this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_LEVEL"),
     this->GetOption("CPACK_THREADS"),
     this->GetOption("GEN_CPACK_DEBIAN_ARCHIVE_TYPE"), controlValues, false, "",
     false, "", false, "", nullptr,
diff --git a/Source/CPack/cmCPackFreeBSDGenerator.cxx b/Source/CPack/cmCPackFreeBSDGenerator.cxx
index e4a308c..62cc672 100644
--- a/Source/CPack/cmCPackFreeBSDGenerator.cxx
+++ b/Source/CPack/cmCPackFreeBSDGenerator.cxx
@@ -388,12 +388,12 @@
     // a file with the package name and version as specified in the
     // manifest, so we look those up (again). lastSlash is the slash
     // itself, we need that as path separator to the calculated package name.
-    std::string actualPackage =
-      ((lastSlash != std::string::npos)
-         ? std::string(currentPackage, 0, lastSlash + 1)
-         : std::string()) +
-      var_lookup("CPACK_FREEBSD_PACKAGE_NAME") + '-' +
-      var_lookup("CPACK_FREEBSD_PACKAGE_VERSION") + FreeBSDPackageSuffix_17;
+    std::string actualPackage = cmStrCat(
+      (lastSlash != std::string::npos)
+        ? cm::string_view(currentPackage).substr(0, lastSlash + 1)
+        : ""_s,
+      var_lookup("CPACK_FREEBSD_PACKAGE_NAME"), '-',
+      var_lookup("CPACK_FREEBSD_PACKAGE_VERSION"), FreeBSDPackageSuffix_17);
 
     this->packageFileNames.clear();
     this->packageFileNames.emplace_back(actualPackage);
@@ -442,7 +442,7 @@
     std::string const packageSubDirectory =
       cmSystemTools::GetParentDirectory(sourceFile);
     std::string const targetFileName =
-      packageSubDirectory + '/' + packageFileName;
+      cmStrCat(packageSubDirectory, '/', packageFileName);
     if (cmSystemTools::RenameFile(sourceFile, targetFileName)) {
       this->packageFileNames.clear();
       this->packageFileNames.emplace_back(targetFileName);
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
index efe15c2..aa07d83 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -760,9 +760,7 @@
                   "-   Install component: " << component << std::endl);
   }
 
-  cmake cm(cmake::RoleScript, cmState::CPack);
-  cm.SetHomeDirectory("");
-  cm.SetHomeOutputDirectory("");
+  cmake cm(cmState::Role::CPack);
   cm.GetCurrentSnapshot().SetDefaultDefinitions();
   cm.AddCMakePaths();
   cm.SetProgressCallback([this](std::string const& msg, float prog) {
@@ -836,7 +834,7 @@
     // Make sure that DESTDIR + CPACK_INSTALL_PREFIX directory
     // exists:
     //
-    if (cmHasLiteralPrefix(dir, "/")) {
+    if (cmHasPrefix(dir, '/')) {
       dir = tempInstallDirectory + dir;
     } else {
       dir = tempInstallDirectory + "/" + dir;
@@ -1612,12 +1610,12 @@
                                               "[Ll][Pp][Tt][1-9]"
                                               ")[.]?$");
     if (reserved_pattern.find(name)) {
-      return "_" + name;
+      return cmStrCat('_', std::move(name));
     }
     // Given name ends in a dot (on Windows)?
     // Then return it appended with an underscore.
     if (name.back() == '.') {
-      return name + '_';
+      return cmStrCat(std::move(name), '_');
     }
 #endif
   }
diff --git a/Source/CPack/cmCPackGeneratorFactory.cxx b/Source/CPack/cmCPackGeneratorFactory.cxx
index c46710c..449e711 100644
--- a/Source/CPack/cmCPackGeneratorFactory.cxx
+++ b/Source/CPack/cmCPackGeneratorFactory.cxx
@@ -46,8 +46,30 @@
 cmCPackGeneratorFactory::cmCPackGeneratorFactory()
 {
   if (cmCPackArchiveGenerator::CanGenerate()) {
-    this->RegisterGenerator("7Z", "7-Zip file format",
-                            cmCPackArchiveGenerator::Create7ZGenerator);
+    this->RegisterGenerator(
+      "7Z", "7-Zip file format with default compression algorithm",
+      cmCPackArchiveGenerator::Create7ZGenerator);
+    this->RegisterGenerator("7Z_STORE",
+                            "7-Zip file format without compression",
+                            cmCPackArchiveGenerator::Create7ZStoreGenerator);
+    this->RegisterGenerator("7Z_DEFLATE",
+                            "7-Zip file format with Deflate compression",
+                            cmCPackArchiveGenerator::Create7ZDeflateGenerator);
+    this->RegisterGenerator("7Z_BZ2",
+                            "7-Zip file format with BZip2 compression",
+                            cmCPackArchiveGenerator::Create7ZBzip2Generator);
+    this->RegisterGenerator("7Z_LZMA",
+                            "7-Zip file format with LZMA compression",
+                            cmCPackArchiveGenerator::Create7ZLzmaGenerator);
+    this->RegisterGenerator("7Z_LZMA2",
+                            "7-Zip file format with LZMA2 compression",
+                            cmCPackArchiveGenerator::Create7ZLzma2Generator);
+    this->RegisterGenerator("7Z_ZSTD",
+                            "7-Zip file format with Zstandard compression",
+                            cmCPackArchiveGenerator::Create7ZZstdGenerator);
+    this->RegisterGenerator("7Z_PPMD",
+                            "7-Zip file format with PPMd compression",
+                            cmCPackArchiveGenerator::Create7ZPPMdGenerator);
     this->RegisterGenerator("TBZ2", "Tar BZip2 compression",
                             cmCPackArchiveGenerator::CreateTBZ2Generator);
     this->RegisterGenerator("TGZ", "Tar GZip compression",
@@ -60,8 +82,26 @@
                             cmCPackArchiveGenerator::CreateTZSTGenerator);
     this->RegisterGenerator("TAR", "Tar no compression",
                             cmCPackArchiveGenerator::CreateTarGenerator);
-    this->RegisterGenerator("ZIP", "ZIP file format",
-                            cmCPackArchiveGenerator::CreateZIPGenerator);
+    this->RegisterGenerator(
+      "ZIP", "ZIP file format with default compression algorithm",
+      cmCPackArchiveGenerator::CreateZIPGenerator);
+    this->RegisterGenerator("ZIP_STORE", "ZIP file format without compression",
+                            cmCPackArchiveGenerator::CreateZipStoreGenerator);
+    this->RegisterGenerator(
+      "ZIP_DEFLATE", "ZIP file format with Deflate compression",
+      cmCPackArchiveGenerator::CreateZipDeflateGenerator);
+    this->RegisterGenerator("ZIP_BZ2",
+                            "ZIP file format with BZip2 compression",
+                            cmCPackArchiveGenerator::CreateZipBzip2Generator);
+    this->RegisterGenerator("ZIP_LZMA",
+                            "ZIP file format with LZMA compression",
+                            cmCPackArchiveGenerator::CreateZipLzmaGenerator);
+    this->RegisterGenerator("ZIP_LZMA2",
+                            "ZIP file format with LZMA2 compression",
+                            cmCPackArchiveGenerator::CreateZipLzma2Generator);
+    this->RegisterGenerator("ZIP_ZSTD",
+                            "ZIP file format with Zstandard compression",
+                            cmCPackArchiveGenerator::CreateZipZstdGenerator);
   }
   if (cmCPackSTGZGenerator::CanGenerate()) {
     this->RegisterGenerator("STGZ", "Self extracting Tar GZip compression",
diff --git a/Source/CPack/cmCPackInnoSetupGenerator.cxx b/Source/CPack/cmCPackInnoSetupGenerator.cxx
index 93641b5..4b8533b 100644
--- a/Source/CPack/cmCPackInnoSetupGenerator.cxx
+++ b/Source/CPack/cmCPackInnoSetupGenerator.cxx
@@ -4,12 +4,12 @@
 #include "cmCPackInnoSetupGenerator.h"
 
 #include <algorithm>
-#include <cctype>
 #include <cstdlib>
 #include <ostream>
 #include <utility>
 
 #include "cmsys/RegularExpression.hxx"
+#include "cmsys/String.h"
 
 #include "cmCPackComponentGroup.h"
 #include "cmCPackLog.h"
@@ -116,7 +116,7 @@
     if (cmSystemTools::LowerCase(i) == "english") {
       params["MessagesFile"] = "\"compiler:Default.isl\"";
     } else {
-      i[0] = static_cast<char>(std::toupper(i[0]));
+      i[0] = static_cast<char>(cmsysString_toupper(i[0]));
       params["MessagesFile"] = cmStrCat("\"compiler:Languages\\", i, ".isl\"");
     }
 
@@ -889,7 +889,7 @@
 {
   // Remove the old archive, if one exists
   std::string const& archiveFile =
-    uploadDirectory + '/' + component->ArchiveFile;
+    cmStrCat(uploadDirectory, '/', component->ArchiveFile);
   cmCPackLogger(cmCPackLog::LOG_OUTPUT,
                 "-   Building downloaded component archive: " << archiveFile
                                                               << std::endl);
diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx
index 85f1786..538222d 100644
--- a/Source/CPack/cmCPackNSISGenerator.cxx
+++ b/Source/CPack/cmCPackNSISGenerator.cxx
@@ -773,7 +773,8 @@
     }
 
     // Remove the old archive, if one exists
-    std::string archiveFile = uploadDirectory + '/' + component->ArchiveFile;
+    std::string archiveFile =
+      cmStrCat(uploadDirectory, '/', component->ArchiveFile);
     cmCPackLogger(cmCPackLog::LOG_OUTPUT,
                   "-   Building downloaded component archive: " << archiveFile
                                                                 << std::endl);
diff --git a/Source/CPack/cmCPackRPMGenerator.cxx b/Source/CPack/cmCPackRPMGenerator.cxx
index 8c2eecd..2bc60c2 100644
--- a/Source/CPack/cmCPackRPMGenerator.cxx
+++ b/Source/CPack/cmCPackRPMGenerator.cxx
@@ -3,12 +3,13 @@
 #include "cmCPackRPMGenerator.h"
 
 #include <algorithm>
-#include <cctype>
 #include <map>
 #include <ostream>
 #include <utility>
 #include <vector>
 
+#include "cmsys/String.h"
+
 #include "cmCPackComponentGroup.h"
 #include "cmCPackGenerator.h"
 #include "cmCPackLog.h"
@@ -143,7 +144,7 @@
            ++compIt) {
         std::string component(compIt->first);
         std::transform(component.begin(), component.end(), component.begin(),
-                       ::toupper);
+                       cmsysString_toupper);
 
         if (this->IsOn("CPACK_RPM_" + compIt->first + "_DEBUGINFO_PACKAGE") ||
             this->IsOn("CPACK_RPM_" + component + "_DEBUGINFO_PACKAGE")) {
@@ -157,7 +158,7 @@
            compGIt != this->ComponentGroups.end(); ++compGIt) {
         std::string component(compGIt->first);
         std::transform(component.begin(), component.end(), component.begin(),
-                       ::toupper);
+                       cmsysString_toupper);
 
         if (this->IsOn("CPACK_RPM_" + compGIt->first + "_DEBUGINFO_PACKAGE") ||
             this->IsOn("CPACK_RPM_" + component + "_DEBUGINFO_PACKAGE")) {
@@ -174,7 +175,7 @@
           if (!compIt->second.Group) {
             std::string component(compIt->first);
             std::transform(component.begin(), component.end(),
-                           component.begin(), ::toupper);
+                           component.begin(), cmsysString_toupper);
 
             if (this->IsOn("CPACK_RPM_" + compIt->first +
                            "_DEBUGINFO_PACKAGE") ||
@@ -206,7 +207,7 @@
 
     std::string mainComponentUpper(mainComponent);
     std::transform(mainComponentUpper.begin(), mainComponentUpper.end(),
-                   mainComponentUpper.begin(), ::toupper);
+                   mainComponentUpper.begin(), cmsysString_toupper);
 
     // The default behavior is to have one package by component group
     // unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
@@ -218,7 +219,7 @@
            compGIt != this->ComponentGroups.end(); ++compGIt) {
         std::string component(compGIt->first);
         std::transform(component.begin(), component.end(), component.begin(),
-                       ::toupper);
+                       cmsysString_toupper);
 
         if (mainComponentUpper == component) {
           // main component will be handled last
@@ -240,7 +241,7 @@
         if (!compIt->second.Group) {
           std::string component(compIt->first);
           std::transform(component.begin(), component.end(), component.begin(),
-                         ::toupper);
+                         cmsysString_toupper);
 
           if (mainComponentUpper == component) {
             // main component will be handled last
@@ -283,7 +284,7 @@
            ++compIt) {
         std::string component(compIt->first);
         std::transform(component.begin(), component.end(), component.begin(),
-                       ::toupper);
+                       cmsysString_toupper);
 
         if (mainComponentUpper == component) {
           // main component will be handled last
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
index d3ac1bf..3a79367 100644
--- a/Source/CPack/cpack.cxx
+++ b/Source/CPack/cpack.cxx
@@ -225,9 +225,7 @@
                      } },
   };
 
-  cmake cminst(cmake::RoleScript, cmState::CPack);
-  cminst.SetHomeDirectory("");
-  cminst.SetHomeOutputDirectory("");
+  cmake cminst(cmState::Role::CPack);
   cminst.SetProgressCallback(cpackProgressCallback);
   cminst.GetCurrentSnapshot().SetDefaultDefinitions();
   cmGlobalGenerator cmgg(&cminst);
diff --git a/Source/CTest/cmCTestBuildAndTest.cxx b/Source/CTest/cmCTestBuildAndTest.cxx
index def87dc..dd4a7bc 100644
--- a/Source/CTest/cmCTestBuildAndTest.cxx
+++ b/Source/CTest/cmCTestBuildAndTest.cxx
@@ -8,8 +8,7 @@
 #include <ratio>
 #include <utility>
 
-#include <cm3p/uv.h>
-
+#include "cmBuildArgs.h"
 #include "cmBuildOptions.h"
 #include "cmCTest.h"
 #include "cmCTestTestHandler.h"
@@ -19,7 +18,6 @@
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
-#include "cmUVHandlePtr.h"
 #include "cmUVProcessChain.h"
 #include "cmUVStream.h"
 #include "cmWorkingDirectory.h"
@@ -91,11 +89,8 @@
   auto chain = builder.Start();
 
   cmProcessOutput processOutput(cmProcessOutput::Auto);
-  cm::uv_pipe_ptr outputStream;
-  outputStream.init(chain.GetLoop(), 0);
-  uv_pipe_open(outputStream, chain.OutputStream());
   auto outputHandle = cmUVStreamRead(
-    outputStream,
+    chain.OutputStream(),
     [&processOutput](std::vector<char> data) {
       std::string decoded;
       processOutput.DecodeText(data.data(), data.size(), decoded);
@@ -179,9 +174,7 @@
     return 1;
   }
 
-  cmake cm(cmake::RoleProject, cmState::Project);
-  cm.SetHomeDirectory("");
-  cm.SetHomeOutputDirectory("");
+  cmake cm(cmState::Role::Project);
   cmCTestBuildAndTestCaptureRAII captureRAII(cm);
   static_cast<void>(captureRAII);
 
@@ -258,12 +251,17 @@
       config = "Debug";
     }
 
+    cmBuildArgs buildArgs;
+    buildArgs.jobs = cmake::NO_BUILD_PARALLEL_LEVEL;
+    buildArgs.binaryDir = this->BinaryDir;
+    buildArgs.projectName = this->BuildProject;
+    buildArgs.verbose = false;
+
     cmBuildOptions buildOptions(!this->BuildNoClean, false,
                                 PackageResolveMode::Disable);
     int retVal = cm.GetGlobalGenerator()->Build(
-      cmake::NO_BUILD_PARALLEL_LEVEL, this->SourceDir, this->BinaryDir,
-      this->BuildProject, { tar }, std::cout, this->BuildMakeProgram, config,
-      buildOptions, false, remainingTime, cmSystemTools::OUTPUT_PASSTHROUGH);
+      buildArgs, { tar }, std::cout, this->BuildMakeProgram, config,
+      buildOptions, remainingTime, cmSystemTools::OUTPUT_PASSTHROUGH);
     // if the build failed then return
     if (retVal) {
       return 1;
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index a468395..71c9e3f 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -514,11 +514,11 @@
     char const* fname = launchDir.GetFile(i);
     if (this->IsLaunchedErrorFile(fname) && numErrorsAllowed) {
       numErrorsAllowed--;
-      fragments.insert(this->CTestLaunchDir + '/' + fname);
+      fragments.insert(cmStrCat(this->CTestLaunchDir, '/', fname));
       ++this->TotalErrors;
     } else if (this->IsLaunchedWarningFile(fname) && numWarningsAllowed) {
       numWarningsAllowed--;
-      fragments.insert(this->CTestLaunchDir + '/' + fname);
+      fragments.insert(cmStrCat(this->CTestLaunchDir, '/', fname));
       ++this->TotalWarnings;
     }
   }
@@ -875,18 +875,14 @@
   }
 
   // For every chunk of data
-  cm::uv_pipe_ptr outputStream;
   bool outFinished = false;
-  cm::uv_pipe_ptr errorStream;
   bool errFinished = false;
-  auto startRead = [this, &chain, &processOutput, &tick,
-                    &ofs](cm::uv_pipe_ptr& pipe, int stream,
+  auto startRead = [this, &processOutput, &tick,
+                    &ofs](uv_stream_t* stream,
                           t_BuildProcessingQueueType& queue, bool& finished,
                           int id) -> std::unique_ptr<cmUVStreamReadHandle> {
-    pipe.init(chain.GetLoop(), 0);
-    uv_pipe_open(pipe, stream);
     return cmUVStreamRead(
-      pipe,
+      stream,
       [this, &processOutput, &queue, id, &tick, &ofs](std::vector<char> data) {
         // Replace '\0' with '\n', since '\0' does not really make sense. This
         // is for Visual Studio output
@@ -912,11 +908,10 @@
         finished = true;
       });
   };
-  auto outputHandle = startRead(outputStream, chain.OutputStream(),
+  auto outputHandle = startRead(chain.OutputStream(),
                                 this->BuildProcessingQueue, outFinished, 1);
-  auto errorHandle =
-    startRead(errorStream, chain.ErrorStream(),
-              this->BuildProcessingErrorQueue, errFinished, 2);
+  auto errorHandle = startRead(
+    chain.ErrorStream(), this->BuildProcessingErrorQueue, errFinished, 2);
 
   while (!timedOut && !(outFinished && errFinished && chain.Finished())) {
     uv_run(&chain.GetLoop(), UV_RUN_ONCE);
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
index 5eb201f..65cbd53 100644
--- a/Source/CTest/cmCTestCoverageHandler.cxx
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -791,14 +791,16 @@
 
   for (std::string const& s : args) {
     if (s.find(' ') == std::string::npos) {
-      ret += s + ' ';
+      ret = cmStrCat(std::move(ret), s, ' ');
     } else {
-      ret += "\"" + s + "\" ";
+      ret = cmStrCat(std::move(ret), '"', s, "\" ");
     }
   }
 
   // drop trailing whitespace
-  ret.erase(ret.size() - 1);
+  if (!ret.empty()) {
+    ret.pop_back();
+  }
 
   return ret;
 }
diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx
index 52adedd..fdb0bb7 100644
--- a/Source/CTest/cmCTestGIT.cxx
+++ b/Source/CTest/cmCTestGIT.cxx
@@ -11,6 +11,7 @@
 #include <cmext/algorithm>
 
 #include "cmsys/FStream.hxx"
+#include "cmsys/String.h"
 
 #include "cmCTest.h"
 #include "cmCTestVC.h"
@@ -412,14 +413,14 @@
 
   char const* ConsumeSpace(char const* c)
   {
-    while (*c && cmIsSpace(*c)) {
+    while (*c && cmsysString_isspace(*c)) {
       ++c;
     }
     return c;
   }
   char const* ConsumeField(char const* c)
   {
-    while (*c && !cmIsSpace(*c)) {
+    while (*c && !cmsysString_isspace(*c)) {
       ++c;
     }
     return c;
@@ -479,7 +480,7 @@
   {
     // Person Name <person@domain.com> 1234567890 +0000
     char const* c = str;
-    while (*c && cmIsSpace(*c)) {
+    while (*c && cmsysString_isspace(*c)) {
       ++c;
     }
 
@@ -488,7 +489,7 @@
       ++c;
     }
     char const* name_last = c;
-    while (name_last != name_first && cmIsSpace(*(name_last - 1))) {
+    while (name_last != name_first && cmsysString_isspace(*(name_last - 1))) {
       --name_last;
     }
     person.Name.assign(name_first, name_last - name_first);
diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx
index 790ac25..5d81676 100644
--- a/Source/CTest/cmCTestLaunch.cxx
+++ b/Source/CTest/cmCTestLaunch.cxx
@@ -27,7 +27,6 @@
 #include "cmStateSnapshot.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
-#include "cmUVHandlePtr.h"
 #include "cmUVProcessChain.h"
 #include "cmUVStream.h"
 #include "cmake.h"
@@ -239,23 +238,19 @@
   auto chain = builder.Start();
 
   // Record child stdout and stderr if necessary.
-  cm::uv_pipe_ptr outPipe;
-  cm::uv_pipe_ptr errPipe;
   bool outFinished = true;
   bool errFinished = true;
   cmProcessOutput processOutput;
   std::unique_ptr<cmUVStreamReadHandle> outputHandle;
   std::unique_ptr<cmUVStreamReadHandle> errorHandle;
   if (!this->Reporter.Passthru) {
-    auto beginRead = [&chain, &processOutput](
-                       cm::uv_pipe_ptr& pipe, int stream, std::ostream& out,
+    auto beginRead =
+      [&processOutput](uv_stream_t* stream, std::ostream& out,
                        cmsys::ofstream& file, bool& haveData, bool& finished,
                        int id) -> std::unique_ptr<cmUVStreamReadHandle> {
-      pipe.init(chain.GetLoop(), 0);
-      uv_pipe_open(pipe, stream);
       finished = false;
       return cmUVStreamRead(
-        pipe,
+        stream,
         [&processOutput, &out, &file, id, &haveData](std::vector<char> data) {
           std::string strdata;
           processOutput.DecodeText(data.data(), data.size(), strdata, id);
@@ -273,9 +268,9 @@
           finished = true;
         });
     };
-    outputHandle = beginRead(outPipe, chain.OutputStream(), std::cout, fout,
+    outputHandle = beginRead(chain.OutputStream(), std::cout, fout,
                              this->HaveOut, outFinished, 1);
-    errorHandle = beginRead(errPipe, chain.ErrorStream(), std::cerr, ferr,
+    errorHandle = beginRead(chain.ErrorStream(), std::cerr, ferr,
                             this->HaveErr, errFinished, 2);
   }
 
@@ -411,9 +406,7 @@
 
 void cmCTestLaunch::LoadConfig()
 {
-  cmake cm(cmake::RoleScript, cmState::CTest);
-  cm.SetHomeDirectory("");
-  cm.SetHomeOutputDirectory("");
+  cmake cm(cmState::Role::CTest);
   cm.GetCurrentSnapshot().SetDefaultDefinitions();
   cmGlobalGenerator gg(&cm);
   cmMakefile mf(&gg, cm.GetCurrentSnapshot());
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index de8651c..97b1d16 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -365,6 +365,8 @@
     if (!skipped) {
       this->TestResult.CompletionStatus = "Completed";
     }
+    this->TestResult.StartTestTime =
+      this->TestProcess->GetSystemStartTime().time_since_epoch();
     this->TestResult.ExecutionTime = this->TestProcess->GetTotalTime();
     this->MemCheckPostProcess();
     this->ComputeWeightedCost();
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index bed2bb7..278d749 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -2,7 +2,6 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "cmCTestScriptHandler.h"
 
-#include <chrono>
 #include <cstdlib>
 #include <functional>
 #include <map>
@@ -11,8 +10,6 @@
 
 #include <cm/memory>
 
-#include <cm3p/uv.h>
-
 #include "cmCTest.h"
 #include "cmCTestBuildCommand.h"
 #include "cmCTestConfigureCommand.h"
@@ -34,7 +31,6 @@
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
 #include "cmSystemTools.h"
-#include "cmUVHandlePtr.h"
 #include "cmUVProcessChain.h"
 #include "cmake.h"
 
@@ -108,20 +104,14 @@
     .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
     .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
   auto process = builder.Start();
-  cm::uv_pipe_ptr outPipe;
-  outPipe.init(process.GetLoop(), 0);
-  uv_pipe_open(outPipe, process.OutputStream());
-  cm::uv_pipe_ptr errPipe;
-  errPipe.init(process.GetLoop(), 0);
-  uv_pipe_open(errPipe, process.ErrorStream());
 
   std::vector<char> out;
   std::vector<char> err;
   std::string line;
-  auto pipe =
-    cmSystemTools::WaitForLine(&process.GetLoop(), outPipe, errPipe, line,
-                               std::chrono::seconds(100), out, err);
-  while (pipe != cmSystemTools::WaitForLineResult::None) {
+  cmSystemTools::WaitForLineResult pipe;
+  while ((pipe = cmSystemTools::WaitForLine(
+            &process.GetLoop(), process.OutputStream(), process.ErrorStream(),
+            line, out, err)) != cmSystemTools::WaitForLineResult::None) {
     cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                "Output: " << line << "\n");
     if (pipe == cmSystemTools::WaitForLineResult::STDERR) {
@@ -129,9 +119,6 @@
     } else if (pipe == cmSystemTools::WaitForLineResult::STDOUT) {
       cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, line << "\n");
     }
-    pipe =
-      cmSystemTools::WaitForLine(&process.GetLoop(), outPipe, errPipe, line,
-                                 std::chrono::seconds(100), out, err);
   }
 
   // Properly handle output of the build command
@@ -172,13 +159,9 @@
 void cmCTestScriptHandler::CreateCMake()
 {
   // create a cmake instance to read the configuration script
-  this->CMake = cm::make_unique<cmake>(cmake::RoleScript, cmState::CTest);
-  this->CMake->SetHomeDirectory("");
-  this->CMake->SetHomeOutputDirectory("");
+  this->CMake = cm::make_unique<cmake>(cmState::Role::CTest);
   this->CMake->GetCurrentSnapshot().SetDefaultDefinitions();
   this->CMake->AddCMakePaths();
-  this->CMake->SetWorkingMode(cmake::SCRIPT_MODE,
-                              cmake::CommandFailureAction::EXIT_CODE);
   this->GlobalGenerator =
     cm::make_unique<cmGlobalGenerator>(this->CMake.get());
 
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index d0045d1..5c6679e 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -652,6 +652,12 @@
       this->LogFile = nullptr;
       return false;
     }
+
+    // We represent some times as a double-precision floating-point number
+    // of seconds since the epoch.  Print them with microsecond precision.
+    // Representable values differ by hundreds of nanoseconds anyway.
+    xmlfile << std::fixed << std::setprecision(6);
+
     cmXMLWriter xml(xmlfile);
     this->GenerateCTestXML(xml);
   }
@@ -1525,6 +1531,9 @@
   xml.Element("Path", this->CTest->GetShortPathToFile(result.Path));
   xml.Element("FullName", this->CTest->GetShortPathToFile(testPath));
   xml.Element("FullCommandLine", result.FullCommandLine);
+  if (result.StartTestTime) {
+    xml.Element("StartTestTime", *result.StartTestTime);
+  }
 }
 
 void cmCTestTestHandler::WriteTestResultFooter(cmXMLWriter& xml,
@@ -1754,9 +1763,7 @@
   }
   cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                      "Constructing a list of tests" << std::endl, this->Quiet);
-  cmake cm(cmake::RoleScript, cmState::CTest);
-  cm.SetHomeDirectory("");
-  cm.SetHomeOutputDirectory("");
+  cmake cm(cmState::Role::CTest);
   cm.GetCurrentSnapshot().SetDefaultDefinitions();
   cmGlobalGenerator gg(&cm);
   cmMakefile mf(&gg, cm.GetCurrentSnapshot());
@@ -2202,7 +2209,7 @@
 
             // Ensure we have complete triples otherwise the data is corrupt.
             if (triples.size() % 3 == 0) {
-              cmState state(cmState::Unknown);
+              cmState state(cmState::Role::Internal);
               rt.Backtrace = cmListFileBacktrace();
 
               // the first entry represents the top of the trace so we need to
@@ -2614,7 +2621,7 @@
       // be ok to put it here as a cmake-list.
       xml.Attribute("value", cmList::to_string(result.Properties->Labels));
       // if we export more properties, this should be done the same way,
-      // i.e. prefix the property name with "cmake_", and it it can be
+      // i.e. prefix the property name with "cmake_", and it can be
       // a list, write it cmake-formatted.
       xml.EndElement(); // </property>
     }
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index e57bc10..3a2e556 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -194,6 +194,7 @@
     std::string TestMeasurementsOutput;
     std::string InstrumentationFile;
     int TestCount = 0;
+    cm::optional<cmDuration> StartTestTime;
     cmCTestTestProperties* Properties = nullptr;
   };
 
diff --git a/Source/CTest/cmParseGTMCoverage.cxx b/Source/CTest/cmParseGTMCoverage.cxx
index c7b2092..c11be30 100644
--- a/Source/CTest/cmParseGTMCoverage.cxx
+++ b/Source/CTest/cmParseGTMCoverage.cxx
@@ -85,7 +85,7 @@
     }
     // Find the full path to the file
     bool found = this->FindMumpsFile(routine, filepath);
-    if (!found && cmHasLiteralSuffix(routine, "%")) {
+    if (!found && cmHasSuffix(routine, '%')) {
       routine.erase(0, 1);
       found = this->FindMumpsFile(routine, filepath);
     }
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
index 9bf81f8..0610672 100644
--- a/Source/CTest/cmProcess.cxx
+++ b/Source/CTest/cmProcess.cxx
@@ -360,7 +360,7 @@
 void cmProcess::Finish()
 {
   this->TotalTime = std::chrono::steady_clock::now() - this->StartTime;
-  // Because of a processor clock scew the runtime may become slightly
+  // Because of a processor clock skew the runtime may become slightly
   // negative. If someone changed the system clock while the process was
   // running this may be even more. Make sure not to report a negative
   // duration here.
diff --git a/Source/Checks/Curses/CMakeLists.txt b/Source/Checks/Curses/CMakeLists.txt
index ed62602..c7b8e5f 100644
--- a/Source/Checks/Curses/CMakeLists.txt
+++ b/Source/Checks/Curses/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.13...4.0 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.13...4.1 FATAL_ERROR)
 project(CheckCurses C)
 
 set(CURSES_NEED_NCURSES TRUE)
diff --git a/Source/Checks/cm_cxx_features.cmake b/Source/Checks/cm_cxx_features.cmake
index f4832b3..edd8118 100644
--- a/Source/Checks/cm_cxx_features.cmake
+++ b/Source/Checks/cm_cxx_features.cmake
@@ -63,6 +63,8 @@
     string(REGEX REPLACE "[^\n]*ld: warning: [^\n]*" "" check_output "${check_output}")
     # Filter out distcc.
     string(REGEX REPLACE "[^\n]*distcc\\[[0-9]+\\][^\n]*[Ww]arning:[^\n]*" "" check_output "${check_output}")
+    # Filter warning on Intel graniterapids CPUs
+    string(REGEX REPLACE "[^\n]*cc1[plus]*: warning: [^\n]*-mavx[^\n]* is aliased[^\n]*" "" check_output "${check_output}")
     # If using the feature causes warnings, treat it as broken/unavailable.
     if(check_output MATCHES "(^|[ :])[Ww][Aa][Rr][Nn][Ii][Nn][Gg]")
       set(CMake_HAVE_CXX_${FEATURE} OFF CACHE INTERNAL "TRY_COMPILE" FORCE)
diff --git a/Source/Checks/cm_cxx_filesystem.cxx b/Source/Checks/cm_cxx_filesystem.cxx
index ccbb339..b9eb1b4 100644
--- a/Source/Checks/cm_cxx_filesystem.cxx
+++ b/Source/Checks/cm_cxx_filesystem.cxx
@@ -31,6 +31,17 @@
       b1.lexically_normal()) {
     return 1;
   }
+
+  // LWG 3070 not implemented on some old Visual Studio compilers (2017, for
+  // example)
+  if (!std::filesystem::path("/a:/b:").lexically_relative("/a:/c:").empty()) {
+    return 1;
+  }
+  // LWG 3096 not implemented on some old Visual Studio compilers (2017, for
+  // example)
+  if (fs::path("/a").lexically_relative("/a/.") != ".") {
+    return 1;
+  }
 #endif
 
   // If std::string is copy-on-write, the std::filesystem::path
diff --git a/Source/CursesDialog/CMakeLists.txt b/Source/CursesDialog/CMakeLists.txt
index bd2aee3..b53baf6 100644
--- a/Source/CursesDialog/CMakeLists.txt
+++ b/Source/CursesDialog/CMakeLists.txt
@@ -60,4 +60,4 @@
 endif()
 
 CMake_OPTIONAL_COMPONENT(ccmake)
-install(TARGETS ccmake DESTINATION ${CMAKE_BIN_DIR} ${COMPONENT})
+install(TARGETS ccmake DESTINATION ${CMake_INSTALL_BIN_DIR} ${COMPONENT})
diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx
index 6de688e..bf6a9ea 100644
--- a/Source/CursesDialog/ccmake.cxx
+++ b/Source/CursesDialog/ccmake.cxx
@@ -75,9 +75,7 @@
   cmDocumentation doc;
   doc.addCMakeStandardDocSections();
   if (doc.CheckOptions(argc, argv)) {
-    cmake hcm(cmake::RoleInternal, cmState::Help);
-    hcm.SetHomeDirectory("");
-    hcm.SetHomeOutputDirectory("");
+    cmake hcm(cmState::Role::Help);
     hcm.AddCMakePaths();
     auto generators = hcm.GetGeneratorsDocumentation();
     doc.SetName("ccmake");
@@ -146,7 +144,7 @@
 
   myform = new cmCursesMainForm(args, x);
   if (myform->LoadCache(cacheDir.c_str())) {
-    curses_clear();
+    clear();
     touchwin(stdscr);
     endwin();
     delete myform;
@@ -186,7 +184,7 @@
   }
 
   // Need to clean-up better
-  curses_clear();
+  clear();
   touchwin(stdscr);
   endwin();
   delete cmCursesForm::CurrentForm;
diff --git a/Source/CursesDialog/cmCursesColor.cxx b/Source/CursesDialog/cmCursesColor.cxx
index 1b29076..a9e5ff6 100644
--- a/Source/CursesDialog/cmCursesColor.cxx
+++ b/Source/CursesDialog/cmCursesColor.cxx
@@ -2,12 +2,13 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "cmCursesColor.h"
 
-#include <cctype>
 #include <cstdlib>
 #include <cstring>
 #include <unordered_map>
 #include <utility>
 
+#include "cmsys/String.h"
+
 #include "cmCursesStandardIncludes.h"
 
 bool cmCursesColor::HasColors()
@@ -42,7 +43,7 @@
   if (!initialized) {
     if (auto* v = getenv("CCMAKE_COLORS")) {
       while (v[0] && v[1] && v[1] == '=') {
-        auto const n = std::toupper(*v);
+        char const n = cmsysString_toupper(*v);
 
         char buffer[12];
         memset(buffer, 0, sizeof(buffer));
diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx
index 8608c37..2607ec0 100644
--- a/Source/CursesDialog/cmCursesLongMessageForm.cxx
+++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx
@@ -89,11 +89,11 @@
   version[width] = '\0';
 
   char fmt_s[] = "%s";
-  curses_move(y - 4, 0);
+  move(y - 4, 0);
   attron(A_STANDOUT);
   printw(fmt_s, bar);
   attroff(A_STANDOUT);
-  curses_move(y - 3, 0);
+  move(y - 3, 0);
   printw(fmt_s, version);
   pos_form_cursor(this->Form);
 }
@@ -110,7 +110,7 @@
   snprintf(firstLine, sizeof(firstLine), "Press [e] to exit screen");
 
   char fmt_s[] = "%s";
-  curses_move(y - 2, 0);
+  move(y - 2, 0);
   printw(fmt_s, firstLine);
   pos_form_cursor(this->Form);
 }
diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx
index 8ca456d..6b465c1 100644
--- a/Source/CursesDialog/cmCursesMainForm.cxx
+++ b/Source/CursesDialog/cmCursesMainForm.cxx
@@ -39,8 +39,7 @@
     "Welcome to ccmake, curses based user interface for CMake.");
   this->HelpMessage.emplace_back();
   this->HelpMessage.emplace_back(s_ConstHelpMessage);
-  this->CMakeInstance =
-    cm::make_unique<cmake>(cmake::RoleProject, cmState::Project);
+  this->CMakeInstance = cm::make_unique<cmake>(cmState::Role::Project);
   this->CMakeInstance->SetCMakeEditCommand(
     cmSystemTools::GetCMakeCursesCommand());
 
@@ -338,17 +337,17 @@
                "      [h] Help              [q] Quit without generating");
     }
 
-    curses_move(y - 4, 0);
+    move(y - 4, 0);
     char fmt[512] = "Keys: [enter] Edit an entry [d] Delete an entry";
     if (process) {
       memset(fmt, ' ', 57);
     }
     printw(fmt_s, fmt);
-    curses_move(y - 3, 0);
+    move(y - 3, 0);
     printw(fmt_s, firstLine);
-    curses_move(y - 2, 0);
+    move(y - 2, 0);
     printw(fmt_s, secondLine);
-    curses_move(y - 1, 0);
+    move(y - 1, 0);
     printw(fmt_s, thirdLine);
   }
 
@@ -356,7 +355,7 @@
     char pageLine[512] = "";
     snprintf(pageLine, sizeof(pageLine), "Page %d of %d", cw->GetPage(),
              this->NumberOfPages);
-    curses_move(0, 65 - static_cast<unsigned int>(strlen(pageLine)) - 1);
+    move(0, 65 - static_cast<unsigned int>(strlen(pageLine)) - 1);
     printw(fmt_s, pageLine);
   }
 
@@ -373,8 +372,8 @@
   // If window size is too small, display error and return
   if (x < cmCursesMainForm::MIN_WIDTH || x < this->InitialWidth ||
       y < cmCursesMainForm::MIN_HEIGHT) {
-    curses_clear();
-    curses_move(0, 0);
+    clear();
+    move(0, 0);
     char fmt[] = "Window is too small. A size of at least %dx%d is required.";
     printw(fmt,
            (cmCursesMainForm::MIN_WIDTH < this->InitialWidth
@@ -417,7 +416,7 @@
   // Pad with spaces to erase any previous text,
   // or truncate as necessary to fit the screen
   bar.resize(x, ' ');
-  curses_move(y - 5, 0);
+  move(y - 5, 0);
   attron(A_STANDOUT);
   char fmt_s[] = "%s";
   printw(fmt_s, bar.c_str());
@@ -439,7 +438,7 @@
   std::string version = "CMake Version ";
   version += cmVersion::GetCMakeVersion();
   version.resize(std::min<std::string::size_type>(x, version.size()));
-  curses_move(y - 4, x - static_cast<int>(version.size()));
+  move(y - 4, x - static_cast<int>(version.size()));
   printw(fmt_s, version.c_str());
 
   pos_form_cursor(this->Form);
@@ -691,8 +690,8 @@
       std::string searchstr = "Search: " + this->SearchString;
       this->UpdateStatusBar(searchstr);
       this->PrintKeys(1);
-      curses_move(y - 5, static_cast<unsigned int>(searchstr.size()));
-      // curses_move(1,1);
+      move(y - 5, static_cast<unsigned int>(searchstr.size()));
+      // move(1,1);
       touchwin(stdscr);
       refresh();
     }
diff --git a/Source/CursesDialog/cmCursesStandardIncludes.h b/Source/CursesDialog/cmCursesStandardIncludes.h
index 9797306..e61a6ec 100644
--- a/Source/CursesDialog/cmCursesStandardIncludes.h
+++ b/Source/CursesDialog/cmCursesStandardIncludes.h
@@ -4,39 +4,16 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
-// Record whether __attribute__ is currently defined.  See purpose below.
-#ifndef __attribute__
-#  define cm_no__attribute__
-#endif
-
 #if defined(__hpux)
 #  define _BOOL_DEFINED
 #  include <sys/time.h>
 #endif
 
-#include <form.h>
-
-// on some machines move erase and clear conflict with stl
-// so remove them from the namespace
-inline void curses_move(unsigned int x, unsigned int y)
-{
-  move(x, y);
-}
-
-inline void curses_clear()
-{
-  erase();
-  clearok(stdscr, TRUE);
-}
-
-#undef move
-#undef erase
-#undef clear
-
-// The curses headers on some platforms (e.g. Solaris) may
-// define __attribute__ as a macro.  This breaks C++ headers
-// in some cases, so undefine it now.
-#if defined(cm_no__attribute__) && defined(__attribute__)
-#  undef __attribute__
+// Tell curses headers on Solaris to not define macros
+// that conflict with C++ standard library interfaces.
+#if defined(__sun__)
+#  define NOMACROS
+#  define NCURSES_NOMACROS
 #endif
-#undef cm_no__attribute__
+
+#include <form.h>
diff --git a/Source/CursesDialog/cmCursesStringWidget.cxx b/Source/CursesDialog/cmCursesStringWidget.cxx
index eb801ca..29759cc 100644
--- a/Source/CursesDialog/cmCursesStringWidget.cxx
+++ b/Source/CursesDialog/cmCursesStringWidget.cxx
@@ -197,15 +197,15 @@
   if (this->InEdit) {
     char fmt_s[] = "%s";
     // Clean the toolbar
-    curses_move(y - 4, 0);
+    move(y - 4, 0);
     clrtoeol();
-    curses_move(y - 3, 0);
+    move(y - 3, 0);
     printw(fmt_s, "Editing option, press [enter] to confirm");
     clrtoeol();
-    curses_move(y - 2, 0);
+    move(y - 2, 0);
     printw(fmt_s, "                press [esc] to cancel");
     clrtoeol();
-    curses_move(y - 1, 0);
+    move(y - 1, 0);
     clrtoeol();
 
     return true;
diff --git a/Source/CursesDialog/form/frm_req_name.c b/Source/CursesDialog/form/frm_req_name.c
index 6fb9183..7079a4e 100644
--- a/Source/CursesDialog/form/frm_req_name.c
+++ b/Source/CursesDialog/form/frm_req_name.c
@@ -147,7 +147,7 @@
       strncpy(buf,str,sizeof(buf));
       while( (i<sizeof(buf)) && (buf[i] != '\0') )
 	{
-	  buf[i] = toupper((int)(buf[i]));
+	  buf[i] = toupper((unsigned char)(buf[i]));
 	  i++;
 	}
       
diff --git a/Source/LexerParser/.gitattributes b/Source/LexerParser/.gitattributes
index 63d9afb..c29315d 100644
--- a/Source/LexerParser/.gitattributes
+++ b/Source/LexerParser/.gitattributes
@@ -1,7 +1,3 @@
-/cmCommandArgumentLexer.cxx        generated
-/cmCommandArgumentLexer.h          generated
-/cmCommandArgumentParser.cxx       generated
-/cmCommandArgumentParserTokens.h   generated
 /cmCTestResourceGroupsLexer.cxx    generated
 /cmCTestResourceGroupsLexer.h      generated
 /cmDependsJavaLexer.cxx            generated
diff --git a/Source/LexerParser/cmExprParser.cxx b/Source/LexerParser/cmExprParser.cxx
index 042e484..b63fbf4 100644
--- a/Source/LexerParser/cmExprParser.cxx
+++ b/Source/LexerParser/cmExprParser.cxx
@@ -569,8 +569,8 @@
 static const yytype_uint8 yyrline[] =
 {
        0,    87,    87,    92,    95,   100,   103,   108,   111,   116,
-     119,   122,   127,   130,   133,   138,   141,   144,   150,   155,
-     158,   161,   164,   169,   172
+     119,   122,   127,   130,   133,   138,   141,   144,   150,   158,
+     161,   164,   167,   172,   175
 };
 #endif
 
@@ -1564,61 +1564,64 @@
   case 18: /* term: term exp_MOD unary  */
 #line 150 "cmExprParser.y"
                      {
+    if (yyvsp[0].Number == 0) {
+      throw std::overflow_error("modulo by zero");
+    }
     (yyval.Number) = (yyvsp[-2].Number) % (yyvsp[0].Number);
   }
-#line 1570 "cmExprParser.cxx"
+#line 1573 "cmExprParser.cxx"
     break;
 
   case 19: /* unary: factor  */
-#line 155 "cmExprParser.y"
+#line 158 "cmExprParser.y"
          {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1578 "cmExprParser.cxx"
+#line 1581 "cmExprParser.cxx"
     break;
 
   case 20: /* unary: exp_PLUS unary  */
-#line 158 "cmExprParser.y"
+#line 161 "cmExprParser.y"
                  {
     (yyval.Number) = + (yyvsp[0].Number);
   }
-#line 1586 "cmExprParser.cxx"
+#line 1589 "cmExprParser.cxx"
     break;
 
   case 21: /* unary: exp_MINUS unary  */
-#line 161 "cmExprParser.y"
+#line 164 "cmExprParser.y"
                   {
     (yyval.Number) = - (yyvsp[0].Number);
   }
-#line 1594 "cmExprParser.cxx"
+#line 1597 "cmExprParser.cxx"
     break;
 
   case 22: /* unary: exp_NOT unary  */
-#line 164 "cmExprParser.y"
+#line 167 "cmExprParser.y"
                 {
     (yyval.Number) = ~ (yyvsp[0].Number);
   }
-#line 1602 "cmExprParser.cxx"
+#line 1605 "cmExprParser.cxx"
     break;
 
   case 23: /* factor: exp_NUMBER  */
-#line 169 "cmExprParser.y"
+#line 172 "cmExprParser.y"
              {
     (yyval.Number) = (yyvsp[0].Number);
   }
-#line 1610 "cmExprParser.cxx"
+#line 1613 "cmExprParser.cxx"
     break;
 
   case 24: /* factor: exp_OPENPARENT exp exp_CLOSEPARENT  */
-#line 172 "cmExprParser.y"
+#line 175 "cmExprParser.y"
                                      {
     (yyval.Number) = (yyvsp[-1].Number);
   }
-#line 1618 "cmExprParser.cxx"
+#line 1621 "cmExprParser.cxx"
     break;
 
 
-#line 1622 "cmExprParser.cxx"
+#line 1625 "cmExprParser.cxx"
 
       default: break;
     }
@@ -1842,7 +1845,7 @@
   return yyresult;
 }
 
-#line 177 "cmExprParser.y"
+#line 180 "cmExprParser.y"
 
 /* End of grammar */
 
diff --git a/Source/LexerParser/cmExprParser.y b/Source/LexerParser/cmExprParser.y
index 68f7882..0cb120c 100644
--- a/Source/LexerParser/cmExprParser.y
+++ b/Source/LexerParser/cmExprParser.y
@@ -148,6 +148,9 @@
     $<Number>$ = $<Number>1 / $<Number>3;
   }
 | term exp_MOD unary {
+    if (yyvsp[0].Number == 0) {
+      throw std::overflow_error("modulo by zero");
+    }
     $<Number>$ = $<Number>1 % $<Number>3;
   }
 
diff --git a/Source/Modules/CMakeBuildUtilities.cmake b/Source/Modules/CMakeBuildUtilities.cmake
index d6879fd..78aa95a 100644
--- a/Source/Modules/CMakeBuildUtilities.cmake
+++ b/Source/Modules/CMakeBuildUtilities.cmake
@@ -22,7 +22,7 @@
 set(KWSYS_USE_Process 1)
 set(KWSYS_USE_CommandLineArguments 1)
 set(KWSYS_HEADER_ROOT ${CMake_BINARY_DIR}/Source)
-set(KWSYS_INSTALL_DOC_DIR "${CMAKE_DOC_DIR}")
+set(KWSYS_INSTALL_DOC_DIR "${CMake_INSTALL_DOC_DIR}")
 if(CMake_NO_CXX_STANDARD)
   set(KWSYS_CXX_STANDARD "")
 endif()
@@ -254,6 +254,7 @@
       IMPORTED_LOCATION "${LibArchive_LIBRARIES}"
       INTERFACE_INCLUDE_DIRECTORIES "${LibArchive_INCLUDE_DIRS}")
   endif ()
+  set(CMake_TEST_LibArchive_VERSION ${LibArchive_VERSION})
 else()
   set(DONT_FAIL_ON_CRC_ERROR OFF)
   set(EXPAT_INCLUDE_DIR ${CMAKE_EXPAT_INCLUDES})
@@ -293,6 +294,7 @@
   set(ENABLE_TEST OFF)
   set(ENABLE_COVERAGE OFF)
   set(ENABLE_INSTALL OFF)
+  set(MSVC_USE_STATIC_CRT OFF)
   set(POSIX_REGEX_LIB "" CACHE INTERNAL "libarchive: No POSIX regular expression support")
   set(ENABLE_SAFESEH "" CACHE INTERNAL "libarchive: No /SAFESEH linker flag")
   set(WINDOWS_VERSION "WIN7" CACHE INTERNAL "libarchive: Set Windows version to use (Windows only)")
diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt
index 7f9e7f0..c9e0bfe 100644
--- a/Source/QtDialog/CMakeLists.txt
+++ b/Source/QtDialog/CMakeLists.txt
@@ -1,6 +1,10 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file LICENSE.rst or https://cmake.org/licensing for details.
 
+if(CMake_GUI_OSX_DEPLOYMENT_TARGET)
+  set(CMAKE_OSX_DEPLOYMENT_TARGET "${CMake_GUI_OSX_DEPLOYMENT_TARGET}")
+endif()
+
 project(QtDialog)
 CMake_OPTIONAL_COMPONENT(cmake-gui)
 set(QT_COMPONENTS
@@ -62,14 +66,8 @@
     PROPERTY COMPILE_DEFINITIONS USE_QXcbIntegrationPlugin)
 endif()
 
-if(CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES)
-  list(APPEND CMake_QT_EXTRA_LIBRARIES ${CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES})
-  set_property(SOURCE CMakeSetup.cxx
-    PROPERTY COMPILE_DEFINITIONS USE_QWindowsIntegrationPlugin)
-endif()
-
 # We need to install platform plugin and add qt.conf for Qt5 on Mac and Windows.
-if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32))
+if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32) AND NOT COMMAND qt_generate_deploy_app_script)
   function(_qt_get_plugin_name_with_version target out_var)
       string(REGEX REPLACE "^Qt::(.+)" "Qt${CMake_QT_MAJOR_VERSION}::\\1"
              qt_plugin_with_version "${target}")
@@ -97,7 +95,7 @@
       elseif(WIN32)
         set(_qt_plugin_dir "plugins")
       endif()
-      set(_qt_plugin_dest "${_qt_plugin_dir}/${_qt_plugin_type}")
+      set(_qt_plugin_dest "${CMake_INSTALL_APP_DIR_SLASH}${_qt_plugin_dir}/${_qt_plugin_type}")
       install(FILES "${_qt_plugin_path}"
         DESTINATION "${_qt_plugin_dest}"
         ${COMPONENT})
@@ -105,45 +103,27 @@
         "${${_qt_plugins_var}};\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${_qt_plugin_dest}/${_qt_plugin_file}")
     endif()
   endmacro()
-  macro(install_qt_plugins _comps _plugins_var)
-    foreach(_qt_comp IN LISTS ${_comps})
-      if(CMake_QT_MAJOR_VERSION VERSION_LESS 6)
-        set(_qt_module_plugins ${Qt${CMake_QT_MAJOR_VERSION}${_qt_comp}_PLUGINS})
-      else()
-        get_target_property(_qt_module_plugins Qt${CMake_QT_MAJOR_VERSION}::${_qt_comp} QT_PLUGINS)
-      endif()
-      foreach(_qt_plugin IN LISTS _qt_module_plugins)
-        if(CMake_QT_MAJOR_VERSION VERSION_GREATER_EQUAL 6)
-          # Qt6 provides the plugins as individual packages that need to be found.
-          find_package(Qt${CMake_QT_MAJOR_VERSION}${_qt_plugin} QUIET
-            PATHS ${Qt${CMake_QT_MAJOR_VERSION}${_qt_comp}_DIR})
-        endif()
-        install_qt_plugin("${_qt_plugin}" "${_plugins_var}")
-      endforeach()
-    endforeach()
-  endmacro()
   if(APPLE)
-    if(CMake_QT_MAJOR_VERSION VERSION_EQUAL 5)
-      install_qt_plugin("Qt5::QCocoaIntegrationPlugin" QT_PLUGINS)
-      if(TARGET Qt5::QMacStylePlugin)
-        install_qt_plugin("Qt5::QMacStylePlugin" QT_PLUGINS)
-      endif()
-    else()
-      # FIXME: Minimize plugins for Qt6.
-      install_qt_plugins(QT_COMPONENTS QT_PLUGINS)
+    if(CMake_QT_MAJOR_VERSION VERSION_GREATER_EQUAL 6)
+      # Qt6 provides the plugins as individual packages that need to be found.
+      find_package(Qt${CMake_QT_MAJOR_VERSION}QCocoaIntegrationPlugin QUIET PATHS ${Qt${CMake_QT_MAJOR_VERSION}Gui_DIR})
+      find_package(Qt${CMake_QT_MAJOR_VERSION}QMacStylePlugin QUIET PATHS ${Qt${CMake_QT_MAJOR_VERSION}Widgets_DIR})
+    endif()
+    install_qt_plugin("Qt${CMake_QT_MAJOR_VERSION}::QCocoaIntegrationPlugin" QT_PLUGINS)
+    if(TARGET Qt${CMake_QT_MAJOR_VERSION}::QMacStylePlugin)
+      install_qt_plugin("Qt${CMake_QT_MAJOR_VERSION}::QMacStylePlugin" QT_PLUGINS)
     endif()
     file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
       "[Paths]\nPlugins = ${_qt_plugin_dir}\n")
     install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
-      DESTINATION "${CMAKE_INSTALL_PREFIX}/Resources"
+      DESTINATION "${CMake_INSTALL_APP_DIR_SLASH}Resources"
       ${COMPONENT})
-  elseif(WIN32 AND NOT CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES)
-    if(CMake_QT_MAJOR_VERSION VERSION_EQUAL 5)
-      install_qt_plugin("Qt5::QWindowsIntegrationPlugin" QT_PLUGINS)
-    else()
-      # FIXME: Minimize plugins for Qt6.
-      install_qt_plugins(QT_COMPONENTS QT_PLUGINS)
+  elseif(WIN32)
+    if(CMake_QT_MAJOR_VERSION VERSION_GREATER_EQUAL 6)
+      # Qt6 provides the plugins as individual packages that need to be found.
+      find_package(Qt${CMake_QT_MAJOR_VERSION}QWindowsIntegrationPlugin QUIET PATHS ${Qt${CMake_QT_MAJOR_VERSION}Gui_DIR})
     endif()
+    install_qt_plugin("Qt${CMake_QT_MAJOR_VERSION}::QWindowsIntegrationPlugin" QT_PLUGINS)
     file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
       "[Paths]\nPlugins = ../${_qt_plugin_dir}\n")
     install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf"
@@ -152,12 +132,6 @@
   endif()
 endif()
 
-get_property(_Qt_Core_LOCATION TARGET Qt${CMake_QT_MAJOR_VERSION}::Core PROPERTY LOCATION)
-get_filename_component(Qt_BIN_DIR "${_Qt_Core_LOCATION}" PATH)
-if(APPLE)
-  get_filename_component(Qt_BIN_DIR "${Qt_BIN_DIR}" PATH)
-endif()
-
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
 add_library(
@@ -250,7 +224,7 @@
 
 if(USE_LGPL)
   install(FILES ${CMake_SOURCE_DIR}/Licenses/LGPLv${USE_LGPL}.txt
-    DESTINATION ${CMAKE_DATA_DIR}/Licenses
+    DESTINATION ${CMake_INSTALL_DATA_DIR}/Licenses
     ${COMPONENT})
   set_property(SOURCE CMakeSetupDialog.cxx
     PROPERTY COMPILE_DEFINITIONS USE_LGPL="${USE_LGPL}")
@@ -311,8 +285,8 @@
   set_target_properties(cmake-gui PROPERTIES
     OUTPUT_NAME CMake
     MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in"
-    MACOSX_BUNDLE_SHORT_VERSION_STRING "${CMAKE_BUNDLE_VERSION}"
-    # TBD: MACOSX_BUNDLE_BUNDLE_VERSION "${CMAKE_BUNDLE_VERSION}"
+    MACOSX_BUNDLE_SHORT_VERSION_STRING "${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}.${CMake_VERSION_PATCH}"
+    # TBD: MACOSX_BUNDLE_BUNDLE_VERSION "${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}.${CMake_VERSION_PATCH}"
     MACOSX_BUNDLE_COPYRIGHT "${CMake_COPYRIGHT_LINE}"
     MACOSX_BUNDLE_GUI_IDENTIFIER "org.cmake.cmake"
     )
@@ -326,14 +300,14 @@
 endif()
 
 install(TARGETS cmake-gui
-  RUNTIME DESTINATION bin ${COMPONENT}
-  BUNDLE DESTINATION "${CMAKE_BUNDLE_LOCATION}" ${COMPONENT})
+  RUNTIME DESTINATION ${CMake_INSTALL_BIN_DIR} ${COMPONENT}
+  BUNDLE  DESTINATION .                        ${COMPONENT})
 
 if(UNIX AND NOT APPLE)
   foreach(size IN ITEMS 32 128)
     install(
       FILES       "${CMAKE_CURRENT_SOURCE_DIR}/CMakeSetup${size}.png"
-      DESTINATION "${CMAKE_XDGDATA_DIR}/icons/hicolor/${size}x${size}/apps"
+      DESTINATION "${CMake_INSTALL_XDGDATA_DIR}/icons/hicolor/${size}x${size}/apps"
       ${COMPONENT}
       RENAME      "CMakeSetup.png")
   endforeach()
@@ -341,32 +315,48 @@
   # install a desktop file so CMake appears in the application start menu
   # with an icon
   install(FILES cmake-gui.desktop
-    DESTINATION "${CMAKE_XDGDATA_DIR}/applications"
+    DESTINATION "${CMake_INSTALL_XDGDATA_DIR}/applications"
     ${COMPONENT})
   install(FILES cmakecache.xml
-    DESTINATION "${CMAKE_XDGDATA_DIR}/mime/packages"
+    DESTINATION "${CMake_INSTALL_XDGDATA_DIR}/mime/packages"
     ${COMPONENT})
 endif()
 
 if(APPLE)
   install(CODE "
     execute_process(COMMAND ln -s \"../MacOS/CMake\" cmake-gui
-        WORKING_DIRECTORY \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/bin)
+        WORKING_DIRECTORY \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMake_INSTALL_BIN_DIR})
   " ${COMPONENT})
 endif()
 
 if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32))
-  # install rules for including 3rd party libs such as Qt
-  # if a system Qt is used (e.g. installed in /usr/lib/), it will not be included in the installation
-  set(fixup_exe "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/bin/cmake-gui${CMAKE_EXECUTABLE_SUFFIX}")
-  if(APPLE)
-    set(fixup_exe "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/MacOS/CMake")
+  if(COMMAND qt_generate_deploy_app_script)
+    # Qt libraries are found via @rpath, so point the runtime path at them.
+    set_property(TARGET cmake-gui PROPERTY INSTALL_RPATH "@executable_path/../Frameworks")
+    qt_generate_deploy_app_script(
+      TARGET cmake-gui
+      OUTPUT_SCRIPT qt_deploy_script
+    )
+    install(SCRIPT "${qt_deploy_script}")
+  else()
+    # install rules for including 3rd party libs such as Qt
+    # if a system Qt is used (e.g. installed in /usr/lib/), it will not be included in the installation
+    set(fixup_exe "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMake_INSTALL_BIN_DIR}/cmake-gui${CMAKE_EXECUTABLE_SUFFIX}")
+    if(APPLE)
+      set(fixup_exe "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMake_INSTALL_APP_DIR_SLASH}MacOS/CMake")
+    endif()
+    get_property(_Qt_Core_LOCATION TARGET Qt${CMake_QT_MAJOR_VERSION}::Core PROPERTY LOCATION)
+    if(APPLE AND _Qt_Core_LOCATION MATCHES [[^(.*)/[^/]*\.framework/]])
+      set(Qt_LIB_DIR "${CMAKE_MATCH_1}")
+    else()
+      get_filename_component(Qt_LIB_DIR "${_Qt_Core_LOCATION}" PATH)
+    endif()
+    install(CODE "
+      include(BundleUtilities)
+      set(BU_CHMOD_BUNDLE_ITEMS ON)
+      fixup_bundle(\"${fixup_exe}\" \"${QT_PLUGINS}\" \"${Qt_LIB_DIR};${QT_LIBRARY_DIR};${QT_BINARY_DIR}\")
+    " ${COMPONENT})
   endif()
-  install(CODE "
-    include(BundleUtilities)
-    set(BU_CHMOD_BUNDLE_ITEMS ON)
-    fixup_bundle(\"${fixup_exe}\" \"${QT_PLUGINS}\" \"${Qt_BIN_DIR};${QT_LIBRARY_DIR};${QT_BINARY_DIR}\")
-  " ${COMPONENT})
 endif()
 
 set(CMAKE_PACKAGE_QTGUI TRUE)
diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx
index cf32461..e74b871 100644
--- a/Source/QtDialog/CMakeSetup.cxx
+++ b/Source/QtDialog/CMakeSetup.cxx
@@ -54,13 +54,6 @@
 Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
 #endif
 
-#if defined(USE_QWindowsIntegrationPlugin)
-Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
-#  if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
-Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin);
-#  endif
-#endif
-
 int CMakeGUIExec(CMakeSetupDialog* window);
 void SetupDefaultQSettings();
 void OpenReferenceManual(QString const& filename);
@@ -82,9 +75,7 @@
   doc.addCMakeStandardDocSections();
   if (argc2 > 1 && doc.CheckOptions(argc2, argv2)) {
     // Construct and print requested documentation.
-    cmake hcm(cmake::RoleInternal, cmState::Help);
-    hcm.SetHomeDirectory("");
-    hcm.SetHomeOutputDirectory("");
+    cmake hcm(cmState::Role::Help);
     hcm.AddCMakePaths();
 
     auto generators = hcm.GetGeneratorsDocumentation();
@@ -289,7 +280,7 @@
 
 static int cmOSXInstall(std::string dir)
 {
-  if (!cmHasLiteralSuffix(dir, "/")) {
+  if (!cmHasSuffix(dir, '/')) {
     dir += "/";
   }
   return (cmOSXInstall(dir, cmSystemTools::GetCMakeCommand()) &&
diff --git a/Source/QtDialog/FirstConfigure.cxx b/Source/QtDialog/FirstConfigure.cxx
index fec62c6..4a3133e 100644
--- a/Source/QtDialog/FirstConfigure.cxx
+++ b/Source/QtDialog/FirstConfigure.cxx
@@ -477,6 +477,10 @@
 
 FirstConfigure::FirstConfigure()
 {
+#ifdef _WIN32
+  // FIXME(QTBUG-123853): Fix window style init for dark mode.
+  this->setWizardStyle(this->wizardStyle());
+#endif
   char const* env_generator = std::getenv("CMAKE_GENERATOR");
   char const* env_generator_platform = nullptr;
   char const* env_generator_toolset = nullptr;
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
index 62b6eb2..cf031b1 100644
--- a/Source/QtDialog/QCMake.cxx
+++ b/Source/QtDialog/QCMake.cxx
@@ -46,8 +46,7 @@
   cmSystemTools::SetStderrCallback(
     [this](std::string const& msg) { this->stderrCallback(msg); });
 
-  this->CMakeInstance =
-    cm::make_unique<cmake>(cmake::RoleProject, cmState::Project);
+  this->CMakeInstance = cm::make_unique<cmake>(cmState::Role::Project);
   this->CMakeInstance->SetCMakeEditCommand(
     cmSystemTools::GetCMakeGUICommand());
   this->CMakeInstance->SetProgressCallback(
diff --git a/Source/QtDialog/QCMakeCacheView.cxx b/Source/QtDialog/QCMakeCacheView.cxx
index 8d4e295..fa2ad3d 100644
--- a/Source/QtDialog/QCMakeCacheView.cxx
+++ b/Source/QtDialog/QCMakeCacheView.cxx
@@ -241,7 +241,10 @@
 
   bool b = this->blockSignals(true);
 
-  this->clear();
+  // Empty the model. Avoid QStandardItemModel::clear(), because that calls
+  // beginResetModel() internally, and we can't nest such calls.
+  this->removeRows(0, this->rowCount());
+
   this->NewPropertyCount = newProps.size();
 
   if (View == FlatView) {
@@ -343,8 +346,6 @@
 
 void QCMakeCacheModel::setViewType(QCMakeCacheModel::ViewType t)
 {
-  this->beginResetModel();
-
   this->View = t;
 
   QCMakePropertyList props = this->properties();
@@ -360,7 +361,6 @@
   this->setProperties(oldProps);
   this->setProperties(props);
   this->blockSignals(b);
-  this->endResetModel();
 }
 
 void QCMakeCacheModel::setPropertyData(QModelIndex const& idx1,
diff --git a/Source/QtDialog/RegexExplorer.cxx b/Source/QtDialog/RegexExplorer.cxx
index 9065f66..b0333cf 100644
--- a/Source/QtDialog/RegexExplorer.cxx
+++ b/Source/QtDialog/RegexExplorer.cxx
@@ -2,6 +2,8 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "RegexExplorer.h"
 
+#include "cmsys/String.h"
+
 RegexExplorer::RegexExplorer(QWidget* p)
   : QDialog(p)
   , m_matched(false)
@@ -147,7 +149,7 @@
       } else if (nextc == 'n') {
         result.append(1, '\n');
         in++;
-      } else if (isalnum(nextc) || nextc == '\0') {
+      } else if (cmsysString_isalnum(nextc) || nextc == '\0') {
         return false;
       } else {
         result.append(1, nextc);
diff --git a/Source/QtDialog/WarningMessagesDialog.cxx b/Source/QtDialog/WarningMessagesDialog.cxx
index a0c72d4..3728693 100644
--- a/Source/QtDialog/WarningMessagesDialog.cxx
+++ b/Source/QtDialog/WarningMessagesDialog.cxx
@@ -26,7 +26,7 @@
 
 void WarningMessagesDialog::setupSignals()
 {
-#if (QT_VERSION >= QT_VERSION_CHECK(6, 7, 0))
+#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
   static auto const checkStateChanged = &QCheckBox::checkStateChanged;
 #else
   static auto const checkStateChanged = &QCheckBox::stateChanged;
@@ -59,7 +59,8 @@
     this->deprecatedWarningsAsErrors->isChecked());
 }
 
-void WarningMessagesDialog::doSuppressDeveloperWarningsChanged(int state)
+void WarningMessagesDialog::doSuppressDeveloperWarningsChanged(
+  CheckState state)
 {
   // no warnings implies no errors either
   if (state) {
@@ -67,7 +68,8 @@
   }
 }
 
-void WarningMessagesDialog::doSuppressDeprecatedWarningsChanged(int state)
+void WarningMessagesDialog::doSuppressDeprecatedWarningsChanged(
+  CheckState state)
 {
   // no warnings implies no errors either
   if (state) {
@@ -75,7 +77,8 @@
   }
 }
 
-void WarningMessagesDialog::doDeveloperWarningsAsErrorsChanged(int state)
+void WarningMessagesDialog::doDeveloperWarningsAsErrorsChanged(
+  CheckState state)
 {
   // warnings as errors implies warnings are not suppressed
   if (state) {
@@ -83,7 +86,8 @@
   }
 }
 
-void WarningMessagesDialog::doDeprecatedWarningsAsErrorsChanged(int state)
+void WarningMessagesDialog::doDeprecatedWarningsAsErrorsChanged(
+  CheckState state)
 {
   // warnings as errors implies warnings are not suppressed
   if (state) {
diff --git a/Source/QtDialog/WarningMessagesDialog.h b/Source/QtDialog/WarningMessagesDialog.h
index 0cde8ff..e5f0660 100644
--- a/Source/QtDialog/WarningMessagesDialog.h
+++ b/Source/QtDialog/WarningMessagesDialog.h
@@ -17,6 +17,12 @@
 {
   Q_OBJECT
 
+#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
+  using CheckState = Qt::CheckState;
+#else
+  using CheckState = int;
+#endif
+
 public:
   WarningMessagesDialog(QWidget* prnt, QCMake* instance);
 
@@ -30,23 +36,23 @@
    * Handler for checked state changed event of the suppress developer warnings
    * checkbox.
    */
-  void doSuppressDeveloperWarningsChanged(int state);
+  void doSuppressDeveloperWarningsChanged(CheckState state);
   /**
    * Handler for checked state changed event of the suppress deprecated
    * warnings checkbox.
    */
-  void doSuppressDeprecatedWarningsChanged(int state);
+  void doSuppressDeprecatedWarningsChanged(CheckState state);
 
   /**
    * Handler for checked state changed event of the developer warnings as
    * errors checkbox.
    */
-  void doDeveloperWarningsAsErrorsChanged(int state);
+  void doDeveloperWarningsAsErrorsChanged(CheckState state);
   /**
    * Handler for checked state changed event of the deprecated warnings as
    * errors checkbox.
    */
-  void doDeprecatedWarningsAsErrorsChanged(int state);
+  void doDeprecatedWarningsAsErrorsChanged(CheckState state);
 
 private:
   QCMake* cmakeInstance;
diff --git a/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in b/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in
index 8cc5835..4e59ec5 100644
--- a/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in
+++ b/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in
@@ -11,7 +11,7 @@
     if (installer.value("os") === "win") {
 
         component.addOperation("CreateShortcut",
-                               "@TargetDir@/%CMAKE_DOC_DIR%/developer-reference/html/index.html",
+                               "@TargetDir@/%CMake_INSTALL_DOC_DIR%/developer-reference/html/index.html",
                                "@StartMenuDir@/CMake Developer Reference.lnk");
 
     }
diff --git a/Source/QtIFW/CMake.Dialogs.QtGUI.qs.in b/Source/QtIFW/CMake.Dialogs.QtGUI.qs.in
index 71f395a..b40c21f 100644
--- a/Source/QtIFW/CMake.Dialogs.QtGUI.qs.in
+++ b/Source/QtIFW/CMake.Dialogs.QtGUI.qs.in
@@ -11,7 +11,7 @@
     if (installer.value("os") === "win") {
 
         component.addOperation("CreateShortcut",
-                               "@TargetDir@/%CMAKE_BIN_DIR%/cmake-gui.exe",
+                               "@TargetDir@/%CMake_INSTALL_BIN_DIR%/cmake-gui.exe",
                                "@StartMenuDir@/CMake (cmake-gui).lnk");
 
     }
diff --git a/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in b/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in
index 54bc14a..14465aa 100644
--- a/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in
+++ b/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in
@@ -11,7 +11,7 @@
     if (installer.value("os") === "win") {
 
         component.addOperation("CreateShortcut",
-                               "@TargetDir@/%CMAKE_DOC_DIR%/html/index.html",
+                               "@TargetDir@/%CMake_INSTALL_DOC_DIR%/html/index.html",
                                "@StartMenuDir@/CMake Documentation.lnk");
 
     }
diff --git a/Source/QtIFW/CMake.qs.in b/Source/QtIFW/CMake.qs.in
index 1f3166e..76ffb92 100644
--- a/Source/QtIFW/CMake.qs.in
+++ b/Source/QtIFW/CMake.qs.in
@@ -11,7 +11,7 @@
     if (installer.value("os") === "win") {
 
         component.addOperation("CreateShortcut",
-                               "@TargetDir@/%CMAKE_DOC_DIR%/cmake.org.html",
+                               "@TargetDir@/%CMake_INSTALL_DOC_DIR%/cmake.org.html",
                                "@StartMenuDir@/CMake Web Site.lnk");
 
         component.addOperation("CreateShortcut",
diff --git a/Source/QtIFW/installscript.qs.in b/Source/QtIFW/installscript.qs.in
index 72d49e8..6abf5ba 100644
--- a/Source/QtIFW/installscript.qs.in
+++ b/Source/QtIFW/installscript.qs.in
@@ -14,7 +14,7 @@
 %_CPACK_IFW_SHORTCUT_OPTIONAL%
 
         component.addOperation("CreateShortcut",
-                               "@TargetDir@/%CMAKE_DOC_DIR%/cmake.org.html",
+                               "@TargetDir@/%CMake_INSTALL_DOC_DIR%/cmake.org.html",
                                "@StartMenuDir@/CMake Web Site.lnk");
 
         component.addOperation("CreateShortcut",
diff --git a/Source/bindexplib.cxx b/Source/bindexplib.cxx
index bbcb0bc..59680aa 100644
--- a/Source/bindexplib.cxx
+++ b/Source/bindexplib.cxx
@@ -72,6 +72,7 @@
 #  include <windows.h>
 
 #  include "cmsys/Encoding.hxx"
+#  include "cmsys/String.h"
 #endif
 
 #include "cmsys/FStream.hxx"
@@ -261,7 +262,7 @@
           }
 
           // clear out any leading spaces
-          while (isspace(symbol[0]))
+          while (cmsysString_isspace(symbol[0]))
             symbol.erase(0, 1);
           // if it starts with _ and has an @ then it is a __cdecl
           // so remove the @ stuff for the export
diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx
index 3a8c890..0adcefd 100644
--- a/Source/cmArchiveWrite.cxx
+++ b/Source/cmArchiveWrite.cxx
@@ -17,12 +17,13 @@
 #include <cm3p/archive_entry.h>
 
 #include "cmsys/Directory.hxx"
-#include "cmsys/Encoding.hxx"
+#ifdef _WIN32
+#  include "cmsys/Encoding.hxx"
+#endif
 #include "cmsys/FStream.hxx"
 
 #include "cm_parse_date.h"
 
-#include "cmLocale.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
@@ -36,16 +37,28 @@
   return e ? e : "unknown error";
 }
 
+// Set path to be written to the archive.
 static void cm_archive_entry_copy_pathname(struct archive_entry* e,
-                                           std::string const& dest)
+                                           char const* dest)
 {
-  archive_entry_copy_pathname_w(e, cmsys::Encoding::ToWide(dest).c_str());
+#ifdef _WIN32
+  // libarchive converts our UTF-8 encoding to the archive's encoding.
+  archive_entry_update_pathname_utf8(e, dest);
+#else
+  // libarchive converts our locale's encoding to the archive's encoding.
+  archive_entry_copy_pathname(e, dest);
+#endif
 }
 
+// Set path used for filesystem access.
 static void cm_archive_entry_copy_sourcepath(struct archive_entry* e,
                                              std::string const& file)
 {
+#ifdef _WIN32
   archive_entry_copy_sourcepath_w(e, cmsys::Encoding::ToWide(file).c_str());
+#else
+  archive_entry_copy_sourcepath(e, file.c_str());
+#endif
 }
 
 class cmArchiveWrite::Entry
@@ -89,6 +102,17 @@
   // Upstream fixed an issue with their integer parsing in 3.4.0
   // which would cause spurious errors to be raised from `strtoull`.
 
+  if (archive_write_set_format_by_name(this->Archive, format.c_str()) !=
+      ARCHIVE_OK) {
+    this->Error = cmStrCat("archive_write_set_format_by_name: ",
+                           cm_archive_error_string(this->Archive));
+    return;
+  }
+
+  bool is7zip = (format == "7zip");
+  bool isZip = (format == "zip");
+  bool isFormatSupportsCompressionNatively = (is7zip || isZip);
+
   if (numThreads < 1) {
     int upperLimit = (numThreads == 0) ? std::numeric_limits<int>::max()
                                        : std::abs(numThreads);
@@ -99,122 +123,228 @@
 
   std::string sNumThreads = std::to_string(numThreads);
 
-  switch (c) {
-    case CompressNone:
-      if (archive_write_add_filter_none(this->Archive) != ARCHIVE_OK) {
-        this->Error = cmStrCat("archive_write_add_filter_none: ",
-                               cm_archive_error_string(this->Archive));
-        return;
-      }
-      break;
-    case CompressCompress:
-      if (archive_write_add_filter_compress(this->Archive) != ARCHIVE_OK) {
-        this->Error = cmStrCat("archive_write_add_filter_compress: ",
-                               cm_archive_error_string(this->Archive));
-        return;
-      }
-      break;
-    case CompressGZip: {
-      if (archive_write_add_filter_gzip(this->Archive) != ARCHIVE_OK) {
-        this->Error = cmStrCat("archive_write_add_filter_gzip: ",
-                               cm_archive_error_string(this->Archive));
-        return;
-      }
-      std::string source_date_epoch;
-      cmSystemTools::GetEnv("SOURCE_DATE_EPOCH", source_date_epoch);
-      if (!source_date_epoch.empty()) {
-        // We're not able to specify an arbitrary timestamp for gzip.
-        // The next best thing is to omit the timestamp entirely.
-        if (archive_write_set_filter_option(this->Archive, "gzip", "timestamp",
-                                            nullptr) != ARCHIVE_OK) {
-          this->Error = cmStrCat("archive_write_set_filter_option: ",
+  if (!isFormatSupportsCompressionNatively) {
+    switch (c) {
+      case CompressNone:
+        if (archive_write_add_filter_none(this->Archive) != ARCHIVE_OK) {
+          this->Error = cmStrCat("archive_write_add_filter_none: ",
                                  cm_archive_error_string(this->Archive));
           return;
         }
-      }
-    } break;
-    case CompressBZip2:
-      if (archive_write_add_filter_bzip2(this->Archive) != ARCHIVE_OK) {
-        this->Error = cmStrCat("archive_write_add_filter_bzip2: ",
-                               cm_archive_error_string(this->Archive));
-        return;
-      }
-      break;
-    case CompressLZMA:
-      if (archive_write_add_filter_lzma(this->Archive) != ARCHIVE_OK) {
-        this->Error = cmStrCat("archive_write_add_filter_lzma: ",
-                               cm_archive_error_string(this->Archive));
-        return;
-      }
-      break;
-    case CompressXZ:
-      if (archive_write_add_filter_xz(this->Archive) != ARCHIVE_OK) {
-        this->Error = cmStrCat("archive_write_add_filter_xz: ",
-                               cm_archive_error_string(this->Archive));
-        return;
-      }
+        break;
+      case CompressCompress:
+        if (archive_write_add_filter_compress(this->Archive) != ARCHIVE_OK) {
+          this->Error = cmStrCat("archive_write_add_filter_compress: ",
+                                 cm_archive_error_string(this->Archive));
+          return;
+        }
+        break;
+      case CompressGZip: {
+        if (archive_write_add_filter_gzip(this->Archive) != ARCHIVE_OK) {
+          this->Error = cmStrCat("archive_write_add_filter_gzip: ",
+                                 cm_archive_error_string(this->Archive));
+          return;
+        }
+        std::string source_date_epoch;
+        cmSystemTools::GetEnv("SOURCE_DATE_EPOCH", source_date_epoch);
+        if (!source_date_epoch.empty()) {
+          // We're not able to specify an arbitrary timestamp for gzip.
+          // The next best thing is to omit the timestamp entirely.
+          if (archive_write_set_filter_option(
+                this->Archive, "gzip", "timestamp", nullptr) != ARCHIVE_OK) {
+            this->Error = cmStrCat("archive_write_set_filter_option: ",
+                                   cm_archive_error_string(this->Archive));
+            return;
+          }
+        }
+      } break;
+      case CompressBZip2:
+        if (archive_write_add_filter_bzip2(this->Archive) != ARCHIVE_OK) {
+          this->Error = cmStrCat("archive_write_add_filter_bzip2: ",
+                                 cm_archive_error_string(this->Archive));
+          return;
+        }
+        break;
+      case CompressLZMA:
+        if (archive_write_add_filter_lzma(this->Archive) != ARCHIVE_OK) {
+          this->Error = cmStrCat("archive_write_add_filter_lzma: ",
+                                 cm_archive_error_string(this->Archive));
+          return;
+        }
+        break;
+      case CompressXZ:
+        if (archive_write_add_filter_xz(this->Archive) != ARCHIVE_OK) {
+          this->Error = cmStrCat("archive_write_add_filter_xz: ",
+                                 cm_archive_error_string(this->Archive));
+          return;
+        }
 
 #if ARCHIVE_VERSION_NUMBER >= 3004000
 
 #  ifdef _AIX
-      // FIXME: Using more than 2 threads creates an empty archive.
-      // Enforce this limit pending further investigation.
-      if (numThreads > 2) {
-        numThreads = 2;
-        sNumThreads = std::to_string(numThreads);
-      }
+        // FIXME: Using more than 2 threads creates an empty archive.
+        // Enforce this limit pending further investigation.
+        if (numThreads > 2) {
+          numThreads = 2;
+          sNumThreads = std::to_string(numThreads);
+        }
 #  endif
-      if (archive_write_set_filter_option(this->Archive, "xz", "threads",
-                                          sNumThreads.c_str()) != ARCHIVE_OK) {
-        this->Error = cmStrCat("archive_compressor_xz_options: ",
-                               cm_archive_error_string(this->Archive));
-        return;
-      }
+        if (archive_write_set_filter_option(this->Archive, "xz", "threads",
+                                            sNumThreads.c_str()) !=
+            ARCHIVE_OK) {
+          this->Error = cmStrCat("archive_compressor_xz_options: ",
+                                 cm_archive_error_string(this->Archive));
+          return;
+        }
 #endif
 
-      break;
-    case CompressZstd:
-      if (archive_write_add_filter_zstd(this->Archive) != ARCHIVE_OK) {
-        this->Error = cmStrCat("archive_write_add_filter_zstd: ",
-                               cm_archive_error_string(this->Archive));
-        return;
-      }
+        break;
+      case CompressZstd:
+        if (archive_write_add_filter_zstd(this->Archive) != ARCHIVE_OK) {
+          this->Error = cmStrCat("archive_write_add_filter_zstd: ",
+                                 cm_archive_error_string(this->Archive));
+          return;
+        }
 
 #if ARCHIVE_VERSION_NUMBER >= 3006000
-      if (archive_write_set_filter_option(this->Archive, "zstd", "threads",
-                                          sNumThreads.c_str()) != ARCHIVE_OK) {
-        this->Error = cmStrCat("archive_compressor_zstd_options: ",
-                               cm_archive_error_string(this->Archive));
-        return;
-      }
+        if (archive_write_set_filter_option(this->Archive, "zstd", "threads",
+                                            sNumThreads.c_str()) !=
+            ARCHIVE_OK) {
+          this->Error = cmStrCat("archive_compressor_zstd_options: ",
+                                 cm_archive_error_string(this->Archive));
+          return;
+        }
 #endif
-      break;
+        break;
+      case CompressPPMd:
+        this->Error = cmStrCat("PPMd is not supported for ", format);
+        return;
+    }
   }
 
-  if (compressionLevel != 0) {
+  if (isFormatSupportsCompressionNatively || compressionLevel != 0) {
     std::string compressionLevelStr = std::to_string(compressionLevel);
     std::string archiveFilterName;
     switch (c) {
       case CompressNone:
+        if (is7zip || isZip) {
+          archiveFilterName = "store";
+        } else {
+          // Nothing to do - the value should be empty
+        }
+        break;
       case CompressCompress:
+        if (is7zip || isZip) {
+          this->Error =
+            cmStrCat("CompressCompress is not supported for ", format);
+        } else {
+          // Nothing to do - the value should be empty
+        }
         break;
       case CompressGZip:
-        archiveFilterName = "gzip";
+        if (is7zip || isZip) {
+          archiveFilterName = "deflate";
+        } else {
+          archiveFilterName = "gzip";
+        }
         break;
       case CompressBZip2:
+#if ARCHIVE_VERSION_NUMBER < 3008000
+        if (isZip) {
+          this->Error = cmStrCat("BZip2 is not supported for ", format,
+                                 ". Please, build CMake with libarchive 3.8.0 "
+                                 "or newer if you want to use it.");
+          return;
+        }
+#endif
         archiveFilterName = "bzip2";
         break;
       case CompressLZMA:
-        archiveFilterName = "lzma";
+#if ARCHIVE_VERSION_NUMBER < 3008000
+        if (isZip) {
+          this->Error = cmStrCat("LZMA is not supported for ", format,
+                                 ". Please, build CMake with libarchive 3.8.0 "
+                                 "or newer if you want to use it.");
+          return;
+        }
+#endif
+        if (is7zip) {
+          archiveFilterName = "lzma1";
+        } else {
+          archiveFilterName = "lzma";
+        }
         break;
       case CompressXZ:
-        archiveFilterName = "xz";
+#if ARCHIVE_VERSION_NUMBER < 3008000
+        if (isZip) {
+          this->Error = cmStrCat("LZMA2 (XZ) is not supported for ", format,
+                                 ". Please, build CMake with libarchive 3.8.0 "
+                                 "or newer if you want to use it.");
+          return;
+        }
+#endif
+        if (is7zip) {
+          archiveFilterName = "lzma2";
+        } else {
+          archiveFilterName = "xz";
+        }
         break;
       case CompressZstd:
+#if ARCHIVE_VERSION_NUMBER < 3008000
+        if (is7zip || isZip) {
+          this->Error = cmStrCat("Zstd is not supported for ", format,
+                                 ". Please, build CMake with libarchive 3.8.0 "
+                                 "or newer if you want to use it.");
+          return;
+        }
+#endif
         archiveFilterName = "zstd";
         break;
+      case CompressPPMd:
+        if (is7zip) {
+          archiveFilterName = "ppmd";
+        } else {
+          this->Error = cmStrCat("PPMd is not supported for ", format);
+        }
+        return;
     }
-    if (!archiveFilterName.empty()) {
+
+    if (isFormatSupportsCompressionNatively) {
+      if (archiveFilterName.empty()) {
+        this->Error = cmStrCat("Unknown compression method for ", format);
+        return;
+      }
+
+      if (archive_write_set_format_option(
+            this->Archive, format.c_str(), "compression",
+            archiveFilterName.c_str()) != ARCHIVE_OK) {
+        this->Error =
+          cmStrCat("archive_write_set_format_option(compression): ",
+                   cm_archive_error_string(this->Archive));
+        return;
+      }
+
+#if ARCHIVE_VERSION_NUMBER >= 3008000
+      if (archive_write_set_format_option(this->Archive, format.c_str(),
+                                          "threads",
+                                          sNumThreads.c_str()) != ARCHIVE_OK) {
+        this->Error = cmStrCat("archive_write_set_format_option(threads): ",
+                               cm_archive_error_string(this->Archive));
+        return;
+      }
+#endif
+
+      if (compressionLevel != 0) {
+        if (archive_write_set_format_option(
+              this->Archive, format.c_str(), "compression-level",
+              compressionLevelStr.c_str()) != ARCHIVE_OK) {
+          this->Error =
+            cmStrCat("archive_write_set_format_option(compression-level): ",
+                     cm_archive_error_string(this->Archive));
+          return;
+        }
+      }
+    } else if (compressionLevel != 0 && !archiveFilterName.empty()) {
       if (archive_write_set_filter_option(
             this->Archive, archiveFilterName.c_str(), "compression-level",
             compressionLevelStr.c_str()) != ARCHIVE_OK) {
@@ -233,13 +363,6 @@
   }
 #endif
 
-  if (archive_write_set_format_by_name(this->Archive, format.c_str()) !=
-      ARCHIVE_OK) {
-    this->Error = cmStrCat("archive_write_set_format_by_name: ",
-                           cm_archive_error_string(this->Archive));
-    return;
-  }
-
   // do not pad the last block!!
   if (archive_write_set_bytes_in_last_block(this->Archive, 1)) {
     this->Error = cmStrCat("archive_write_set_bytes_in_last_block: ",
@@ -325,9 +448,6 @@
   }
   char const* out = file + skip;
 
-  cmLocaleRAII localeRAII;
-  static_cast<void>(localeRAII);
-
   // Meta-data.
   std::string dest = cmStrCat(prefix ? prefix : "", out);
   if (this->Verbose) {
@@ -335,11 +455,12 @@
   }
   Entry e;
   cm_archive_entry_copy_sourcepath(e, file);
-  cm_archive_entry_copy_pathname(e, dest);
+  cm_archive_entry_copy_pathname(e, dest.c_str());
   if (archive_read_disk_entry_from_file(this->Disk, e, -1, nullptr) !=
       ARCHIVE_OK) {
-    this->Error = cmStrCat("Unable to read from file '", file,
-                           "': ", cm_archive_error_string(this->Disk));
+    this->Error =
+      cmStrCat("Unable to read from file:\n  ", file, "\nbecause:\n  ",
+               cm_archive_error_string(this->Disk));
     return false;
   }
   if (!this->MTime.empty()) {
diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h
index 3937e49..dac0a57 100644
--- a/Source/cmArchiveWrite.h
+++ b/Source/cmArchiveWrite.h
@@ -49,7 +49,8 @@
     CompressBZip2,
     CompressLZMA,
     CompressXZ,
-    CompressZstd
+    CompressZstd,
+    CompressPPMd,
   };
 
   /** Construct with output stream to which to write archive.  */
diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx
index 765e9cb..30bdadc 100644
--- a/Source/cmArgumentParser.cxx
+++ b/Source/cmArgumentParser.cxx
@@ -5,6 +5,7 @@
 #include <algorithm>
 
 #include "cmArgumentParserTypes.h"
+#include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmStringAlgorithms.h"
@@ -72,6 +73,16 @@
     ExpectAtLeast{ 1 });
 }
 
+void Instance::Bind(MaybeEmpty<std::string>& val)
+{
+  this->Bind(
+    [&val](cm::string_view arg) -> Continue {
+      val = std::string(arg);
+      return Continue::No;
+    },
+    ExpectAtLeast{ 1 });
+}
+
 void Instance::Bind(NonEmpty<std::string>& val)
 {
   this->Bind(
@@ -204,11 +215,39 @@
     return false;
   }
   std::string e;
-  for (auto const& ke : this->KeywordErrors) {
-    e = cmStrCat(e, "Error after keyword \"", ke.first, "\":\n", ke.second);
+  for (auto const& kel : this->KeywordErrors) {
+    e = cmStrCat(std::move(e), "Error after keyword \"", kel.first, "\":\n",
+                 cmJoin(kel.second, {}));
   }
   mf.IssueMessage(MessageType::FATAL_ERROR, e);
   return true;
 }
 
+bool ParseResult::Check(cm::string_view context,
+                        std::vector<std::string> const* unparsedArguments,
+                        cmExecutionStatus& status) const
+{
+  if (unparsedArguments && !unparsedArguments->empty()) {
+    status.SetError(cmStrCat(context, " given unknown argument: \""_s,
+                             unparsedArguments->front(), "\"."_s));
+    return false;
+  }
+
+  if (!this->KeywordErrors.empty()) {
+    std::string msg = cmStrCat(
+      context, (context.empty() ? ""_s : " "_s), "given invalid "_s,
+      (this->KeywordErrors.size() > 1 ? "arguments:"_s : "argument:"_s));
+    for (auto const& kel : this->KeywordErrors) {
+      for (auto const& ke : kel.second) {
+        msg =
+          cmStrCat(msg, "\n  "_s, kel.first, ": "_s, cmStripWhitespace(ke));
+      }
+    }
+    status.SetError(msg);
+    return false;
+  }
+
+  return true;
+}
+
 } // namespace ArgumentParser
diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h
index 2b37869..6bc2250 100644
--- a/Source/cmArgumentParser.h
+++ b/Source/cmArgumentParser.h
@@ -8,6 +8,7 @@
 #include <cstddef>
 #include <functional>
 #include <map>
+#include <set>
 #include <string>
 #include <utility>
 #include <vector>
@@ -23,13 +24,17 @@
 template <typename Result>
 class cmArgumentParser; // IWYU pragma: keep
 
+class cmExecutionStatus;
 class cmMakefile;
 
 namespace ArgumentParser {
 
 class ParseResult
 {
-  std::map<cm::string_view, std::string> KeywordErrors;
+  using KeywordErrorList = std::set<std::string>;
+  using KeywordErrorMap = std::map<cm::string_view, KeywordErrorList>;
+
+  KeywordErrorMap KeywordErrors;
 
 public:
   explicit operator bool() const { return this->KeywordErrors.empty(); }
@@ -37,15 +42,21 @@
   void AddKeywordError(cm::string_view key, cm::string_view text)
 
   {
-    this->KeywordErrors[key] += text;
+    this->KeywordErrors[key].emplace(text);
   }
 
-  std::map<cm::string_view, std::string> const& GetKeywordErrors() const
+  KeywordErrorMap const& GetKeywordErrors() const
   {
     return this->KeywordErrors;
   }
 
   bool MaybeReportError(cmMakefile& mf) const;
+
+  /// Check if argument parsing succeeded. Return \c false and set an error if
+  /// any errors were encountered, or if \p unparsedArguments is non-empty.
+  bool Check(cm::string_view context,
+             std::vector<std::string> const* unparsedArguments,
+             cmExecutionStatus& status) const;
 };
 
 template <typename Result>
@@ -212,6 +223,7 @@
   void Bind(std::function<Continue(cm::string_view)> f, ExpectAtLeast expect);
   void Bind(bool& val);
   void Bind(std::string& val);
+  void Bind(MaybeEmpty<std::string>& val);
   void Bind(NonEmpty<std::string>& val);
   void Bind(Maybe<std::string>& val);
   void Bind(MaybeEmpty<std::vector<std::string>>& val);
diff --git a/Source/cmArgumentParserTypes.h b/Source/cmArgumentParserTypes.h
index bd14f9b..6ac71ca 100644
--- a/Source/cmArgumentParserTypes.h
+++ b/Source/cmArgumentParserTypes.h
@@ -36,6 +36,12 @@
   using std::vector<T>::vector;
   using std::vector<T>::operator=;
 };
+template <>
+struct MaybeEmpty<std::string> : public std::string
+{
+  using std::string::basic_string;
+  using std::string::operator=;
+};
 
 template <typename T>
 struct NonEmpty;
diff --git a/Source/cmBinUtilsLinker.cxx b/Source/cmBinUtilsLinker.cxx
index 4cce608..9766f8d 100644
--- a/Source/cmBinUtilsLinker.cxx
+++ b/Source/cmBinUtilsLinker.cxx
@@ -3,7 +3,14 @@
 
 #include "cmBinUtilsLinker.h"
 
+#include <utility>
+
+#include "cmCMakePath.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
 #include "cmRuntimeDependencyArchive.h"
+#include "cmStringAlgorithms.h"
 
 cmBinUtilsLinker::cmBinUtilsLinker(cmRuntimeDependencyArchive* archive)
   : Archive(archive)
@@ -14,3 +21,29 @@
 {
   this->Archive->SetError(e);
 }
+
+void cmBinUtilsLinker::NormalizePath(std::string& path) const
+{
+  std::string normalizedPath =
+    cmCMakePath(path, cmCMakePath::auto_format).GenericString();
+
+  if (path == normalizedPath) {
+    return;
+  }
+
+  cmPolicies::PolicyStatus policy =
+    this->Archive->GetMakefile()->GetPolicyStatus(cmPolicies::CMP0207);
+  if (policy == cmPolicies::WARN) {
+    this->Archive->GetMakefile()->IssueMessage(
+      MessageType::AUTHOR_WARNING,
+      cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0207),
+               "\n"
+               "Path\n  \"",
+               path,
+               "\"\n"
+               "would be converted to\n  \"",
+               normalizedPath, "\"\n"));
+  } else if (policy == cmPolicies::NEW) {
+    path = std::move(normalizedPath);
+  }
+}
diff --git a/Source/cmBinUtilsLinker.h b/Source/cmBinUtilsLinker.h
index 5b41309..f093860 100644
--- a/Source/cmBinUtilsLinker.h
+++ b/Source/cmBinUtilsLinker.h
@@ -24,4 +24,6 @@
   cmRuntimeDependencyArchive* Archive;
 
   void SetError(std::string const& e);
+
+  void NormalizePath(std::string& path) const;
 };
diff --git a/Source/cmBinUtilsLinuxELFLinker.cxx b/Source/cmBinUtilsLinuxELFLinker.cxx
index cf338a9..e3ea16c 100644
--- a/Source/cmBinUtilsLinuxELFLinker.cxx
+++ b/Source/cmBinUtilsLinuxELFLinker.cxx
@@ -204,6 +204,7 @@
     path = cmStrCat(searchPath, '/', name);
     if (cmSystemTools::PathExists(path) &&
         FileHasArchitecture(path.c_str(), this->Machine)) {
+      this->NormalizePath(path);
       resolved = true;
       return true;
     }
diff --git a/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx
index 82e956c..d4a7a8a 100644
--- a/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx
+++ b/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx
@@ -48,7 +48,7 @@
   static cmsys::RegularExpression const neededRegex("^ *NEEDED *([^\n]*)$");
   static cmsys::RegularExpression const rpathRegex("^ *RPATH *([^\n]*)$");
   static cmsys::RegularExpression const runpathRegex("^ *RUNPATH *([^\n]*)$");
-  cmUVPipeIStream output(process.GetLoop(), process.OutputStream());
+  cmUVIStream output(process.OutputStream());
   while (std::getline(output, line)) {
     cmsys::RegularExpressionMatch match;
     if (neededRegex.find(line.c_str(), match)) {
diff --git a/Source/cmBinUtilsMacOSMachOLinker.cxx b/Source/cmBinUtilsMacOSMachOLinker.cxx
index 9867318..97dce1a 100644
--- a/Source/cmBinUtilsMacOSMachOLinker.cxx
+++ b/Source/cmBinUtilsMacOSMachOLinker.cxx
@@ -170,6 +170,7 @@
   } else {
     resolved = true;
     path = name;
+    this->NormalizePath(path);
   }
 
   if (resolved && !cmSystemTools::FileIsFullPath(path)) {
@@ -198,6 +199,7 @@
     return true;
   }
 
+  this->NormalizePath(path);
   resolved = true;
   return true;
 }
@@ -220,6 +222,7 @@
     return true;
   }
 
+  this->NormalizePath(path);
   resolved = true;
   return true;
 }
@@ -252,7 +255,7 @@
       /*
        * paraphrasing @ben.boeckel:
        *  if /b/libB.dylib is supposed to be used,
-       *  /a/libbB.dylib will be found first if it exists. CMake tries to
+       *  /a/libB.dylib will be found first if it exists. CMake tries to
        *  sort rpath directories to avoid this, but sometimes there is no
        *  right answer.
        *
@@ -268,7 +271,9 @@
        *  so as long as this method's resolution guarantees priority
        *  in that manner further checking should not be necessary?
        */
-      path = searchFile;
+      path = std::move(searchFile);
+
+      this->NormalizePath(path);
       resolved = true;
       return true;
     }
diff --git a/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx
index 5fed9c9..7dbd131 100644
--- a/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx
+++ b/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx
@@ -51,7 +51,7 @@
     "^ *path (.*) \\(offset [0-9]+\\)$");
   static cmsys::RegularExpression const nameRegex(
     "^ *name (.*) \\(offset [0-9]+\\)$");
-  cmUVPipeIStream output(process.GetLoop(), process.OutputStream());
+  cmUVIStream output(process.OutputStream());
   while (std::getline(output, line)) {
     cmsys::RegularExpressionMatch cmdMatch;
     if (rpathRegex.find(line.c_str(), cmdMatch)) {
diff --git a/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx
index 47ee8e8..cb4ec31 100644
--- a/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx
+++ b/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx
@@ -45,7 +45,7 @@
   std::string line;
   static cmsys::RegularExpression const regex(
     "^    ([^\n]*\\.[Dd][Ll][Ll])\r$");
-  cmUVPipeIStream output(process.GetLoop(), process.OutputStream());
+  cmUVIStream output(process.OutputStream());
   while (std::getline(output, line)) {
     cmsys::RegularExpressionMatch match;
     if (regex.find(line.c_str(), match)) {
diff --git a/Source/cmBinUtilsWindowsPELinker.cxx b/Source/cmBinUtilsWindowsPELinker.cxx
index 70ddaf2..2864e30 100644
--- a/Source/cmBinUtilsWindowsPELinker.cxx
+++ b/Source/cmBinUtilsWindowsPELinker.cxx
@@ -155,6 +155,7 @@
   for (auto const& searchPath : dirs) {
     path = cmStrCat(searchPath, '/', name);
     if (cmSystemTools::PathExists(path)) {
+      this->NormalizePath(path);
       resolved = true;
       return true;
     }
diff --git a/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
index a83485c..5019682 100644
--- a/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
+++ b/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
@@ -46,7 +46,7 @@
   std::string line;
   static cmsys::RegularExpression const regex(
     "^[\t ]*DLL Name: ([^\n]*\\.[Dd][Ll][Ll])$");
-  cmUVPipeIStream output(process.GetLoop(), process.OutputStream());
+  cmUVIStream output(process.OutputStream());
   while (cmSystemTools::GetLineFromStream(output, line)) {
     cmsys::RegularExpressionMatch match;
     if (regex.find(line.c_str(), match)) {
diff --git a/Source/cmBuildArgs.h b/Source/cmBuildArgs.h
new file mode 100644
index 0000000..b483b9d
--- /dev/null
+++ b/Source/cmBuildArgs.h
@@ -0,0 +1,21 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include <string>
+
+#include "cmDuration.h"
+
+class cmBuildArgs
+{
+public:
+  static constexpr int NO_BUILD_PARALLEL_LEVEL = -1;
+  static constexpr int DEFAULT_BUILD_PARALLEL_LEVEL = 0;
+
+  std::string projectName;
+  std::string binaryDir;
+  int jobs = NO_BUILD_PARALLEL_LEVEL;
+  bool verbose = false;
+  std::string config;
+  cmDuration timeout;
+};
diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx
index 642cc91..55e93ee 100644
--- a/Source/cmCMakeHostSystemInformationCommand.cxx
+++ b/Source/cmCMakeHostSystemInformationCommand.cxx
@@ -4,7 +4,6 @@
 
 #include <algorithm>
 #include <cassert>
-#include <cctype>
 #include <cstddef>
 #include <initializer_list>
 #include <map>
@@ -13,10 +12,16 @@
 
 #include <cm/optional>
 #include <cm/string_view>
+#include <cm/type_traits>
 #include <cmext/string_view>
 
+#if !defined(_WIN32)
+#  include <langinfo.h>
+#endif
+
 #include "cmsys/FStream.hxx"
 #include "cmsys/Glob.hxx"
+#include "cmsys/String.h"
 #include "cmsys/SystemInformation.hxx"
 
 #include "cmArgumentParser.h"
@@ -41,7 +46,9 @@
 std::string const DELIM[2] = { {}, ";" };
 
 // BEGIN Private functions
-std::string ValueToString(std::size_t const value)
+template <typename T>
+cm::enable_if_t<std::is_arithmetic<T>::value, std::string> ValueToString(
+  T const& value)
 {
   return std::to_string(value);
 }
@@ -71,6 +78,22 @@
   if (key == "FQDN"_s) {
     return ValueToString(info.GetFullyQualifiedDomainName());
   }
+  if (key == "LOCALE_CHARSET"_s) {
+#if defined(_WIN32)
+    // On Windows we always use UTF-8.
+    return ValueToString("UTF-8");
+#else
+    // On non-Windows platforms we use the locale's encoding.
+    if (char const* charset = nl_langinfo(CODESET)) {
+      if (cmsysString_strcasecmp(charset, "utf-8") == 0 ||
+          cmsysString_strcasecmp(charset, "utf8") == 0) {
+        charset = "UTF-8";
+      }
+      return ValueToString(charset);
+    }
+    return ValueToString("");
+#endif
+  }
   if (key == "TOTAL_VIRTUAL_MEMORY"_s) {
     return ValueToString(info.GetTotalVirtualMemory());
   }
@@ -130,6 +153,14 @@
     return ValueToString(info.DoesCPUSupportFeature(
       cmsys::SystemInformation::CPU_FEATURE_SERIALNUMBER));
   }
+  if (key == "HAS_APIC"_s) {
+    return ValueToString(
+      info.DoesCPUSupportFeature(cmsys::SystemInformation::CPU_FEATURE_APIC));
+  }
+  if (key == "HAS_L1_CACHE"_s) {
+    return ValueToString(info.DoesCPUSupportFeature(
+      cmsys::SystemInformation::CPU_FEATURE_L1CACHE));
+  }
   if (key == "PROCESSOR_NAME"_s) {
     return ValueToString(info.GetExtendedProcessorName());
   }
@@ -151,6 +182,38 @@
   if (key == "OS_PLATFORM"_s) {
     return ValueToString(info.GetOSPlatform());
   }
+  if (key == "FAMILY_ID"_s) {
+    return ValueToString(info.GetFamilyID());
+  }
+  if (key == "MODEL_ID"_s) {
+    return ValueToString(info.GetModelID());
+  }
+  if (key == "MODEL_NAME"_s) {
+    return ValueToString(info.GetModelName());
+  }
+  if (key == "PROCESSOR_APIC_ID"_s) {
+    int apicId = info.GetProcessorAPICID();
+    if (apicId) {
+      return ValueToString(apicId);
+    }
+    return "";
+  }
+  if (key == "PROCESSOR_CACHE_SIZE"_s) {
+    int cacheSize = info.GetProcessorCacheSize();
+    if (cacheSize > 0) {
+      return ValueToString(cacheSize);
+    }
+    return "";
+  }
+  if (key == "PROCESSOR_CLOCK_FREQUENCY"_s) {
+    return ValueToString(info.GetProcessorClockFrequency());
+  }
+  if (key == "VENDOR_ID"_s) {
+    return ValueToString(info.GetVendorID());
+  }
+  if (key == "VENDOR_STRING"_s) {
+    return ValueToString(info.GetVendorString());
+  }
   return {};
 }
 
@@ -175,10 +238,10 @@
   for (auto ch : line) {
     switch (state) {
       case PARSE_KEY_1ST:
-        if (std::isalpha(ch) || ch == '_') {
+        if (cmsysString_isalpha(ch) || ch == '_') {
           key += ch;
           state = PARSE_KEY;
-        } else if (!cmIsSpace(ch)) {
+        } else if (!cmsysString_isspace(ch)) {
           state = IGNORE_REST;
         }
         break;
@@ -186,7 +249,7 @@
       case PARSE_KEY:
         if (ch == '=') {
           state = FOUND_EQ;
-        } else if (std::isalnum(ch) || ch == '_') {
+        } else if (cmsysString_isalnum(ch) || ch == '_') {
           key += ch;
         } else {
           state = IGNORE_REST;
@@ -238,7 +301,7 @@
         break;
 
       case PARSE_VALUE:
-        if (ch == '#' || cmIsSpace(ch)) {
+        if (ch == '#' || cmsysString_isspace(ch)) {
           state = IGNORE_REST;
         } else {
           value += ch;
@@ -312,8 +375,8 @@
     auto const& filename = cmSystemTools::GetFilenameName(filepath);
     // NOTE Minimum filename length expected:
     //   NNN-<at-least-one-char-name>.cmake  --> 11
-    return (filename.size() < 11) || !std::isdigit(filename[0]) ||
-      !std::isdigit(filename[1]) || !std::isdigit(filename[2]) ||
+    return (filename.size() < 11) || !cmsysString_isdigit(filename[0]) ||
+      !cmsysString_isdigit(filename[1]) || !cmsysString_isdigit(filename[2]) ||
       filename[3] != '-';
   };
   scripts.erase(std::remove_if(scripts.begin(), scripts.end(), checkName),
diff --git a/Source/cmCMakeLanguageCommand.cxx b/Source/cmCMakeLanguageCommand.cxx
index a093f8d..2a90065 100644
--- a/Source/cmCMakeLanguageCommand.cxx
+++ b/Source/cmCMakeLanguageCommand.cxx
@@ -397,9 +397,7 @@
       return FatalError(status, "EXIT requires one argument");
     }
 
-    auto workingMode =
-      status.GetMakefile().GetCMakeInstance()->GetWorkingMode();
-    if (workingMode != cmake::SCRIPT_MODE) {
+    if (!status.GetMakefile().GetCMakeInstance()->RoleSupportsExitCode()) {
       return FatalError(status, "EXIT can be used only in SCRIPT mode");
     }
 
@@ -411,9 +409,7 @@
                                  expArgs[expArg], '\"'));
     }
 
-    if (workingMode == cmake::SCRIPT_MODE) {
-      status.SetExitCode(static_cast<int>(retCode));
-    }
+    status.SetExitCode(static_cast<int>(retCode));
     return true;
   }
 
diff --git a/Source/cmCMakePath.cxx b/Source/cmCMakePath.cxx
index 5f6db32..d046c93 100644
--- a/Source/cmCMakePath.cxx
+++ b/Source/cmCMakePath.cxx
@@ -7,6 +7,8 @@
 
 #include <string>
 
+#include "cmStringAlgorithms.h"
+
 #if defined(_WIN32)
 #  include <cstdlib>
 #endif
@@ -17,7 +19,6 @@
 #if defined(_WIN32)
 #  include <cmext/string_view>
 
-#  include "cmStringAlgorithms.h"
 #endif
 
 cmCMakePath& cmCMakePath::ReplaceWideExtension(cm::string_view extension)
@@ -33,7 +34,7 @@
     if (extension[0] != '.') {
       file += '.';
     }
-    file.append(std::string(extension));
+    file = cmStrCat(std::move(file), extension);
   }
   this->Path.replace_filename(file);
   return *this;
diff --git a/Source/cmCMakePresetsErrors.cxx b/Source/cmCMakePresetsErrors.cxx
index c77a528..f2cbe84 100644
--- a/Source/cmCMakePresetsErrors.cxx
+++ b/Source/cmCMakePresetsErrors.cxx
@@ -183,6 +183,12 @@
     "File version must be 10 or higher for graphviz preset support");
 }
 
+void JOBS_PROC_UNSUPPORTED(cmJSONState* state)
+{
+  state->AddError("File version must be 11 or higher for "
+                  "processor-count-based jobs preset support");
+}
+
 void CYCLIC_INCLUDE(std::string const& file, cmJSONState* state)
 {
   state->AddError(cmStrCat("Cyclic include among preset files: ", file));
diff --git a/Source/cmCMakePresetsErrors.h b/Source/cmCMakePresetsErrors.h
index 8bb9de9..372ceb8 100644
--- a/Source/cmCMakePresetsErrors.h
+++ b/Source/cmCMakePresetsErrors.h
@@ -72,6 +72,8 @@
 
 void GRAPHVIZ_FILE_UNSUPPORTED(cmJSONState* state);
 
+void JOBS_PROC_UNSUPPORTED(cmJSONState* state);
+
 void CYCLIC_INCLUDE(std::string const& file, cmJSONState* state);
 
 void TEST_OUTPUT_TRUNCATION_UNSUPPORTED(cmJSONState* state);
diff --git a/Source/cmCMakePresetsGraph.h b/Source/cmCMakePresetsGraph.h
index 2ba6fba..4ce0ace 100644
--- a/Source/cmCMakePresetsGraph.h
+++ b/Source/cmCMakePresetsGraph.h
@@ -167,7 +167,7 @@
 
     std::string ConfigurePreset;
     cm::optional<bool> InheritConfigureEnvironment;
-    cm::optional<int> Jobs;
+    cm::optional<unsigned int> Jobs;
     std::vector<std::string> Targets;
     std::string Configuration;
     cm::optional<bool> CleanFirst;
@@ -289,7 +289,7 @@
 
       cm::optional<bool> StopOnFailure;
       cm::optional<bool> EnableFailover;
-      cm::optional<int> Jobs;
+      cm::optional<cm::optional<unsigned int>> Jobs;
       std::string ResourceSpecFile;
       cm::optional<int> TestLoad;
       cm::optional<ShowOnlyEnum> ShowOnly;
diff --git a/Source/cmCMakePresetsGraphInternal.h b/Source/cmCMakePresetsGraphInternal.h
index eaa215a..02c99ee 100644
--- a/Source/cmCMakePresetsGraphInternal.h
+++ b/Source/cmCMakePresetsGraphInternal.h
@@ -218,6 +218,12 @@
 bool PresetOptionalIntHelper(cm::optional<int>& out, Json::Value const* value,
                              cmJSONState* state);
 
+bool PresetUIntHelper(unsigned int& out, Json::Value const* value,
+                      cmJSONState* state);
+
+bool PresetOptionalUIntHelper(cm::optional<unsigned int>& out,
+                              Json::Value const* value, cmJSONState* state);
+
 bool PresetVectorIntHelper(std::vector<int>& out, Json::Value const* value,
                            cmJSONState* state);
 
diff --git a/Source/cmCMakePresetsGraphReadJSON.cxx b/Source/cmCMakePresetsGraphReadJSON.cxx
index 4880186..d141b10 100644
--- a/Source/cmCMakePresetsGraphReadJSON.cxx
+++ b/Source/cmCMakePresetsGraphReadJSON.cxx
@@ -40,7 +40,7 @@
 using cmCMakePresetsGraphInternal::ExpandMacros;
 
 constexpr int MIN_VERSION = 1;
-constexpr int MAX_VERSION = 10;
+constexpr int MAX_VERSION = 11;
 
 struct CMakeVersion
 {
@@ -384,6 +384,21 @@
   return helper(out, value, state);
 }
 
+bool PresetUIntHelper(unsigned int& out, Json::Value const* value,
+                      cmJSONState* state)
+{
+  static auto const helper = JSONHelperBuilder::UInt();
+  return helper(out, value, state);
+}
+
+bool PresetOptionalUIntHelper(cm::optional<unsigned int>& out,
+                              Json::Value const* value, cmJSONState* state)
+{
+  static auto const helper =
+    JSONHelperBuilder::Optional<unsigned int>(PresetUIntHelper);
+  return helper(out, value, state);
+}
+
 bool PresetVectorIntHelper(std::vector<int>& out, Json::Value const* value,
                            cmJSONState* state)
 {
@@ -678,6 +693,13 @@
       return false;
     }
 
+    // Support for processor-count-based jobs added in version 11.
+    if (v < 11 && preset.Execution && preset.Execution->Jobs.has_value() &&
+        !preset.Execution->Jobs->has_value()) {
+      cmCMakePresetsErrors::JOBS_PROC_UNSUPPORTED(&this->parseState);
+      return false;
+    }
+
     this->TestPresetOrder.push_back(preset.Name);
   }
 
diff --git a/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx b/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx
index dd95137..cadbcd1 100644
--- a/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx
+++ b/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx
@@ -83,7 +83,7 @@
           &BuildPreset::InheritConfigureEnvironment,
           cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
     .Bind("jobs"_s, &BuildPreset::Jobs,
-          cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
+          cmCMakePresetsGraphInternal::PresetOptionalUIntHelper, false)
     .Bind("targets"_s, &BuildPreset::Targets,
           cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper,
           false)
diff --git a/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx b/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx
index 2d2669a..d716445 100644
--- a/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx
+++ b/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx
@@ -301,6 +301,32 @@
   JSONHelperBuilder::Optional<TestPreset::ExecutionOptions::NoTestsActionEnum>(
     TestPresetExecutionNoTestsActionHelper);
 
+bool TestPresetExecutionJobsHelper(cm::optional<unsigned int>& out,
+                                   Json::Value const* value,
+                                   cmJSONState* state)
+{
+  if (value->isString()) {
+    if (!value->asString().empty()) {
+      cmCMakePresetsErrors::INVALID_PRESET(value, state);
+      return false;
+    }
+    out.reset();
+    return true;
+  }
+
+  if (value->isUInt()) {
+    out.emplace(value->asUInt());
+    return true;
+  }
+
+  cmCMakePresetsErrors::INVALID_PRESET(value, state);
+  return false;
+}
+
+auto const TestPresetOptionalExecutionJobsHelper =
+  JSONHelperBuilder::Optional<cm::optional<unsigned int>>(
+    TestPresetExecutionJobsHelper);
+
 auto const TestPresetExecutionHelper =
   JSONHelperBuilder::Optional<TestPreset::ExecutionOptions>(
     JSONHelperBuilder::Object<TestPreset::ExecutionOptions>()
@@ -309,7 +335,7 @@
       .Bind("enableFailover"_s, &TestPreset::ExecutionOptions::EnableFailover,
             cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)
       .Bind("jobs"_s, &TestPreset::ExecutionOptions::Jobs,
-            cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)
+            TestPresetOptionalExecutionJobsHelper, false)
       .Bind("resourceSpecFile"_s,
             &TestPreset::ExecutionOptions::ResourceSpecFile,
             cmCMakePresetsGraphInternal::PresetStringHelper, false)
diff --git a/Source/cmCMakeString.cxx b/Source/cmCMakeString.cxx
new file mode 100644
index 0000000..c7f1c13
--- /dev/null
+++ b/Source/cmCMakeString.cxx
@@ -0,0 +1,326 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cmCMakeString.hxx"
+
+#include <cstdio>
+#include <cstdlib>
+#include <memory>
+#include <stdexcept>
+#include <vector>
+
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmCryptoHash.h"
+#include "cmGeneratorExpression.h"
+#include "cmMakefile.h"
+#include "cmPolicies.h"
+#include "cmStringAlgorithms.h"
+#include "cmStringReplaceHelper.h"
+#include "cmSystemTools.h"
+#include "cmTimestamp.h"
+#include "cmUuid.h"
+
+namespace cm {
+bool CMakeString::Compare(CompOperator op, cm::string_view other)
+{
+  switch (op) {
+    case CompOperator::EQUAL:
+      return this->String_ == other;
+    case CompOperator::LESS:
+      return this->String_ < other;
+    case CompOperator::LESS_EQUAL:
+      return this->String_ <= other;
+    case CompOperator::GREATER:
+      return this->String_ > other;
+    case CompOperator::GREATER_EQUAL:
+      return this->String_ >= other;
+    default:
+      return false;
+  }
+}
+
+CMakeString& CMakeString::Replace(std::string const& matchExpression,
+                                  std::string const& replaceExpression,
+                                  Regex regex, cmMakefile* makefile)
+{
+  if (regex == Regex::Yes) {
+    if (makefile) {
+      makefile->ClearMatches();
+    }
+
+    cmStringReplaceHelper replaceHelper(matchExpression, replaceExpression,
+                                        makefile);
+    if (!replaceHelper.IsReplaceExpressionValid()) {
+      throw std::invalid_argument(replaceHelper.GetError());
+    }
+    if (!replaceHelper.IsRegularExpressionValid()) {
+      throw std::invalid_argument(
+        cmStrCat("Failed to compile regex \"", matchExpression, '"'));
+    }
+
+    std ::string output;
+    if (!replaceHelper.Replace(this->String_, output)) {
+      throw std::runtime_error(replaceHelper.GetError());
+    }
+    this->String_ = std::move(output);
+  } else {
+    std::string output = this->String_.str();
+    cmsys::SystemTools::ReplaceString(output, matchExpression,
+                                      replaceExpression);
+    this->String_ = std::move(output);
+  }
+
+  return *this;
+};
+
+cmList CMakeString::Match(std::string const& matchExpression,
+                          MatchItems matchItems, cmMakefile* makefile) const
+{
+  if (makefile) {
+    makefile->ClearMatches();
+  }
+
+  // Compile the regular expression.
+  cmsys::RegularExpression re;
+  if (!re.compile(matchExpression)) {
+    throw std::invalid_argument(
+      cmStrCat("Failed to compile regex \"", matchExpression, '"'));
+  }
+
+  cmList output;
+  if (matchItems == MatchItems::Once) {
+    if (re.find(this->String_.data())) {
+      if (makefile) {
+        makefile->StoreMatches(re);
+      }
+      output.push_back(re.match());
+    }
+  } else {
+    unsigned optAnchor = 0;
+    if (makefile &&
+        makefile->GetPolicyStatus(cmPolicies::CMP0186) != cmPolicies::NEW) {
+      optAnchor = cmsys::RegularExpression::BOL_AT_OFFSET;
+    }
+
+    // Scan through the input for all matches.
+    std::string::size_type base = 0;
+    unsigned optNonEmpty = 0;
+    while (re.find(this->String_.data(), base, optAnchor | optNonEmpty)) {
+      if (makefile) {
+        makefile->ClearMatches();
+        makefile->StoreMatches(re);
+      }
+
+      output.push_back(re.match());
+      base = re.end();
+
+      if (re.start() == this->String_.length()) {
+        break;
+      }
+      if (re.start() == re.end()) {
+        optNonEmpty = cmsys::RegularExpression::NONEMPTY_AT_OFFSET;
+      } else {
+        optNonEmpty = 0;
+      }
+    }
+  }
+
+  return output;
+}
+
+CMakeString CMakeString::Substring(long begin, long count) const
+{
+  if (begin < 0 || static_cast<size_type>(begin) > this->String_.size()) {
+    throw std::out_of_range(cmStrCat(
+      "begin index: ", begin, " is out of range 0 - ", this->String_.size()));
+  }
+  if (count < -1) {
+    throw std::out_of_range(
+      cmStrCat("end index: ", count, " should be -1 or greater"));
+  }
+
+  return this->String_.substr(static_cast<size_type>(begin),
+                              count == -1 ? npos
+                                          : static_cast<size_type>(count));
+}
+
+CMakeString& CMakeString::Strip(StripItems stripItems)
+{
+  if (stripItems == StripItems::Space) {
+    this->String_ = cmTrimWhitespace(this->String_);
+  } else {
+    this->String_ = cmGeneratorExpression::Preprocess(
+      this->String_, cmGeneratorExpression::StripAllGeneratorExpressions);
+  }
+
+  return *this;
+}
+
+CMakeString& CMakeString::Repeat(size_type count)
+{
+  switch (this->Size()) {
+    case 0u:
+      // Nothing to do for zero length input strings
+      break;
+    case 1u:
+      // NOTE If the string to repeat consists of the only character,
+      // use the appropriate constructor.
+      this->String_ = std::string(count, this->String_[0]);
+      break;
+    default:
+      std::string result;
+      auto size = this->Size();
+
+      result.reserve(size * count);
+      for (auto i = 0u; i < count; ++i) {
+        result.insert(i * size, this->String_.data(), size);
+      }
+      this->String_ = std::move(result);
+      break;
+  }
+  return *this;
+}
+
+CMakeString& CMakeString::Quote(QuoteItems)
+{
+  std ::string output;
+  // Escape all regex special characters
+  cmStringReplaceHelper replaceHelper("([][()+*^.$?|\\\\])", R"(\\\1)");
+  if (!replaceHelper.Replace(this->String_, output)) {
+    throw std::runtime_error(replaceHelper.GetError());
+  }
+
+  this->String_ = std::move(output);
+  return *this;
+}
+
+CMakeString& CMakeString::Hash(cm::string_view hashAlgorithm)
+{
+  std::unique_ptr<cmCryptoHash> hash(cmCryptoHash::New(hashAlgorithm));
+  if (hash) {
+    this->String_ = hash->HashString(this->String_);
+    return *this;
+  }
+
+  throw std::invalid_argument(
+    cmStrCat(hashAlgorithm, ": invalid hash algorithm."));
+}
+
+CMakeString& CMakeString::FromASCII(string_range codes)
+{
+  std::string output;
+  output.reserve(codes.size());
+
+  for (auto const& code : codes) {
+    try {
+      auto ch = std::stoi(code);
+      if (ch > 0 && ch < 256) {
+        output += static_cast<char>(ch);
+      } else {
+        throw std::invalid_argument(
+          cmStrCat("Character with code ", code, " does not exist."));
+      }
+    } catch (...) {
+      throw std::invalid_argument(
+        cmStrCat("Character with code ", code, " does not exist."));
+    }
+  }
+  this->String_ = std::move(output);
+  return *this;
+}
+
+CMakeString& CMakeString::ToHexadecimal(cm::string_view str)
+{
+  std::string output(str.size() * 2, ' ');
+  std::string::size_type hexIndex = 0;
+
+  for (auto const& c : str) {
+    std::snprintf(&output[hexIndex], 3, "%.2x", c & 0xFFu);
+    hexIndex += 2;
+  }
+  this->String_ = output;
+  return *this;
+}
+
+cm::string_view const CMakeString::RandomDefaultAlphabet{
+  "qwertyuiopasdfghjklzxcvbnm"
+  "QWERTYUIOPASDFGHJKLZXCVBNM"
+  "0123456789"
+};
+bool CMakeString::Seeded = false;
+
+CMakeString& CMakeString::Random(unsigned int seed, std::size_t length,
+                                 cm::string_view alphabet)
+{
+  if (alphabet.empty()) {
+    alphabet = RandomDefaultAlphabet;
+  }
+
+  if (length < 1) {
+    throw std::out_of_range("Invoked with bad length.");
+  }
+
+  if (!this->Seeded) {
+    this->Seeded = true;
+    std::srand(seed);
+  }
+
+  double alphabetSize = static_cast<double>(alphabet.size());
+  std::vector<char> result;
+  result.reserve(length + 1);
+
+  for (std::size_t i = 0; i < length; i++) {
+    auto index = static_cast<std::string::size_type>(
+      alphabetSize * std::rand() / (RAND_MAX + 1.0));
+    result.push_back(alphabet[index]);
+  }
+  result.push_back(0);
+
+  this->String_ = result.data();
+  return *this;
+}
+
+CMakeString& CMakeString::Timestamp(cm::string_view format, UTC utc)
+{
+  cmTimestamp timestamp;
+  this->String_ = timestamp.CurrentTime(format, utc == UTC::Yes);
+  return *this;
+}
+
+CMakeString& CMakeString::UUID(cm::string_view nameSpace, cm::string_view name,
+                               UUIDType type, Case uuidCase)
+{
+#if !defined(CMAKE_BOOTSTRAP)
+  cmUuid uuidGenerator;
+  std::vector<unsigned char> uuidNamespace;
+  std::string uuid;
+
+  if (!uuidGenerator.StringToBinary(nameSpace, uuidNamespace)) {
+    throw std::invalid_argument("malformed NAMESPACE UUID");
+  }
+
+  if (type == UUIDType::MD5) {
+    uuid = uuidGenerator.FromMd5(uuidNamespace, name);
+  } else if (type == UUIDType::SHA1) {
+    uuid = uuidGenerator.FromSha1(uuidNamespace, name);
+  }
+
+  if (uuid.empty()) {
+    throw std::runtime_error("generation failed");
+  }
+
+  if (uuidCase == Case::Upper) {
+    uuid = cmSystemTools::UpperCase(uuid);
+  }
+
+  this->String_ = std::move(uuid);
+  return *this;
+#else
+  throw std::runtime_error("not available during bootstrap");
+#endif
+}
+
+}
diff --git a/Source/cmCMakeString.hxx b/Source/cmCMakeString.hxx
new file mode 100644
index 0000000..3c29871
--- /dev/null
+++ b/Source/cmCMakeString.hxx
@@ -0,0 +1,259 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <cstddef>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/string_view>
+
+#include "cmList.h"
+#include "cmRange.h"
+#include "cmString.hxx"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmValue.h"
+
+class cmMakefile;
+
+//
+// Class offering various string operations which is used by
+// * CMake string() command
+// * $<STRING> generator expression
+//
+
+namespace cm {
+
+class CMakeString
+{
+public:
+  using size_type = cm::String::size_type;
+  static auto const npos = cm::String::npos;
+
+  using string_range = cmRange<std::vector<std::string>::const_iterator>;
+
+  CMakeString(std::string const& str)
+    : String_(cm::String::borrow(str))
+  {
+  }
+  CMakeString(cm::string_view str)
+    : String_(cm::String::borrow(str))
+  {
+  }
+  CMakeString(cm::String const& str)
+    : String_(str)
+  {
+  }
+  CMakeString(cm::String&& str)
+    : String_(std::move(str))
+  {
+  }
+  CMakeString(cmValue value)
+    : String_(cm::String::borrow(*value))
+  {
+  }
+  CMakeString(string_range range,
+              cm::string_view separator = cm::string_view{})
+    : String_(cmJoin(range, separator))
+  {
+  }
+
+  CMakeString() = default;
+  CMakeString(CMakeString const&) = default;
+  CMakeString(CMakeString&&) = default;
+
+  CMakeString& operator=(CMakeString const& string)
+  {
+    if (this != &string) {
+      this->String_ = string.String_;
+    }
+    return *this;
+  }
+  CMakeString& operator=(CMakeString&& string) noexcept
+  {
+    if (this != &string) {
+      this->String_ = std::move(string.String_);
+    }
+    return *this;
+  }
+  CMakeString& operator=(cm::string_view string)
+  {
+    this->String_ = string;
+    return *this;
+  }
+
+  // conversions
+  string_view view() const noexcept { return this->String_.view(); }
+  operator cm::string_view() noexcept { return this->String_.view(); }
+  operator std::string const&() { return this->String_.str(); }
+
+  size_type Size() const { return this->String_.size(); }
+  size_type Length() const { return this->String_.size(); }
+
+  enum class CompOperator
+  {
+    EQUAL,
+    LESS,
+    LESS_EQUAL,
+    GREATER,
+    GREATER_EQUAL
+  };
+  bool Compare(CompOperator op, cm::string_view other);
+
+  enum class FindFrom
+  {
+    Begin,
+    End
+  };
+  size_type Find(cm::string_view substring,
+                 FindFrom from = FindFrom::Begin) const
+  {
+    return from == FindFrom::Begin ? this->String_.find(substring)
+                                   : this->String_.rfind(substring);
+  }
+
+  enum class Regex
+  {
+    No,
+    Yes
+  };
+  // Throw std::invalid_argument if regular expression is invalid
+  //       std::runtime_error if replacement failed
+  CMakeString& Replace(std::string const& matchExpression,
+                       std::string const& replaceExpression,
+                       Regex regex = Regex::No,
+                       cmMakefile* makefile = nullptr);
+
+  enum class MatchItems
+  {
+    Once,
+    All
+  };
+  // Throw std::invalid_argument if regular expression is invalid
+  cmList Match(std::string const& matchExpression,
+               MatchItems matchItems = MatchItems::Once,
+               cmMakefile* makefile = nullptr) const;
+
+  CMakeString& Append(cm::string_view str)
+  {
+    this->String_.append(str);
+    return *this;
+  }
+  CMakeString& Append(string_range range)
+  {
+    this->Append(cmJoin(range, {}));
+    return *this;
+  }
+  CMakeString& Prepend(cm::string_view str)
+  {
+    this->String_.insert(0, str);
+    return *this;
+  }
+  CMakeString& Prepend(string_range range)
+  {
+    this->Prepend(cmJoin(range, {}));
+    return *this;
+  }
+
+  CMakeString& ToLower()
+  {
+    this->String_ = cmSystemTools::LowerCase(this->String_);
+    return *this;
+  }
+  CMakeString& ToLower(cm::string_view str)
+  {
+    this->String_ = cmSystemTools::LowerCase(str);
+    return *this;
+  }
+  CMakeString& ToUpper()
+  {
+    this->String_ = cmSystemTools::UpperCase(this->String_);
+    return *this;
+  }
+  CMakeString& ToUpper(cm::string_view str)
+  {
+    this->String_ = cmSystemTools::UpperCase(str);
+    return *this;
+  }
+
+  // Throw std::out_of_range if pos or count are outside of the expected range
+  CMakeString Substring(long pos = 0, long count = -1) const;
+
+  enum class StripItems
+  {
+    Space,
+    Genex
+  };
+  CMakeString& Strip(StripItems stripItems = StripItems::Space);
+
+  // Throw std::runtime_error  if quoting string failed
+  enum class QuoteItems
+  {
+    Regex
+  };
+  CMakeString& Quote(QuoteItems quoteItems = QuoteItems::Regex);
+
+  CMakeString& Repeat(size_type count);
+
+  // Throw std::invalid_argument if the hash algorithm is invalid
+  CMakeString& Hash(cm::string_view hashAlgorithm);
+
+  // Throw std::invalid_argument if one of the codes is invalid
+  CMakeString& FromASCII(string_range codes);
+  CMakeString& ToHexadecimal() { return this->ToHexadecimal(this->String_); }
+  CMakeString& ToHexadecimal(cm::string_view str);
+
+  CMakeString& MakeCIdentifier()
+  {
+    this->String_ = cmSystemTools::MakeCidentifier(this->String_.str());
+    return *this;
+  }
+  CMakeString& MakeCIdentifier(std::string const& str)
+  {
+    this->String_ = cmSystemTools::MakeCidentifier(str);
+    return *this;
+  }
+
+  static cm::string_view const RandomDefaultAlphabet;
+  // Throw std::invalid_argument if the alphabet is invalid
+  //       std::out_of_range if length is outside valid range
+  CMakeString& Random(std::size_t length = 5,
+                      cm::string_view alphabet = RandomDefaultAlphabet)
+  {
+    return this->Random(cmSystemTools::RandomSeed(), length, alphabet);
+  }
+  CMakeString& Random(unsigned int seed, std::size_t length = 5,
+                      cm::string_view alphabet = RandomDefaultAlphabet);
+
+  enum class UTC
+  {
+    No,
+    Yes
+  };
+  CMakeString& Timestamp(cm::string_view format, UTC utc = UTC::No);
+
+  enum class UUIDType
+  {
+    MD5,
+    SHA1
+  };
+  enum class Case
+  {
+    Lower,
+    Upper
+  };
+  // Throw std::invalid_argument if namespace or the type are invalid
+  //       std::runtime_error if the UUID cannot be generated
+  CMakeString& UUID(cm::string_view nameSpace, cm::string_view name,
+                    UUIDType type, Case uuidCase = Case::Lower);
+
+private:
+  static bool Seeded;
+  cm::String String_;
+};
+}
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index e62743b..ed1516f 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -3,7 +3,6 @@
 #include "cmCTest.h"
 
 #include <algorithm>
-#include <cctype>
 #include <chrono>
 #include <cstdint>
 #include <cstdio>
@@ -34,6 +33,7 @@
 #include "cmsys/Directory.hxx"
 #include "cmsys/FStream.hxx"
 #include "cmsys/RegularExpression.hxx"
+#include "cmsys/String.h"
 #include "cmsys/SystemInformation.hxx"
 #ifndef _WIN32
 #  include <unistd.h> // IWYU pragma: keep
@@ -299,7 +299,8 @@
 {
   std::string out;
   for (char const* c = in.c_str(); *c; ++c) {
-    if (*c == '%' && isxdigit(*(c + 1)) && isxdigit(*(c + 2))) {
+    if (*c == '%' && cmsysString_isxdigit(*(c + 1)) &&
+        cmsysString_isxdigit(*(c + 2))) {
       char buf[3] = { *(c + 1), *(c + 2), 0 };
       out.append(1, static_cast<char>(strtoul(buf, nullptr, 16)));
       c += 2;
@@ -663,7 +664,7 @@
       return false;
     }
   }
-  std::string filename = testingDir + "/" + name;
+  std::string filename = cmStrCat(testingDir, '/', name);
   stream.Open(filename);
   if (!stream) {
     cmCTestLog(this, ERROR_MESSAGE,
@@ -695,8 +696,8 @@
 
 bool cmCTest::CTestFileExists(std::string const& filename)
 {
-  std::string testingDir = this->Impl->BinaryDir + "/Testing/" +
-    this->Impl->CurrentTag + "/" + filename;
+  std::string testingDir = cmStrCat(this->Impl->BinaryDir, "/Testing/",
+                                    this->Impl->CurrentTag, '/', filename);
   return cmSystemTools::FileExists(testingDir);
 }
 
@@ -821,7 +822,7 @@
     unsigned long kk;
     for (kk = 0; kk < d.GetNumberOfFiles(); kk++) {
       char const* file = d.GetFile(kk);
-      std::string fullname = notes_dir + "/" + file;
+      std::string fullname = cmStrCat(notes_dir, '/', file);
       if (cmSystemTools::FileExists(fullname, true)) {
         if (!this->Impl->NotesFiles.empty()) {
           this->Impl->NotesFiles += ";";
@@ -921,9 +922,7 @@
     builder.SetWorkingDirectory(dir);
   }
   auto chain = builder.Start();
-  cm::uv_pipe_ptr outputStream;
-  outputStream.init(chain.GetLoop(), 0);
-  uv_pipe_open(outputStream, chain.OutputStream());
+  uv_stream_t* outputStream = chain.OutputStream();
 
   // Initialize tick's
   std::string::size_type tick = 0;
@@ -1032,8 +1031,8 @@
 
   std::string buildname =
     cmCTest::SafeBuildIdField(this->GetCTestConfiguration("BuildName"));
-  std::string stamp = cmCTest::SafeBuildIdField(this->Impl->CurrentTag + "-" +
-                                                this->GetTestGroupString());
+  std::string stamp = cmCTest::SafeBuildIdField(
+    cmStrCat(this->Impl->CurrentTag, '-', this->GetTestGroupString()));
   std::string site =
     cmCTest::SafeBuildIdField(this->GetCTestConfiguration("Site"));
 
@@ -1150,8 +1149,9 @@
                             "<file:///Dart/Source/Server/XSL/Build.xsl> \"");
   xml.StartElement("Site");
   xml.Attribute("BuildName", buildname);
-  xml.Attribute("BuildStamp",
-                this->Impl->CurrentTag + "-" + this->GetTestGroupString());
+  xml.Attribute(
+    "BuildStamp",
+    cmStrCat(this->Impl->CurrentTag, '-', this->GetTestGroupString()));
   xml.Attribute("Name", this->GetCTestConfiguration("Site"));
   xml.Attribute("Generator",
                 std::string("ctest-") + cmVersion::GetCMakeVersion());
@@ -1175,7 +1175,7 @@
       }
       ifs.close();
     } else {
-      xml.Content("Problem reading file: " + file + "\n");
+      xml.Content(cmStrCat("Problem reading file: ", file, '\n'));
       cmCTestLog(this, ERROR_MESSAGE,
                  "Problem reading file: " << file << " while creating notes"
                                           << std::endl);
@@ -1667,12 +1667,12 @@
           auto const& start = expandedPreset->Filter->Include->Index->Start;
           auto const& end = expandedPreset->Filter->Include->Index->End;
           auto const& stride = expandedPreset->Filter->Include->Index->Stride;
-          std::string indexOptions;
-          indexOptions += (start ? std::to_string(*start) : "") + ",";
-          indexOptions += (end ? std::to_string(*end) : "") + ",";
-          indexOptions += (stride ? std::to_string(*stride) : "") + ",";
-          indexOptions +=
-            cmJoin(expandedPreset->Filter->Include->Index->SpecificTests, ",");
+          std::string indexOptions = cmStrCat(
+            (start ? std::to_string(*start) : std::string{}), ',',
+            (end ? std::to_string(*end) : std::string{}), ',',
+            (stride ? std::to_string(*stride) : std::string{}), ',',
+            cmJoin(expandedPreset->Filter->Include->Index->SpecificTests,
+                   ","));
 
           this->Impl->TestOptions.TestsToRunInformation = indexOptions;
         } else {
@@ -1711,8 +1711,12 @@
       expandedPreset->Execution->EnableFailover.value_or(false);
 
     if (expandedPreset->Execution->Jobs) {
-      auto jobs = *expandedPreset->Execution->Jobs;
-      this->SetParallelLevel(jobs);
+      cm::optional<unsigned int> jobs = *expandedPreset->Execution->Jobs;
+      if (jobs.has_value()) {
+        this->SetParallelLevel(static_cast<size_t>(jobs.value()));
+      } else {
+        this->SetParallelLevel(cm::nullopt);
+      }
       this->Impl->ParallelLevelSetInCli = true;
     }
 
@@ -2531,7 +2535,7 @@
         this->Impl->BuildAndTest.TestCommandArgs.emplace_back(args[i]);
       }
     }
-    if (!matched && cmHasLiteralPrefix(arg, "-") &&
+    if (!matched && cmHasPrefix(arg, '-') &&
         !cmHasLiteralPrefix(arg, "--preset")) {
       cmSystemTools::Error(cmStrCat("Unknown argument: ", arg));
       cmSystemTools::Error("Run 'ctest --help' for all supported options.");
@@ -2660,9 +2664,7 @@
   cmCTestTestHandler handler(this);
 
   {
-    cmake cm(cmake::RoleScript, cmState::CTest);
-    cm.SetHomeDirectory("");
-    cm.SetHomeOutputDirectory("");
+    cmake cm(cmState::Role::CTest);
     cm.GetCurrentSnapshot().SetDefaultDefinitions();
     cmGlobalGenerator gg(&cm);
     cmMakefile mf(&gg, cm.GetCurrentSnapshot());
@@ -3295,19 +3297,14 @@
 
   std::vector<char> tempOutput;
   bool outFinished = false;
-  cm::uv_pipe_ptr outStream;
   std::vector<char> tempError;
   bool errFinished = false;
-  cm::uv_pipe_ptr errStream;
   cmProcessOutput processOutput(encoding);
-  auto startRead = [this, &chain, &processOutput](
-                     cm::uv_pipe_ptr& pipe, int stream,
-                     std::vector<char>& temp,
+  auto startRead = [this, &processOutput](
+                     uv_stream_t* stream, std::vector<char>& temp,
                      bool& finished) -> std::unique_ptr<cmUVStreamReadHandle> {
-    pipe.init(chain.GetLoop(), 0);
-    uv_pipe_open(pipe, stream);
     return cmUVStreamRead(
-      pipe,
+      stream,
       [this, &temp, &processOutput](std::vector<char> data) {
         cm::append(temp, data);
         if (this->Impl->ExtraVerbose) {
@@ -3318,10 +3315,8 @@
       },
       [&finished]() { finished = true; });
   };
-  auto outputHandle =
-    startRead(outStream, chain.OutputStream(), tempOutput, outFinished);
-  auto errorHandle =
-    startRead(errStream, chain.ErrorStream(), tempError, errFinished);
+  auto outputHandle = startRead(chain.OutputStream(), tempOutput, outFinished);
+  auto errorHandle = startRead(chain.ErrorStream(), tempError, errFinished);
   while (!timedOut && !(outFinished && errFinished)) {
     uv_run(&chain.GetLoop(), UV_RUN_ONCE);
   }
@@ -3708,7 +3703,7 @@
   bool generating_test_xml = root["role"] == "test";
   if (!generating_test_xml) {
     std::string element_name = root["role"].asString();
-    element_name[0] = static_cast<char>(std::toupper(element_name[0]));
+    element_name[0] = static_cast<char>(cmsysString_toupper(element_name[0]));
     xml.StartElement(element_name);
     std::vector<std::string> keys = root.getMemberNames();
     for (auto const& key : keys) {
@@ -3740,7 +3735,8 @@
   std::vector<std::string> keys = dynamic_information.getMemberNames();
   for (auto const& key : keys) {
     std::string measurement_name = key;
-    measurement_name[0] = static_cast<char>(std::toupper(measurement_name[0]));
+    measurement_name[0] =
+      static_cast<char>(cmsysString_toupper(measurement_name[0]));
 
     xml.StartElement("NamedMeasurement");
     xml.Attribute("type", "numeric/double");
diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx
index cc4498f..23d6751 100644
--- a/Source/cmCacheManager.cxx
+++ b/Source/cmCacheManager.cxx
@@ -71,10 +71,9 @@
     }
     while (realbuffer[0] == '/' && realbuffer[1] == '/') {
       if ((realbuffer[2] == '\\') && (realbuffer[3] == 'n')) {
-        helpString += '\n';
-        helpString += &realbuffer[4];
+        helpString = cmStrCat(std::move(helpString), '\n', &realbuffer[4]);
       } else {
-        helpString += &realbuffer[2];
+        helpString = cmStrCat(std::move(helpString), &realbuffer[2]);
       }
       cmSystemTools::GetLineFromStream(fin, buffer);
       lineno++;
@@ -149,17 +148,17 @@
     std::string currentcwd = path;
     std::string oldcwd = *oldDir;
     cmSystemTools::ConvertToUnixSlashes(currentcwd);
-    currentcwd += "/CMakeCache.txt";
-    oldcwd += "/CMakeCache.txt";
+    currentcwd = cmStrCat(std::move(currentcwd), "/CMakeCache.txt");
+    oldcwd = cmStrCat(std::move(oldcwd), "/CMakeCache.txt");
     if (!cmSystemTools::SameFile(oldcwd, currentcwd)) {
       cmValue dir = this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR");
-      std::ostringstream message;
-      message << "The current CMakeCache.txt directory " << currentcwd
-              << " is different than the directory " << (dir ? *dir : "")
-              << " where CMakeCache.txt was created. This may result "
+      std::string message =
+        cmStrCat("The current CMakeCache.txt directory ", currentcwd,
+                 " is different than the directory ", (dir ? *dir : ""),
+                 " where CMakeCache.txt was created. This may result "
                  "in binaries being created in the wrong place. If you "
-                 "are not sure, reedit the CMakeCache.txt";
-      cmSystemTools::Error(message.str());
+                 "are not sure, reedit the CMakeCache.txt");
+      cmSystemTools::Error(message);
     }
   }
   this->CacheLoaded = true;
@@ -225,7 +224,8 @@
   cmGeneratedFileStream fout(cacheFile);
   fout.SetCopyIfDifferent(true);
   if (!fout) {
-    cmSystemTools::Error("Unable to open cache file for save. " + cacheFile);
+    cmSystemTools::Error(
+      cmStrCat("Unable to open cache file for save. ", std::move(cacheFile)));
     cmSystemTools::ReportLastSystemError("");
     return false;
   }
@@ -292,7 +292,8 @@
     if (!ce.Initialized) {
       /*
         // This should be added in, but is not for now.
-      cmSystemTools::Error("Cache entry \"" + i.first + "\" is uninitialized");
+      cmSystemTools::Error(cmStrCat("Cache entry \"", i.first, "\" is
+      uninitialized"));
       */
     } else if (t != cmStateEnums::INTERNAL) {
       // Format is key:type=value
@@ -341,11 +342,12 @@
   fout.Close();
   std::string checkCacheFile = cmStrCat(path, "/CMakeFiles");
   cmSystemTools::MakeDirectory(checkCacheFile);
-  checkCacheFile += "/cmake.check_cache";
+  checkCacheFile = cmStrCat(std::move(checkCacheFile), "/cmake.check_cache");
   cmsys::ofstream checkCache(checkCacheFile.c_str());
   if (!checkCache) {
-    cmSystemTools::Error("Unable to open check cache file for write. " +
-                         checkCacheFile);
+    cmSystemTools::Error(
+      cmStrCat("Unable to open check cache file for write. ",
+               std::move(checkCacheFile)));
     return false;
   }
   checkCache << "# This file is generated by cmake for dependency checking "
diff --git a/Source/cmCommandLineArgument.h b/Source/cmCommandLineArgument.h
index f11d1fb..4c88f23 100644
--- a/Source/cmCommandLineArgument.h
+++ b/Source/cmCommandLineArgument.h
@@ -2,11 +2,11 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #pragma once
 
-#include <cctype>
-
 #include <cm/optional>
 #include <cm/string_view>
 
+#include "cmsys/String.h"
+
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
@@ -288,6 +288,6 @@
   static bool IsFlag(cm::string_view arg)
   {
     return !arg.empty() && arg[0] == '-' &&
-      !(arg.size() >= 2 && std::isdigit(arg[1]));
+      !(arg.size() >= 2 && cmsysString_isdigit(arg[1]));
   }
 };
diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx
index f5f46e6..baa1198 100644
--- a/Source/cmCommonTargetGenerator.cxx
+++ b/Source/cmCommonTargetGenerator.cxx
@@ -275,8 +275,8 @@
   manifests.reserve(manifest_srcs.size());
 
   std::string lang = this->GeneratorTarget->GetLinkerLanguage(config);
-  std::string manifestFlag =
-    this->Makefile->GetDefinition("CMAKE_" + lang + "_LINKER_MANIFEST_FLAG");
+  std::string manifestFlag = this->Makefile->GetDefinition(
+    cmStrCat("CMAKE_", lang, "_LINKER_MANIFEST_FLAG"));
   for (cmSourceFile const* manifest_src : manifest_srcs) {
     manifests.push_back(manifestFlag +
                         this->LocalCommonGenerator->ConvertToOutputFormat(
@@ -360,6 +360,7 @@
   std::string cpplint;
   std::string cppcheck;
   std::string icstat;
+  std::string pvs;
 
   auto evaluateProp = [&](std::string const& prop) -> std::string {
     auto const value = this->GeneratorTarget->GetProperty(prop);
@@ -386,16 +387,21 @@
 
     std::string const icstat_prop = cmStrCat(lang, "_ICSTAT");
     icstat = evaluateProp(icstat_prop);
+
+    std::string const pvs_prop = cmStrCat(lang, "_PVS_STUDIO");
+    pvs = evaluateProp(pvs_prop);
   }
+
   if (cmNonempty(iwyu) || cmNonempty(tidy) || cmNonempty(cpplint) ||
-      cmNonempty(cppcheck) || cmNonempty(icstat)) {
+      cmNonempty(cppcheck) || cmNonempty(icstat) || cmNonempty(pvs)) {
     std::string code_check = cmakeCmd + " -E __run_co_compile";
     if (!compilerLauncher.empty()) {
       // In __run_co_compile case the launcher command is supplied
       // via --launcher=<maybe-list> and consumed
-      code_check += " --launcher=";
-      code_check += this->GeneratorTarget->GetLocalGenerator()->EscapeForShell(
-        compilerLauncher);
+      code_check =
+        cmStrCat(std::move(code_check), " --launcher=",
+                 this->GeneratorTarget->GetLocalGenerator()->EscapeForShell(
+                   compilerLauncher));
       compilerLauncher.clear();
     }
     if (cmNonempty(iwyu)) {
@@ -425,7 +431,7 @@
     if (cmNonempty(tidy)) {
       code_check += " --tidy=";
       cmValue const p = this->Makefile->GetDefinition(
-        "CMAKE_" + lang + "_CLANG_TIDY_DRIVER_MODE");
+        cmStrCat("CMAKE_", lang, "_CLANG_TIDY_DRIVER_MODE"));
       std::string driverMode;
       if (cmNonempty(p)) {
         driverMode = *p;
@@ -475,6 +481,29 @@
                      exportFixes));
       }
     }
+    if (cmNonempty(pvs)) {
+      cmMakefile* mf =
+        this->GeneratorTarget->GetLocalGenerator()->GetMakefile();
+      std::string extraPvsArgs;
+      if (lang == "CXX") {
+        extraPvsArgs +=
+          cmStrCat(";--cxx;", mf->GetDefinition("CMAKE_CXX_COMPILER"));
+      } else if (lang == "C") {
+        extraPvsArgs +=
+          cmStrCat(";--cc;", mf->GetDefinition("CMAKE_C_COMPILER"));
+      }
+      // cocompile args
+      code_check += " --pvs-studio=";
+      code_check += this->GeneratorTarget->GetLocalGenerator()->EscapeForShell(
+        cmStrCat(pvs, extraPvsArgs));
+      code_check += " --object=";
+      code_check +=
+        this->GeneratorTarget->GetLocalGenerator()->ConvertToOutputFormat(
+          cmSystemTools::CollapseFullPath(
+            cmStrCat(this->GeneratorTarget->GetObjectDirectory(config), '/',
+                     this->GeneratorTarget->GetObjectName(&source))),
+          cmOutputConverter::SHELL);
+    }
     if (cmNonempty(cpplint)) {
       code_check += " --cpplint=";
       code_check +=
@@ -503,7 +532,8 @@
       code_check += this->GeneratorTarget->GetLocalGenerator()->EscapeForShell(
         cmStrCat(icstat, checksParam, dbParam));
     }
-    if (cmNonempty(tidy) || (cmNonempty(cpplint)) || (cmNonempty(cppcheck))) {
+    if (cmNonempty(tidy) || (cmNonempty(cpplint)) || (cmNonempty(cppcheck)) ||
+        cmNonempty(pvs)) {
       code_check += " --source=";
       code_check +=
         this->GeneratorTarget->GetLocalGenerator()->ConvertToOutputFormat(
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index 44cb884..5ff8784 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -3,7 +3,6 @@
 #include "cmComputeLinkInformation.h"
 
 #include <algorithm>
-#include <cctype>
 #include <sstream>
 #include <utility>
 
@@ -13,6 +12,8 @@
 #include <cmext/algorithm>
 #include <cmext/string_view>
 
+#include "cmsys/String.h"
+
 #include "cmComputeLinkDepends.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
@@ -1556,8 +1557,8 @@
       ret += c;
     } else {
       ret += '[';
-      ret += static_cast<char>(tolower(c));
-      ret += static_cast<char>(toupper(c));
+      ret += static_cast<char>(cmsysString_tolower(c));
+      ret += static_cast<char>(cmsysString_toupper(c));
       ret += ']';
     }
   }
diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx
index 986a314..4b165b1 100644
--- a/Source/cmComputeTargetDepends.cxx
+++ b/Source/cmComputeTargetDepends.cxx
@@ -224,7 +224,7 @@
         for (cmLinkItem const& lib : impl->Libraries) {
           // Don't emit the same library twice for this target.
           if (emitted.insert(lib).second) {
-            this->AddTargetDepend(depender_index, lib, true, false);
+            this->AddTargetDepend(depender_index, lib, true, false, emitted);
             this->AddInterfaceDepends(depender_index, lib, it, emitted);
           }
         }
@@ -255,7 +255,8 @@
     for (cmLinkItem const& litem : tutils) {
       // Don't emit the same utility twice for this target.
       if (emitted.insert(litem).second) {
-        this->AddTargetDepend(depender_index, litem, false, litem.Cross);
+        this->AddTargetDepend(depender_index, litem, false, litem.Cross,
+                              emitted);
       }
     }
   }
@@ -277,7 +278,7 @@
         // code in the project that caused this dependency to be added.
         cmLinkItem libBT = lib;
         libBT.Backtrace = dependee_backtrace;
-        this->AddTargetDepend(depender_index, libBT, true, false);
+        this->AddTargetDepend(depender_index, libBT, true, false, emitted);
         this->AddInterfaceDepends(depender_index, libBT, config, emitted);
       }
     }
@@ -343,7 +344,8 @@
 
 void cmComputeTargetDepends::AddTargetDepend(size_t depender_index,
                                              cmLinkItem const& dependee_name,
-                                             bool linking, bool cross)
+                                             bool linking, bool cross,
+                                             std::set<cmLinkItem>& emitted)
 {
   // Get the depender.
   cmGeneratorTarget const* depender = this->Targets[depender_index];
@@ -370,22 +372,25 @@
 
   if (dependee) {
     this->AddTargetDepend(depender_index, dependee, dependee_name.Backtrace,
-                          linking, cross);
+                          linking, cross, emitted);
   }
 }
 
 void cmComputeTargetDepends::AddTargetDepend(
   size_t depender_index, cmGeneratorTarget const* dependee,
-  cmListFileBacktrace const& dependee_backtrace, bool linking, bool cross)
+  cmListFileBacktrace const& dependee_backtrace, bool linking, bool cross,
+  std::set<cmLinkItem>& emitted)
 {
   if (!dependee->IsInBuildSystem()) {
     // Skip targets that are not in the buildsystem but follow their
     // utility dependencies.
     std::set<cmLinkItem> const& utils = dependee->GetUtilityItems();
     for (cmLinkItem const& i : utils) {
-      if (cmGeneratorTarget const* transitive_dependee = i.Target) {
-        this->AddTargetDepend(depender_index, transitive_dependee, i.Backtrace,
-                              false, i.Cross);
+      if (emitted.insert(i).second) {
+        if (cmGeneratorTarget const* transitive_dependee = i.Target) {
+          this->AddTargetDepend(depender_index, transitive_dependee,
+                                i.Backtrace, false, i.Cross, emitted);
+        }
       }
     }
   } else {
diff --git a/Source/cmComputeTargetDepends.h b/Source/cmComputeTargetDepends.h
index cb5bd16..26569b5 100644
--- a/Source/cmComputeTargetDepends.h
+++ b/Source/cmComputeTargetDepends.h
@@ -54,11 +54,13 @@
   void CollectDepends();
   void CollectTargetDepends(size_t depender_index);
   void AddTargetDepend(size_t depender_index, cmLinkItem const& dependee_name,
-                       bool linking, bool cross);
+                       bool linking, bool cross,
+                       std::set<cmLinkItem>& emitted);
   void AddTargetDepend(size_t depender_index,
                        cmGeneratorTarget const* dependee,
                        cmListFileBacktrace const& dependee_backtrace,
-                       bool linking, bool cross);
+                       bool linking, bool cross,
+                       std::set<cmLinkItem>& emitted);
   void CollectSideEffects();
   void CollectSideEffectsForTarget(std::set<size_t>& visited,
                                    size_t depender_index);
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index c1d7054..6befcbf 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -575,9 +575,9 @@
     for (auto const& source : sources) {
       auto const& si = source.first;
       std::string ext = cmSystemTools::GetFilenameLastExtension(si);
-      std::string lang = gg->GetLanguageFromExtension(ext.c_str());
+      cm::string_view lang = gg->GetLanguageFromExtension(ext);
       if (!lang.empty()) {
-        testLangs.insert(lang);
+        testLangs.insert(std::string(lang));
       } else {
         std::ostringstream err;
         err << "Unknown extension \"" << ext
@@ -794,6 +794,43 @@
     fprintf(fout,
             "set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS}"
             " ${EXE_LINKER_FLAGS}\")\n");
+
+    switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0210)) {
+      case cmPolicies::WARN:
+        // This policy does WARN, but not during try_compile.
+        CM_FALLTHROUGH;
+      case cmPolicies::OLD:
+        // OLD behavior is to do nothing here. CMAKE_<LANG>_LINK_FLAGS was
+        // previously used internally by executables only, and not during
+        // try_compile.
+        break;
+      case cmPolicies::NEW:
+        // NEW behavior is to propagate language-specific link flags (stored
+        // in both the default and per-configuration variables, similar to the
+        // NEW behavior of CMP0066) to the test project.
+        for (std::string const& li : testLangs) {
+          std::string langLinkFlags = cmStrCat("CMAKE_", li, "_LINK_FLAGS");
+          cmValue flags = this->Makefile->GetDefinition(langLinkFlags);
+          fprintf(fout, "set(CMAKE_%s_LINK_FLAGS %s)\n", li.c_str(),
+                  cmOutputConverter::EscapeForCMake(*flags).c_str());
+          std::string langLinkFlagsConfig =
+            cmStrCat("CMAKE_", li, "_LINK_FLAGS_", tcConfig);
+          cmValue flagsConfig =
+            this->Makefile->GetDefinition(langLinkFlagsConfig);
+          fprintf(fout, "set(CMAKE_%s_LINK_FLAGS_%s %s)\n", li.c_str(),
+                  tcConfig.c_str(),
+                  cmOutputConverter::EscapeForCMake(*flagsConfig).c_str());
+
+          if (flags) {
+            cmakeVariables.emplace(langLinkFlags, *flags);
+          }
+          if (flagsConfig) {
+            cmakeVariables.emplace(langLinkFlagsConfig, *flagsConfig);
+          }
+        }
+        break;
+    }
+
     fprintf(fout, "include_directories(${INCLUDE_DIRECTORIES})\n");
     fprintf(fout, "set(CMAKE_SUPPRESS_REGENERATION 1)\n");
     fprintf(fout, "link_directories(${LINK_DIRECTORIES})\n");
@@ -832,8 +869,9 @@
               fprintf(fout, "add_executable(\"%s\" ALIAS \"%s\")\n", i.c_str(),
                       alias->second.c_str());
             } else {
-              // Other cases like UTILITY and GLOBAL_TARGET are excluded when
-              // arguments.LinkLibraries is initially parsed in this function.
+              // Other cases like UTILITY and GLOBAL_TARGET are excluded
+              // when arguments.LinkLibraries is initially parsed in this
+              // function.
               fprintf(fout, "add_library(\"%s\" ALIAS \"%s\")\n", i.c_str(),
                       alias->second.c_str());
             }
@@ -865,7 +903,8 @@
         ? "OLD"
         : "NEW");
 
-    /* Set the appropriate policy information for the LINKER: prefix expansion
+    /* Set the appropriate policy information for the LINKER: prefix
+     * expansion
      */
     fprintf(fout, "cmake_policy(SET CMP0181 %s)\n",
             this->Makefile->GetPolicyStatus(cmPolicies::CMP0181) ==
@@ -873,8 +912,17 @@
               ? "NEW"
               : "OLD");
 
-    // Workaround for -Wl,-headerpad_max_install_names issue until we can avoid
-    // adding that flag in the platform and compiler language files
+    /* Set the appropriate policy information for passing
+     * CMAKE_<LANG>_LINK_FLAGS
+     */
+    fprintf(fout, "cmake_policy(SET CMP0210 %s)\n",
+            this->Makefile->GetPolicyStatus(cmPolicies::CMP0210) ==
+                cmPolicies::NEW
+              ? "NEW"
+              : "OLD");
+
+    // Workaround for -Wl,-headerpad_max_install_names issue until we can
+    // avoid adding that flag in the platform and compiler language files
     fprintf(fout,
             "include(\"${CMAKE_ROOT}/Modules/Internal/"
             "HeaderpadWorkaround.cmake\")\n");
diff --git a/Source/cmCryptoHash.cxx b/Source/cmCryptoHash.cxx
index 5d1936f..e01f2d6 100644
--- a/Source/cmCryptoHash.cxx
+++ b/Source/cmCryptoHash.cxx
@@ -153,10 +153,9 @@
   return this->Finalize();
 }
 
-std::vector<unsigned char> cmCryptoHash::ByteHashFile(std::string const& file)
+std::vector<unsigned char> cmCryptoHash::ByteHashStream(std::istream& sin)
 {
-  cmsys::ifstream fin(file.c_str(), std::ios::in | std::ios::binary);
-  if (fin) {
+  if (sin) {
     this->Initialize();
     {
       // Should be efficient enough on most system:
@@ -169,14 +168,14 @@
       // incorrect to not check the error condition on the fin.read()
       // before using the data, but the fin.gcount() will be zero if an
       // error occurred.  Therefore, the loop should be safe everywhere.
-      while (fin) {
-        fin.read(buffer_c, sizeof(buffer));
-        if (int gcount = static_cast<int>(fin.gcount())) {
+      while (sin) {
+        sin.read(buffer_c, sizeof(buffer));
+        if (int gcount = static_cast<int>(sin.gcount())) {
           this->Append(buffer_uc, gcount);
         }
       }
     }
-    if (fin.eof()) {
+    if (sin.eof()) {
       // Success
       return this->Finalize();
     }
@@ -187,11 +186,22 @@
   return std::vector<unsigned char>();
 }
 
+std::vector<unsigned char> cmCryptoHash::ByteHashFile(std::string const& file)
+{
+  cmsys::ifstream fin(file.c_str(), std::ios::in | std::ios::binary);
+  return this->ByteHashStream(fin);
+}
+
 std::string cmCryptoHash::HashString(cm::string_view input)
 {
   return ByteHashToString(this->ByteHashString(input));
 }
 
+std::string cmCryptoHash::HashStream(std::istream& sin)
+{
+  return ByteHashToString(this->ByteHashStream(sin));
+}
+
 std::string cmCryptoHash::HashFile(std::string const& file)
 {
   return ByteHashToString(this->ByteHashFile(file));
diff --git a/Source/cmCryptoHash.h b/Source/cmCryptoHash.h
index 600a50c..80ffa49 100644
--- a/Source/cmCryptoHash.h
+++ b/Source/cmCryptoHash.h
@@ -5,6 +5,7 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <cstddef>
+#include <iostream>
 #include <memory>
 #include <string>
 #include <vector>
@@ -58,6 +59,12 @@
   /// @return Binary hash vector
   std::vector<unsigned char> ByteHashString(cm::string_view input);
 
+  /// @brief Calculates a binary hash from stream content
+  /// @see ByteHashString()
+  /// @return Non empty binary hash vector if the stream was read successfully.
+  ///         An empty vector otherwise.
+  std::vector<unsigned char> ByteHashStream(std::istream& sin);
+
   /// @brief Calculates a binary hash from file content
   /// @see ByteHashString()
   /// @return Non empty binary hash vector if the file was read successfully.
@@ -68,6 +75,12 @@
   /// @return Sequence of hex characters pairs for each byte of the binary hash
   std::string HashString(cm::string_view input);
 
+  /// @brief Calculates a hash string from stream content
+  /// @see HashString()
+  /// @return Non empty hash string if the stream was read successfully.
+  ///         An empty string otherwise.
+  std::string HashStream(std::istream& sin);
+
   /// @brief Calculates a hash string from file content
   /// @see HashString()
   /// @return Non empty hash string if the file was read successfully.
diff --git a/Source/cmCurl.cxx b/Source/cmCurl.cxx
index 627e302..ab30dc6 100644
--- a/Source/cmCurl.cxx
+++ b/Source/cmCurl.cxx
@@ -2,6 +2,8 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "cmCurl.h"
 
+#include <utility>
+
 #include <cm/string_view>
 #include <cmext/string_view>
 
@@ -28,9 +30,9 @@
 #define check_curl_result(result, errstr)                                     \
   do {                                                                        \
     if ((result) != CURLE_OK && (result) != CURLE_NOT_BUILT_IN) {             \
-      e += e.empty() ? "" : "\n";                                             \
-      e += (errstr);                                                          \
-      e += ::curl_easy_strerror(result);                                      \
+      bool isNeedNewline = !e.empty();                                        \
+      e = cmStrCat(std::move(e), isNeedNewline ? "\n"_s : ""_s, (errstr),     \
+                   ::curl_easy_strerror(result));                             \
     }                                                                         \
   } while (false)
 
@@ -225,38 +227,6 @@
   return e;
 }
 
-std::string cmCurlFixFileURL(std::string url)
-{
-  if (!cmHasLiteralPrefix(url, "file://")) {
-    return url;
-  }
-
-  // libcurl 7.77 and below accidentally allowed spaces in URLs in some cases.
-  // One such case was file:// URLs, which CMake has long accepted as a result.
-  // Explicitly encode spaces for a URL.
-  cmSystemTools::ReplaceString(url, " ", "%20");
-
-#if defined(_WIN32)
-  // libcurl doesn't support file:// urls for unicode filenames on Windows.
-  // Convert string from UTF-8 to ACP if this is a file:// URL.
-  std::wstring wurl = cmsys::Encoding::ToWide(url);
-  if (!wurl.empty()) {
-    int mblen = WideCharToMultiByte(CP_ACP, 0, wurl.c_str(), -1, nullptr, 0,
-                                    nullptr, nullptr);
-    if (mblen > 0) {
-      std::vector<char> chars(mblen);
-      mblen = WideCharToMultiByte(CP_ACP, 0, wurl.c_str(), -1, &chars[0],
-                                  mblen, nullptr, nullptr);
-      if (mblen > 0) {
-        url = &chars[0];
-      }
-    }
-  }
-#endif
-
-  return url;
-}
-
 ::CURL* cm_curl_easy_init()
 {
   ::CURL* curl = curl_easy_init();
diff --git a/Source/cmCurl.h b/Source/cmCurl.h
index 3d60671..321ef5a 100644
--- a/Source/cmCurl.h
+++ b/Source/cmCurl.h
@@ -21,7 +21,6 @@
 std::string cmCurlSetCAInfo(::CURL* curl, std::string const& cafile = {});
 std::string cmCurlSetNETRCOption(::CURL* curl, std::string const& netrc_level,
                                  std::string const& netrc_file);
-std::string cmCurlFixFileURL(std::string url);
 
 ::CURLcode cm_curl_global_init(long flags);
 ::CURL* cm_curl_easy_init();
diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx
index 4d34d66..b63d2a6 100644
--- a/Source/cmCustomCommandGenerator.cxx
+++ b/Source/cmCustomCommandGenerator.cxx
@@ -53,7 +53,7 @@
         ++pos;
         continue;
       }
-      if (cmHasLiteralPrefix(cur, ">")) {
+      if (cmHasPrefix(cur, '>')) {
         --nestingLevel;
         if (nestingLevel == 0) {
           ++pos;
diff --git a/Source/cmCxxModuleMapper.cxx b/Source/cmCxxModuleMapper.cxx
index 7c72dad..343e0d6 100644
--- a/Source/cmCxxModuleMapper.cxx
+++ b/Source/cmCxxModuleMapper.cxx
@@ -148,15 +148,15 @@
       // extension.
       mm << "-x c++-module\n";
 
-      mm << "-fmodule-output=" << bmi_loc.Location() << '\n';
+      mm << "-fmodule-output=\"" << bmi_loc.Location() << "\"\n";
       break;
     }
   }
 
   auto all_usages = GetTransitiveUsages(loc, obj.Requires, usages);
   for (auto const& usage : all_usages) {
-    mm << "-fmodule-file=" << usage.LogicalName << '=' << usage.Location
-       << '\n';
+    mm << "-fmodule-file=\"" << usage.LogicalName << '=' << usage.Location
+       << "\"\n";
   }
 
   return mm.str();
@@ -229,7 +229,7 @@
 
     auto bmi_loc = loc.BmiGeneratorPathForModule(p.LogicalName);
     if (bmi_loc.IsKnown()) {
-      mm << "-ifcOutput " << bmi_loc.Location() << '\n';
+      mm << "-ifcOutput \"" << bmi_loc.Location() << "\"\n";
     }
   }
 
@@ -237,7 +237,8 @@
   for (auto const& usage : all_usages) {
     auto flag = flag_for_method(usage.Method);
 
-    mm << flag << ' ' << usage.LogicalName << '=' << usage.Location << '\n';
+    mm << flag << " \"" << usage.LogicalName << '=' << usage.Location
+       << "\"\n";
   }
 
   return mm.str();
diff --git a/Source/cmCxxModuleMetadata.cxx b/Source/cmCxxModuleMetadata.cxx
new file mode 100644
index 0000000..bf3a875
--- /dev/null
+++ b/Source/cmCxxModuleMetadata.cxx
@@ -0,0 +1,598 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+#include "cmCxxModuleMetadata.h"
+
+#include <algorithm>
+#include <set>
+#include <string>
+#include <utility>
+
+#include <cmext/string_view>
+
+#include <cm3p/json/value.h>
+#include <cm3p/json/writer.h>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmFileSet.h"
+#include "cmGeneratedFileStream.h"
+#include "cmJSONState.h"
+#include "cmListFileCache.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+
+namespace {
+
+bool JsonIsStringArray(Json::Value const& v)
+{
+  return v.isArray() &&
+    std::all_of(v.begin(), v.end(),
+                [](Json::Value const& it) { return it.isString(); });
+}
+
+bool ParsePreprocessorDefine(Json::Value& dval,
+                             cmCxxModuleMetadata::PreprocessorDefineData& out,
+                             cmJSONState* state)
+{
+  if (!dval.isObject()) {
+    state->AddErrorAtValue("each entry in 'definitions' must be an object",
+                           &dval);
+    return false;
+  }
+
+  if (!dval.isMember("name") || !dval["name"].isString() ||
+      dval["name"].asString().empty()) {
+    state->AddErrorAtValue(
+      "preprocessor definition requires a non-empty 'name'", &dval["name"]);
+    return false;
+  }
+  out.Name = dval["name"].asString();
+
+  if (dval.isMember("value")) {
+    if (dval["value"].isString()) {
+      out.Value = dval["value"].asString();
+    } else if (!dval["value"].isNull()) {
+      state->AddErrorAtValue(
+        "'value' in preprocessor definition must be string or null",
+        &dval["value"]);
+      return false;
+    }
+  }
+
+  if (dval.isMember("undef")) {
+    if (!dval["undef"].isBool()) {
+      state->AddErrorAtValue(
+        "'undef' in preprocessor definition must be boolean", &dval["undef"]);
+      return false;
+    }
+    out.Undef = dval["undef"].asBool();
+  }
+
+  return true;
+}
+
+bool ParseCMakeLocalArgumentsVendor(
+  Json::Value& cmlav, cmCxxModuleMetadata::LocalArgumentsData& out,
+  cmJSONState* state)
+{
+
+  if (!cmlav.isObject()) {
+    state->AddErrorAtValue("'vendor' must be an object", &cmlav);
+    return false;
+  }
+
+  if (cmlav.isMember("compile-options")) {
+    if (!JsonIsStringArray(cmlav["compile-options"])) {
+      state->AddErrorAtValue("'compile-options' must be an array of strings",
+                             &cmlav["compile-options"]);
+      return false;
+    }
+    for (auto const& s : cmlav["compile-options"]) {
+      out.CompileOptions.push_back(s.asString());
+    }
+  }
+
+  if (cmlav.isMember("compile-features")) {
+    if (!JsonIsStringArray(cmlav["compile-features"])) {
+      state->AddErrorAtValue("'compile-features' must be an array of strings",
+                             &cmlav["compile-features"]);
+      return false;
+    }
+    for (auto const& s : cmlav["compile-features"]) {
+      out.CompileFeatures.push_back(s.asString());
+    }
+  }
+
+  return true;
+}
+
+bool ParseLocalArguments(Json::Value& lav,
+                         cmCxxModuleMetadata::LocalArgumentsData& out,
+                         cmJSONState* state)
+{
+  if (!lav.isObject()) {
+    state->AddErrorAtValue("'local-arguments' must be an object", &lav);
+    return false;
+  }
+
+  if (lav.isMember("include-directories")) {
+    if (!JsonIsStringArray(lav["include-directories"])) {
+      state->AddErrorAtValue(
+        "'include-directories' must be an array of strings",
+        &lav["include-directories"]);
+      return false;
+    }
+    for (auto const& s : lav["include-directories"]) {
+      out.IncludeDirectories.push_back(s.asString());
+    }
+  }
+
+  if (lav.isMember("system-include-directories")) {
+    if (!JsonIsStringArray(lav["system-include-directories"])) {
+      state->AddErrorAtValue(
+        "'system-include-directories' must be an array of strings",
+        &lav["system-include-directories"]);
+      return false;
+    }
+    for (auto const& s : lav["system-include-directories"]) {
+      out.SystemIncludeDirectories.push_back(s.asString());
+    }
+  }
+
+  if (lav.isMember("definitions")) {
+    if (!lav["definitions"].isArray()) {
+      state->AddErrorAtValue("'definitions' must be an array",
+                             &lav["definitions"]);
+      return false;
+    }
+    for (Json::Value& dval : lav["definitions"]) {
+      out.Definitions.emplace_back();
+      if (!ParsePreprocessorDefine(dval, out.Definitions.back(), state)) {
+        return false;
+      }
+    }
+  }
+
+  if (lav.isMember("vendor")) {
+    if (!ParseCMakeLocalArgumentsVendor(lav["vendor"], out, state)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool ParseModule(Json::Value& mval, cmCxxModuleMetadata::ModuleData& mod,
+                 cmJSONState* state)
+{
+  if (!mval.isObject()) {
+    state->AddErrorAtValue("each entry in 'modules' must be an object", &mval);
+    return false;
+  }
+
+  if (!mval.isMember("logical-name") || !mval["logical-name"].isString() ||
+      mval["logical-name"].asString().empty()) {
+    state->AddErrorAtValue(
+      "module entries require a non-empty 'logical-name' string",
+      &mval["logical-name"]);
+    return false;
+  }
+  mod.LogicalName = mval["logical-name"].asString();
+
+  if (!mval.isMember("source-path") || !mval["source-path"].isString() ||
+      mval["source-path"].asString().empty()) {
+    state->AddErrorAtValue(
+      "module entries require a non-empty 'source-path' string",
+      &mval["source-path"]);
+    return false;
+  }
+  mod.SourcePath = mval["source-path"].asString();
+
+  if (mval.isMember("is-interface")) {
+    if (!mval["is-interface"].isBool()) {
+      state->AddErrorAtValue("'is-interface' must be boolean",
+                             &mval["is-interface"]);
+      return false;
+    }
+    mod.IsInterface = mval["is-interface"].asBool();
+  } else {
+    mod.IsInterface = true;
+  }
+
+  if (mval.isMember("is-std-library")) {
+    if (!mval["is-std-library"].isBool()) {
+      state->AddErrorAtValue("'is-std-library' must be boolean",
+                             &mval["is-std-library"]);
+      return false;
+    }
+    mod.IsStdLibrary = mval["is-std-library"].asBool();
+  } else {
+    mod.IsStdLibrary = false;
+  }
+
+  if (mval.isMember("local-arguments")) {
+    mod.LocalArguments.emplace();
+    if (!ParseLocalArguments(mval["local-arguments"], *mod.LocalArguments,
+                             state)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool ParseRoot(Json::Value& root, cmCxxModuleMetadata& meta,
+               cmJSONState* state)
+{
+  if (!root.isMember("version") || !root["version"].isInt()) {
+    state->AddErrorAtValue(
+      "Top-level member 'version' is required and must be an integer", &root);
+    return false;
+  }
+  meta.Version = root["version"].asInt();
+
+  if (root.isMember("revision")) {
+    if (!root["revision"].isInt()) {
+      state->AddErrorAtValue("'revision' must be an integer",
+                             &root["revision"]);
+      return false;
+    }
+    meta.Revision = root["revision"].asInt();
+  }
+
+  if (meta.Version != 1) {
+    state->AddErrorAtValue(cmStrCat("Module manifest version number, '",
+                                    meta.Version, '.', meta.Revision,
+                                    "' is newer than max supported (1.1)"),
+                           &root);
+    return false;
+  }
+
+  if (root.isMember("modules")) {
+    if (!root["modules"].isArray()) {
+      state->AddErrorAtValue("'modules' must be an array", &root["modules"]);
+      return false;
+    }
+    for (Json::Value& mval : root["modules"]) {
+      meta.Modules.emplace_back();
+      if (!ParseModule(mval, meta.Modules.back(), state)) {
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+} // namespace
+
+cmCxxModuleMetadata::ParseResult cmCxxModuleMetadata::LoadFromFile(
+  std::string const& path)
+{
+  ParseResult res;
+
+  Json::Value root;
+  cmJSONState parseState(path, &root);
+  if (!parseState.errors.empty()) {
+    res.Error = parseState.GetErrorMessage();
+    return res;
+  }
+
+  cmCxxModuleMetadata meta;
+  if (!ParseRoot(root, meta, &parseState)) {
+    res.Error = parseState.GetErrorMessage();
+    return res;
+  }
+
+  meta.MetadataFilePath = path;
+  res.Meta = std::move(meta);
+  return res;
+}
+
+namespace {
+
+Json::Value SerializePreprocessorDefine(
+  cmCxxModuleMetadata::PreprocessorDefineData const& d)
+{
+  Json::Value dv(Json::objectValue);
+  dv["name"] = d.Name;
+  if (d.Value) {
+    dv["value"] = *d.Value;
+  }
+  if (d.Undef) {
+    dv["undef"] = d.Undef;
+  }
+  return dv;
+}
+
+Json::Value SerializeCMakeLocalArgumentsVendor(
+  cmCxxModuleMetadata::LocalArgumentsData const& la)
+{
+  Json::Value vend(Json::objectValue);
+
+  if (!la.CompileOptions.empty()) {
+    Json::Value& opts = vend["compile-options"] = Json::arrayValue;
+    for (auto const& s : la.CompileOptions) {
+      opts.append(s);
+    }
+  }
+
+  if (!la.CompileFeatures.empty()) {
+    Json::Value& feats = vend["compile-features"] = Json::arrayValue;
+    for (auto const& s : la.CompileFeatures) {
+      feats.append(s);
+    }
+  }
+
+  return vend;
+}
+
+Json::Value SerializeLocalArguments(
+  cmCxxModuleMetadata::LocalArgumentsData const& la)
+{
+  Json::Value lav(Json::objectValue);
+
+  if (!la.IncludeDirectories.empty()) {
+    Json::Value& inc = lav["include-directories"] = Json::arrayValue;
+    for (auto const& s : la.IncludeDirectories) {
+      inc.append(s);
+    }
+  }
+
+  if (!la.SystemIncludeDirectories.empty()) {
+    Json::Value& sinc = lav["system-include-directories"] = Json::arrayValue;
+    for (auto const& s : la.SystemIncludeDirectories) {
+      sinc.append(s);
+    }
+  }
+
+  if (!la.Definitions.empty()) {
+    Json::Value& defs = lav["definitions"] = Json::arrayValue;
+    for (auto const& d : la.Definitions) {
+      defs.append(SerializePreprocessorDefine(d));
+    }
+  }
+
+  Json::Value vend = SerializeCMakeLocalArgumentsVendor(la);
+  if (!vend.empty()) {
+    Json::Value& cmvend = lav["vendor"] = Json::objectValue;
+    cmvend["cmake"] = std::move(vend);
+  }
+
+  return lav;
+}
+
+Json::Value SerializeModule(std::string& manifestRoot,
+                            cmCxxModuleMetadata::ModuleData const& m)
+{
+  Json::Value mv(Json::objectValue);
+  mv["logical-name"] = m.LogicalName;
+  if (cmSystemTools::FileIsFullPath(m.SourcePath)) {
+    mv["source-path"] = m.SourcePath;
+  } else {
+    mv["source-path"] = cmSystemTools::ForceToRelativePath(
+      manifestRoot, cmStrCat('/', m.SourcePath));
+  }
+  mv["is-interface"] = m.IsInterface;
+  mv["is-std-library"] = m.IsStdLibrary;
+
+  if (m.LocalArguments) {
+    mv["local-arguments"] = SerializeLocalArguments(*m.LocalArguments);
+  }
+
+  return mv;
+}
+
+} // namespace
+
+Json::Value cmCxxModuleMetadata::ToJsonValue(cmCxxModuleMetadata const& meta)
+{
+  Json::Value root(Json::objectValue);
+
+  root["version"] = meta.Version;
+  root["revision"] = meta.Revision;
+
+  Json::Value& modules = root["modules"] = Json::arrayValue;
+  std::string manifestRoot =
+    cmSystemTools::GetFilenamePath(meta.MetadataFilePath);
+
+  if (!cmSystemTools::FileIsFullPath(meta.MetadataFilePath)) {
+    manifestRoot = cmStrCat('/', manifestRoot);
+  }
+
+  for (auto const& m : meta.Modules) {
+    modules.append(SerializeModule(manifestRoot, m));
+  }
+
+  return root;
+}
+
+cmCxxModuleMetadata::SaveResult cmCxxModuleMetadata::SaveToFile(
+  std::string const& path, cmCxxModuleMetadata const& meta)
+{
+  SaveResult st;
+
+  cmGeneratedFileStream ofs(path);
+  if (!ofs.is_open()) {
+    st.Error = "Unable to open temp file for writing";
+    return st;
+  }
+
+  Json::StreamWriterBuilder wbuilder;
+  wbuilder["indentation"] = "  ";
+  ofs << Json::writeString(wbuilder, ToJsonValue(meta));
+
+  ofs.Close();
+
+  if (!ofs.good()) {
+    st.Error = cmStrCat("Write failed for file: "_s, path);
+    return st;
+  }
+
+  st.Ok = true;
+  return st;
+}
+
+namespace {
+
+struct MetaDataProperties
+{
+  std::string MetadataDir;
+  std::set<cm::string_view> AllCompileFeatures;
+  std::set<cm::string_view> AllCompileOptions;
+  std::set<std::string> AllIncludeDirectories;
+  std::set<std::string> AllCompileDefinitions;
+  std::set<std::string> BaseDirs;
+  std::set<std::string> Sources;
+
+  std::string NormalizePath(std::string const& in) const
+  {
+    std::string out = in;
+    if (!cmSystemTools::FileIsFullPath(in)) {
+      out = cmStrCat(MetadataDir, '/', in);
+    }
+    return cmSystemTools::CollapseFullPath(out);
+  }
+};
+
+MetaDataProperties CollectMetaProperties(cmCxxModuleMetadata const& meta)
+{
+  MetaDataProperties props;
+
+  props.MetadataDir = cmSystemTools::GetFilenamePath(meta.MetadataFilePath);
+
+  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));
+
+    if (module.LocalArguments) {
+      for (auto const& incDir : module.LocalArguments->IncludeDirectories) {
+        props.AllIncludeDirectories.emplace(props.NormalizePath(incDir));
+      }
+      for (auto const& sysIncDir :
+           module.LocalArguments->SystemIncludeDirectories) {
+        props.AllIncludeDirectories.emplace(props.NormalizePath(sysIncDir));
+      }
+      for (auto const& opt : module.LocalArguments->CompileOptions) {
+        props.AllCompileOptions.emplace(opt);
+      }
+      for (auto const& opt : module.LocalArguments->CompileFeatures) {
+        props.AllCompileFeatures.emplace(opt);
+      }
+
+      for (auto const& def : module.LocalArguments->Definitions) {
+        if (!def.Undef) {
+          if (def.Value) {
+            props.AllCompileDefinitions.emplace(
+              cmStrCat(def.Name, "="_s, *def.Value));
+          } else {
+            props.AllCompileDefinitions.emplace(def.Name);
+          }
+        }
+      }
+    }
+  }
+
+  return props;
+}
+
+void PopulateFileSet(cmTarget& target, MetaDataProperties const& props)
+{
+  auto fileSet = target.GetOrCreateFileSet("CXX_MODULES", "CXX_MODULES",
+                                           cmFileSetVisibility::Public);
+
+  for (auto const& source : props.Sources) {
+    fileSet.first->AddFileEntry(source);
+  }
+
+  for (auto const& baseDir : props.BaseDirs) {
+    fileSet.first->AddDirectoryEntry(baseDir);
+  }
+}
+
+void PopulateLocalTarget(cmTarget& target, MetaDataProperties const& props)
+{
+  if (!props.AllIncludeDirectories.empty()) {
+    target.AppendProperty("INCLUDE_DIRECTORIES",
+                          cmJoin(props.AllIncludeDirectories, ";"));
+  }
+
+  if (!props.AllCompileDefinitions.empty()) {
+    target.AppendProperty("COMPILE_DEFINITIONS",
+                          cmJoin(props.AllCompileDefinitions, ";"));
+  }
+
+  if (!props.AllCompileOptions.empty()) {
+    target.AppendProperty("COMPILE_OPTIONS",
+                          cmJoin(props.AllCompileOptions, ";"));
+  }
+
+  if (!props.AllCompileFeatures.empty()) {
+    target.AppendProperty("COMPILE_FEATURES",
+                          cmJoin(props.AllCompileFeatures, ";"));
+  }
+}
+
+void PopulateImportedTarget(cmTarget& target, MetaDataProperties const& props,
+                            cmCxxModuleMetadata const& meta,
+                            std::vector<std::string> const& configs)
+{
+  if (!props.AllIncludeDirectories.empty()) {
+    target.SetProperty("IMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES",
+                       cmJoin(props.AllIncludeDirectories, ";"));
+  }
+
+  if (!props.AllCompileDefinitions.empty()) {
+    target.SetProperty("IMPORTED_CXX_MODULES_COMPILE_DEFINITIONS",
+                       cmJoin(props.AllCompileDefinitions, ";"));
+  }
+
+  if (!props.AllCompileOptions.empty()) {
+    target.SetProperty("IMPORTED_CXX_MODULES_COMPILE_OPTIONS",
+                       cmJoin(props.AllCompileOptions, ";"));
+  }
+
+  if (!props.AllCompileFeatures.empty()) {
+    target.SetProperty("IMPORTED_CXX_MODULES_COMPILE_FEATURES",
+                       cmJoin(props.AllCompileFeatures, ";"));
+  }
+
+  for (auto const& config : configs) {
+    std::vector<std::string> moduleList;
+    for (auto const& module : meta.Modules) {
+      if (module.IsInterface) {
+        moduleList.push_back(cmStrCat(module.LogicalName, "="_s,
+                                      props.NormalizePath(module.SourcePath)));
+      }
+    }
+
+    if (!moduleList.empty()) {
+      std::string upperConfig = cmSystemTools::UpperCase(config);
+      std::string propertyName =
+        cmStrCat("IMPORTED_CXX_MODULES_"_s, upperConfig);
+      target.SetProperty(propertyName, cmJoin(moduleList, ";"));
+    }
+  }
+}
+
+} // namespace
+
+void cmCxxModuleMetadata::PopulateTarget(
+  cmTarget& target, cmCxxModuleMetadata const& meta,
+  std::vector<std::string> const& configs)
+{
+  auto props = CollectMetaProperties(meta);
+  PopulateFileSet(target, props);
+
+  if (target.IsImported()) {
+    PopulateImportedTarget(target, props, meta, configs);
+  } else {
+    PopulateLocalTarget(target, props);
+  }
+}
diff --git a/Source/cmCxxModuleMetadata.h b/Source/cmCxxModuleMetadata.h
new file mode 100644
index 0000000..2df94a7
--- /dev/null
+++ b/Source/cmCxxModuleMetadata.h
@@ -0,0 +1,101 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+#include <cm/string_view>
+
+#include <cm3p/json/value.h>
+
+class cmTarget;
+
+class cmCxxModuleMetadata
+{
+public:
+  struct PreprocessorDefineData
+  {
+    // definition["name"]
+    std::string Name;
+    // definition["value"]
+    cm::optional<std::string> Value;
+    // definition["undef"]
+    bool Undef = false;
+  };
+
+  struct LocalArgumentsData
+  {
+    // local-arguments["include-directories"]
+    std::vector<std::string> IncludeDirectories;
+    // local-arguments["system-include-directories"]
+    std::vector<std::string> SystemIncludeDirectories;
+    // local-arguments["definitions"]
+    std::vector<PreprocessorDefineData> Definitions;
+
+    // These are CMake vendor extensions
+    // local-arguments["vendor"]["cmake"]["compile-options"]
+    std::vector<std::string> CompileOptions;
+    // local-arguments["vendor"]["cmake"]["compile-features"]
+    std::vector<std::string> CompileFeatures;
+  };
+
+  struct ModuleData
+  {
+    // module["logical-name"]
+    std::string LogicalName;
+    // module["source-path"]
+    std::string SourcePath;
+    // module["is-interface"]
+    bool IsInterface = true;
+    // module["is-std-library"]
+    bool IsStdLibrary = false;
+    // module["local-arguments"]
+    cm::optional<LocalArgumentsData> LocalArguments;
+  };
+
+  // root["version"]
+  int Version = 1;
+  // root["revision"]
+  int Revision = 1;
+  // root["modules"]
+  std::vector<ModuleData> Modules;
+
+  // The path to the manifest file, either absolute or relative to the
+  // installation root
+  std::string MetadataFilePath;
+
+  struct ParseResult;
+
+  struct SaveResult
+  {
+    bool Ok = false;
+    std::string Error;
+    explicit operator bool() const { return Ok; }
+  };
+
+  static ParseResult LoadFromFile(std::string const& path);
+  static Json::Value ToJsonValue(cmCxxModuleMetadata const& meta);
+  static SaveResult SaveToFile(std::string const& path,
+                               cmCxxModuleMetadata const& meta);
+  static void PopulateTarget(cmTarget& target, cmCxxModuleMetadata const& meta,
+                             std::vector<std::string> const& configs);
+  static void PopulateTarget(cmTarget& target, cmCxxModuleMetadata const& meta,
+                             cm::string_view config)
+  {
+    PopulateTarget(target, meta,
+                   std::vector<std::string>{ std::string(config) });
+  }
+  static void PopulateTarget(cmTarget& target, cmCxxModuleMetadata const& meta)
+  {
+    PopulateTarget(target, meta, "NOCONFIG");
+  }
+};
+
+struct cmCxxModuleMetadata::ParseResult
+{
+  cm::optional<cmCxxModuleMetadata> Meta;
+  std::string Error;
+  explicit operator bool() const { return static_cast<bool>(Meta); }
+};
diff --git a/Source/cmCxxModuleUsageEffects.h b/Source/cmCxxModuleUsageEffects.h
index 1c3933c..56a85b9 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;
 class cmTarget;
@@ -19,4 +22,5 @@
 
 private:
   std::string Hash;
+  std::vector<BT<std::string>> CompileFeatures;
 };
diff --git a/Source/cmDebuggerVariablesHelper.cxx b/Source/cmDebuggerVariablesHelper.cxx
index efe5c89..07d9802 100644
--- a/Source/cmDebuggerVariablesHelper.cxx
+++ b/Source/cmDebuggerVariablesHelper.cxx
@@ -127,7 +127,7 @@
       ret.reserve(values.size());
       int i = 0;
       for (std::string const& value : values) {
-        ret.emplace_back("[" + std::to_string(i++) + "]", value);
+        ret.emplace_back(cmStrCat('[', i++, ']'), value);
       }
       return ret;
     });
@@ -151,7 +151,7 @@
       ret.reserve(values.size());
       int i = 0;
       for (std::string const& value : values) {
-        ret.emplace_back("[" + std::to_string(i++) + "]", value);
+        ret.emplace_back(cmStrCat('[', i++, ']'), value);
       }
       return ret;
     });
@@ -176,7 +176,7 @@
       ret.reserve(list.size());
       int i = 0;
       for (auto const& item : list) {
-        ret.emplace_back("[" + std::to_string(i++) + "]", item.Value);
+        ret.emplace_back(cmStrCat('[', i++, ']'), item.Value);
       }
 
       return ret;
@@ -426,8 +426,8 @@
   for (auto const& key : keys) {
     auto entry = std::make_shared<cmDebuggerVariables>(
       variablesManager,
-      key + ":" +
-        cmState::CacheEntryTypeToString(state->GetCacheEntryType(key)),
+      cmStrCat(key, ':',
+               cmState::CacheEntryTypeToString(state->GetCacheEntryType(key))),
       supportsVariableType, [=]() {
         std::vector<cmDebuggerVariableEntry> ret;
         auto properties = state->GetCacheEntryPropertyList(key);
diff --git a/Source/cmDebuggerWindowsPipeConnection.cxx b/Source/cmDebuggerWindowsPipeConnection.cxx
index 1e8c35b..2392371 100644
--- a/Source/cmDebuggerWindowsPipeConnection.cxx
+++ b/Source/cmDebuggerWindowsPipeConnection.cxx
@@ -8,6 +8,8 @@
 #include <stdexcept>
 #include <utility>
 
+#include "cmStringAlgorithms.h"
+
 namespace cmDebugger {
 
 #ifdef _WIN32
@@ -131,8 +133,8 @@
       FORMAT_MESSAGE_IGNORE_INSERTS,
     nullptr, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
     (LPSTR)&message, 0, nullptr);
-  std::string errorMessage = "Internal Error with " + this->PipeName + ": " +
-    std::string(message, size);
+  std::string errorMessage = cmStrCat("Internal Error with ", this->PipeName,
+                                      ": ", std::string(message, size));
   LocalFree(message);
   return errorMessage;
 }
@@ -238,7 +240,7 @@
     nullptr, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
     (LPSTR)&message, 0, nullptr);
   std::string errorMessage =
-    this->PipeName + ": " + std::string(message, size);
+    cmStrCat(this->PipeName, ": ", std::string(message, size));
   LocalFree(message);
   return errorMessage;
 }
diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx
index f63b7ca..48725dc 100644
--- a/Source/cmDependsC.cxx
+++ b/Source/cmDependsC.cxx
@@ -160,7 +160,8 @@
       // regex.
       if (fullName.empty() &&
           this->IncludeRegexComplain.find(current.FileName)) {
-        cmSystemTools::Error("Cannot find file \"" + current.FileName + "\".");
+        cmSystemTools::Error(
+          cmStrCat("Cannot find file \"", current.FileName, "\"."));
         return false;
       }
 
diff --git a/Source/cmDependsJavaParserHelper.cxx b/Source/cmDependsJavaParserHelper.cxx
index a24bcd0..1cf6fdd 100644
--- a/Source/cmDependsJavaParserHelper.cxx
+++ b/Source/cmDependsJavaParserHelper.cxx
@@ -14,6 +14,7 @@
 #include "cmsys/FStream.hxx"
 
 #include "cmDependsJavaLexer.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
 int cmDependsJava_yyparse(yyscan_t yyscanner);
@@ -40,8 +41,7 @@
 {
   std::string rname;
   if (prefix) {
-    rname += prefix;
-    rname += sep;
+    rname = cmStrCat(std::move(rname), prefix, sep);
   }
   rname += this->Name;
   files->push_back(rname);
@@ -310,10 +310,10 @@
                                               char const* str2)
 {
   if (this->CurrentCombine.empty() && str1) {
-    this->CurrentCombine = str1;
+    // We can reuse allocated memory from `this->CurrentCombine`
+    this->CurrentCombine = cmStrCat(std::move(this->CurrentCombine), str1);
   }
-  this->CurrentCombine += ".";
-  this->CurrentCombine += str2;
+  this->CurrentCombine = cmStrCat(std::move(this->CurrentCombine), '.', str2);
 }
 
 int cmDependsJavaParserHelper::ParseFile(char const* file)
@@ -329,7 +329,7 @@
   std::string fullfile;
   std::string line;
   while (cmSystemTools::GetLineFromStream(ifs, line)) {
-    fullfile += line + "\n";
+    fullfile = cmStrCat(std::move(fullfile), line, '\n');
   }
   return this->ParseString(fullfile.c_str(), 0);
 }
diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx
index 2cd57b6..66e3730 100644
--- a/Source/cmDocumentation.cxx
+++ b/Source/cmDocumentation.cxx
@@ -3,13 +3,20 @@
 #include "cmDocumentation.h"
 
 #include <algorithm>
-#include <cctype>
 #include <cstring>
 #include <utility>
 
 #include "cmsys/FStream.hxx"
 #include "cmsys/Glob.hxx"
 #include "cmsys/RegularExpression.hxx"
+#include "cmsys/String.h"
+
+#if !defined(CMAKE_BOOTSTRAP)
+#  include <memory>
+
+#  include <cm3p/json/value.h>
+#  include <cm3p/json/writer.h>
+#endif
 
 #include "cmDocumentationEntry.h"
 #include "cmDocumentationSection.h"
@@ -21,7 +28,9 @@
 namespace {
 cmDocumentationEntry const cmDocumentationStandardOptions[21] = {
   { "-h,-H,--help,-help,-usage,/?", "Print usage information and exit." },
-  { "--version,-version,/V [<file>]", "Print version number and exit." },
+  { "--version[=json-v1],-version[=json-v1],/V[=json-v1],/version[=json-v1] "
+    "[<file>]",
+    "Print version number and exit." },
   { "--help <keyword> [<file>]", "Print help for one keyword and exit." },
   { "--help-full [<file>]", "Print all help manuals and exit." },
   { "--help-manual <man> [<file>]", "Print one help manual and exit." },
@@ -86,6 +95,60 @@
   return true;
 }
 
+bool cmDocumentation::PrintVersionJson(std::ostream& os)
+{
+#if !defined(CMAKE_BOOTSTRAP)
+  Json::Value root = Json::objectValue;
+
+  // Output version information
+  root["version"] = Json::objectValue;
+  root["version"]["major"] = 1;
+  root["version"]["minor"] = 0;
+
+  // CMake tool name
+  root["program"] = Json::objectValue;
+  root["program"]["name"] = this->GetNameString();
+
+  // CMake version information
+  root["program"]["version"] = Json::objectValue;
+  root["program"]["version"]["string"] = cmVersion::GetCMakeVersion();
+  root["program"]["version"]["major"] = cmVersion::GetMajorVersion();
+  root["program"]["version"]["minor"] = cmVersion::GetMinorVersion();
+  root["program"]["version"]["patch"] = cmVersion::GetPatchVersion();
+
+  // Dependencies
+  root["dependencies"] = Json::arrayValue;
+  std::vector<cmVersion::DependencyInfo> const& deps =
+    cmVersion::CollectDependencyInfo();
+  for (cmVersion::DependencyInfo const& dep : deps) {
+    Json::Value depJson = Json::objectValue;
+    depJson["name"] = dep.name;
+    if (!dep.version.empty()) {
+      depJson["version"] = dep.version;
+    }
+    depJson["type"] =
+      dep.type == cmVersion::DependencyType::System ? "system" : "bundled";
+    if (!dep.cameFrom.empty()) {
+      depJson["via"] = dep.cameFrom;
+    }
+    root["dependencies"].append(std::move(depJson));
+  }
+
+  // Output JSON
+  Json::StreamWriterBuilder builder;
+  builder["indentation"] = "  ";
+  std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
+  writer->write(root, &os);
+  os << std::endl;
+
+  return true;
+#else
+  os << "{\"error\":\"JSON version output not available in bootstrap build\"}"
+     << std::endl;
+  return false;
+#endif
+}
+
 bool cmDocumentation::PrintDocumentation(Type ht, std::ostream& os)
 {
   switch (ht) {
@@ -125,6 +188,8 @@
       return this->PrintHelpListGenerators(os);
     case cmDocumentation::Version:
       return this->PrintVersion(os);
+    case cmDocumentation::VersionJson:
+      return this->PrintVersionJson(os);
     case cmDocumentation::OldCustomModules:
       return this->PrintOldCustomModules(os);
     default:
@@ -376,9 +441,16 @@
       return true;
     } else if ((strcmp(argv[i], "--version") == 0) ||
                (strcmp(argv[i], "-version") == 0) ||
-               (strcmp(argv[i], "/V") == 0)) {
+               (strcmp(argv[i], "/V") == 0) ||
+               (strcmp(argv[i], "/version") == 0)) {
       help.HelpType = cmDocumentation::Version;
       i += int(get_opt_argument(i + 1, help.Filename));
+    } else if (strcmp(argv[i], "--version=json-v1") == 0 ||
+               strcmp(argv[i], "-version=json-v1") == 0 ||
+               strcmp(argv[i], "/V=json-v1") == 0 ||
+               strcmp(argv[i], "/version=json-v1") == 0) {
+      help.HelpType = cmDocumentation::VersionJson;
+      i += int(get_opt_argument(i + 1, help.Filename));
     }
     if (help.HelpType != None) {
       // This is a help option.  See if there is a file name given.
@@ -444,7 +516,7 @@
     std::string line;
     cmsys::ifstream fin(f.c_str());
     while (fin && cmSystemTools::GetLineFromStream(fin, line)) {
-      if (!line.empty() && (isalnum(line[0]) || line[0] == '<')) {
+      if (!line.empty() && (cmsysString_isalnum(line[0]) || line[0] == '<')) {
         names.push_back(line);
         break;
       }
@@ -462,7 +534,7 @@
   std::vector<std::string> files;
   this->GlobHelp(files, pattern);
   std::sort(files.begin(), files.end());
-  cmRST r(os, cmSystemTools::GetCMakeRoot() + "/Help");
+  cmRST r(os, cmStrCat(cmSystemTools::GetCMakeRoot(), "/Help"));
   for (std::string const& f : files) {
     found = r.ProcessFile(f) || found;
   }
@@ -479,7 +551,7 @@
   std::string mname = this->CurrentArgument;
   std::string::size_type mlen = mname.length();
   if (mlen > 3 && mname[mlen - 3] == '(' && mname[mlen - 1] == ')') {
-    mname = mname.substr(0, mlen - 3) + "." + mname[mlen - 2];
+    mname = cmStrCat(mname.substr(0, mlen - 3), '.', mname[mlen - 2]);
   }
   if (this->PrintFiles(os, cmStrCat("manual/", mname)) ||
       this->PrintFiles(os, cmStrCat("manual/", mname, ".[0-9]"))) {
diff --git a/Source/cmDocumentation.h b/Source/cmDocumentation.h
index 392e9a9..dd0fadb 100644
--- a/Source/cmDocumentation.h
+++ b/Source/cmDocumentation.h
@@ -24,6 +24,7 @@
   {
     None,
     Version,
+    VersionJson,
     Usage,
     Help,
     Full,
@@ -116,6 +117,7 @@
   bool PrintFiles(std::ostream& os, std::string const& pattern);
 
   bool PrintVersion(std::ostream& os);
+  bool PrintVersionJson(std::ostream& os);
   bool PrintUsage(std::ostream& os);
   bool PrintHelp(std::ostream& os);
   bool PrintHelpFull(std::ostream& os);
diff --git a/Source/cmDyndepCollation.cxx b/Source/cmDyndepCollation.cxx
index 7f8a9b8..2a17925 100644
--- a/Source/cmDyndepCollation.cxx
+++ b/Source/cmDyndepCollation.cxx
@@ -17,6 +17,7 @@
 #include <cm3p/json/value.h>
 
 #include "cmBuildDatabase.h"
+#include "cmCxxModuleMetadata.h"
 #include "cmExportBuildFileGenerator.h"
 #include "cmExportSet.h"
 #include "cmFileSet.h"
@@ -29,6 +30,7 @@
 #include "cmInstallExportGenerator.h"
 #include "cmInstallFileSetGenerator.h"
 #include "cmInstallGenerator.h"
+#include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmOutputConverter.h"
@@ -175,6 +177,30 @@
         Json::Value& tdi_module_info = tdi_cxx_module_info[obj_path] =
           Json::objectValue;
 
+        Json::Value& tdi_include_dirs =
+          tdi_module_info["include-directories"] = Json::arrayValue;
+        for (auto const& i : gt->GetIncludeDirectories(config, "CXX")) {
+          tdi_include_dirs.append(i.Value);
+        }
+
+        Json::Value& tdi_defs = tdi_module_info["definitions"] =
+          Json::arrayValue;
+        for (auto const& i : gt->GetCompileDefinitions(config, "CXX")) {
+          tdi_defs.append(i.Value);
+        }
+
+        Json::Value& tdi_opts = tdi_module_info["compile-options"] =
+          Json::arrayValue;
+        for (auto const& i : gt->GetCompileOptions(config, "CXX")) {
+          tdi_opts.append(i.Value);
+        }
+
+        Json::Value& tdi_feats = tdi_module_info["compile-features"] =
+          Json::arrayValue;
+        for (auto const& i : gt->GetCompileFeatures(config)) {
+          tdi_feats.append(i.Value);
+        }
+
         tdi_module_info["source"] = full_file;
         tdi_module_info["bmi-only"] = ct == CompileType::BmiOnly;
         tdi_module_info["relative-directory"] = files_per_dir.first;
@@ -343,6 +369,7 @@
 
   return tdi_exports;
 }
+
 }
 
 void cmDyndepCollation::AddCollationInformation(
@@ -373,6 +400,10 @@
   std::string Type;
   cmFileSetVisibility Visibility = cmFileSetVisibility::Private;
   cm::optional<std::string> Destination;
+  std::vector<std::string> IncludeDirectories;
+  std::vector<std::string> Definitions;
+  std::vector<std::string> CompileOptions;
+  std::vector<std::string> CompileFeatures;
 };
 
 struct CxxModuleDatabaseInfo
@@ -403,6 +434,13 @@
   bool Install;
 };
 
+struct CxxModuleExportOutputHelper
+{
+  CxxModuleExport const* Export;
+  std::unique_ptr<cmGeneratedFileStream> File;
+  cmCxxModuleMetadata Manifest;
+};
+
 struct cmCxxModuleExportInfo
 {
   std::map<std::string, SourceInfo> ObjectToSource;
@@ -489,6 +527,18 @@
       if (tdi_fs_dest.isString()) {
         fsi.Destination = tdi_fs_dest.asString();
       }
+      for (auto const& j : tdi_cxx_module_info["include-directories"]) {
+        fsi.IncludeDirectories.push_back(j.asString());
+      }
+      for (auto const& j : tdi_cxx_module_info["definitions"]) {
+        fsi.Definitions.push_back(j.asString());
+      }
+      for (auto const& j : tdi_cxx_module_info["compile-options"]) {
+        fsi.CompileOptions.push_back(j.asString());
+      }
+      for (auto const& j : tdi_cxx_module_info["compile-features"]) {
+        fsi.CompileFeatures.push_back(j.asString());
+      }
     }
   }
   Json::Value const& tdi_sources = tdi["sources"];
@@ -520,25 +570,30 @@
   // Prepare the export information blocks.
   std::string const config_upper =
     cmSystemTools::UpperCase(export_info.Config);
-  std::vector<
-    std::pair<std::unique_ptr<cmGeneratedFileStream>, CxxModuleExport const*>>
-    exports;
+  std::vector<CxxModuleExportOutputHelper> exports;
   for (auto const& exp : export_info.Exports) {
-    std::unique_ptr<cmGeneratedFileStream> properties;
+    CxxModuleExportOutputHelper exp_helper;
 
     std::string const export_dir =
       cmStrCat(exp.Prefix, '/', exp.CxxModuleInfoDir, '/');
     std::string const property_file_path =
-      cmStrCat(export_dir, "target-", exp.FilesystemName, '-',
-               export_info.Config, ".cmake");
-    properties = cm::make_unique<cmGeneratedFileStream>(property_file_path);
+      cmStrCat(export_dir, "target-"_s, exp.FilesystemName, '-',
+               export_info.Config, ".cmake"_s);
+    exp_helper.Manifest.MetadataFilePath =
+      cmStrCat(exp.Destination, '/', exp.CxxModuleInfoDir, "/target-"_s,
+               exp.FilesystemName, '-', export_info.Config, ".modules.json"_s);
+
+    exp_helper.File =
+      cm::make_unique<cmGeneratedFileStream>(property_file_path);
 
     // Set up the preamble.
-    *properties << "set_property(TARGET \"" << exp.Namespace << exp.Name
-                << "\"\n"
-                << "  PROPERTY IMPORTED_CXX_MODULES_" << config_upper << '\n';
+    *exp_helper.File << "set_property(TARGET \"" << exp.Namespace << exp.Name
+                     << "\"\n"
+                        "  PROPERTY IMPORTED_CXX_MODULES_"
+                     << config_upper << '\n';
 
-    exports.emplace_back(std::move(properties), &exp);
+    exp_helper.Export = &exp;
+    exports.emplace_back(std::move(exp_helper));
   }
 
   std::unique_ptr<cmBuildDatabase> module_database;
@@ -714,25 +769,30 @@
       auto m = cb.ModuleFile(p.LogicalName);
       if (m) {
         install_bmi_path = cmStrCat(
-          bmi_destination, cmEscape(cmSystemTools::GetFilenameName(*m)));
+          bmi_destination, cmEscape(cmSystemTools::GetFilenameNameView(*m)));
         build_bmi_path = cmEscape(*m);
       }
 
-      for (auto const& exp : exports) {
+      for (auto& exp : exports) {
         std::string iface_source;
-        if (exp.second->Install && file_set.Destination) {
-          auto dest = install_destination(*file_set.Destination);
+        cmCxxModuleMetadata::ModuleData mod;
+
+        if (exp.Export->Install && file_set.Destination) {
+          auto rel =
+            cmStrCat('/', file_set.RelativeDirectory,
+                     cmSystemTools::GetFilenameNameView(file_set.SourcePath));
           iface_source = cmStrCat(
-            dest.second, '/', cmEscape(file_set.RelativeDirectory),
-            cmEscape(cmSystemTools::GetFilenameName(file_set.SourcePath)));
+            install_destination(*file_set.Destination).second, cmEscape(rel));
+          mod.SourcePath = cmStrCat(*file_set.Destination, rel);
         } else {
           iface_source = cmEscape(file_set.SourcePath);
+          mod.SourcePath = file_set.SourcePath;
         }
 
         std::string bmi_path;
-        if (exp.second->Install && export_info.BmiInstallation) {
+        if (exp.Export->Install && export_info.BmiInstallation) {
           bmi_path = install_bmi_path;
-        } else if (!exp.second->Install) {
+        } else if (!exp.Export->Install) {
           bmi_path = build_bmi_path;
         }
 
@@ -742,12 +802,23 @@
           continue;
         }
 
-        *exp.first << "    \"" << cmEscape(p.LogicalName) << '='
-                   << iface_source;
+        mod.LogicalName = p.LogicalName;
+        mod.IsInterface = p.IsInterface;
+
+        // FIXME(#27565): Local arguments may refer to include directories or
+        // other resources which live in unknown locations on the consuming
+        // machine. There's no general-purpose way to solve this with module
+        // manifests as currently specified. For now, forego serializing them
+        // and rely on CPS to fill in the blanks.
+
+        exp.Manifest.Modules.emplace_back(std::move(mod));
+
+        *exp.File << "    \"" << cmEscape(p.LogicalName) << '='
+                  << iface_source;
         if (!bmi_path.empty()) {
-          *exp.first << ',' << bmi_path;
+          *exp.File << ',' << bmi_path;
         }
-        *exp.first << "\"\n";
+        *exp.File << "\"\n";
       }
 
       if (bmi_install_script) {
@@ -782,7 +853,7 @@
           *bmi_install_script
             << "  list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n"
                "    \""
-            << cmEscape(cmSystemTools::GetFilenameName(*m))
+            << cmEscape(cmSystemTools::GetFilenameNameView(*m))
             << "\")\n"
                "  if (CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n"
                "    message(WARNING\n"
@@ -800,9 +871,15 @@
     }
   }
 
-  // Add trailing parenthesis for the `set_property` call.
   for (auto const& exp : exports) {
-    *exp.first << ")\n";
+
+    cmCxxModuleMetadata::SaveToFile(
+      cmStrCat(exp.Export->Prefix, '/', exp.Export->CxxModuleInfoDir,
+               "/target-"_s, exp.Export->FilesystemName, '-',
+               export_info.Config, ".modules.json"_s),
+      exp.Manifest);
+
+    *exp.File << ")\n";
   }
 
   // Check that public sources only require public modules.
diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx
index 372fb9b..228e539 100644
--- a/Source/cmELF.cxx
+++ b/Source/cmELF.cxx
@@ -2,6 +2,7 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "cmELF.h"
 
+#include <algorithm>
 #include <cstddef>
 #include <cstdint>
 #include <map>
@@ -103,7 +104,7 @@
   virtual ~cmELFInternal() = default;
 
   // Forward to the per-class implementation.
-  virtual unsigned int GetNumberOfSections() const = 0;
+  virtual std::size_t GetNumberOfSections() const = 0;
   virtual unsigned long GetDynamicEntryPosition(int j) = 0;
   virtual cmELF::DynamicEntryList GetDynamicEntries() = 0;
   virtual std::vector<char> EncodeDynamicEntries(
@@ -213,7 +214,7 @@
                     ByteOrderType order);
 
   // Return the number of sections as specified by the ELF header.
-  unsigned int GetNumberOfSections() const override
+  std::size_t GetNumberOfSections() const override
   {
     return static_cast<unsigned int>(this->ELFHeader.e_shnum +
                                      this->SectionHeaders[0].sh_size);
@@ -371,12 +372,13 @@
     return !this->Stream->fail();
   }
 
-  bool LoadSectionHeader(unsigned int i)
+  bool LoadSectionHeader(std::size_t i)
   {
     // Read the section header from the file.
     this->Stream->seekg(this->ELFHeader.e_shoff +
                         this->ELFHeader.e_shentsize * i);
     if (!this->Read(this->SectionHeaders[i])) {
+      this->SetErrorMessage("Failed to load section headers.");
       return false;
     }
 
@@ -448,13 +450,16 @@
   this->Machine = this->ELFHeader.e_machine;
 
   // Load the section headers.
-  this->SectionHeaders.resize(
-    this->ELFHeader.e_shnum == 0 ? 1 : this->ELFHeader.e_shnum);
-  this->LoadSectionHeader(0);
-  this->SectionHeaders.resize(this->GetNumberOfSections());
-  for (unsigned int i = 1; i < this->GetNumberOfSections(); ++i) {
+  std::size_t const minSections = 1;
+  std::size_t numSections = this->ELFHeader.e_shnum;
+  this->SectionHeaders.resize(std::max(numSections, minSections));
+  if (!this->LoadSectionHeader(0)) {
+    return;
+  }
+  numSections = this->GetNumberOfSections();
+  this->SectionHeaders.resize(std::max(numSections, minSections));
+  for (std::size_t i = 1; i < numSections; ++i) {
     if (!this->LoadSectionHeader(i)) {
-      this->SetErrorMessage("Failed to load section headers.");
       return;
     }
   }
@@ -740,7 +745,7 @@
   return 0;
 }
 
-unsigned int cmELF::GetNumberOfSections() const
+std::size_t cmELF::GetNumberOfSections() const
 {
   if (this->Valid()) {
     return this->Internal->GetNumberOfSections();
diff --git a/Source/cmELF.h b/Source/cmELF.h
index 041b986..0528925 100644
--- a/Source/cmELF.h
+++ b/Source/cmELF.h
@@ -4,6 +4,7 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include <cstddef>
 #include <cstdint>
 #include <iosfwd>
 #include <memory>
@@ -73,7 +74,7 @@
   std::uint16_t GetMachine() const;
 
   /** Get the number of ELF sections present.  */
-  unsigned int GetNumberOfSections() const;
+  std::size_t GetNumberOfSections() const;
 
   /** Get the position of a DYNAMIC section header entry.  Returns
       zero on error.  */
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
index 2c04d60..63dcb60 100644
--- a/Source/cmExecuteProcessCommand.cxx
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -24,6 +24,8 @@
 #  include "cm_fileno.hxx"
 #endif
 
+#include "cmsys/String.h"
+
 #include "cmArgumentParser.h"
 #include "cmExecutionStatus.h"
 #include "cmList.h"
@@ -40,7 +42,7 @@
 namespace {
 bool cmExecuteProcessCommandIsWhitespace(char c)
 {
-  return (cmIsSpace(c) || c == '\n' || c == '\r');
+  return (cmsysString_isspace(c) || c == '\n' || c == '\r');
 }
 
 FILE* FopenCLOEXEC(std::string const& path, char const* mode)
@@ -326,12 +328,14 @@
   // Read the process output.
   struct ReadData
   {
+    uv_stream_t* Stream = nullptr;
     bool Finished = false;
     std::vector<char> Output;
-    cm::uv_pipe_ptr Stream;
   };
   ReadData outputData;
   ReadData errorData;
+  outputData.Stream = chain.OutputStream();
+  errorData.Stream = chain.ErrorStream();
   cmPolicies::PolicyStatus const cmp0176 =
     status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0176);
   cmProcessOutput::Encoding encoding =
@@ -353,9 +357,7 @@
   std::string strdata;
 
   std::unique_ptr<cmUVStreamReadHandle> outputHandle;
-  if (chain.OutputStream() >= 0) {
-    outputData.Stream.init(chain.GetLoop(), 0);
-    uv_pipe_open(outputData.Stream, chain.OutputStream());
+  if (outputData.Stream) {
     outputHandle = cmUVStreamRead(
       outputData.Stream,
       [&arguments, &processOutput, &outputData,
@@ -377,10 +379,7 @@
     outputData.Finished = true;
   }
   std::unique_ptr<cmUVStreamReadHandle> errorHandle;
-  if (chain.ErrorStream() >= 0 &&
-      chain.ErrorStream() != chain.OutputStream()) {
-    errorData.Stream.init(chain.GetLoop(), 0);
-    uv_pipe_open(errorData.Stream, chain.ErrorStream());
+  if (errorData.Stream) {
     errorHandle = cmUVStreamRead(
       errorData.Stream,
       [&arguments, &processOutput, &errorData,
diff --git a/Source/cmExperimental.cxx b/Source/cmExperimental.cxx
index b7aec46..acf8e5c 100644
--- a/Source/cmExperimental.cxx
+++ b/Source/cmExperimental.cxx
@@ -31,28 +31,19 @@
     cmExperimental::TryCompileCondition::Always },
   // CxxImportStd
   { "CxxImportStd",
-    "d0edc3af-4c50-42ea-a356-e2862fe7a444",
+    "451f2fe2-a8a2-47c3-bc32-94786d8fc91b",
     "CMAKE_EXPERIMENTAL_CXX_IMPORT_STD",
     "CMake's support for `import std;` in C++23 and newer is experimental. It "
     "is meant only for experimentation and feedback to CMake developers.",
     {},
     cmExperimental::TryCompileCondition::Always },
-  // ImportPackageInfo
-  { "ImportPackageInfo",
-    "e82e467b-f997-4464-8ace-b00808fff261",
-    "CMAKE_EXPERIMENTAL_FIND_CPS_PACKAGES",
-    "CMake's support for importing package information in the Common Package "
-    "Specification format (via find_package) is experimental. It is meant "
-    "only for experimentation and feedback to CMake developers.",
-    {},
-    cmExperimental::TryCompileCondition::Always },
-  // ExportPackageInfo
-  { "ExportPackageInfo",
-    "b80be207-778e-46ba-8080-b23bba22639e",
-    "CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO",
-    "CMake's support for exporting package information in the Common Package "
-    "Specification format is experimental. It is meant only for "
-    "experimentation and feedback to CMake developers.",
+  // MappedPackageInfo
+  { "MappedPackageInfo",
+    "ababa1b5-7099-495f-a9cd-e22d38f274f2",
+    "CMAKE_EXPERIMENTAL_MAPPED_PACKAGE_INFO",
+    "CMake's support for generating package information in the Common Package "
+    "Specification format from CMake script exports is experimental. It is "
+    "meant only for experimentation and feedback to CMake developers.",
     {},
     cmExperimental::TryCompileCondition::Always },
   // ExportBuildDatabase
@@ -63,12 +54,20 @@
     "meant only for experimentation and feedback to CMake developers.",
     {},
     cmExperimental::TryCompileCondition::Never },
-  // Instrumentation
-  { "Instrumentation",
-    "ec7aa2dc-b87f-45a3-8022-fe01c5f59984",
-    "CMAKE_EXPERIMENTAL_INSTRUMENTATION",
-    "CMake's support for collecting instrumentation data is experimental. It "
-    "is meant only for experimentation and feedback to CMake developers.",
+  { "GenerateSbom",
+    "ca494ed3-b261-4205-a01f-603c95e4cae0",
+    "CMAKE_EXPERIMENTAL_GENERATE_SBOM",
+    "CMake's support for generating software bill of materials (Sbom) "
+    "information in SPDX format is experimental. It is meant only for "
+    "experimentation and feedback to CMake developers.",
+    {},
+    cmExperimental::TryCompileCondition::Never },
+  // Rust support
+  { "Rust",
+    "3cc9b32c-47d3-4056-8953-d74e69fc0d6c",
+    "CMAKE_EXPERIMENTAL_RUST",
+    "CMake's support for the Rust programming language is experimental. "
+    "It is meant only for experimentation and feedback to CMake developers.",
     {},
     cmExperimental::TryCompileCondition::Never },
 };
diff --git a/Source/cmExperimental.h b/Source/cmExperimental.h
index 54fd691..dcd99eb 100644
--- a/Source/cmExperimental.h
+++ b/Source/cmExperimental.h
@@ -19,10 +19,10 @@
   {
     ExportPackageDependencies,
     CxxImportStd,
-    ImportPackageInfo,
-    ExportPackageInfo,
+    MappedPackageInfo,
     ExportBuildDatabase,
-    Instrumentation,
+    GenerateSbom,
+    Rust,
 
     Sentinel,
   };
diff --git a/Source/cmExportAndroidMKGenerator.cxx b/Source/cmExportAndroidMKGenerator.cxx
index 524fe58..0b125f7 100644
--- a/Source/cmExportAndroidMKGenerator.cxx
+++ b/Source/cmExportAndroidMKGenerator.cxx
@@ -68,9 +68,9 @@
 
             if (gt->GetType() == cmStateEnums::SHARED_LIBRARY ||
                 gt->GetType() == cmStateEnums::MODULE_LIBRARY) {
-              sharedLibs += " " + lib;
+              sharedLibs = cmStrCat(std::move(sharedLibs), ' ', lib);
             } else {
-              staticLibs += " " + lib;
+              staticLibs = cmStrCat(std::move(staticLibs), ' ', lib);
             }
           } else {
             bool relpath = false;
@@ -82,10 +82,10 @@
             // if it is full or a link library then use string directly
             if (cmSystemTools::FileIsFullPath(lib) ||
                 cmHasLiteralPrefix(lib, "-l") || relpath) {
-              ldlibs += " " + lib;
+              ldlibs = cmStrCat(std::move(ldlibs), ' ', lib);
               // if it is not a path and does not have a -l then add -l
             } else if (!lib.empty()) {
-              ldlibs += " -l" + lib;
+              ldlibs = cmStrCat(std::move(ldlibs), " -l", lib);
             }
           }
         }
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index 332a6c1..ee12b1d 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -16,7 +16,6 @@
 #include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
-#include "cmMessageType.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmTarget.h"
@@ -242,12 +241,11 @@
   this->ReportError(e.str());
 }
 
-void cmExportBuildFileGenerator::ReportError(
-  std::string const& errorMessage) const
+void cmExportBuildFileGenerator::IssueMessage(MessageType type,
+                                              std::string const& message) const
 {
   this->LG->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
-    MessageType::FATAL_ERROR, errorMessage,
-    this->LG->GetMakefile()->GetBacktrace());
+    type, message, this->LG->GetMakefile()->GetBacktrace());
 }
 
 std::string cmExportBuildFileGenerator::InstallNameDir(
diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h
index 6b30815..575d8e2 100644
--- a/Source/cmExportBuildFileGenerator.h
+++ b/Source/cmExportBuildFileGenerator.h
@@ -86,7 +86,8 @@
   void ComplainAboutDuplicateTarget(
     std::string const& targetName) const override;
 
-  void ReportError(std::string const& errorMessage) const override;
+  void IssueMessage(MessageType type,
+                    std::string const& message) const override;
 
   /** Fill in properties indicating built file locations.  */
   void SetImportLocationProperty(std::string const& config,
diff --git a/Source/cmExportBuildPackageInfoGenerator.cxx b/Source/cmExportBuildPackageInfoGenerator.cxx
index a8546c0..dda6dc8 100644
--- a/Source/cmExportBuildPackageInfoGenerator.cxx
+++ b/Source/cmExportBuildPackageInfoGenerator.cxx
@@ -32,7 +32,7 @@
     return false;
   }
 
-  if (!this->CheckDefaultTargets()) {
+  if (!this->CheckPackage()) {
     return false;
   }
 
@@ -114,6 +114,9 @@
 
   Json::Value component =
     this->GenerateInterfaceConfigProperties(suffix, properties);
+
+  this->GenerateCxxModules(component, target, this->FileDir, config);
+
   if (!component.empty()) {
     configurations[config.empty() ? std::string{ "noconfig" } : config] =
       std::move(component);
@@ -122,7 +125,5 @@
 
 std::string cmExportBuildPackageInfoGenerator::GetCxxModulesDirectory() const
 {
-  // TODO: Implement a not-CMake-specific mechanism for providing module
-  // information.
-  return {};
+  return this->CxxModulesDirectory;
 }
diff --git a/Source/cmExportBuildPackageInfoGenerator.h b/Source/cmExportBuildPackageInfoGenerator.h
index 0851d33..6be0c43 100644
--- a/Source/cmExportBuildPackageInfoGenerator.h
+++ b/Source/cmExportBuildPackageInfoGenerator.h
@@ -46,5 +46,4 @@
                                          std::string const& config);
 
   std::string GetCxxModulesDirectory() const override;
-  // TODO: Generate C++ module info in a not-CMake-specific format.
 };
diff --git a/Source/cmExportBuildSbomGenerator.cxx b/Source/cmExportBuildSbomGenerator.cxx
new file mode 100644
index 0000000..afb1491
--- /dev/null
+++ b/Source/cmExportBuildSbomGenerator.cxx
@@ -0,0 +1,89 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#include "cmExportBuildSbomGenerator.h"
+
+#include <functional>
+#include <utility>
+#include <vector>
+
+#include <cmext/string_view>
+
+#include "cmGeneratorExpression.h"
+#include "cmSbomArguments.h"
+#include "cmSbomObject.h"
+#include "cmSpdx.h"
+#include "cmStringAlgorithms.h"
+
+class cmGeneratorTarget;
+
+cmExportBuildSbomGenerator::cmExportBuildSbomGenerator(cmSbomArguments args)
+  : cmExportSbomGenerator(args)
+{
+  this->SetNamespace(cmStrCat(this->GetPackageName(), "::"_s));
+}
+
+bool cmExportBuildSbomGenerator::GenerateMainFile(std::ostream& os)
+{
+  if (!this->CollectExports([&](cmGeneratorTarget const*) {})) {
+    return false;
+  }
+
+  cmSbomDocument doc;
+  doc.Graph.reserve(256);
+
+  cmSpdxCreationInfo const* ci =
+    insert_back(doc.Graph, this->GenerateCreationInfo());
+  cmSpdxDocument* project = insert_back(doc.Graph, this->GenerateSbom(ci));
+  std::vector<TargetProperties> targets;
+
+  for (auto const& exp : this->Exports) {
+    cmGeneratorTarget const* target = exp.Target;
+
+    ImportPropertyMap properties;
+    this->PopulateInterfaceProperties(target, properties);
+    this->PopulateInterfaceLinkLibrariesProperty(
+      target, cmGeneratorExpression::BuildInterface, properties);
+    this->PopulateLinkLibrariesProperty(
+      target, cmGeneratorExpression::BuildInterface, properties);
+
+    targets.push_back(
+      TargetProperties{ insert_back(project->RootElements,
+                                    this->GenerateImportTarget(ci, target)),
+                        target, std::move(properties) });
+  }
+
+  for (auto const& target : targets) {
+    this->GenerateProperties(doc, project, ci, target, targets);
+  }
+
+  this->WriteSbom(doc, os);
+  return true;
+}
+
+void cmExportBuildSbomGenerator::HandleMissingTarget(
+  std::string& /* link_libs */, cmGeneratorTarget const* /* depender */,
+  cmGeneratorTarget* /* dependee */)
+{
+}
+
+std::string cmExportBuildSbomGenerator::GetCxxModulesDirectory() const
+{
+  return {};
+}
+
+cm::string_view cmExportBuildSbomGenerator::GetImportPrefixWithSlash() const
+{
+  return "";
+}
+
+std::string cmExportBuildSbomGenerator::GetCxxModuleFile(
+  std::string const& /*name*/) const
+{
+  return {};
+}
+
+void cmExportBuildSbomGenerator::GenerateCxxModuleConfigInformation(
+  std::string const& /*name*/, std::ostream& /*os*/) const
+{
+  // TODO
+}
diff --git a/Source/cmExportBuildSbomGenerator.h b/Source/cmExportBuildSbomGenerator.h
new file mode 100644
index 0000000..c84c373
--- /dev/null
+++ b/Source/cmExportBuildSbomGenerator.h
@@ -0,0 +1,41 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <iosfwd>
+#include <string>
+
+#include <cm/string_view>
+
+#include "cmExportBuildFileGenerator.h"
+#include "cmExportSbomGenerator.h"
+
+class cmSbomArguments;
+
+class cmExportBuildSbomGenerator
+  : public cmExportBuildFileGenerator
+  , public cmExportSbomGenerator
+{
+public:
+  cmExportBuildSbomGenerator(cmSbomArguments args);
+
+protected:
+  void HandleMissingTarget(std::string& link_libs,
+                           cmGeneratorTarget const* depender,
+                           cmGeneratorTarget* dependee) override;
+  bool GenerateMainFile(std::ostream& os) override;
+  void GenerateImportTargetsConfig(std::ostream&, std::string const&,
+                                   std::string const&) override
+  {
+  }
+  std::string GetCxxModulesDirectory() const override;
+
+  cm::string_view GetImportPrefixWithSlash() const override;
+
+  std::string GetCxxModuleFile(std::string const& /*name*/) const override;
+
+  void GenerateCxxModuleConfigInformation(std::string const& /*name*/,
+                                          std::ostream& /*os*/) const override;
+};
diff --git a/Source/cmExportCMakeConfigGenerator.cxx b/Source/cmExportCMakeConfigGenerator.cxx
index 47ea974..83307d7 100644
--- a/Source/cmExportCMakeConfigGenerator.cxx
+++ b/Source/cmExportCMakeConfigGenerator.cxx
@@ -173,7 +173,7 @@
   // Isolate the file policy level.
   // Support CMake versions as far back as the
   // RequiredCMakeVersion{Major,Minor,Patch}, but also support using NEW
-  // policy settings for up to CMake 4.0 (this upper limit may be reviewed
+  // policy settings for up to CMake 4.1 (this upper limit may be reviewed
   // and increased from time to time). This reduces the opportunity for CMake
   // warnings when an older export file is later used with newer CMake
   // versions.
@@ -182,7 +182,7 @@
         "cmake_policy(VERSION "
      << this->RequiredCMakeVersionMajor << '.'
      << this->RequiredCMakeVersionMinor << '.'
-     << this->RequiredCMakeVersionPatch << "...4.0)\n";
+     << this->RequiredCMakeVersionPatch << "...4.1)\n";
   /* clang-format on */
 }
 
diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx
index b4f7343..38c2458 100644
--- a/Source/cmExportCommand.cxx
+++ b/Source/cmExportCommand.cxx
@@ -22,6 +22,7 @@
 #include "cmExportBuildCMakeConfigGenerator.h"
 #include "cmExportBuildFileGenerator.h"
 #include "cmExportBuildPackageInfoGenerator.h"
+#include "cmExportBuildSbomGenerator.h"
 #include "cmExportSet.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
@@ -30,6 +31,7 @@
 #include "cmPackageInfoArguments.h"
 #include "cmPolicies.h"
 #include "cmRange.h"
+#include "cmSbomArguments.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSubcommandTable.h"
@@ -49,6 +51,42 @@
 static void StorePackageRegistry(cmMakefile& mf, std::string const& package,
                                  char const* content, char const* hash);
 
+static cm::optional<cmExportSet*> GetExportSet(std::string const& name,
+                                               cmGlobalGenerator* generator,
+                                               cmExecutionStatus& status)
+{
+  cmExportSetMap& setMap = generator->GetExportSets();
+  auto const it = setMap.find(name);
+  if (it == setMap.end()) {
+    status.SetError(cmStrCat("Export set \""_s, name, "\" not found."_s));
+    return cm::nullopt;
+  }
+  return &it->second;
+}
+
+static void AddExportGenerator(
+  cmMakefile& makefile, cmGlobalGenerator* globalGenerator,
+  std::unique_ptr<cmExportBuildFileGenerator> exportGenerator,
+  std::string const& fileName, cmExportSet* exportSet,
+  std::string const& cxxModulesDirectory)
+{
+  exportGenerator->SetExportFile(fileName.c_str());
+  exportGenerator->SetCxxModuleDirectory(cxxModulesDirectory);
+  if (exportSet) {
+    exportGenerator->SetExportSet(exportSet);
+  }
+  std::vector<std::string> configurationTypes =
+    makefile.GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+
+  for (std::string const& ct : configurationTypes) {
+    exportGenerator->AddConfiguration(ct);
+  }
+  if (exportSet) {
+    globalGenerator->AddBuildExportExportSet(exportGenerator.get());
+  }
+  makefile.AddExportBuildFileGenerator(std::move(exportGenerator));
+}
+
 static bool HandleTargetsMode(std::vector<std::string> const& args,
                               cmExecutionStatus& status)
 {
@@ -79,7 +117,8 @@
   Arguments arguments = parser.Parse(args, &unknownArgs);
 
   if (!unknownArgs.empty()) {
-    status.SetError("Unknown argument: \"" + unknownArgs.front() + "\".");
+    status.SetError(
+      cmStrCat("Unknown argument: \"", unknownArgs.front(), "\"."));
     return false;
   }
 
@@ -92,8 +131,7 @@
     fname = arguments.ExportSetName + ".cmake";
   } else {
     // Make sure the file has a .cmake extension.
-    if (cmSystemTools::GetFilenameLastExtension(arguments.Filename) !=
-        ".cmake") {
+    if (!cmHasSuffix(arguments.Filename, ".cmake"_s)) {
       std::ostringstream e;
       e << "FILE option given filename \"" << arguments.Filename
         << "\" which does not have an extension of \".cmake\".\n";
@@ -117,7 +155,7 @@
   } else {
     // Interpret relative paths with respect to the current build dir.
     std::string const& dir = mf.GetCurrentBinaryDirectory();
-    fname = dir + "/" + fname;
+    fname = cmStrCat(dir, '/', fname);
   }
 
   std::vector<cmExportBuildFileGenerator::TargetExport> targets;
@@ -209,13 +247,12 @@
 static bool HandleExportMode(std::vector<std::string> const& args,
                              cmExecutionStatus& status)
 {
-  struct ExportArguments
+  struct ExportArguments : public ArgumentParser::ParseResult
   {
     ArgumentParser::NonEmpty<std::string> ExportSetName;
-    ArgumentParser::NonEmpty<std::string> Namespace;
+    ArgumentParser::MaybeEmpty<std::string> Namespace;
     ArgumentParser::NonEmpty<std::string> Filename;
     ArgumentParser::NonEmpty<std::string> CxxModulesDirectory;
-    cm::optional<cmPackageInfoArguments> PackageInfo;
     bool ExportPackageDependencies = false;
   };
 
@@ -233,57 +270,32 @@
                 &ExportArguments::ExportPackageDependencies);
   }
 
-  cmArgumentParser<cmPackageInfoArguments> packageInfoParser;
-  cmPackageInfoArguments::Bind(packageInfoParser);
-
-  if (cmExperimental::HasSupportEnabled(
-        status.GetMakefile(), cmExperimental::Feature::ExportPackageInfo)) {
-    parser.BindSubParser("PACKAGE_INFO"_s, packageInfoParser,
-                         &ExportArguments::PackageInfo);
-  }
-
   std::vector<std::string> unknownArgs;
   ExportArguments arguments = parser.Parse(args, &unknownArgs);
 
   cmMakefile& mf = status.GetMakefile();
   cmGlobalGenerator* gg = mf.GetGlobalGenerator();
 
-  if (arguments.PackageInfo) {
-    if (arguments.PackageInfo->PackageName.empty()) {
-      // TODO: Fix our use of the parser to enforce this.
-      status.SetError("PACKAGE_INFO missing required value.");
+  if (!arguments.Check(args[0], &unknownArgs, status)) {
+    cmPolicies::PolicyStatus const p =
+      status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0208);
+    if (!unknownArgs.empty() || p == cmPolicies::NEW) {
       return false;
     }
-    if (!arguments.Filename.empty()) {
-      status.SetError("PACKAGE_INFO and FILE are mutually exclusive.");
-      return false;
+    if (p == cmPolicies::WARN) {
+      status.GetMakefile().IssueMessage(
+        MessageType::AUTHOR_WARNING, cmStrCat("export "_s, status.GetError()));
+      status.GetMakefile().IssueMessage(
+        MessageType::AUTHOR_WARNING,
+        cmPolicies::GetPolicyWarning(cmPolicies::CMP0208));
     }
-    if (!arguments.Namespace.empty()) {
-      status.SetError("PACKAGE_INFO and NAMESPACE are mutually exclusive.");
-      return false;
-    }
-    if (!arguments.PackageInfo->Check(status) ||
-        !arguments.PackageInfo->SetMetadataFromProject(status)) {
-      return false;
-    }
-  }
-
-  if (!unknownArgs.empty()) {
-    status.SetError("EXPORT given unknown argument: \"" + unknownArgs.front() +
-                    "\".");
-    return false;
   }
 
   std::string fname;
   if (arguments.Filename.empty()) {
-    if (arguments.PackageInfo) {
-      fname = arguments.PackageInfo->GetPackageFileName();
-    } else {
-      fname = arguments.ExportSetName + ".cmake";
-    }
+    fname = arguments.ExportSetName + ".cmake";
   } else {
-    if (cmSystemTools::GetFilenameLastExtension(arguments.Filename) !=
-        ".cmake") {
+    if (!cmHasSuffix(arguments.Filename, ".cmake"_s)) {
       std::ostringstream e;
       e << "FILE option given filename \"" << arguments.Filename
         << "\" which does not have an extension of \".cmake\".\n";
@@ -304,60 +316,111 @@
   } else {
     // Interpret relative paths with respect to the current build dir.
     std::string const& dir = mf.GetCurrentBinaryDirectory();
-    fname = dir + "/" + fname;
+    fname = cmStrCat(dir, '/', fname);
   }
 
-  if (gg->GetExportedTargetsFile(fname)) {
-    if (arguments.PackageInfo) {
-      status.SetError(cmStrCat("command already specified for the file "_s,
-                               cmSystemTools::GetFilenameName(fname), '.'));
-      return false;
-    }
-  }
-
-  cmExportSet* exportSet = nullptr;
-  cmExportSetMap& setMap = gg->GetExportSets();
-  auto const it = setMap.find(arguments.ExportSetName);
-  if (it == setMap.end()) {
-    std::ostringstream e;
-    e << "Export set \"" << arguments.ExportSetName << "\" not found.";
-    status.SetError(e.str());
+  cm::optional<cmExportSet*> const exportSet =
+    GetExportSet(arguments.ExportSetName, gg, status);
+  if (!exportSet) {
     return false;
   }
-  exportSet = &it->second;
 
   // Set up export file generation.
-  std::unique_ptr<cmExportBuildFileGenerator> ebfg = nullptr;
-  if (arguments.PackageInfo) {
-    auto ebpg = cm::make_unique<cmExportBuildPackageInfoGenerator>(
-      *arguments.PackageInfo);
-    ebfg = std::move(ebpg);
-  } else {
-    auto ebcg = cm::make_unique<cmExportBuildCMakeConfigGenerator>();
-    ebcg->SetNamespace(arguments.Namespace);
-    ebcg->SetExportPackageDependencies(arguments.ExportPackageDependencies);
-    ebfg = std::move(ebcg);
-  }
+  auto ebcg = cm::make_unique<cmExportBuildCMakeConfigGenerator>();
+  ebcg->SetNamespace(arguments.Namespace);
+  ebcg->SetExportPackageDependencies(arguments.ExportPackageDependencies);
 
-  ebfg->SetExportFile(fname.c_str());
-  ebfg->SetCxxModuleDirectory(arguments.CxxModulesDirectory);
-  if (exportSet) {
-    ebfg->SetExportSet(exportSet);
-  }
-  std::vector<std::string> configurationTypes =
-    mf.GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
-
-  for (std::string const& ct : configurationTypes) {
-    ebfg->AddConfiguration(ct);
-  }
-  if (exportSet) {
-    gg->AddBuildExportExportSet(ebfg.get());
-  }
-
-  mf.AddExportBuildFileGenerator(std::move(ebfg));
+  AddExportGenerator(mf, gg, std::move(ebcg), fname, *exportSet,
+                     arguments.CxxModulesDirectory);
   return true;
 }
 
+template <typename ArgumentsType, typename GeneratorType>
+static bool HandleSpecialExportMode(std::vector<std::string> const& args,
+                                    cmExecutionStatus& status)
+{
+  struct ExportArguments
+    : public ArgumentsType
+    , public ArgumentParser::ParseResult
+  {
+    ArgumentParser::NonEmpty<std::string> ExportSetName;
+    ArgumentParser::NonEmpty<std::string> CxxModulesDirectory;
+
+    using ArgumentsType::Check;
+    using ArgumentParser::ParseResult::Check;
+  };
+
+  auto parser =
+    cmArgumentParser<ExportArguments>{}
+      .Bind("EXPORT"_s, &ExportArguments::ExportSetName)
+      .Bind("CXX_MODULES_DIRECTORY"_s, &ExportArguments::CxxModulesDirectory);
+  ArgumentsType::Bind(parser);
+
+  std::vector<std::string> unknownArgs;
+  ExportArguments arguments = parser.Parse(args, &unknownArgs);
+
+  if (!arguments.Check(args[0], &unknownArgs, status)) {
+    return false;
+  }
+
+  if (arguments.ExportSetName.empty()) {
+    status.SetError(cmStrCat(args[0], " missing EXPORT."));
+    return false;
+  }
+
+  if (!arguments.Check(status) || !arguments.SetMetadataFromProject(status)) {
+    return false;
+  }
+
+  cmMakefile& mf = status.GetMakefile();
+  cmGlobalGenerator* gg = mf.GetGlobalGenerator();
+
+  std::string const& dir = mf.GetCurrentBinaryDirectory();
+  std::string const fname = cmStrCat(dir, '/', arguments.GetPackageFileName());
+
+  if (gg->GetExportedTargetsFile(fname)) {
+    status.SetError(cmStrCat("command already specified for the file "_s,
+                             cmSystemTools::GetFilenameNameView(fname), '.'));
+    return false;
+  }
+
+  // Look up the export set
+  cm::optional<cmExportSet*> const exportSet =
+    GetExportSet(arguments.ExportSetName, gg, status);
+  if (!exportSet) {
+    return false;
+  }
+
+  // Create the export build generator
+  auto ebpg = cm::make_unique<GeneratorType>(arguments);
+  AddExportGenerator(mf, gg, std::move(ebpg), fname, *exportSet,
+                     arguments.CxxModulesDirectory);
+  return true;
+}
+
+static bool HandlePackageInfoMode(std::vector<std::string> const& args,
+                                  cmExecutionStatus& status)
+{
+  using arg_t = cmPackageInfoArguments;
+  using gen_t = cmExportBuildPackageInfoGenerator;
+  return HandleSpecialExportMode<arg_t, gen_t>(args, status);
+}
+
+static bool HandleSbomMode(std::vector<std::string> const& args,
+                           cmExecutionStatus& status)
+{
+  if (!cmExperimental::HasSupportEnabled(
+        status.GetMakefile(), cmExperimental::Feature::GenerateSbom)) {
+    status.SetError("does not recognize sub-command SBOM");
+    return false;
+  }
+
+  using arg_t = cmSbomArguments;
+  using gen_t = cmExportBuildSbomGenerator;
+  status.GetMakefile().SetExplicitlyGeneratesSbom(true);
+  return HandleSpecialExportMode<arg_t, gen_t>(args, status);
+}
+
 static bool HandleSetupMode(std::vector<std::string> const& args,
                             cmExecutionStatus& status)
 {
@@ -414,8 +477,8 @@
         cmMakeRange(packageDependencyArgs).advance(1), &unknownArgs);
 
     if (!unknownArgs.empty()) {
-      status.SetError("PACKAGE_DEPENDENCY given unknown argument: \"" +
-                      unknownArgs.front() + "\".");
+      status.SetError(cmStrCat("PACKAGE_DEPENDENCY given unknown argument: \"",
+                               unknownArgs.front(), "\"."));
       return false;
     }
     auto& packageDependency =
@@ -457,8 +520,8 @@
       targetParser.Parse(cmMakeRange(targetArgs).advance(1), &unknownArgs);
 
     if (!unknownArgs.empty()) {
-      status.SetError("TARGET given unknown argument: \"" +
-                      unknownArgs.front() + "\".");
+      status.SetError(cmStrCat("TARGET given unknown argument: \"",
+                               unknownArgs.front(), "\"."));
       return false;
     }
     exportSet.SetXcFrameworkLocation(targetArgs.front(),
@@ -630,6 +693,8 @@
     { "EXPORT"_s, HandleExportMode },
     { "SETUP"_s, HandleSetupMode },
     { "PACKAGE"_s, HandlePackageMode },
+    { "PACKAGE_INFO"_s, HandlePackageInfoMode },
+    { "SBOM"_s, HandleSbomMode },
   };
 
   return subcommand(args[0], args, status);
diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h
index bae6b50..f53cba7 100644
--- a/Source/cmExportFileGenerator.h
+++ b/Source/cmExportFileGenerator.h
@@ -13,6 +13,7 @@
 #include <cm/string_view>
 
 #include "cmGeneratorExpression.h"
+#include "cmMessageType.h"
 
 class cmExportSet;
 class cmGeneratorTarget;
@@ -120,7 +121,13 @@
     cmGeneratorExpression::PreprocessContext preprocessRule,
     ImportPropertyMap& properties);
 
-  virtual void ReportError(std::string const& errorMessage) const = 0;
+  virtual void IssueMessage(MessageType type,
+                            std::string const& message) const = 0;
+
+  void ReportError(std::string const& errorMessage) const
+  {
+    this->IssueMessage(MessageType::FATAL_ERROR, errorMessage);
+  }
 
   struct ExportInfo
   {
diff --git a/Source/cmExportInstallCMakeConfigGenerator.cxx b/Source/cmExportInstallCMakeConfigGenerator.cxx
index 1eb3394..d803121 100644
--- a/Source/cmExportInstallCMakeConfigGenerator.cxx
+++ b/Source/cmExportInstallCMakeConfigGenerator.cxx
@@ -157,11 +157,11 @@
   } else {
     // Add code to compute the installation prefix relative to the
     // import file location.
-    std::string absDest = installPrefix + "/" + expDest;
-    std::string absDestS = absDest + "/";
+    std::string absDest = cmStrCat(installPrefix, '/', expDest);
+    std::string absDestS = absDest + '/';
     os << "# Compute the installation prefix relative to this file.\n"
-       << "get_filename_component(_IMPORT_PREFIX"
-       << " \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n";
+          "get_filename_component(_IMPORT_PREFIX"
+          " \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n";
     if (cmHasLiteralPrefix(absDestS, "/lib/") ||
         cmHasLiteralPrefix(absDestS, "/lib64/") ||
         cmHasLiteralPrefix(absDestS, "/libx32/") ||
@@ -189,9 +189,9 @@
       dest = cmSystemTools::GetFilenamePath(dest);
     }
     os << "if(_IMPORT_PREFIX STREQUAL \"/\")\n"
-       << "  set(_IMPORT_PREFIX \"\")\n"
-       << "endif()\n"
-       << "\n";
+          "  set(_IMPORT_PREFIX \"\")\n"
+          "endif()\n"
+          "\n";
   }
 }
 
@@ -200,8 +200,8 @@
 {
   /* clang-format off */
   os << "# Cleanup temporary variables.\n"
-     << "set(_IMPORT_PREFIX)\n"
-     << "\n";
+        "set(_IMPORT_PREFIX)\n"
+        "\n";
   /* clang-format on */
 }
 
@@ -210,14 +210,14 @@
   // Now load per-configuration properties for them.
   /* clang-format off */
   os << "# Load information for each installed configuration.\n"
-     << "file(GLOB _cmake_config_files \"${CMAKE_CURRENT_LIST_DIR}/"
-     << this->GetConfigImportFileGlob() << "\")\n"
-     << "foreach(_cmake_config_file IN LISTS _cmake_config_files)\n"
-     << "  include(\"${_cmake_config_file}\")\n"
-     << "endforeach()\n"
-     << "unset(_cmake_config_file)\n"
-     << "unset(_cmake_config_files)\n"
-     << "\n";
+        "file(GLOB _cmake_config_files \"${CMAKE_CURRENT_LIST_DIR}/"
+        << this->GetConfigImportFileGlob() << "\")\n"
+        "foreach(_cmake_config_file IN LISTS _cmake_config_files)\n"
+        "  include(\"${_cmake_config_file}\")\n"
+        "endforeach()\n"
+        "unset(_cmake_config_file)\n"
+        "unset(_cmake_config_files)\n"
+        "\n";
   /* clang-format on */
 }
 
@@ -382,7 +382,7 @@
       auto prefix = it.first.empty() ? "" : cmStrCat(it.first, '/');
       for (auto const& filename : it.second) {
         auto relFile =
-          cmStrCat(prefix, cmSystemTools::GetFilenameName(filename));
+          cmStrCat(prefix, cmSystemTools::GetFilenameNameView(filename));
         auto escapedFile =
           cmStrCat(dest,
                    cmOutputConverter::EscapeForCMake(
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index 9accd7d..db75480 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -335,11 +335,11 @@
   this->ReportError(e.str());
 }
 
-void cmExportInstallFileGenerator::ReportError(
-  std::string const& errorMessage) const
+void cmExportInstallFileGenerator::IssueMessage(
+  MessageType type, std::string const& message) const
 {
   this->IEGen->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
-    MessageType::FATAL_ERROR, errorMessage,
+    type, message,
     this->IEGen->GetLocalGenerator()->GetMakefile()->GetBacktrace());
 }
 
@@ -388,9 +388,8 @@
   cmGeneratorTarget const* const gt = targetExport->Target;
 
   std::string includesDestinationDirs;
-  this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", gt,
-                                  cmGeneratorExpression::InstallInterface,
-                                  properties);
+  this->PopulateSystemIncludeDirectoriesInterface(
+    gt, cmGeneratorExpression::InstallInterface, properties);
   this->PopulateIncludeDirectoriesInterface(
     gt, cmGeneratorExpression::InstallInterface, properties, *targetExport,
     includesDestinationDirs);
@@ -440,11 +439,11 @@
     if (cmHasPrefix(li, this->GetImportPrefixWithSlash())) {
       continue;
     }
-    std::ostringstream e;
     if (genexPos != std::string::npos) {
       hadFatalError = true;
     }
     if (!cmSystemTools::FileIsFullPath(li)) {
+      std::ostringstream e;
       /* clang-format off */
       e << "Target \"" << target->GetName() << "\" " << prop <<
            " property contains relative path:\n"
@@ -466,6 +465,7 @@
       }
     }
     if (inBinary) {
+      std::ostringstream e;
       /* clang-format off */
       e << "Target \"" << target->GetName() << "\" " << prop <<
            " property contains path:\n"
@@ -476,6 +476,7 @@
     }
     if (!inSourceBuild) {
       if (inSource) {
+        std::ostringstream e;
         e << "Target \"" << target->GetName() << "\" " << prop
           << " property contains path:\n"
              "  \""
@@ -519,6 +520,38 @@
   }
 }
 
+void cmExportInstallFileGenerator::PopulateSystemIncludeDirectoriesInterface(
+  cmGeneratorTarget const* target,
+  cmGeneratorExpression::PreprocessContext preprocessRule,
+  ImportPropertyMap& properties)
+{
+  assert(preprocessRule == cmGeneratorExpression::InstallInterface);
+
+  char const* const propName = "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES";
+  cmValue input = target->GetProperty(propName);
+
+  if (!input) {
+    return;
+  }
+  if (input->empty()) {
+    // Set to empty
+    properties[propName].clear();
+    return;
+  }
+
+  std::string includes = (input ? *input : "");
+  std::string prepro = cmGeneratorExpression::Preprocess(
+    includes, preprocessRule, this->GetImportPrefixWithSlash());
+  if (!prepro.empty()) {
+    this->ResolveTargetsInGeneratorExpressions(prepro, target);
+
+    if (!this->CheckInterfaceDirs(prepro, target, propName)) {
+      return;
+    }
+    properties[propName] = prepro;
+  }
+}
+
 void cmExportInstallFileGenerator::PopulateIncludeDirectoriesInterface(
   cmGeneratorTarget const* target,
   cmGeneratorExpression::PreprocessContext preprocessRule,
diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h
index 738fbb7..5a72903 100644
--- a/Source/cmExportInstallFileGenerator.h
+++ b/Source/cmExportInstallFileGenerator.h
@@ -94,7 +94,8 @@
 
   ExportInfo FindExportInfo(cmGeneratorTarget const* target) const override;
 
-  void ReportError(std::string const& errorMessage) const override;
+  void IssueMessage(MessageType type,
+                    std::string const& message) const override;
 
   /** Generate a per-configuration file for the targets.  */
   virtual bool GenerateImportFileConfig(std::string const& config);
@@ -134,6 +135,10 @@
                                 ImportPropertyMap& properties,
                                 std::set<std::string>& importedLocations);
 
+  virtual bool CheckInterfaceDirs(std::string const& prepro,
+                                  cmGeneratorTarget const* target,
+                                  std::string const& prop) const;
+
   cmInstallExportGenerator* IEGen;
 
   // The import file generated for each configuration.
@@ -144,9 +149,6 @@
   std::map<std::string, std::vector<std::string>> ConfigCxxModuleTargetFiles;
 
 private:
-  bool CheckInterfaceDirs(std::string const& prepro,
-                          cmGeneratorTarget const* target,
-                          std::string const& prop) const;
   void PopulateCompatibleInterfaceProperties(cmGeneratorTarget const* target,
                                              ImportPropertyMap& properties);
   void PopulateCustomTransitiveInterfaceProperties(
@@ -158,6 +160,10 @@
     cmGeneratorExpression::PreprocessContext preprocessRule,
     ImportPropertyMap& properties, cmTargetExport const& te,
     std::string& includesDestinationDirs);
+  void PopulateSystemIncludeDirectoriesInterface(
+    cmGeneratorTarget const* target,
+    cmGeneratorExpression::PreprocessContext preprocessRule,
+    ImportPropertyMap& properties);
   void PopulateSourcesInterface(
     cmGeneratorTarget const* target,
     cmGeneratorExpression::PreprocessContext preprocessRule,
diff --git a/Source/cmExportInstallPackageInfoGenerator.cxx b/Source/cmExportInstallPackageInfoGenerator.cxx
index 7fab8dc..f14942d 100644
--- a/Source/cmExportInstallPackageInfoGenerator.cxx
+++ b/Source/cmExportInstallPackageInfoGenerator.cxx
@@ -66,7 +66,7 @@
     }
   }
 
-  if (!this->CheckDefaultTargets()) {
+  if (!this->CheckPackage()) {
     return false;
   }
 
@@ -112,7 +112,7 @@
 
     // Set configuration-agnostic properties for component.
     this->GenerateInterfaceProperties(*component, gt, properties);
-    if (!this->GenerateFileSetProperties(*component, gt, te)) {
+    if (!this->GenerateFileSetProperties(*component, gt, te, packagePath)) {
       return false;
     }
   }
@@ -143,6 +143,8 @@
   root["name"] = this->GetPackageName();
   root["configuration"] = (config.empty() ? "noconfig" : config);
 
+  std::string const& packagePath = this->GenerateImportPrefix();
+
   Json::Value& components = root["components"];
 
   for (auto const& te : this->GetExportSet()->GetTargetExports()) {
@@ -158,7 +160,8 @@
 
     Json::Value component =
       this->GenerateInterfaceConfigProperties(suffix, properties);
-    this->GenerateFileSetProperties(component, te->Target, te.get(), config);
+    this->GenerateFileSetProperties(component, te->Target, te.get(),
+                                    packagePath, config);
 
     if (!component.empty()) {
       components[te->Target->GetExportName()] = std::move(component);
@@ -212,10 +215,7 @@
 
 std::string cmExportInstallPackageInfoGenerator::GetCxxModulesDirectory() const
 {
-  // TODO: Implement a not-CMake-specific mechanism for providing module
-  // information.
-  // return IEGen->GetCxxModuleDirectory();
-  return {};
+  return IEGen->GetCxxModuleDirectory();
 }
 
 cm::optional<std::string>
@@ -265,8 +265,9 @@
 
 bool cmExportInstallPackageInfoGenerator::GenerateFileSetProperties(
   Json::Value& component, cmGeneratorTarget* gte, cmTargetExport const* te,
-  cm::optional<std::string> config)
+  std::string const& packagePath, cm::optional<std::string> config)
 {
+  bool hasModules = false;
   std::set<std::string> seenIncludeDirectories;
   for (auto const& name : gte->Target->GetAllInterfaceFileSets()) {
     cmFileSet* fileSet = gte->Target->GetFileSet(name);
@@ -290,9 +291,18 @@
         seenIncludeDirectories.insert(*fileSetDirectory);
       }
     } else if (fileSet->GetType() == "CXX_MODULES"_s) {
-      /* TODO: Handle the CXX_MODULE directory */
+      hasModules = true;
+      this->RequiresConfigFiles = true;
     }
   }
 
+  if (hasModules && config) {
+    std::string const manifestPath =
+      this->GenerateCxxModules(component, gte, packagePath, *config);
+    if (!manifestPath.empty()) {
+      this->ConfigCxxModuleFiles[*config] =
+        cmStrCat(this->FileDir, '/', manifestPath);
+    }
+  }
   return true;
 }
diff --git a/Source/cmExportInstallPackageInfoGenerator.h b/Source/cmExportInstallPackageInfoGenerator.h
index 0cb79c8..1501234 100644
--- a/Source/cmExportInstallPackageInfoGenerator.h
+++ b/Source/cmExportInstallPackageInfoGenerator.h
@@ -69,7 +69,6 @@
                              std::string const& config) override;
 
   std::string GetCxxModulesDirectory() const override;
-  // TODO: Generate C++ module info in a not-CMake-specific format.
 
   cm::optional<std::string> GetFileSetDirectory(
     cmGeneratorTarget* gte, cmTargetExport const* te, cmFileSet* fileSet,
@@ -78,5 +77,6 @@
   bool GenerateFileSetProperties(Json::Value& component,
                                  cmGeneratorTarget* gte,
                                  cmTargetExport const* te,
+                                 std::string const& packagePath,
                                  cm::optional<std::string> config = {});
 };
diff --git a/Source/cmExportInstallSbomGenerator.cxx b/Source/cmExportInstallSbomGenerator.cxx
new file mode 100644
index 0000000..c5c9acb
--- /dev/null
+++ b/Source/cmExportInstallSbomGenerator.cxx
@@ -0,0 +1,250 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#include "cmExportInstallSbomGenerator.h"
+
+#include <functional>
+#include <map>
+#include <memory>
+#include <set>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include <cmext/string_view>
+
+#include "cmExportSet.h"
+#include "cmFileSet.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmInstallExportGenerator.h"
+#include "cmInstallFileSetGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmOutputConverter.h"
+#include "cmSbomArguments.h"
+#include "cmSbomObject.h"
+#include "cmSpdx.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTargetExport.h"
+
+cmExportInstallSbomGenerator::cmExportInstallSbomGenerator(
+  cmInstallExportGenerator* iegen, cmSbomArguments args)
+  : cmExportSbomGenerator(std::move(args))
+  , cmExportInstallFileGenerator(iegen)
+{
+  this->SetNamespace(cmStrCat(this->GetPackageName(), "::"_s));
+}
+
+std::string cmExportInstallSbomGenerator::GetConfigImportFileGlob() const
+{
+  std::string glob = cmStrCat(this->FileBase, "@*", this->FileExt);
+  return glob;
+}
+
+std::string const& cmExportInstallSbomGenerator::GetExportName() const
+{
+  return this->GetPackageName();
+}
+
+cm::string_view cmExportInstallSbomGenerator::GetImportPrefixWithSlash() const
+{
+  return "@prefix@/"_s;
+}
+
+bool cmExportInstallSbomGenerator::GenerateMainFile(std::ostream& os)
+{
+  std::vector<cmTargetExport const*> allTargets;
+  {
+    auto visitor = [&](cmTargetExport const* te) { allTargets.push_back(te); };
+
+    if (!this->CollectExports(visitor)) {
+      return false;
+    }
+  }
+  cmSbomDocument doc;
+  doc.Graph.reserve(256);
+
+  cmSpdxCreationInfo const* ci =
+    insert_back(doc.Graph, this->GenerateCreationInfo());
+  cmSpdxDocument* project = insert_back(doc.Graph, this->GenerateSbom(ci));
+  std::vector<TargetProperties> targets;
+  targets.reserve(allTargets.size());
+
+  for (cmTargetExport const* te : allTargets) {
+    cmGeneratorTarget const* gt = te->Target;
+    ImportPropertyMap properties;
+    if (!this->PopulateInterfaceProperties(te, properties)) {
+      return false;
+    }
+    this->PopulateLinkLibrariesProperty(
+      gt, cmGeneratorExpression::InstallInterface, properties);
+    this->PopulateInterfaceLinkLibrariesProperty(
+      gt, cmGeneratorExpression::InstallInterface, properties);
+
+    targets.push_back(TargetProperties{
+      insert_back(project->RootElements,
+                  this->GenerateImportTarget(ci, te->Target)),
+      te->Target, std::move(properties) });
+  }
+
+  for (auto const& target : targets) {
+    this->GenerateProperties(doc, project, ci, target, targets);
+  }
+
+  this->WriteSbom(doc, os);
+  return true;
+}
+
+void cmExportInstallSbomGenerator::GenerateImportTargetsConfig(
+  std::ostream& os, std::string const& config, std::string const& suffix)
+{
+  cmSbomDocument doc;
+  doc.Graph.reserve(256);
+
+  cmSpdxCreationInfo const* ci =
+    insert_back(doc.Graph, this->GenerateCreationInfo());
+  cmSpdxDocument* project = insert_back(doc.Graph, this->GenerateSbom(ci));
+
+  std::vector<TargetProperties> targets;
+  std::string cfg = (config.empty() ? "noconfig" : config);
+
+  for (auto const& te : this->GetExportSet()->GetTargetExports()) {
+    ImportPropertyMap properties;
+    std::set<std::string> importedLocations;
+
+    if (this->GetExportTargetType(te.get()) !=
+        cmStateEnums::INTERFACE_LIBRARY) {
+      this->PopulateImportProperties(config, suffix, te.get(), properties,
+                                     importedLocations);
+    }
+    this->PopulateInterfaceProperties(te.get(), properties);
+    this->PopulateInterfaceLinkLibrariesProperty(
+      te->Target, cmGeneratorExpression::InstallInterface, properties);
+    this->PopulateLinkLibrariesProperty(
+      te->Target, cmGeneratorExpression::InstallInterface, properties);
+
+    targets.push_back(TargetProperties{
+      insert_back(project->RootElements,
+                  this->GenerateImportTarget(ci, te->Target)),
+      te->Target, std::move(properties) });
+  }
+
+  for (auto const& target : targets) {
+    this->GenerateProperties(doc, project, ci, target, targets);
+  }
+
+  this->WriteSbom(doc, os);
+}
+
+std::string cmExportInstallSbomGenerator::GenerateImportPrefix() const
+{
+  std::string expDest = this->IEGen->GetDestination();
+  if (cmSystemTools::FileIsFullPath(expDest)) {
+    std::string const& installPrefix =
+      this->IEGen->GetLocalGenerator()->GetMakefile()->GetSafeDefinition(
+        "CMAKE_INSTALL_PREFIX");
+    if (cmHasPrefix(expDest, installPrefix)) {
+      auto n = installPrefix.length();
+      while (n < expDest.length() && expDest[n] == '/') {
+        ++n;
+      }
+      expDest = expDest.substr(n);
+    } else {
+      this->ReportError(
+        cmStrCat("install(SBOM \"", this->GetExportName(),
+                 "\" ...) specifies DESTINATION \"", expDest,
+                 "\" which is not a subdirectory of the install prefix."));
+      return {};
+    }
+  }
+
+  if (expDest.empty()) {
+    return this->GetInstallPrefix();
+  }
+  return cmStrCat(this->GetImportPrefixWithSlash(), expDest);
+}
+
+void cmExportInstallSbomGenerator::HandleMissingTarget(
+  std::string& /* link_libs */, cmGeneratorTarget const* /* depender */,
+  cmGeneratorTarget* /* dependee */)
+{
+}
+
+bool cmExportInstallSbomGenerator::CheckInterfaceDirs(
+  std::string const& /* prepro */, cmGeneratorTarget const* /* target */,
+  std::string const& /* prop */) const
+{
+  return true;
+}
+
+std::string cmExportInstallSbomGenerator::InstallNameDir(
+  cmGeneratorTarget const* target, std::string const& config)
+{
+  std::string install_name_dir;
+
+  cmMakefile* mf = target->Target->GetMakefile();
+  if (mf->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
+    install_name_dir =
+      target->GetInstallNameDirForInstallTree(config, "@prefix@");
+  }
+
+  return install_name_dir;
+}
+
+std::string cmExportInstallSbomGenerator::GetCxxModulesDirectory() const
+{
+  return {};
+}
+
+void cmExportInstallSbomGenerator::GenerateCxxModuleConfigInformation(
+  std::string const&, std::ostream&) const
+{
+}
+
+std::string cmExportInstallSbomGenerator::GetCxxModuleFile(
+  std::string const& /* name */) const
+{
+  return {};
+}
+
+cm::optional<std::string> cmExportInstallSbomGenerator::GetFileSetDirectory(
+  cmGeneratorTarget* gte, cmTargetExport const* te, cmFileSet* fileSet,
+  cm::optional<std::string> const& config)
+{
+  cmGeneratorExpression ge(*gte->Makefile->GetCMakeInstance());
+  auto cge =
+    ge.Parse(te->FileSetGenerators.at(fileSet->GetName())->GetDestination());
+
+  std::string const unescapedDest =
+    cge->Evaluate(gte->LocalGenerator, config.value_or(""), gte);
+  bool const isConfigDependent = cge->GetHadContextSensitiveCondition();
+
+  if (config && !isConfigDependent) {
+    return {};
+  }
+
+  std::string const& type = fileSet->GetType();
+  if (config && (type == "CXX_MODULES"_s)) {
+    cmMakefile* mf = gte->LocalGenerator->GetMakefile();
+    std::ostringstream e;
+    e << "The \"" << gte->GetName() << "\" target's interface file set \""
+      << fileSet->GetName() << "\" of type \"" << type
+      << "\" contains context-sensitive base file entries which is not "
+         "supported.";
+    mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    return {};
+  }
+
+  cm::optional<std::string> dest = cmOutputConverter::EscapeForCMake(
+    unescapedDest, cmOutputConverter::WrapQuotes::NoWrap);
+
+  if (!cmSystemTools::FileIsFullPath(unescapedDest)) {
+    dest = cmStrCat("@prefix@/"_s, *dest);
+  }
+
+  return dest;
+}
diff --git a/Source/cmExportInstallSbomGenerator.h b/Source/cmExportInstallSbomGenerator.h
new file mode 100644
index 0000000..c7fb9b6
--- /dev/null
+++ b/Source/cmExportInstallSbomGenerator.h
@@ -0,0 +1,68 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <iosfwd>
+#include <string>
+
+#include <cm/optional>
+#include <cm/string_view>
+
+#include "cmExportInstallFileGenerator.h"
+#include "cmExportSbomGenerator.h"
+
+class cmFileSet;
+class cmGeneratorTarget;
+class cmInstallExportGenerator;
+class cmSbomArguments;
+class cmTargetExport;
+
+class cmExportInstallSbomGenerator
+  : public cmExportSbomGenerator
+  , public cmExportInstallFileGenerator
+{
+public:
+  /** Construct with the export installer that will install the
+      files.  */
+  cmExportInstallSbomGenerator(cmInstallExportGenerator* iegen,
+                               cmSbomArguments arguments);
+
+  /** Compute the globbing expression used to load per-config import
+      files from the main file.  */
+  std::string GetConfigImportFileGlob() const override;
+
+protected:
+  std::string const& GetExportName() const override;
+
+  cm::string_view GetImportPrefixWithSlash() const override;
+  std::string GetCxxModuleFile(std::string const& name) const override;
+  void GenerateCxxModuleConfigInformation(std::string const&,
+                                          std::ostream& os) const override;
+
+  // Implement virtual methods from the superclass.
+  bool GenerateMainFile(std::ostream& os) override;
+  void GenerateImportTargetsConfig(std::ostream& os, std::string const& config,
+                                   std::string const& suffix) override;
+
+  void HandleMissingTarget(std::string& /* link_libs */,
+                           cmGeneratorTarget const* /* depender */,
+                           cmGeneratorTarget* /* dependee */) override;
+
+  bool CheckInterfaceDirs(std::string const& /* prepro */,
+                          cmGeneratorTarget const* /* target */,
+                          std::string const& /* prop */) const override;
+
+  char GetConfigFileNameSeparator() const override { return '@'; }
+
+  std::string GenerateImportPrefix() const;
+  std::string InstallNameDir(cmGeneratorTarget const* target,
+                             std::string const& config) override;
+
+  std::string GetCxxModulesDirectory() const override;
+
+  cm::optional<std::string> GetFileSetDirectory(
+    cmGeneratorTarget* gte, cmTargetExport const* te, cmFileSet* fileSet,
+    cm::optional<std::string> const& config = {});
+};
diff --git a/Source/cmExportPackageInfoGenerator.cxx b/Source/cmExportPackageInfoGenerator.cxx
index a790f60..62a01e5 100644
--- a/Source/cmExportPackageInfoGenerator.cxx
+++ b/Source/cmExportPackageInfoGenerator.cxx
@@ -2,7 +2,6 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "cmExportPackageInfoGenerator.h"
 
-#include <cstddef>
 #include <memory>
 #include <set>
 #include <utility>
@@ -16,6 +15,8 @@
 #include <cm3p/json/value.h>
 #include <cm3p/json/writer.h>
 
+#include "cmsys/RegularExpression.hxx"
+
 #include "cmArgumentParserTypes.h"
 #include "cmExportSet.h"
 #include "cmFindPackageStack.h"
@@ -29,7 +30,7 @@
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 
-static std::string const kCPS_VERSION_STR = "0.13.0";
+static std::string const kCPS_VERSION_STR = "0.14.1";
 
 cmExportPackageInfoGenerator::cmExportPackageInfoGenerator(
   cmPackageInfoArguments arguments)
@@ -88,6 +89,63 @@
     }
   }
 }
+
+bool CheckSimpleVersion(std::string const& version)
+{
+  cmsys::RegularExpression regex("^[0-9]+([.][0-9]+)*([-+].*)?$");
+  return regex.find(version);
+}
+}
+
+bool cmExportPackageInfoGenerator::CheckVersion() const
+{
+  if (!this->PackageVersion.empty()) {
+    std::string const& schema = [&] {
+      if (this->PackageVersionSchema.empty()) {
+        return std::string{ "simple" };
+      }
+      return cmSystemTools::LowerCase(this->PackageVersionSchema);
+    }();
+    bool (*validator)(std::string const&) = nullptr;
+    bool result = true;
+
+    if (schema == "simple"_s) {
+      validator = &CheckSimpleVersion;
+    } else if (schema == "dpkg"_s || schema == "rpm"_s ||
+               schema == "pep440"_s) {
+      // TODO
+      // We don't validate these at this time. Eventually, we would like to do
+      // so, but will probably need to introduce a policy whether to treat
+      // invalid versions as an error.
+    } else if (schema != "custom"_s) {
+      this->IssueMessage(MessageType::AUTHOR_WARNING,
+                         cmStrCat("Package \""_s, this->GetPackageName(),
+                                  "\" uses unrecognized version schema \""_s,
+                                  this->PackageVersionSchema, "\"."_s));
+    }
+
+    if (validator) {
+      if (!(*validator)(this->PackageVersion)) {
+        this->ReportError(cmStrCat("Package \""_s, this->GetPackageName(),
+                                   "\" version \""_s, this->PackageVersion,
+                                   "\" does not conform to the \""_s, schema,
+                                   "\" schema."_s));
+        result = false;
+      }
+      if (!this->PackageVersionCompat.empty() &&
+          !(*validator)(this->PackageVersionCompat)) {
+        this->ReportError(
+          cmStrCat("Package \""_s, this->GetPackageName(),
+                   "\" compatibility version \""_s, this->PackageVersionCompat,
+                   "\" does not conform to the \""_s, schema, "\" schema."_s));
+        result = false;
+      }
+    }
+
+    return result;
+  }
+
+  return true;
 }
 
 bool cmExportPackageInfoGenerator::CheckDefaultTargets() const
@@ -236,51 +294,6 @@
   return result;
 }
 
-namespace {
-bool ForbidGeneratorExpressions(
-  cmGeneratorTarget const* target, std::string const& propertyName,
-  std::string const& propertyValue, std::string& evaluatedValue,
-  std::map<std::string, std::vector<std::string>>& allowList)
-{
-  size_t const allowedExpressions = allowList.size();
-  evaluatedValue = cmGeneratorExpression::Collect(propertyValue, allowList);
-  if (evaluatedValue != propertyValue &&
-      allowList.size() > allowedExpressions) {
-    target->Makefile->IssueMessage(
-      MessageType::FATAL_ERROR,
-      cmStrCat("Property \"", propertyName, "\" of target \"",
-               target->GetName(),
-               "\" contains a generator expression. This is not allowed."));
-    return false;
-  }
-  // Forbid Nested Generator Expressions
-  for (auto const& genexp : allowList) {
-    for (auto const& value : genexp.second) {
-      if (value.find("$<") != std::string::npos) {
-        target->Makefile->IssueMessage(
-          MessageType::FATAL_ERROR,
-          cmStrCat(
-            "$<", genexp.first, ":...> expression in \"", propertyName,
-            "\" of target \"", target->GetName(),
-            "\" contains a generator expression. This is not allowed."));
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-bool ForbidGeneratorExpressions(cmGeneratorTarget const* target,
-                                std::string const& propertyName,
-                                std::string const& propertyValue)
-{
-  std::map<std::string, std::vector<std::string>> allowList;
-  std::string evaluatedValue;
-  return ForbidGeneratorExpressions(target, propertyName, propertyValue,
-                                    evaluatedValue, allowList);
-}
-}
-
 bool cmExportPackageInfoGenerator::NoteLinkedTarget(
   cmGeneratorTarget const* target, std::string const& linkedName,
   cmGeneratorTarget const* linkedTarget)
@@ -374,6 +387,28 @@
   return false;
 }
 
+std::vector<std::string> cmExportPackageInfoGenerator::ExtractRequirements(
+  std::vector<std::string> const& names, bool& result,
+  std::vector<std::string>& libraryPaths) const
+{
+  std::vector<std::string> output;
+
+  for (auto const& name : names) {
+    auto const& ti = this->LinkTargets.find(name);
+    if (ti != this->LinkTargets.end()) {
+      if (ti->second.empty()) {
+        result = false;
+      } else {
+        output.emplace_back(ti->second);
+      }
+    } else {
+      libraryPaths.emplace_back(name);
+    }
+  }
+
+  return output;
+}
+
 void cmExportPackageInfoGenerator::GenerateInterfaceLinkProperties(
   bool& result, Json::Value& component, cmGeneratorTarget const* target,
   ImportPropertyMap const& properties) const
@@ -385,42 +420,31 @@
 
   // Extract any $<LINK_ONLY:...> from the link libraries, and assert that no
   // other generator expressions are present.
-  std::map<std::string, std::vector<std::string>> allowList = { { "LINK_ONLY",
-                                                                  {} } };
+  std::map<std::string, std::vector<std::string>>
+    allowedGeneratorExpressions = {
+      { "COMPILE_ONLY", {} },
+      { "LINK_ONLY", {} },
+    };
   std::string interfaceLinkLibraries;
-  if (!ForbidGeneratorExpressions(target, iter->first, iter->second,
-                                  interfaceLinkLibraries, allowList)) {
+  if (!cmGeneratorExpression::ForbidGeneratorExpressions(
+        target, iter->first, iter->second, interfaceLinkLibraries,
+        allowedGeneratorExpressions)) {
     result = false;
     return;
   }
 
   std::vector<std::string> linkLibraries;
-  std::vector<std::string> linkRequires;
-  std::vector<std::string> buildRequires;
-
-  auto addLibraries = [this, &linkLibraries,
-                       &result](std::vector<std::string> const& names,
-                                std::vector<std::string>& output) -> void {
-    for (auto const& name : names) {
-      auto const& ti = this->LinkTargets.find(name);
-      if (ti != this->LinkTargets.end()) {
-        if (ti->second.empty()) {
-          result = false;
-        } else {
-          output.emplace_back(ti->second);
-        }
-      } else {
-        linkLibraries.emplace_back(name);
-      }
-    }
-  };
-
-  addLibraries(allowList["LINK_ONLY"], linkRequires);
-  addLibraries(cmList{ interfaceLinkLibraries }, buildRequires);
+  std::vector<std::string> buildRequires = this->ExtractRequirements(
+    cmList{ interfaceLinkLibraries }, result, linkLibraries);
+  std::vector<std::string> compileRequires = this->ExtractRequirements(
+    allowedGeneratorExpressions["COMPILE_ONLY"], result, linkLibraries);
+  std::vector<std::string> linkRequires = this->ExtractRequirements(
+    allowedGeneratorExpressions["LINK_ONLY"], result, linkLibraries);
 
   BuildArray(component, "requires", buildRequires);
   BuildArray(component, "link_requires", linkRequires);
   BuildArray(component, "link_libraries", linkLibraries);
+  BuildArray(component, "compile_requires", compileRequires);
 }
 
 void cmExportPackageInfoGenerator::GenerateInterfaceCompileFeatures(
@@ -432,7 +456,8 @@
     return;
   }
 
-  if (!ForbidGeneratorExpressions(target, iter->first, iter->second)) {
+  if (!cmGeneratorExpression::ForbidGeneratorExpressions(target, iter->first,
+                                                         iter->second)) {
     result = false;
     return;
   }
@@ -441,7 +466,7 @@
   for (auto const& value : cmList{ iter->second }) {
     if (cmHasLiteralPrefix(value, "c_std_")) {
       auto suffix = cm::string_view{ value }.substr(6, 2);
-      features.emplace(cmStrCat("cxx", suffix));
+      features.emplace(cmStrCat("c", suffix));
     } else if (cmHasLiteralPrefix(value, "cxx_std_")) {
       auto suffix = cm::string_view{ value }.substr(8, 2);
       features.emplace(cmStrCat("c++", suffix));
@@ -461,7 +486,8 @@
   }
 
   // TODO: Support language-specific defines.
-  if (!ForbidGeneratorExpressions(target, iter->first, iter->second)) {
+  if (!cmGeneratorExpression::ForbidGeneratorExpressions(target, iter->first,
+                                                         iter->second)) {
     result = false;
     return;
   }
@@ -492,7 +518,8 @@
     return;
   }
 
-  if (!ForbidGeneratorExpressions(target, prop, iter->second)) {
+  if (!cmGeneratorExpression::ForbidGeneratorExpressions(target, prop,
+                                                         iter->second)) {
     result = false;
     return;
   }
@@ -513,7 +540,8 @@
     return;
   }
 
-  if (!ForbidGeneratorExpressions(target, inName, iter->second)) {
+  if (!cmGeneratorExpression::ForbidGeneratorExpressions(target, inName,
+                                                         iter->second)) {
     result = false;
     return;
   }
@@ -538,6 +566,22 @@
       component["location"] = p.second;
     } else if (prop == "IMPLIB") {
       component["link_location"] = p.second;
+    } else if (prop == "LINK_DEPENDENT_LIBRARIES") {
+      bool result;
+      std::vector<std::string> libraries;
+      std::vector<std::string> components =
+        this->ExtractRequirements(cmList{ p.second }, result, libraries);
+      BuildArray(component, "dyld_requires", components);
+      if (!libraries.empty()) {
+        // In theory this can never happen?
+        this->IssueMessage(
+          MessageType::AUTHOR_WARNING,
+          cmStrCat("Package \""_s, this->GetPackageName(),
+                   "\" has IMPORTED_LINK_DEPENDENT_LIBRARIES \""_s,
+                   cmJoin(libraries, ";"_s), this->PackageVersionSchema,
+                   "\". These cannot be exported. "
+                   "Consumers may encounter link errors."_s));
+      }
     } else if (prop == "LINK_INTERFACE_LANGUAGES") {
       std::vector<std::string> languages;
       for (auto const& lang : cmList{ p.second }) {
@@ -554,3 +598,22 @@
 
   return component;
 }
+
+std::string cmExportPackageInfoGenerator::GenerateCxxModules(
+  Json::Value& component, cmGeneratorTarget* target,
+  std::string const& packagePath, std::string const& config)
+{
+  std::string manifestPath;
+
+  std::string const cxxModulesDirName = this->GetCxxModulesDirectory();
+  if (cxxModulesDirName.empty() || !target->HaveCxx20ModuleSources()) {
+    return manifestPath;
+  }
+
+  manifestPath =
+    cmStrCat(cxxModulesDirName, "/target-", target->GetFilesystemExportName(),
+             '-', config.empty() ? "noconfig" : config, ".modules.json");
+
+  component["cpp_module_metadata"] = cmStrCat(packagePath, '/', manifestPath);
+  return manifestPath;
+}
diff --git a/Source/cmExportPackageInfoGenerator.h b/Source/cmExportPackageInfoGenerator.h
index 0614e27..d7eeba2 100644
--- a/Source/cmExportPackageInfoGenerator.h
+++ b/Source/cmExportPackageInfoGenerator.h
@@ -47,7 +47,10 @@
   // Methods to implement export file code generation.
   bool GenerateImportFile(std::ostream& os) override;
 
-  bool CheckDefaultTargets() const;
+  bool CheckPackage() const
+  {
+    return this->CheckVersion() && this->CheckDefaultTargets();
+  }
 
   Json::Value GeneratePackageInfo() const;
   Json::Value* GenerateImportTarget(Json::Value& components,
@@ -67,21 +70,34 @@
 
   std::string GetCxxModuleFile(std::string const& /*name*/) const override
   {
-    // TODO
+    // CPS does not have a general CxxModuleFile, we use the config-specific
+    // manifests directly
     return {};
   }
 
   void GenerateCxxModuleConfigInformation(std::string const& /*name*/,
                                           std::ostream& /*os*/) const override
   {
-    // TODO
+    // We embed this directly in the CPS json
   }
 
+  std::string GenerateCxxModules(Json::Value& component,
+                                 cmGeneratorTarget* target,
+                                 std::string const& packagePath,
+                                 std::string const& config);
+
   bool NoteLinkedTarget(cmGeneratorTarget const* target,
                         std::string const& linkedName,
                         cmGeneratorTarget const* linkedTarget) override;
 
 private:
+  bool CheckVersion() const;
+  bool CheckDefaultTargets() const;
+
+  std::vector<std::string> ExtractRequirements(
+    std::vector<std::string> const& names, bool& result,
+    std::vector<std::string>& libraryPaths) const;
+
   void GenerateInterfaceLinkProperties(
     bool& result, Json::Value& component, cmGeneratorTarget const* target,
     ImportPropertyMap const& properties) const;
diff --git a/Source/cmExportSbomGenerator.cxx b/Source/cmExportSbomGenerator.cxx
new file mode 100644
index 0000000..c99141f
--- /dev/null
+++ b/Source/cmExportSbomGenerator.cxx
@@ -0,0 +1,388 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#include "cmExportSbomGenerator.h"
+
+#include <array>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+#include <cmext/algorithm>
+
+#include "cmArgumentParserTypes.h"
+#include "cmFindPackageStack.h"
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmList.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmSbomArguments.h"
+#include "cmSbomObject.h"
+#include "cmSpdx.h"
+#include "cmSpdxSerializer.h"
+#include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmValue.h"
+
+cmSpdxPackage::PurposeId GetPurpose(cmStateEnums::TargetType type)
+{
+  switch (type) {
+    case cmStateEnums::TargetType::EXECUTABLE:
+      return cmSpdxPackage::PurposeId::APPLICATION;
+    case cmStateEnums::TargetType::STATIC_LIBRARY:
+    case cmStateEnums::TargetType::SHARED_LIBRARY:
+    case cmStateEnums::TargetType::MODULE_LIBRARY:
+    case cmStateEnums::TargetType::OBJECT_LIBRARY:
+    case cmStateEnums::TargetType::INTERFACE_LIBRARY:
+      return cmSpdxPackage::PurposeId::LIBRARY;
+    case cmStateEnums::TargetType::UTILITY:
+      return cmSpdxPackage::PurposeId::SOURCE;
+    case cmStateEnums::TargetType::GLOBAL_TARGET:
+    case cmStateEnums::TargetType::UNKNOWN_LIBRARY:
+    default:
+      return cmSpdxPackage::PurposeId::ARCHIVE;
+  }
+}
+
+cmExportSbomGenerator::cmExportSbomGenerator(cmSbomArguments args)
+  : PackageName(std::move(args.PackageName))
+  , PackageVersion(std::move(args.Version))
+  , PackageDescription(std::move(args.Description))
+  , PackageWebsite(std::move(args.Website))
+  , PackageLicense(std::move(args.License))
+  , PackageFormat(args.GetFormat())
+{
+}
+
+bool cmExportSbomGenerator::GenerateImportFile(std::ostream& os)
+{
+  return this->GenerateMainFile(os);
+}
+
+void cmExportSbomGenerator::WriteSbom(cmSbomDocument& doc,
+                                      std::ostream& os) const
+{
+  switch (this->PackageFormat) {
+    case cmSbomArguments::SbomFormat::SPDX_3_0_JSON:
+      cmSpdxSerializer{}.WriteSbom(os, cmSbomObject(doc));
+      break;
+    case cmSbomArguments::SbomFormat::NONE:
+      break;
+  }
+}
+
+bool cmExportSbomGenerator::AddPackageInformation(
+  cmSpdxPackage& artifact, std::string const& name,
+  cmPackageInformation const& package) const
+{
+  if (name.empty()) {
+    return false;
+  }
+
+  cmSpdxOrganization org;
+  org.SpdxId = cmStrCat("urn:", name, "#Organization");
+  org.Name = name;
+  org.CreationInfo = artifact.CreationInfo;
+  artifact.OriginatedBy.emplace_back(std::move(org));
+
+  if (package.Description) {
+    artifact.Description = *package.Description;
+  }
+
+  if (package.Version) {
+    artifact.PackageVersion = *package.Version;
+  }
+
+  if (package.PackageUrl) {
+    artifact.PackageUrl = *package.PackageUrl;
+  }
+
+  if (package.License) {
+    artifact.CopyrightText = *package.License;
+  }
+
+  artifact.BuiltTime = cmSystemTools::GetCurrentDateTime("%FT%TZ");
+  cmSpdxExternalRef externalRef;
+  externalRef.Locator = cmStrCat("cmake:find_package(", name, ")");
+  externalRef.ExternalRefType = "buildSystem";
+  return true;
+}
+
+cmSpdxCreationInfo cmExportSbomGenerator::GenerateCreationInfo() const
+{
+  cmSpdxCreationInfo ci;
+  ci.SpdxId = "_:Build#CreationInfo";
+  ci.Created = cmSystemTools::GetCurrentDateTime("%FT%TZ");
+  ci.CreatedBy = { "https://gitlab.kitware.com/cmake/cmake" };
+  ci.Comment = "This SBOM was generated from the CMakeLists.txt File";
+  ci.SpecVersion = "3.0.1";
+  return ci;
+}
+
+cmSpdxDocument cmExportSbomGenerator::GenerateSbom(
+  cmSpdxCreationInfo const* ci) const
+{
+  cmSpdxDocument proj;
+  proj.Name = PackageName;
+  proj.SpdxId = cmStrCat("urn:", PackageName, "#SPDXDocument");
+  proj.ProfileConformance = { "core", "software" };
+  proj.CreationInfo = ci;
+
+  if (!this->PackageDescription.empty()) {
+    proj.Description = this->PackageDescription;
+  }
+
+  if (!this->PackageLicense.empty()) {
+    proj.DataLicense = this->PackageLicense;
+  }
+
+  return proj;
+}
+
+cmSpdxPackage cmExportSbomGenerator::GenerateImportTarget(
+  cmSpdxCreationInfo const* ci, cmGeneratorTarget const* target) const
+{
+  cmSpdxPackage package;
+  package.SpdxId = cmStrCat("urn:", target->GetName(), "#Package");
+  package.Name = target->GetName();
+  package.PrimaryPurpose = GetPurpose(target->GetType());
+  package.CreationInfo = ci;
+
+  if (!this->PackageVersion.empty()) {
+    package.PackageVersion = this->PackageVersion;
+  }
+
+  if (!this->PackageWebsite.empty()) {
+    package.Homepage = this->PackageWebsite;
+  }
+
+  if (!this->PackageUrl.empty()) {
+    package.DownloadLocation = this->PackageUrl;
+  }
+
+  return package;
+}
+
+void cmExportSbomGenerator::GenerateLinkProperties(
+  cmSbomDocument& doc, cmSpdxDocument* project, cmSpdxCreationInfo const* ci,
+  std::string const& libraries, TargetProperties const& current,
+  std::vector<TargetProperties> const& allTargets) const
+{
+  auto itProp = current.Properties.find(libraries);
+  if (itProp == current.Properties.end()) {
+    return;
+  }
+
+  std::map<std::string, std::vector<std::string>> allowList = { { "LINK_ONLY",
+                                                                  {} } };
+  std::string interfaceLinkLibraries;
+  if (!cmGeneratorExpression::ForbidGeneratorExpressions(
+        current.Target, itProp->first, itProp->second, interfaceLinkLibraries,
+        allowList)) {
+    return;
+  }
+
+  auto makeRel = [&](char const* id, char const* desc) {
+    cmSpdxRelationship r;
+    r.SpdxId = cmStrCat("urn:", id, "#Relationship");
+    r.RelationshipType = cmSpdxRelationship::RelationshipTypeId::DEPENDS_ON;
+    r.Description = desc;
+    r.From = current.Package;
+    r.CreationInfo = ci;
+    return r;
+  };
+
+  auto linkLibraries = makeRel("Static", "Linked Libraries");
+  auto linkRequires = makeRel("Dynamic", "Required Runtime Libraries");
+  auto buildRequires = makeRel("Shared", "Required Build-Time Libraries");
+
+  auto addArtifact =
+    [&](std::string const& name) -> std::pair<bool, cmSpdxPackage const*> {
+    auto it = this->LinkTargets.find(name);
+    if (it != this->LinkTargets.end()) {
+      LinkInfo const& linkInfo = it->second;
+      if (linkInfo.Package.empty()) {
+        for (auto const& t : allTargets) {
+          if (t.Target->GetName() == linkInfo.Component) {
+            return { true, t.Package };
+          }
+        }
+      }
+      std::string pkgName =
+        cmStrCat(linkInfo.Package, ":", linkInfo.Component);
+      cmSpdxPackage pkg;
+      pkg.Name = pkgName;
+      pkg.SpdxId = cmStrCat("urn:", pkgName, "#Package");
+      pkg.CreationInfo = ci;
+      if (!linkInfo.Package.empty()) {
+        auto const& pkgIt = this->Requirements.find(linkInfo.Package);
+        if (pkgIt != this->Requirements.end() &&
+            pkgIt->second.Components.count(linkInfo.Component) > 0) {
+          this->AddPackageInformation(pkg, pkgIt->first, pkgIt->second);
+        }
+      }
+      return { true, insert_back(project->Elements, std::move(pkg)) };
+    }
+
+    cmSpdxPackage pkg;
+    pkg.SpdxId = cmStrCat("urn:", name, "#Package");
+    pkg.Name = name;
+    pkg.CreationInfo = ci;
+    return { false, insert_back(project->Elements, std::move(pkg)) };
+  };
+
+  auto handleDependencies = [&](std::vector<std::string> const& names,
+                                cmSpdxRelationship& internalDeps,
+                                cmSpdxRelationship& externalDeps) {
+    for (auto const& n : names) {
+      auto res = addArtifact(n);
+      if (!res.second) {
+        continue;
+      }
+
+      if (res.first) {
+        internalDeps.To.push_back(res.second);
+      } else {
+        externalDeps.To.push_back(res.second);
+      }
+    }
+  };
+
+  handleDependencies(allowList["LINK_ONLY"], linkLibraries, linkRequires);
+  handleDependencies(cmList{ interfaceLinkLibraries }, linkLibraries,
+                     buildRequires);
+
+  if (!linkLibraries.To.empty()) {
+    insert_back(doc.Graph, std::move(linkLibraries));
+  }
+  if (!linkRequires.To.empty()) {
+    insert_back(doc.Graph, std::move(linkRequires));
+  }
+  if (!buildRequires.To.empty()) {
+    insert_back(doc.Graph, std::move(buildRequires));
+  }
+}
+
+bool cmExportSbomGenerator::GenerateProperties(
+  cmSbomDocument& doc, cmSpdxDocument* proj, cmSpdxCreationInfo const* ci,
+  TargetProperties const& current,
+  std::vector<TargetProperties> const& allTargets) const
+{
+  this->GenerateLinkProperties(doc, proj, ci, "LINK_LIBRARIES", current,
+                               allTargets);
+  this->GenerateLinkProperties(doc, proj, ci, "INTERFACE_LINK_LIBRARIES",
+                               current, allTargets);
+  return true;
+}
+
+bool cmExportSbomGenerator::PopulateLinkLibrariesProperty(
+  cmGeneratorTarget const* target,
+  cmGeneratorExpression::PreprocessContext preprocessRule,
+  ImportPropertyMap& properties)
+{
+  static std::array<std::string, 3> const linkIfaceProps = {
+    { "LINK_LIBRARIES", "LINK_LIBRARIES_DIRECT",
+      "LINK_LIBRARIES_DIRECT_EXCLUDE" }
+  };
+  bool hadLINK_LIBRARIES = false;
+  for (std::string const& linkIfaceProp : linkIfaceProps) {
+    if (cmValue input = target->GetProperty(linkIfaceProp)) {
+      std::string prepro =
+        cmGeneratorExpression::Preprocess(*input, preprocessRule);
+      if (!prepro.empty()) {
+        this->ResolveTargetsInGeneratorExpressions(prepro, target,
+                                                   ReplaceFreeTargets);
+        properties[linkIfaceProp] = prepro;
+        hadLINK_LIBRARIES = true;
+      }
+    }
+  }
+  return hadLINK_LIBRARIES;
+}
+
+bool cmExportSbomGenerator::NoteLinkedTarget(
+  cmGeneratorTarget const* target, std::string const& linkedName,
+  cmGeneratorTarget const* linkedTarget)
+{
+  if (cm::contains(this->ExportedTargets, linkedTarget)) {
+    this->LinkTargets.emplace(linkedName,
+                              LinkInfo{ "", linkedTarget->GetExportName() });
+    return true;
+  }
+
+  if (linkedTarget->IsImported()) {
+    using Package = cm::optional<std::pair<std::string, cmPackageInformation>>;
+    auto pkgInfo = [](cmTarget* t) -> Package {
+      cmFindPackageStack pkgStack = t->GetFindPackageStack();
+      if (!pkgStack.Empty()) {
+        return std::make_pair(pkgStack.Top().Name,
+                              *pkgStack.Top().PackageInfo);
+      }
+      std::string const pkgName =
+        t->GetSafeProperty("EXPORT_FIND_PACKAGE_NAME");
+      if (pkgName.empty()) {
+        return cm::nullopt;
+      }
+      cmPackageInformation package;
+      return std::make_pair(pkgName, package);
+    }(linkedTarget->Target);
+
+    if (!pkgInfo) {
+      target->Makefile->IssueMessage(
+        MessageType::AUTHOR_WARNING,
+        cmStrCat("Target \"", target->GetName(),
+                 "\" references imported target \"", linkedName,
+                 "\" which does not come from any known package."));
+      return false;
+    }
+
+    std::string const& pkgName = pkgInfo->first;
+    auto const& prefix = cmStrCat(pkgName, "::");
+    std::string component;
+    if (!cmHasPrefix(linkedName, prefix)) {
+      component = linkedName;
+    } else {
+      component = linkedName.substr(prefix.length());
+    }
+    this->LinkTargets.emplace(linkedName, LinkInfo{ pkgName, component });
+    cmPackageInformation& req =
+      this->Requirements.insert(std::move(*pkgInfo)).first->second;
+    req.Components.emplace(std::move(component));
+    return true;
+  }
+
+  // Target belongs to another export from this build.
+  auto const& exportInfo = this->FindExportInfo(linkedTarget);
+  if (exportInfo.Namespaces.size() == 1 && exportInfo.Sets.size() == 1) {
+    auto const& linkNamespace = *exportInfo.Namespaces.begin();
+    if (!cmHasSuffix(linkNamespace, "::")) {
+      target->Makefile->IssueMessage(
+        MessageType::AUTHOR_WARNING,
+        cmStrCat("Target \"", target->GetName(), "\" references target \"",
+                 linkedName,
+                 "\", which does not use the standard namespace separator. "
+                 "This is not allowed."));
+    }
+
+    std::string pkgName{ linkNamespace.data(), linkNamespace.size() - 2 };
+    std::string component = linkedTarget->GetExportName();
+    if (pkgName == this->GetPackageName()) {
+      this->LinkTargets.emplace(linkedName, LinkInfo{ "", component });
+    } else {
+      this->LinkTargets.emplace(linkedName, LinkInfo{ pkgName, component });
+      this->Requirements[pkgName].Components.emplace(std::move(component));
+    }
+    return true;
+  }
+
+  // Target belongs to multiple namespaces or multiple export sets.
+  // cmExportFileGenerator::HandleMissingTarget should have complained about
+  // this already.
+  return false;
+}
diff --git a/Source/cmExportSbomGenerator.h b/Source/cmExportSbomGenerator.h
new file mode 100644
index 0000000..6fb67a1
--- /dev/null
+++ b/Source/cmExportSbomGenerator.h
@@ -0,0 +1,86 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details. */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <iosfwd>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "cmExportFileGenerator.h"
+#include "cmFindPackageStack.h"
+#include "cmGeneratorExpression.h"
+#include "cmSbomArguments.h"
+
+class cmGeneratorTarget;
+struct cmSbomDocument;
+struct cmSpdxDocument;
+struct cmSpdxPackage;
+struct cmSpdxCreationInfo;
+
+class cmExportSbomGenerator : virtual public cmExportFileGenerator
+{
+public:
+  cmExportSbomGenerator(cmSbomArguments args);
+  using cmExportFileGenerator::GenerateImportFile;
+
+protected:
+  using ImportPropertyMap = std::map<std::string, std::string>;
+
+  struct TargetProperties
+  {
+    cmSpdxPackage const* Package;
+    cmGeneratorTarget const* Target;
+    ImportPropertyMap Properties;
+  };
+
+  void WriteSbom(cmSbomDocument& doc, std::ostream& os) const;
+
+  cmSpdxCreationInfo GenerateCreationInfo() const;
+  cmSpdxDocument GenerateSbom(cmSpdxCreationInfo const* ci) const;
+  cmSpdxPackage GenerateImportTarget(cmSpdxCreationInfo const* ci,
+                                     cmGeneratorTarget const* target) const;
+
+  std::string const& GetPackageName() const { return this->PackageName; }
+
+  bool GenerateImportFile(std::ostream& os) override;
+  bool AddPackageInformation(cmSpdxPackage& artifact, std::string const& name,
+                             cmPackageInformation const& package) const;
+
+  bool GenerateProperties(
+    cmSbomDocument& doc, cmSpdxDocument* project, cmSpdxCreationInfo const* ci,
+    TargetProperties const& current,
+    std::vector<TargetProperties> const& allTargets) const;
+
+  void GenerateLinkProperties(
+    cmSbomDocument& doc, cmSpdxDocument* project, cmSpdxCreationInfo const* ci,
+    std::string const& libraries, TargetProperties const& current,
+    std::vector<TargetProperties> const& allTargets) const;
+
+  bool NoteLinkedTarget(cmGeneratorTarget const* target,
+                        std::string const& linkedName,
+                        cmGeneratorTarget const* linkedTarget) override;
+
+  bool PopulateLinkLibrariesProperty(cmGeneratorTarget const* target,
+                                     cmGeneratorExpression::PreprocessContext,
+                                     ImportPropertyMap& properties);
+
+private:
+  struct LinkInfo
+  {
+    std::string Package;
+    std::string Component;
+  };
+
+  std::string const PackageName;
+  std::string const PackageVersion;
+  std::string const PackageDescription;
+  std::string const PackageWebsite;
+  std::string const PackageLicense;
+  std::string const PackageUrl;
+  cmSbomArguments::SbomFormat const PackageFormat;
+  std::map<std::string, LinkInfo> LinkTargets;
+  std::map<std::string, cmPackageInformation> Requirements;
+};
diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx
index f78eaab..886c639 100644
--- a/Source/cmExportTryCompileFileGenerator.cxx
+++ b/Source/cmExportTryCompileFileGenerator.cxx
@@ -6,6 +6,7 @@
 #include <utility>
 
 #include <cm/memory>
+#include <cmext/string_view>
 
 #include "cmFileSet.h"
 #include "cmGenExContext.h"
@@ -16,6 +17,7 @@
 #include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
+#include "cmMessageType.h"
 #include "cmOutputConverter.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
@@ -31,10 +33,25 @@
   gg->CreateImportedGenerationObjects(mf, targets, this->Exports);
 }
 
-void cmExportTryCompileFileGenerator::ReportError(
-  std::string const& errorMessage) const
+void cmExportTryCompileFileGenerator::IssueMessage(
+  MessageType type, std::string const& message) const
 {
-  cmSystemTools::Error(errorMessage);
+  switch (type) {
+    case MessageType::FATAL_ERROR:
+    case MessageType::AUTHOR_ERROR:
+    case MessageType::INTERNAL_ERROR:
+    case MessageType::DEPRECATION_ERROR:
+      cmSystemTools::Error(message);
+      break;
+    case MessageType::WARNING:
+    case MessageType::AUTHOR_WARNING:
+    case MessageType::DEPRECATION_WARNING:
+      cmSystemTools::Message(cmStrCat("CMake Warning: "_s, message),
+                             "Warning");
+      break;
+    default:
+      cmSystemTools::Message(message);
+  }
 }
 
 bool cmExportTryCompileFileGenerator::GenerateMainFile(std::ostream& os)
diff --git a/Source/cmExportTryCompileFileGenerator.h b/Source/cmExportTryCompileFileGenerator.h
index d9a8361..00231ba 100644
--- a/Source/cmExportTryCompileFileGenerator.h
+++ b/Source/cmExportTryCompileFileGenerator.h
@@ -30,7 +30,8 @@
   // Implement virtual methods from the superclass.
   void ComplainAboutDuplicateTarget(
     std::string const& /*targetName*/) const override {};
-  void ReportError(std::string const& errorMessage) const override;
+  void IssueMessage(MessageType type,
+                    std::string const& message) const override;
 
   bool GenerateMainFile(std::ostream& os) override;
 
diff --git a/Source/cmExprParserHelper.cxx b/Source/cmExprParserHelper.cxx
index eabda19..e2a2553 100644
--- a/Source/cmExprParserHelper.cxx
+++ b/Source/cmExprParserHelper.cxx
@@ -52,12 +52,13 @@
                              this->InputBuffer, "\": ", fail.what(), '.');
     this->SetError(std::move(e));
   } catch (std::out_of_range const&) {
-    std::string e = "cannot evaluate the expression: \"" + this->InputBuffer +
-      "\": a numeric value is out of range.";
+    std::string e =
+      cmStrCat("cannot evaluate the expression: \"", this->InputBuffer,
+               "\": a numeric value is out of range.");
     this->SetError(std::move(e));
   } catch (...) {
     std::string e =
-      "cannot parse the expression: \"" + this->InputBuffer + "\".";
+      cmStrCat("cannot parse the expression: \"", this->InputBuffer, "\".");
     this->SetError(std::move(e));
   }
   cmExpr_yylex_destroy(yyscanner);
diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx
index a484f42..306b765 100644
--- a/Source/cmExtraCodeBlocksGenerator.cxx
+++ b/Source/cmExtraCodeBlocksGenerator.cxx
@@ -154,9 +154,10 @@
 void Tree::BuildVirtualFolderImpl(std::string& virtualFolders,
                                   std::string const& prefix) const
 {
-  virtualFolders += "CMake Files\\" + prefix + this->path + "\\;";
+  virtualFolders += cmStrCat("CMake Files\\", prefix, this->path, "\\;");
   for (Tree const& folder : this->folders) {
-    folder.BuildVirtualFolderImpl(virtualFolders, prefix + this->path + "\\");
+    folder.BuildVirtualFolderImpl(virtualFolders,
+                                  cmStrCat(prefix, this->path, '\\'));
   }
 }
 
@@ -452,7 +453,7 @@
   }
 
   // Add CMakeLists.txt
-  tree.BuildUnit(xml, mf->GetHomeDirectory() + "/");
+  tree.BuildUnit(xml, mf->GetHomeDirectory() + '/');
 
   xml.EndElement(); // Project
   xml.EndElement(); // CodeBlocks_project_file
@@ -474,7 +475,7 @@
     fout << "# This is a dummy file for the OBJECT library "
          << target->GetName()
          << " for the CMake CodeBlocks project generator.\n"
-         << "# Don't edit, this file will be overwritten.\n";
+            "# Don't edit, this file will be overwritten.\n";
     /* clang-format on */
   }
   return filename;
diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx
index 3d8c939..466dfa5 100644
--- a/Source/cmExtraCodeLiteGenerator.cxx
+++ b/Source/cmExtraCodeLiteGenerator.cxx
@@ -185,9 +185,8 @@
 {
   std::string const& outputDir = lgs[0]->GetCurrentBinaryDirectory();
   std::string projectName = lgs[0]->GetProjectName();
-  std::string filename = outputDir + "/";
+  std::string filename = cmStrCat(outputDir, '/', projectName, ".project");
 
-  filename += projectName + ".project";
   this->CreateNewProjectFile(lgs, filename);
 }
 
@@ -661,8 +660,8 @@
 std::string cmExtraCodeLiteGenerator::GetRebuildCommand(
   cmMakefile const* mf, std::string const& targetName) const
 {
-  return this->GetCleanCommand(mf, targetName) + " && " +
-    this->GetBuildCommand(mf, targetName);
+  return cmStrCat(this->GetCleanCommand(mf, targetName), " && ",
+                  this->GetBuildCommand(mf, targetName));
 }
 
 std::string cmExtraCodeLiteGenerator::GetSingleFileBuildCommand(
diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx
index 968145c..9a5e109 100644
--- a/Source/cmExtraEclipseCDT4Generator.cxx
+++ b/Source/cmExtraEclipseCDT4Generator.cxx
@@ -10,6 +10,8 @@
 #include <sstream>
 #include <utility>
 
+#include <cmext/string_view>
+
 #include "cmsys/RegularExpression.hxx"
 
 #include "cmGeneratedFileStream.h"
@@ -461,21 +463,21 @@
 }
 
 void cmExtraEclipseCDT4Generator::WriteGroups(
-  std::vector<cmSourceGroup> const& sourceGroups, std::string& linkName,
+  SourceGroupVector const& sourceGroups, std::string& linkName,
   cmXMLWriter& xml)
 {
-  for (cmSourceGroup const& sg : sourceGroups) {
-    std::string linkName3 = cmStrCat(linkName, '/', sg.GetFullName());
+  for (auto const& sg : sourceGroups) {
+    std::string linkName3 = cmStrCat(linkName, '/', sg->GetFullName());
 
     std::replace(linkName3.begin(), linkName3.end(), '\\', '/');
 
     cmExtraEclipseCDT4Generator::AppendLinkedResource(
       xml, linkName3, "virtual:/virtual", VirtualFolder);
-    std::vector<cmSourceGroup> const& children = sg.GetGroupChildren();
+    SourceGroupVector const& children = sg->GetGroupChildren();
     if (!children.empty()) {
       this->WriteGroups(children, linkName, xml);
     }
-    std::vector<cmSourceFile const*> sFiles = sg.GetSourceFiles();
+    std::vector<cmSourceFile const*> sFiles = sg->GetSourceFiles();
     for (cmSourceFile const* file : sFiles) {
       std::string const& fullPath = file->GetFullPath();
 
@@ -518,8 +520,6 @@
           if (!this->GenerateLinkedResources) {
             break; // skip generating the linked resources to the source files
           }
-          std::vector<cmSourceGroup> sourceGroups =
-            makefile->GetSourceGroups();
           // get the files from the source lists then add them to the groups
           std::vector<cmSourceFile*> files;
           target->GetSourceFiles(
@@ -527,12 +527,11 @@
           for (cmSourceFile* sf : files) {
             // Add the file to the list of sources.
             std::string const& source = sf->ResolveFullPath();
-            cmSourceGroup* sourceGroup =
-              makefile->FindSourceGroup(source, sourceGroups);
+            cmSourceGroup* sourceGroup = lg->FindSourceGroup(source);
             sourceGroup->AssignSource(sf);
           }
 
-          this->WriteGroups(sourceGroups, linkName2, xml);
+          this->WriteGroups(makefile->GetSourceGroups(), linkName2, xml);
         } break;
         // ignore all others:
         default:
@@ -739,7 +738,7 @@
     // - only if not named the same as an output directory
     if (!cmSystemTools::FileIsDirectory(
           cmStrCat(this->HomeOutputDirectory, '/', p))) {
-      excludeFromOut += p + "/|";
+      excludeFromOut = cmStrCat(std::move(excludeFromOut), p, "/|");
     }
   }
 
@@ -1080,7 +1079,7 @@
 std::string cmExtraEclipseCDT4Generator::GenerateProjectName(
   std::string const& name, std::string const& type, std::string const& path)
 {
-  return name + (type.empty() ? "" : "-") + type + "@" + path;
+  return cmStrCat(name, (type.empty() ? ""_s : "-"_s), type, '@', path);
 }
 
 // Helper functions
diff --git a/Source/cmExtraEclipseCDT4Generator.h b/Source/cmExtraEclipseCDT4Generator.h
index d59a28a..aa7cc25 100644
--- a/Source/cmExtraEclipseCDT4Generator.h
+++ b/Source/cmExtraEclipseCDT4Generator.h
@@ -10,10 +10,10 @@
 #include <vector>
 
 #include "cmExternalMakefileProjectGenerator.h"
+#include "cmSourceGroup.h"
 
 class cmLocalGenerator;
 class cmMakefile;
-class cmSourceGroup;
 class cmXMLWriter;
 
 /** \class cmExtraEclipseCDT4Generator
@@ -87,7 +87,7 @@
   static void AddEnvVar(std::ostream& out, char const* envVar,
                         cmLocalGenerator& lg);
 
-  void WriteGroups(std::vector<cmSourceGroup> const& sourceGroups,
+  void WriteGroups(SourceGroupVector const& sourceGroups,
                    std::string& linkName, cmXMLWriter& xml);
   void CreateLinksToSubprojects(cmXMLWriter& xml, std::string const& baseDir);
   void CreateLinksForTargets(cmXMLWriter& xml);
diff --git a/Source/cmExtraKateGenerator.cxx b/Source/cmExtraKateGenerator.cxx
index 6bb3739..8045b4c 100644
--- a/Source/cmExtraKateGenerator.cxx
+++ b/Source/cmExtraKateGenerator.cxx
@@ -209,7 +209,7 @@
          << make << " -C \\\"" << (this->UseNinja ? homeOutputDir : path)
          << "\\\" "
          << ((this->UseNinja && configs.size() > 1)
-               ? std::string(" -f build-") + conf + ".ninja"
+               ? cmStrCat(" -f build-", conf, ".ninja")
                : std::string())
          << makeArgs << " " << target << "\"}\n";
 
@@ -328,7 +328,7 @@
   std::string const& name, std::string const& type,
   std::string const& path) const
 {
-  return name + (type.empty() ? "" : "-") + type + '@' + path;
+  return cmStrCat(name, (type.empty() ? "" : "-"), type, '@', path);
 }
 
 std::string cmExtraKateGenerator::GetPathBasename(
diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx
index 8d0ed60..ad371d5 100644
--- a/Source/cmExtraSublimeTextGenerator.cxx
+++ b/Source/cmExtraSublimeTextGenerator.cxx
@@ -87,7 +87,7 @@
   std::string projectName = lgs[0]->GetProjectName();
 
   std::string const filename =
-    outputDir + "/" + projectName + ".sublime-project";
+    cmStrCat(outputDir, '/', projectName, ".sublime-project");
 
   this->CreateNewProjectFile(lgs, filename);
 }
@@ -318,14 +318,12 @@
   std::string generator = this->GlobalGenerator->GetName();
   if (generator == "NMake Makefiles") {
     std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
-    command += R"(, "/NOLOGO", "/f", ")";
-    command += makefileName + "\"";
-    command += ", \"" + target + "\"";
+    command = cmStrCat(std::move(command), R"(, "/NOLOGO", "/f", ")",
+                       std::move(makefileName), "\", \"", target, '"');
   } else if (generator == "Ninja") {
     std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
-    command += R"(, "-f", ")";
-    command += makefileName + "\"";
-    command += ", \"" + target + "\"";
+    command = cmStrCat(std::move(command), R"(, "-f", ")",
+                       std::move(makefileName), "\", \"", target, '"');
   } else {
     std::string makefileName;
     if (generator == "MinGW Makefiles") {
@@ -335,9 +333,8 @@
     } else {
       makefileName = cmSystemTools::ConvertToOutputPath(makefile);
     }
-    command += R"(, "-f", ")";
-    command += makefileName + "\"";
-    command += ", \"" + target + "\"";
+    command = cmStrCat(std::move(command), R"(, "-f", ")",
+                       std::move(makefileName), "\", \"", target, '"');
   }
   return command;
 }
@@ -456,7 +453,8 @@
     return false;
   }
 
-  std::string filename = bindir + "/" + projectName + ".sublime-project";
+  std::string filename =
+    cmStrCat(bindir, '/', projectName, ".sublime-project");
   if (dryRun) {
     return cmSystemTools::FileExists(filename, true);
   }
diff --git a/Source/cmFastbuildNormalTargetGenerator.cxx b/Source/cmFastbuildNormalTargetGenerator.cxx
index fb7b8e5..ee9e9fb 100644
--- a/Source/cmFastbuildNormalTargetGenerator.cxx
+++ b/Source/cmFastbuildNormalTargetGenerator.cxx
@@ -97,8 +97,8 @@
     "\"" FASTBUILD_DOLLAR_TAG "TargetOutputImplib" FASTBUILD_DOLLAR_TAG "\"");
   for (auto const& lang : Languages) {
     TargetIncludesByLanguage[lang] = this->GetIncludes(lang, Config);
-    LogMessage("targetIncludes for lang " + lang + " = " +
-               TargetIncludesByLanguage[lang]);
+    LogMessage(cmStrCat("targetIncludes for lang ", lang, " = ",
+                        TargetIncludesByLanguage[lang]));
 
     for (auto const& arch : this->GetArches()) {
       auto& flags = CompileFlagsByLangAndArch[std::make_pair(lang, arch)];
@@ -191,7 +191,7 @@
   if (iter != compilers.end()) {
     LogMessage("Linker launcher: " + iter->first);
     outLinkerExecutable = iter->second.Executable;
-    outLinkerArgs = cmStrCat(iter->second.Args, " ", command);
+    outLinkerArgs = cmStrCat(iter->second.Args, ' ', command);
   } else {
     SplitLinkerFromArgs(command, outLinkerExecutable, outLinkerArgs);
   }
@@ -277,8 +277,7 @@
   vars.CMTargetType = cmState::GetTargetTypeName(targetType).c_str();
   vars.Config = Config.c_str();
   vars.Language = linkLanguage.c_str();
-  std::string const manifests =
-    cmJoin(this->GetManifestsAsFastbuildPath(), " ");
+  std::string const manifests = this->GetManifests(Config);
   vars.Manifests = manifests.c_str();
 
   std::string const stdLibString = this->Makefile->GetSafeDefinition(
@@ -365,7 +364,7 @@
     this->GetGeneratorTarget(), "RULE_LAUNCH_LINK", Config);
   if (cmNonempty(val)) {
     LogMessage("RULE_LAUNCH_LINK: " + val);
-    command = cmStrCat(val, " ", command);
+    command = cmStrCat(val, ' ', command);
   }
 }
 
@@ -562,7 +561,7 @@
     execNode.Name = target.Name + "-def-files";
     execNode.ExecExecutable = cmSystemTools::GetCMakeCommand();
     execNode.ExecArguments =
-      cmStrCat("-E __create_def ", FASTBUILD_2_INPUT_PLACEHOLDER, " ",
+      cmStrCat("-E __create_def ", FASTBUILD_2_INPUT_PLACEHOLDER, ' ',
                FASTBUILD_1_INPUT_PLACEHOLDER);
     std::string const obj_list_file = mdi->DefFile + ".objs";
 
@@ -857,6 +856,12 @@
   this->GeneratorTarget->CheckCxxModuleStatus(Config);
 
   FastbuildTarget fastbuildTarget;
+  auto const addUtilDepToTarget = [&fastbuildTarget](std::string depName) {
+    FastbuildTargetDep dep{ depName };
+    dep.Type = FastbuildTargetDepType::UTIL;
+    fastbuildTarget.PreBuildDependencies.emplace(std::move(dep));
+  };
+
   fastbuildTarget.Name = GetTargetName();
   fastbuildTarget.BaseName = this->GeneratorTarget->GetName();
 
@@ -882,7 +887,7 @@
 
   for (auto& cc : GenerateCommands(FastbuildBuildStep::PRE_BUILD).Nodes) {
     fastbuildTarget.PreBuildExecNodes.PreBuildDependencies.emplace(cc.Name);
-    fastbuildTarget.PreBuildDependencies.emplace(cc.Name);
+    addUtilDepToTarget(cc.Name);
     this->GetGlobalGenerator()->AddTarget(std::move(cc));
   }
   for (auto& cc : GenerateCommands(FastbuildBuildStep::PRE_LINK).Nodes) {
@@ -1000,27 +1005,15 @@
   if (this->GetGlobalGenerator()->GetCMakeInstance()->GetIsInTryCompile()) {
     return;
   }
-  auto manifests = this->GetManifestsAsFastbuildPath();
-  if (manifests.empty()) {
-    return;
-  }
+  std::vector<std::string> const manifests =
+    this->GetManifestsAsFastbuildPath();
   // Manifests should always be in .Libraries2, so we re-link when needed.
   // Tested in RunCMake.BuildDepends
+  linkerNode.Libraries2.reserve(linkerNode.Libraries2.size() +
+                                manifests.size());
   for (auto const& manifest : manifests) {
     linkerNode.Libraries2.emplace_back(manifest);
   }
-
-  if (this->Makefile->GetSafeDefinition("CMAKE_C_COMPILER_ID") != "MSVC") {
-    return;
-  }
-
-  for (auto const& manifest : manifests) {
-    linkerNode.LinkerOptions =
-      cmStrCat("/MANIFESTINPUT:", manifest, ' ', linkerNode.LinkerOptions);
-  }
-  // /MANIFESTINPUT only works with /MANIFEST:EMBED
-  linkerNode.LinkerOptions =
-    cmStrCat("/MANIFEST:EMBED ", linkerNode.LinkerOptions);
 }
 
 void cmFastbuildNormalTargetGenerator::AddStampExeIfApplicable(
@@ -1519,7 +1512,7 @@
 
   for (auto& val : nodesPermutations) {
     auto& objectListNode = val.second;
-    objectListNode.Name = cmStrCat(objectListNode.Name, "_", ++groupNameCount);
+    objectListNode.Name = cmStrCat(objectListNode.Name, '_', ++groupNameCount);
     LogMessage(cmStrCat("ObjectList name: ", objectListNode.Name));
   }
   std::vector<FastbuildObjectListNode>& objects = target.ObjectListNodes;
@@ -1792,7 +1785,8 @@
       // Tested in "RunCMake.Framework - ImportedFrameworkConsumption".
       std::string const decorated =
         item.GetFormattedItem(item.Value.Value).Value;
-      LogMessage("Adding framework dep <" + decorated + "> to command line");
+      LogMessage(
+        cmStrCat("Adding framework dep <", decorated, "> to command line"));
       linkerNode.LinkerOptions += (" " + decorated);
       return;
     }
@@ -1829,8 +1823,9 @@
       // It moves the dep outside of FASTBuild control, so the binary won't
       // be re-built if the shared lib has changed.
       // Tested in "BuildDepends" test.
-      LogMessage("LINK_DEPENDS_NO_SHARED is set on the target, adding dep" +
-                 item.Value.Value + " as is");
+      LogMessage(
+        cmStrCat("LINK_DEPENDS_NO_SHARED is set on the target, adding dep",
+                 item.Value.Value, " as is"));
       linkerNode.LinkerOptions +=
         (" " + cmGlobalFastbuildGenerator::QuoteIfHasSpaces(item.Value.Value));
       return;
@@ -1838,6 +1833,9 @@
     // Just add path to binary artifact to command line (except for OBJECT
     // libraries which we will link directly).
     if (UsingCommandLine && depType != cmStateEnums::OBJECT_LIBRARY) {
+      // Take transitively linked objects into account,
+      // so we don't link them again.
+      AppendTransitivelyLinkedObjects(*item.Target, linkedObjects);
       AppendCommandLineDep(linkerNode, item);
       return;
     }
@@ -1865,7 +1863,7 @@
     // inject any properties in between). Tested in
     // "RunCMake.target_link_libraries-LINK_LIBRARY" test.
     if (isFeature) {
-      LogMessage("AppendTargetDep: " + dep + " as prebuild");
+      LogMessage(cmStrCat("AppendTargetDep: ", dep, " as prebuild"));
       linkerNode.PreBuildDependencies.emplace(dep);
       return;
     }
@@ -1906,7 +1904,7 @@
       linkerNode.PreBuildDependencies.insert(std::move(fastbuildTargetName));
     } else {
       if (!cmIsNOTFOUND(linkDep)) {
-        LogMessage("Adding dep " + linkDep + " for sorting");
+        LogMessage(cmStrCat("Adding dep ", linkDep, " for sorting"));
         linkerNode.PreBuildDependencies.insert(linkDep);
       }
     }
@@ -1954,7 +1952,8 @@
   }
   formatted = this->ConvertToFastbuildPath(formatted);
 
-  LogMessage("Unknown link dep: " + formatted + ", adding to command line");
+  LogMessage(
+    cmStrCat("Unknown link dep: ", formatted, ", adding to command line"));
 
   // Only add real artifacts to .Libraries2, otherwise Fastbuild will always
   // consider the target out-of-date (since its input doesn't exist).
@@ -1976,7 +1975,7 @@
   // target out-of-date (since it never exists).
   if (this->GeneratorTarget->IsApple() &&
       cmSystemTools::StringStartsWith(dep, "-framework")) {
-    LogMessage("Not adding framework: " + dep + " to .Libraries2");
+    LogMessage(cmStrCat("Not adding framework: ", dep, " to .Libraries2"));
     return;
   }
 
@@ -1986,13 +1985,13 @@
   if (this->GeneratorTarget->IsApple() && target &&
       !target->LinkerNode.empty() &&
       target->LinkerNode[0].Type == FastbuildLinkerNode::EXECUTABLE) {
-    LogMessage("Not adding DLL/Executable(" + linkerNode.Name +
-               " to .Libraries2");
+    LogMessage(cmStrCat("Not adding DLL/Executable(", linkerNode.Name,
+                        " to .Libraries2"));
     return;
   }
 
-  // Additing to .Libraries2 for tracking.
-  LogMessage("Adding " + dep + " .Libraries2");
+  // Adding to .Libraries2 for tracking.
+  LogMessage(cmStrCat("Adding ", dep, " .Libraries2"));
   linkerNode.Libraries2.emplace_back(std::move(dep));
 }
 
@@ -2016,8 +2015,8 @@
 void cmFastbuildNormalTargetGenerator::AppendLinkDep(
   FastbuildLinkerNode& linkerNode, std::string dep) const
 {
-  LogMessage("AppendLinkDep: " + dep +
-             " to .LibrarianAdditionalInputs/.Libraries");
+  LogMessage(cmStrCat("AppendLinkDep: ", dep,
+                      " to .LibrarianAdditionalInputs/.Libraries"));
   linkerNode.LibrarianAdditionalInputs.emplace_back(std::move(dep));
 }
 
@@ -2115,8 +2114,8 @@
         }
       }
     } else if (linkerNode.Type == FastbuildLinkerNode::STATIC_LIBRARY) {
-      LogMessage("Skipping linking to STATIC_LIBRARY (" + linkerNode.Name +
-                 ")");
+      LogMessage(cmStrCat("Skipping linking to STATIC_LIBRARY (",
+                          linkerNode.Name, ')'));
       continue;
     }
     // We're linked to exact target.
@@ -2162,8 +2161,8 @@
   for (auto const& ArchSpecificTarget : target.LinkerNode) {
     exec.ExecInput.emplace_back(ArchSpecificTarget.LinkerOutput);
   }
-  exec.ExecArguments +=
-    "-create -output " + target.RealOutput + " " + cmJoin(exec.ExecInput, " ");
+  exec.ExecArguments += cmStrCat("-create -output ", target.RealOutput, " ",
+                                 cmJoin(exec.ExecInput, " "));
   target.PostBuildExecNodes.Alias.PreBuildDependencies.emplace(
     exec.ExecOutput);
   target.PostBuildExecNodes.Nodes.emplace_back(std::move(exec));
@@ -2253,9 +2252,7 @@
       std::string outpath = GeneratorTarget->GetDirectory(Config);
       this->OSXBundleGenerator->CreateAppBundle(targetNames.Output, outpath,
                                                 Config);
-      targetOutputReal = outpath;
-      targetOutputReal += "/";
-      targetOutputReal += outputReal;
+      targetOutputReal = cmStrCat(outpath, '/', outputReal);
       targetOutputReal = this->ConvertToFastbuildPath(targetOutputReal);
     } else if (GeneratorTarget->IsFrameworkOnApple()) {
       // Create the library framework.
@@ -2347,17 +2344,17 @@
       if (from.empty() || to.empty() || from == to) {
         return;
       }
-      LogMessage("Symlinking " + from + " -> " + to);
+      LogMessage(cmStrCat("Symlinking ", from, " -> ", to));
       FastbuildExecNode postBuildExecNode;
       postBuildExecNode.Name = "cmake_symlink_" + to;
       postBuildExecNode.ExecOutput =
         cmJoin({ GeneratorTarget->GetDirectory(Config), to }, "/");
       postBuildExecNode.ExecExecutable = cmSystemTools::GetCMakeCommand();
-      postBuildExecNode.ExecArguments =
-        "-E cmake_symlink_executable " +
-        cmGlobalFastbuildGenerator::QuoteIfHasSpaces(from) + " " +
+      postBuildExecNode.ExecArguments = cmStrCat(
+        "-E cmake_symlink_executable ",
+        cmGlobalFastbuildGenerator::QuoteIfHasSpaces(from), ' ',
         cmGlobalFastbuildGenerator::QuoteIfHasSpaces(
-          this->ConvertToFastbuildPath(postBuildExecNode.ExecOutput));
+          this->ConvertToFastbuildPath(postBuildExecNode.ExecOutput)));
       res.emplace_back(std::move(postBuildExecNode));
     };
     generateSymlinkCommand(targetNames.Real, targetNames.Output);
diff --git a/Source/cmFastbuildTargetGenerator.cxx b/Source/cmFastbuildTargetGenerator.cxx
index afcddb2..06f6ab9 100644
--- a/Source/cmFastbuildTargetGenerator.cxx
+++ b/Source/cmFastbuildTargetGenerator.cxx
@@ -306,8 +306,8 @@
     exec.ExecOutput = this->ConvertToFastbuildPath(dummyOutput);
     for (auto const& output : exec.OutputsAlias.PreBuildDependencies) {
       OutputsToReplace[output.Name] = exec.ExecOutput;
-      LogMessage("Adding replace from " + output.Name + " to " +
-                 exec.ExecOutput);
+      LogMessage(cmStrCat("Adding replace from ", output.Name, " to ",
+                          exec.ExecOutput));
     }
   };
 
@@ -339,9 +339,9 @@
 void cmFastbuildTargetGenerator::AddExecArguments(
   FastbuildExecNode& exec, std::string const& scriptFilename) const
 {
-  exec.ExecArguments = FASTBUILD_SCRIPT_FILE_ARG;
-  exec.ExecArguments +=
-    cmGlobalFastbuildGenerator::QuoteIfHasSpaces(scriptFilename);
+  exec.ExecArguments =
+    cmStrCat(FASTBUILD_SCRIPT_FILE_ARG,
+             cmGlobalFastbuildGenerator::QuoteIfHasSpaces(scriptFilename));
 
   exec.ScriptFile = scriptFilename;
   exec.ExecExecutable =
@@ -372,15 +372,16 @@
 
     auto const targetInfo = this->LocalGenerator->GetSourcesWithOutput(dep);
     if (targetInfo.Target) {
-      LogMessage("dep: " + dep + ", target: " + targetInfo.Target->GetName());
+      LogMessage(
+        cmStrCat("dep: ", dep, ", target: ", targetInfo.Target->GetName()));
       auto const& target = targetInfo.Target;
       auto const processCCs = [this, &currentCCName, &targetDep,
                                dep](std::vector<cmCustomCommand> const& ccs,
                                     FastbuildBuildStep step) {
         for (auto const& cc : ccs) {
           for (auto const& output : cc.GetOutputs()) {
-            LogMessage("dep: " + dep + ", post output: " +
-                       this->ConvertToFastbuildPath(output));
+            LogMessage(cmStrCat("dep: ", dep, ", post output: ",
+                                this->ConvertToFastbuildPath(output)));
             if (this->ConvertToFastbuildPath(output) == dep) {
               auto ccName = this->GetCustomCommandTargetName(cc, step);
               if (ccName != currentCCName) {
@@ -390,8 +391,8 @@
             }
           }
           for (auto const& byproduct : cc.GetByproducts()) {
-            LogMessage("dep: " + dep + ", post byproduct: " +
-                       this->ConvertToFastbuildPath(byproduct));
+            LogMessage(cmStrCat("dep: ", dep, ", post byproduct: ",
+                                this->ConvertToFastbuildPath(byproduct)));
             if (this->ConvertToFastbuildPath(byproduct) == dep) {
               auto ccName = this->GetCustomCommandTargetName(cc, step);
               if (ccName != currentCCName) {
@@ -409,8 +410,8 @@
       continue;
     }
     if (!targetInfo.Source) {
-      LogMessage("dep: " + dep + ", no source, byproduct: " +
-                 std::to_string(targetInfo.SourceIsByproduct));
+      LogMessage(cmStrCat("dep: ", dep, ", no source, byproduct: ",
+                          targetInfo.SourceIsByproduct));
       // Tested in "OutDir" test.
       if (!cmSystemTools::FileIsFullPath(orig)) {
         targetDep.emplace(std::move(orig));
@@ -418,7 +419,7 @@
       continue;
     }
     if (!targetInfo.Source->GetCustomCommand()) {
-      LogMessage("dep: " + dep + ", no GetCustomCommand");
+      LogMessage(cmStrCat("dep: ", dep, ", no GetCustomCommand"));
       continue;
     }
     if (targetInfo.Source && targetInfo.Source->GetCustomCommand()) {
@@ -491,7 +492,7 @@
     return res;
   }
 
-  res.Name = "create_" + names.ImportOutput + "_text_stub";
+  res.Name = cmStrCat("create_", names.ImportOutput, "_text_stub");
   res.ExecExecutable = std::move(executable);
   res.ExecArguments = std::move(args);
   res.ExecWorkingDir = this->LocalCommonGenerator->GetCurrentBinaryDirectory();
@@ -509,18 +510,16 @@
   exec.ExecUseStdOutAsOutput = true;
   exec.ExecOutput = depender.ExecOutput + ".deps-checker";
   exec.ExecExecutable = cmSystemTools::GetCMakeCommand();
-  exec.ExecArguments += "-E cmake_fastbuild_check_depends ";
-  exec.ExecArguments += depender.ExecOutput + " ";
-  char const* sep = "";
+  exec.ExecArguments =
+    cmStrCat(std::move(exec.ExecArguments),
+             "-E cmake_fastbuild_check_depends ", depender.ExecOutput);
   for (auto const& dep : depender.OutputsAlias.PreBuildDependencies) {
-    exec.ExecArguments += sep;
-    exec.ExecArguments += dep.Name;
-    sep = " ";
+    exec.ExecArguments =
+      cmStrCat(std::move(exec.ExecArguments), ' ', dep.Name);
   }
   for (auto const& dep : depender.ByproductsAlias.PreBuildDependencies) {
-    exec.ExecArguments += sep;
-    exec.ExecArguments += dep.Name;
-    sep = " ";
+    exec.ExecArguments =
+      cmStrCat(std::move(exec.ExecArguments), ' ', dep.Name);
   }
   return exec;
 }
@@ -593,7 +592,7 @@
     FastbuildExecNode execNode;
     execNode.Name = execName;
 
-    // Add depncencies to "ExecInput" so that FASTBuild will re-run the Exec
+    // Add dependencies to "ExecInput" so that FASTBuild will re-run the Exec
     // when needed, but also add to "PreBuildDependencies" for correct sorting.
     // Tested in "ObjectLibrary / complexOneConfig" tests.
     GetDepends(ccg, execName, execNode.ExecInput,
@@ -652,7 +651,7 @@
       }
     }
     for (auto const& out : execNode.OutputsAlias.PreBuildDependencies) {
-      LogMessage("Adding replace from " + out.Name + " to " + execName);
+      LogMessage(cmStrCat("Adding replace from ", out.Name, " to ", execName));
       OutputToExecName[out.Name] = execName;
     }
     execs.Nodes.emplace_back(std::move(execNode));
@@ -661,7 +660,8 @@
     for (auto& inputFile : exec.ExecInput) {
       auto const iter = OutputsToReplace.find(inputFile);
       if (iter != OutputsToReplace.end()) {
-        LogMessage("Replacing input: " + inputFile + " with " + iter->second);
+        LogMessage(
+          cmStrCat("Replacing input: ", inputFile, " with ", iter->second));
         inputFile = iter->second;
       }
       auto const depIter = std::find_if(
@@ -670,8 +670,8 @@
           return !OutputToExecName[dep.Name].empty();
         });
       if (depIter != exec.PreBuildDependencies.end()) {
-        LogMessage("Replacing dep " + depIter->Name + " with " +
-                   OutputToExecName[depIter->Name]);
+        LogMessage(cmStrCat("Replacing dep ", depIter->Name, " with ",
+                            OutputToExecName[depIter->Name]));
         exec.PreBuildDependencies.emplace(OutputToExecName[depIter->Name]);
         exec.PreBuildDependencies.erase(depIter);
       }
diff --git a/Source/cmFastbuildUtilityTargetGenerator.cxx b/Source/cmFastbuildUtilityTargetGenerator.cxx
index 1936f7f..a0de264 100644
--- a/Source/cmFastbuildUtilityTargetGenerator.cxx
+++ b/Source/cmFastbuildUtilityTargetGenerator.cxx
@@ -15,7 +15,9 @@
 #include "cmGlobalFastbuildGenerator.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
+#include "cmSourceFile.h"
 #include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
 #include "cmTarget.h"
 #include "cmTargetDepend.h"
 
@@ -27,6 +29,9 @@
 
 void cmFastbuildUtilityTargetGenerator::Generate()
 {
+  if (!this->GetGeneratorTarget()->IsInBuildSystem()) {
+    return;
+  }
   std::string targetName = GeneratorTarget->GetName();
 
   if (this->GeneratorTarget->GetType() == cmStateEnums::GLOBAL_TARGET) {
@@ -34,7 +39,14 @@
   }
 
   FastbuildAliasNode fastbuildTarget;
+  auto const addUtilDepToTarget = [&fastbuildTarget](std::string depName) {
+    FastbuildTargetDep dep{ depName };
+    dep.Type = FastbuildTargetDepType::UTIL;
+    fastbuildTarget.PreBuildDependencies.emplace(std::move(dep));
+  };
+
   fastbuildTarget.Name = targetName;
+  fastbuildTarget.BaseName = targetName;
 
   LogMessage("<-------------->");
   LogMessage("Generate Utility target: " + targetName);
@@ -66,16 +78,15 @@
         LogMessage("Transitively propagating iface dep: " + depName +
                    ", is cross: " + std::to_string(dep.Value.second));
         nonImportedUtils.emplace_back(depName);
-        fastbuildTarget.PreBuildDependencies.emplace(
-          this->ConvertToFastbuildPath(depName));
+        addUtilDepToTarget(this->ConvertToFastbuildPath(depName));
       }
     } else {
       nonImportedUtils.emplace_back(utilTargetName);
-      fastbuildTarget.PreBuildDependencies.emplace(utilTargetName);
+      addUtilDepToTarget(utilTargetName);
     }
   }
   if (this->GetGlobalGenerator()->IsExcluded(this->GetGeneratorTarget())) {
-    LogMessage("Excluding " + targetName + " from ALL");
+    LogMessage(cmStrCat("Excluding ", targetName, " from ALL"));
     fastbuildTarget.ExcludeFromAll = true;
   }
   auto preBuild = GenerateCommands(FastbuildBuildStep::PRE_BUILD);
@@ -83,7 +94,7 @@
   // Tested in "RunCMake.CPack*" tests.
   // Utility target "package" has packaging steps as "POST_BUILD".
   for (auto& exec : GenerateCommands(FastbuildBuildStep::POST_BUILD).Nodes) {
-    fastbuildTarget.PreBuildDependencies.emplace(exec.Name);
+    addUtilDepToTarget(exec.Name);
     for (std::string const& util : nonImportedUtils) {
       LogMessage("Adding: util " + util);
       exec.PreBuildDependencies.emplace(util);
@@ -99,12 +110,12 @@
 
   for (auto& exec : preBuild.Nodes) {
     LogMessage("Adding exec " + exec.Name);
-    fastbuildTarget.PreBuildDependencies.emplace(exec.Name);
+    addUtilDepToTarget(exec.Name);
     this->GetGlobalGenerator()->AddTarget(std::move(exec));
   }
 
   for (auto& exec : GenerateCommands(FastbuildBuildStep::REST).Nodes) {
-    fastbuildTarget.PreBuildDependencies.emplace(exec.Name);
+    addUtilDepToTarget(exec.Name);
     for (auto const& dep : TargetDirectDependencies) {
       LogMessage("Direct dep " + dep->GetName() +
                  "-all propagating to CC: " + exec.Name);
@@ -114,13 +125,33 @@
     }
     this->GetGlobalGenerator()->AddTarget(std::move(exec));
   }
+  // The target has to be in the build system, but has no custom commands
+  // associated with it.
   if (fastbuildTarget.PreBuildDependencies.empty()) {
-    if (fastbuildTarget.ExcludeFromAll) {
-      return;
+    std::vector<cmSourceFile*> sources;
+    this->GetGeneratorTarget()->GetSourceFiles(sources, this->Config);
+    if (sources.empty()) {
+      FastbuildTargetDep dep{ FASTBUILD_NOOP_FILE_NAME };
+      dep.Type = FastbuildTargetDepType::ORDER_ONLY;
+      fastbuildTarget.PreBuildDependencies.emplace(std::move(dep));
+    } else {
+      for (cmSourceFile const* source : sources) {
+        FastbuildTargetDep dep{
+          this->GetGlobalGenerator()->ConvertToFastbuildPath(
+            source->GetFullPath())
+        };
+        dep.Type = FastbuildTargetDepType::ARTIFACT;
+        fastbuildTarget.PreBuildDependencies.emplace(std::move(dep));
+      }
     }
-    fastbuildTarget.PreBuildDependencies.emplace(FASTBUILD_NOOP_FILE_NAME);
   }
+
   fastbuildTarget.Hidden = false;
   this->AdditionalCleanFiles();
+
+  fastbuildTarget.BasePath = this->GetMakefile()->GetCurrentSourceDirectory();
+  if (this->GetGeneratorTarget()->GetType() != cmStateEnums::GLOBAL_TARGET) {
+    this->GetGlobalGenerator()->AddIDEProject(fastbuildTarget, Config);
+  }
   this->GetGlobalGenerator()->AddTarget(std::move(fastbuildTarget));
 }
diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx
index c2b8042..fa9c1c5 100644
--- a/Source/cmFileAPI.cxx
+++ b/Source/cmFileAPI.cxx
@@ -392,7 +392,7 @@
 void cmFileAPI::ReadClient(std::string const& client)
 {
   // Load queries for the client.
-  std::string clientDir = this->APIv1 + "/query/" + client;
+  std::string clientDir = cmStrCat(this->APIv1, "/query/", client);
   std::vector<std::string> queries = this->LoadDir(clientDir);
 
   // Read the queries and save for later.
@@ -410,7 +410,8 @@
 void cmFileAPI::ReadClientQuery(std::string const& client, ClientQueryJson& q)
 {
   // Read the query.json file.
-  std::string queryFile = this->APIv1 + "/query/" + client + "/query.json";
+  std::string queryFile =
+    cmStrCat(this->APIv1, "/query/", client, "/query.json");
   Json::Value query;
   if (!this->ReadJsonFile(queryFile, query, q.Error)) {
     return;
@@ -641,7 +642,7 @@
   } else if (kindName == this->ObjectKindName(ObjectKind::InternalTest)) {
     r.Kind = ObjectKind::InternalTest;
   } else {
-    r.Error = "unknown request kind '" + kindName + "'";
+    r.Error = cmStrCat("unknown request kind '", kindName, '\'');
     return r;
   }
 
@@ -821,7 +822,7 @@
 // Update the following files as well when updating this constant:
 //   Help/manual/cmake-file-api.7.rst
 //   Tests/RunCMake/FileAPI/codemodel-v2-check.py (check_objects())
-static unsigned int const CodeModelV2Minor = 9;
+static unsigned int const CodeModelV2Minor = 10;
 
 void cmFileAPI::BuildClientRequestCodeModel(
   ClientRequest& r, std::vector<RequestVersion> const& versions)
@@ -960,7 +961,7 @@
 
 // The "toolchains" object kind.
 
-static unsigned int const ToolchainsV1Minor = 0;
+static unsigned int const ToolchainsV1Minor = 1;
 
 void cmFileAPI::BuildClientRequestToolchains(
   ClientRequest& r, std::vector<RequestVersion> const& versions)
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index 35afd91..2950c67 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -439,7 +439,6 @@
   std::string const& Config;
   std::string TopSource;
   std::string TopBuild;
-  std::vector<cmSourceGroup> SourceGroupsLocal;
   BacktraceData Backtraces;
 
   std::map<std::string, CompileData> CompileDataMap;
@@ -451,6 +450,7 @@
   {
     std::string Name;
     Json::Value SourceIndexes = Json::arrayValue;
+    Json::Value InterfaceSourceIndexes = Json::arrayValue;
   };
   std::unordered_map<cmSourceGroup const*, Json::ArrayIndex> SourceGroupsMap;
   std::vector<SourceGroup> SourceGroups;
@@ -465,6 +465,8 @@
 
   using FileSetDatabase = std::map<std::string, Json::ArrayIndex>;
 
+  std::vector<cmFileSetVisibility> FileSetVisibilities;
+
   template <typename T>
   JBT<T> ToJBT(BT<T> const& bt)
   {
@@ -485,7 +487,7 @@
   void ProcessLanguages();
   void ProcessLanguage(std::string const& lang);
 
-  Json::ArrayIndex AddSourceGroup(cmSourceGroup* sg, Json::ArrayIndex si);
+  Json::ArrayIndex AddSourceGroup(cmSourceGroup* sg);
   CompileData BuildCompileData(cmSourceFile* sf);
   CompileData MergeCompileData(CompileData const& fd);
   Json::ArrayIndex AddSourceCompileGroup(cmSourceFile* sf,
@@ -505,6 +507,9 @@
   Json::Value DumpSources(FileSetDatabase const& fsdb);
   Json::Value DumpSource(cmGeneratorTarget::SourceAndKind const& sk,
                          Json::ArrayIndex si, FileSetDatabase const& fsdb);
+  Json::Value DumpInterfaceSources(FileSetDatabase const& fsdb);
+  Json::Value DumpInterfaceSource(std::string path, Json::ArrayIndex si,
+                                  FileSetDatabase const& fsdb);
   Json::Value DumpSourceGroups();
   Json::Value DumpSourceGroup(SourceGroup& sg);
   Json::Value DumpCompileGroups();
@@ -1067,7 +1072,7 @@
     installer["destination"] = installDir->GetDestination(this->Config);
     Json::Value paths = Json::arrayValue;
     for (std::string const& dir : dirs) {
-      if (cmHasLiteralSuffix(dir, "/")) {
+      if (cmHasSuffix(dir, '/')) {
         paths.append(this->DumpInstallerPath(
           this->TopSource, dir.substr(0, dir.size() - 1), "."));
       } else {
@@ -1162,7 +1167,7 @@
       for (auto const& file : it.second) {
         files.append(this->DumpInstallerPath(
           this->TopSource, file,
-          cmStrCat(dir, cmSystemTools::GetFilenameName(file))));
+          cmStrCat(dir, cmSystemTools::GetFilenameNameView(file))));
       }
     }
     installer["paths"] = std::move(files);
@@ -1256,7 +1261,6 @@
   , TopSource(gt->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
   , TopBuild(
       gt->GetGlobalGenerator()->GetCMakeInstance()->GetHomeOutputDirectory())
-  , SourceGroupsLocal(this->GT->Makefile->GetSourceGroups())
   , Backtraces(this->TopSource)
 {
 }
@@ -1375,6 +1379,11 @@
     // output a sources array to preserve backward compatibility
     target["sources"] = this->DumpSources(fileSetInfo.second);
 
+    auto interfaceSources = this->DumpInterfaceSources(fileSetInfo.second);
+    if (!interfaceSources.empty()) {
+      target["interfaceSources"] = std::move(interfaceSources);
+    }
+
     Json::Value folder = this->DumpFolder();
     if (!folder.isNull()) {
       target["folder"] = std::move(folder);
@@ -1468,7 +1477,7 @@
   }
 }
 
-Json::ArrayIndex Target::AddSourceGroup(cmSourceGroup* sg, Json::ArrayIndex si)
+Json::ArrayIndex Target::AddSourceGroup(cmSourceGroup* sg)
 {
   auto i = this->SourceGroupsMap.find(sg);
   if (i == this->SourceGroupsMap.end()) {
@@ -1478,7 +1487,6 @@
     g.Name = sg->GetFullName();
     this->SourceGroups.push_back(std::move(g));
   }
-  this->SourceGroups[i->second].SourceIndexes.append(si);
   return i->second;
 }
 
@@ -1712,6 +1720,11 @@
   Json::Value fsJson = Json::nullValue;
   FileSetDatabase fsdb;
 
+  // We record the visibility of each file set for later use when dumping
+  // interface sources, which needs to map files to file set visibility
+  // with only an index available. Those indexes match this vector.
+  this->FileSetVisibilities.clear();
+
   // Build the fileset database.
   auto const* tgt = this->GT->Target;
   auto const& fs_names = tgt->GetAllFileSetNames();
@@ -1739,6 +1752,7 @@
         fs->EvaluateDirectoryEntries(directoryEntries, context, this->GT);
 
       fsJson.append(this->DumpFileSet(fs, directories));
+      this->FileSetVisibilities.push_back(fs->GetVisibility());
 
       std::map<std::string, std::vector<std::string>> files_per_dirs;
       for (auto const& entry : fileEntries) {
@@ -1750,7 +1764,7 @@
         auto const& dir = files_per_dir.first;
         for (auto const& file : files_per_dir.second) {
           std::string sf_path;
-          if (dir.empty()) {
+          if (dir.empty() || cmSystemTools::FileIsFullPath(file)) {
             sf_path = file;
           } else {
             sf_path = cmStrCat(dir, '/', file);
@@ -1815,9 +1829,10 @@
     source["fileSetIndex"] = fsit->second;
   }
 
-  if (cmSourceGroup* sg =
-        this->GT->Makefile->FindSourceGroup(path, this->SourceGroupsLocal)) {
-    source["sourceGroupIndex"] = this->AddSourceGroup(sg, si);
+  if (cmSourceGroup* sg = this->GT->LocalGenerator->FindSourceGroup(path)) {
+    Json::ArrayIndex const groupIndex = this->AddSourceGroup(sg);
+    source["sourceGroupIndex"] = groupIndex;
+    this->SourceGroups[groupIndex].SourceIndexes.append(si);
   }
 
   switch (sk.Kind) {
@@ -1844,6 +1859,69 @@
   return source;
 }
 
+Json::Value Target::DumpInterfaceSources(FileSetDatabase const& fsdb)
+{
+  Json::Value interfaceSources = Json::arrayValue;
+  auto dumpFile = [this, &interfaceSources, &fsdb](std::string const& file) {
+    std::string path = file;
+    if (!cmSystemTools::FileIsFullPath(path)) {
+      path = cmStrCat(
+        this->GT->GetLocalGenerator()->GetCurrentSourceDirectory(), '/', file);
+    }
+    path = cmSystemTools::CollapseFullPath(path);
+
+    interfaceSources.append(
+      this->DumpInterfaceSource(path, interfaceSources.size(), fsdb));
+  };
+
+  cmValue prop = this->GT->GetProperty("INTERFACE_SOURCES");
+  if (prop) {
+    cmList files{ cmGeneratorExpression::Evaluate(
+      *prop, this->GT->GetLocalGenerator(), this->Config, this->GT) };
+
+    for (std::string const& file : files) {
+      dumpFile(file);
+    }
+  }
+
+  for (auto const& fsIter : fsdb) {
+    Json::ArrayIndex const index = fsIter.second;
+    // FileSetVisibilities was populated by DumpFileSets() and will always
+    // have the same size as the file sets array that index is indexing into
+    if (this->FileSetVisibilities[index] != cmFileSetVisibility::Private) {
+      dumpFile(fsIter.first);
+    }
+  }
+
+  return interfaceSources;
+}
+
+Json::Value Target::DumpInterfaceSource(std::string path, Json::ArrayIndex si,
+                                        FileSetDatabase const& fsdb)
+{
+  Json::Value source = Json::objectValue;
+
+  cmSourceFile* sf = this->GT->Makefile->GetOrCreateSource(path);
+  path = sf->ResolveFullPath();
+  source["path"] = RelativeIfUnder(this->TopSource, path);
+  if (sf->GetIsGenerated()) {
+    source["isGenerated"] = true;
+  }
+
+  auto fsit = fsdb.find(path);
+  if (fsit != fsdb.end()) {
+    source["fileSetIndex"] = fsit->second;
+  }
+
+  if (cmSourceGroup* sg = this->GT->LocalGenerator->FindSourceGroup(path)) {
+    Json::ArrayIndex const groupIndex = this->AddSourceGroup(sg);
+    source["sourceGroupIndex"] = groupIndex;
+    this->SourceGroups[groupIndex].InterfaceSourceIndexes.append(si);
+  }
+
+  return source;
+}
+
 Json::Value Target::DumpCompileData(CompileData const& cd)
 {
   Json::Value result = Json::objectValue;
@@ -1954,6 +2032,9 @@
   Json::Value group = Json::objectValue;
   group["name"] = sg.Name;
   group["sourceIndexes"] = std::move(sg.SourceIndexes);
+  if (!sg.InterfaceSourceIndexes.empty()) {
+    group["interfaceSourceIndexes"] = std::move(sg.InterfaceSourceIndexes);
+  }
   return group;
 }
 
@@ -2084,9 +2165,9 @@
       this->GT->GetOutputInfo(this->Config);
     if (output && !output->PdbDir.empty()) {
       Json::Value artifact = Json::objectValue;
-      artifact["path"] = RelativeIfUnder(this->TopBuild,
-                                         output->PdbDir + '/' +
-                                           this->GT->GetPDBName(this->Config));
+      artifact["path"] = RelativeIfUnder(
+        this->TopBuild,
+        cmStrCat(output->PdbDir, '/', this->GT->GetPDBName(this->Config)));
       artifacts.append(std::move(artifact)); // NOLINT(*)
     }
   }
diff --git a/Source/cmFileAPICommand.cxx b/Source/cmFileAPICommand.cxx
index ca5389f..091fbc8 100644
--- a/Source/cmFileAPICommand.cxx
+++ b/Source/cmFileAPICommand.cxx
@@ -4,13 +4,14 @@
 
 #include <algorithm>
 #include <array>
-#include <cctype>
 #include <cstdlib>
 #include <utility>
 
 #include <cm/string_view>
 #include <cmext/string_view>
 
+#include "cmsys/String.h"
+
 #include "cmArgumentParser.h"
 #include "cmArgumentParserTypes.h"
 #include "cmExecutionStatus.h"
@@ -23,11 +24,6 @@
 
 namespace {
 
-bool isCharDigit(char ch)
-{
-  return std::isdigit(static_cast<unsigned char>(ch));
-}
-
 std::string processObjectKindVersions(cmFileAPI& fileApi,
                                       cmFileAPI::ObjectKind objectKind,
                                       cm::string_view keyword,
@@ -97,13 +93,13 @@
     return true;
   }
   if (!unparsedArguments.empty()) {
-    status.SetError("QUERY given unknown argument \"" +
-                    unparsedArguments.front() + "\".");
+    status.SetError(cmStrCat("QUERY given unknown argument \"",
+                             unparsedArguments.front(), "\"."));
     return false;
   }
 
   if (!std::all_of(arguments.ApiVersion.begin(), arguments.ApiVersion.end(),
-                   isCharDigit)) {
+                   cmsysString_isdigit)) {
     status.SetError("QUERY given non-integer API_VERSION.");
     return false;
   }
diff --git a/Source/cmFileAPIToolchains.cxx b/Source/cmFileAPIToolchains.cxx
index c156ca1..498bf35 100644
--- a/Source/cmFileAPIToolchains.cxx
+++ b/Source/cmFileAPIToolchains.cxx
@@ -24,6 +24,7 @@
   std::string ObjectKey;
   std::string VariableSuffix;
   bool IsList;
+  bool OmitEmpty;
 };
 
 class Toolchains
@@ -74,22 +75,23 @@
 Json::Value Toolchains::DumpToolchain(std::string const& lang)
 {
   static std::vector<ToolchainVariable> const CompilerVariables{
-    { "path", "COMPILER", false },
-    { "id", "COMPILER_ID", false },
-    { "version", "COMPILER_VERSION", false },
-    { "target", "COMPILER_TARGET", false },
+    { "path", "COMPILER", false, false },
+    { "commandFragment", "COMPILER_ARG1", false, true },
+    { "id", "COMPILER_ID", false, false },
+    { "version", "COMPILER_VERSION", false, false },
+    { "target", "COMPILER_TARGET", false, false },
   };
 
   static std::vector<ToolchainVariable> const CompilerImplicitVariables{
-    { "includeDirectories", "IMPLICIT_INCLUDE_DIRECTORIES", true },
-    { "linkDirectories", "IMPLICIT_LINK_DIRECTORIES", true },
-    { "linkFrameworkDirectories", "IMPLICIT_LINK_FRAMEWORK_DIRECTORIES",
-      true },
-    { "linkLibraries", "IMPLICIT_LINK_LIBRARIES", true },
+    { "includeDirectories", "IMPLICIT_INCLUDE_DIRECTORIES", true, false },
+    { "linkDirectories", "IMPLICIT_LINK_DIRECTORIES", true, false },
+    { "linkFrameworkDirectories", "IMPLICIT_LINK_FRAMEWORK_DIRECTORIES", true,
+      false },
+    { "linkLibraries", "IMPLICIT_LINK_LIBRARIES", true, false },
   };
 
   static ToolchainVariable const SourceFileExtensionsVariable{
-    "sourceFileExtensions", "SOURCE_FILE_EXTENSIONS", true
+    "sourceFileExtensions", "SOURCE_FILE_EXTENSIONS", true, false
   };
 
   auto const& mf =
@@ -128,15 +130,17 @@
     cmValue data = mf->GetDefinition(variableName);
     if (data) {
       cmList values(data);
-      Json::Value jsonArray = Json::arrayValue;
-      for (auto const& value : values) {
-        jsonArray.append(value);
+      if (!variable.OmitEmpty || !values.empty()) {
+        Json::Value jsonArray = Json::arrayValue;
+        for (auto const& value : values) {
+          jsonArray.append(value);
+        }
+        object[variable.ObjectKey] = jsonArray;
       }
-      object[variable.ObjectKey] = jsonArray;
     }
   } else {
     cmValue def = mf->GetDefinition(variableName);
-    if (def) {
+    if (def && (!variable.OmitEmpty || !def.IsEmpty())) {
       object[variable.ObjectKey] = *def;
     }
   }
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 057b3fa..f79cd39 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -4,7 +4,6 @@
 
 #include <algorithm>
 #include <cassert>
-#include <cctype>
 #include <cmath>
 #include <cstdio>
 #include <cstdlib>
@@ -26,6 +25,7 @@
 #include "cmsys/FStream.hxx"
 #include "cmsys/Glob.hxx"
 #include "cmsys/RegularExpression.hxx"
+#include "cmsys/String.h"
 
 #include "cm_sys_stat.h"
 
@@ -93,8 +93,8 @@
   i++;
 
   if (!status.GetMakefile().CanIWriteThisFile(fileName)) {
-    std::string e =
-      "attempted to write a file: " + fileName + " into a source directory.";
+    std::string e = cmStrCat("attempted to write a file: ", fileName,
+                             " into a source directory.");
     status.SetError(e);
     cmSystemTools::SetFatalErrorOccurred();
     return false;
@@ -519,7 +519,8 @@
     }
 
     if (c >= 0 && c <= 0xFF &&
-        (isprint(c) || c == '\t' || (c == '\n' && newline_consume))) {
+        (cmsysString_isprint(static_cast<char>(c)) || c == '\t' ||
+         (c == '\n' && newline_consume))) {
       // This is an ASCII character that may be part of a string.
       // Cast added to avoid compiler warning. Cast is ok because
       // c is guaranteed to fit in char by the above if...
@@ -686,7 +687,6 @@
   std::vector<std::string> files;
   bool configureDepends = false;
   bool warnConfigureLate = false;
-  cmake::WorkingMode const workingMode = cm->GetWorkingMode();
   while (i != args.end()) {
     if (*i == "LIST_DIRECTORIES") {
       ++i; // skip LIST_DIRECTORIES
@@ -737,7 +737,7 @@
           "CONFIGURE_DEPENDS flag was given after a glob expression was "
           "already evaluated.");
       }
-      if (workingMode != cmake::NORMAL_MODE) {
+      if (cm->GetState()->GetRole() != cmState::Role::Project) {
         status.GetMakefile().IssueMessage(
           MessageType::FATAL_ERROR,
           "CONFIGURE_DEPENDS is invalid for script and find package modes.");
@@ -771,13 +771,13 @@
           if (globMessage.type == cmsys::Glob::cyclicRecursion) {
             status.GetMakefile().IssueMessage(
               MessageType::AUTHOR_WARNING,
-              "Cyclic recursion detected while globbing for '" + *i + "':\n" +
-                globMessage.content);
+              cmStrCat("Cyclic recursion detected while globbing for '", *i,
+                       "':\n", globMessage.content));
           } else if (globMessage.type == cmsys::Glob::error) {
             status.GetMakefile().IssueMessage(
               MessageType::FATAL_ERROR,
-              "Error has occurred while globbing for '" + *i + "' - " +
-                globMessage.content);
+              cmStrCat("Error has occurred while globbing for '", *i, "' - ",
+                       globMessage.content));
             shouldExit = true;
           } else if (cm->GetDebugOutput() || cm->GetTrace()) {
             status.GetMakefile().IssueMessage(
@@ -930,8 +930,8 @@
         cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', arg);
     }
     if (!status.GetMakefile().CanIWriteThisFile(tfile)) {
-      std::string e =
-        "attempted to touch a file: " + tfile + " in a source directory.";
+      std::string e = cmStrCat("attempted to touch a file: ", tfile,
+                               " in a source directory.");
       status.SetError(e);
       cmSystemTools::SetFatalErrorOccurred();
       return false;
@@ -1608,9 +1608,10 @@
   {
     std::string fileName = arg;
     if (fileName.empty()) {
-      std::string const r = recurse ? "REMOVE_RECURSE" : "REMOVE";
+      std::string r = recurse ? "REMOVE_RECURSE" : "REMOVE";
       status.GetMakefile().IssueMessage(
-        MessageType::AUTHOR_WARNING, "Ignoring empty file name in " + r + ".");
+        MessageType::AUTHOR_WARNING,
+        cmStrCat("Ignoring empty file name in ", std::move(r), '.'));
       continue;
     }
     if (!cmsys::SystemTools::FileIsFullPath(fileName)) {
@@ -1698,6 +1699,16 @@
 // Stuff for curl download/upload
 using cmFileCommandVectorOfChar = std::vector<char>;
 
+std::string CurlCompatFileURL(std::string url)
+{
+  if (cmHasLiteralPrefix(url, "file://")) {
+    // libcurl 7.77 and below accidentally allowed spaces in file:// URLs,
+    // which CMake has long accepted as a result.  Explicitly encode spaces.
+    cmSystemTools::ReplaceString(url, " ", "%20");
+  }
+  return url;
+}
+
 size_t cmWriteToFileCallback(void* ptr, size_t size, size_t nmemb, void* data)
 {
   int realsize = static_cast<int>(size * nmemb);
@@ -2139,7 +2150,7 @@
     }
   }
 
-  url = cmCurlFixFileURL(url);
+  url = CurlCompatFileURL(url);
 
   ::CURL* curl;
   cm_curl_global_init(CURL_GLOBAL_DEFAULT);
@@ -2196,8 +2207,9 @@
   }
 
   for (auto const& range : curl_ranges) {
-    std::string curl_range = range.first + '-' +
-      (range.second.has_value() ? range.second.value() : "");
+    std::string curl_range =
+      cmStrCat(range.first, '-',
+               (range.second.has_value() ? range.second.value() : ""));
     res = ::curl_easy_setopt(curl, CURLOPT_RANGE, curl_range.c_str());
     check_curl_result(res, "DOWNLOAD cannot set range: ");
   }
@@ -2540,7 +2552,7 @@
 
   unsigned long file_size = cmsys::SystemTools::FileLength(filename);
 
-  url = cmCurlFixFileURL(url);
+  url = CurlCompatFileURL(url);
 
   ::CURL* curl;
   cm_curl_global_init(CURL_GLOBAL_DEFAULT);
@@ -3018,7 +3030,7 @@
     cmSystemTools::SetFatalErrorOccurred();
     return false;
   }
-  FILE* file = cmsys::SystemTools::Fopen(path, "w");
+  FILE* file = cmsys::SystemTools::Fopen(path, "a");
   if (!file) {
     status.GetMakefile().IssueMessage(
       MessageType::FATAL_ERROR,
@@ -3107,8 +3119,9 @@
     if (args[argsIndex] == "UTC") {
       utcFlag = true;
     } else {
-      std::string e = " TIMESTAMP sub-command does not recognize option " +
-        args[argsIndex] + ".";
+      std::string e =
+        cmStrCat(" TIMESTAMP sub-command does not recognize option ",
+                 args[argsIndex], '.');
       status.SetError(e);
       return false;
     }
@@ -3203,7 +3216,8 @@
     parser.Parse(cmMakeRange(args).advance(3), &unconsumedArgs);
 
   if (!unconsumedArgs.empty()) {
-    status.SetError("unknown argument: \"" + unconsumedArgs.front() + '\"');
+    status.SetError(cmStrCat("unknown argument: \"",
+                             std::move(unconsumedArgs.front()), '\"'));
     return false;
   }
 
@@ -3221,9 +3235,15 @@
     return false;
   }
 
+  cmPolicies::PolicyStatus const cmp0205 =
+    status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0205);
+
   // Hard link requires original file to exist.
-  if (!arguments.Symbolic && !cmSystemTools::FileExists(fileName)) {
-    result = "Cannot hard link \'" + fileName + "\' as it does not exist.";
+  if (!arguments.Symbolic &&
+      (!cmSystemTools::PathExists(fileName) ||
+       (cmp0205 != cmPolicies::NEW && !cmSystemTools::FileExists(fileName)))) {
+    result =
+      cmStrCat("Cannot hard link \'", fileName, "\' as it does not exist.");
     if (!arguments.Result.empty()) {
       status.GetMakefile().AddDefinition(arguments.Result, result);
       return true;
@@ -3233,20 +3253,31 @@
   }
 
   // Check if the new file already exists and remove it.
-  if (cmSystemTools::PathExists(newFileName) &&
-      !cmSystemTools::RemoveFile(newFileName)) {
-    auto err = cmStrCat("Failed to create link '", newFileName,
-                        "' because existing path cannot be removed: ",
-                        cmSystemTools::GetLastSystemError(), '\n');
-
-    if (!arguments.Result.empty()) {
-      status.GetMakefile().AddDefinition(arguments.Result, err);
-      return true;
+  if (cmSystemTools::PathExists(newFileName)) {
+    cmsys::Status rmStatus;
+    if (cmp0205 == cmPolicies::NEW && arguments.CopyOnError &&
+        cmSystemTools::FileIsDirectory(newFileName) &&
+        !cmSystemTools::FileIsSymlink(newFileName)) {
+      rmStatus = cmSystemTools::RepeatedRemoveDirectory(newFileName);
+    } else {
+      rmStatus = cmSystemTools::RemoveFile(newFileName);
     }
-    status.SetError(err);
-    return false;
+    if (!rmStatus) {
+      std::string err = cmStrCat("Failed to create link '", newFileName,
+                                 "' because existing path cannot be removed: ",
+                                 rmStatus.GetString(), '\n');
+
+      if (!arguments.Result.empty()) {
+        status.GetMakefile().AddDefinition(arguments.Result, err);
+        return true;
+      }
+      status.SetError(err);
+      return false;
+    }
   }
 
+  bool const sourceIsDirectory = cmSystemTools::FileIsDirectory(fileName);
+
   // Whether the operation completed successfully.
   bool completed = false;
 
@@ -3261,20 +3292,54 @@
                         "': ", linked.GetString());
     }
   } else {
-    cmsys::Status linked =
-      cmSystemTools::CreateLinkQuietly(fileName, newFileName);
-    if (linked) {
-      completed = true;
-    } else {
-      result = cmStrCat("failed to create link '", newFileName,
-                        "': ", linked.GetString());
+    bool needToTry = true;
+    if (sourceIsDirectory) {
+      if (cmp0205 == cmPolicies::NEW) {
+        needToTry = false;
+      } else if (cmp0205 == cmPolicies::WARN && arguments.CopyOnError) {
+        status.GetMakefile().IssueMessage(
+          MessageType::AUTHOR_WARNING,
+          cmStrCat("Path\n  ", fileName,
+                   "\nis a directory. Hard link creation is not supported "
+                   "for directories.\n",
+                   cmPolicies::GetPolicyWarning(cmPolicies::CMP0205)));
+      }
     }
+
+    if (needToTry) {
+      cmsys::Status linked =
+        cmSystemTools::CreateLinkQuietly(fileName, newFileName);
+      if (linked) {
+        completed = true;
+      } else {
+        result = cmStrCat("failed to create link '", newFileName,
+                          "': ", linked.GetString());
+      }
+    } else {
+      result =
+        cmStrCat("failed to create link '", newFileName, "': not supported");
+    }
+  }
+
+  if (cmp0205 == cmPolicies::WARN && arguments.CopyOnError &&
+      sourceIsDirectory) {
+    status.GetMakefile().IssueMessage(
+      MessageType::AUTHOR_WARNING,
+      cmStrCat("Path\n  ", fileName,
+               "\nis a directory. It will be copied "
+               "recursively when CMP0205 is set to NEW.\n",
+               cmPolicies::GetPolicyWarning(cmPolicies::CMP0205)));
   }
 
   // Check if copy-on-error is enabled in the arguments.
   if (!completed && arguments.CopyOnError) {
-    cmsys::Status copied =
-      cmsys::SystemTools::CopyFileAlways(fileName, newFileName);
+    cmsys::Status copied;
+    if (cmp0205 == cmPolicies::NEW && sourceIsDirectory) {
+      copied = cmsys::SystemTools::CopyADirectory(fileName, newFileName);
+    } else {
+      copied = cmsys::SystemTools::CopyFileAlways(fileName, newFileName);
+    }
+
     if (copied) {
       completed = true;
     } else {
@@ -3312,7 +3377,7 @@
     return false;
   }
 
-  if (status.GetMakefile().GetState()->GetMode() == cmState::Project) {
+  if (status.GetMakefile().GetState()->GetRole() == cmState::Role::Project) {
     status.GetMakefile().IssueMessage(
       MessageType::AUTHOR_WARNING,
       "You have used file(GET_RUNTIME_DEPENDENCIES)"
@@ -3421,7 +3486,7 @@
       deps.push_back(firstPath);
       if (!parsedArgs.RPathPrefix.empty()) {
         status.GetMakefile().AddDefinition(
-          parsedArgs.RPathPrefix + "_" + firstPath,
+          cmStrCat(parsedArgs.RPathPrefix, '_', firstPath),
           cmList::to_string(archive.GetRPaths().at(firstPath)));
       }
     } else if (!parsedArgs.ConflictingDependenciesPrefix.empty()) {
@@ -3429,7 +3494,7 @@
       std::vector<std::string> paths;
       paths.insert(paths.begin(), val.second.begin(), val.second.end());
       std::string varName =
-        parsedArgs.ConflictingDependenciesPrefix + "_" + val.first;
+        cmStrCat(parsedArgs.ConflictingDependenciesPrefix, '_', val.first);
       std::string pathsStr = cmList::to_string(paths);
       status.GetMakefile().AddDefinition(varName, pathsStr);
     } else {
@@ -3618,6 +3683,7 @@
     // accepted without one and treated as if an empty value were given.
     // Fixing this would require a policy.
     ArgumentParser::Maybe<std::string> MTime;
+    std::string Threads;
     std::string WorkingDirectory;
     bool Verbose = false;
     // "PATHS" requires at least one value, but use a custom check below.
@@ -3631,6 +3697,7 @@
       .Bind("COMPRESSION"_s, &Arguments::Compression)
       .Bind("COMPRESSION_LEVEL"_s, &Arguments::CompressionLevel)
       .Bind("MTIME"_s, &Arguments::MTime)
+      .Bind("THREADS"_s, &Arguments::Threads)
       .Bind("WORKING_DIRECTORY"_s, &Arguments::WorkingDirectory)
       .Bind("VERBOSE"_s, &Arguments::Verbose)
       .Bind("PATHS"_s, &Arguments::Paths);
@@ -3662,23 +3729,18 @@
     return false;
   }
 
-  char const* zipFileFormats[] = { "7zip", "zip" };
-  if (!parsedArgs.Compression.empty() &&
-      cm::contains(zipFileFormats, parsedArgs.Format)) {
-    status.SetError(cmStrCat("archive format ", parsedArgs.Format,
-                             " does not support COMPRESSION arguments"));
-    cmSystemTools::SetFatalErrorOccurred();
-    return false;
-  }
-
   static std::map<std::string, cmSystemTools::cmTarCompression>
     compressionTypeMap = { { "None", cmSystemTools::TarCompressNone },
                            { "BZip2", cmSystemTools::TarCompressBZip2 },
+                           { "Deflate", cmSystemTools::TarCompressGZip },
                            { "GZip", cmSystemTools::TarCompressGZip },
+                           { "LZMA", cmSystemTools::TarCompressLZMA },
+                           { "LZMA2", cmSystemTools::TarCompressXZ },
+                           { "PPMd", cmSystemTools::TarCompressPPMd },
                            { "XZ", cmSystemTools::TarCompressXZ },
                            { "Zstd", cmSystemTools::TarCompressZstd } };
 
-  cmSystemTools::cmTarCompression compress = cmSystemTools::TarCompressNone;
+  cmSystemTools::cmTarCompression compress = cmSystemTools::TarCompressAuto;
   auto typeIt = compressionTypeMap.find(parsedArgs.Compression);
   if (typeIt != compressionTypeMap.end()) {
     compress = typeIt->second;
@@ -3689,16 +3751,25 @@
     return false;
   }
 
+  if (compress == cmSystemTools::TarCompressPPMd &&
+      parsedArgs.Format != "7zip") {
+    status.SetError(cmStrCat("PPMd compression is not supported for ",
+                             parsedArgs.Format, " format"));
+    cmSystemTools::SetFatalErrorOccurred();
+    return false;
+  }
+
   int compressionLevel = 0;
-  int minCompressionLevel = 0;
+  constexpr int minCompressionLevel = 0;
   int maxCompressionLevel = 9;
-  if (compress == cmSystemTools::TarCompressZstd) {
+  if (compress == cmSystemTools::TarCompressZstd &&
+      parsedArgs.Format != "zip") {
     maxCompressionLevel = 19;
   }
 
   if (!parsedArgs.CompressionLevel.empty()) {
     if (parsedArgs.CompressionLevel.size() != 1 &&
-        !std::isdigit(parsedArgs.CompressionLevel[0])) {
+        !cmsysString_isdigit(parsedArgs.CompressionLevel[0])) {
       status.SetError(
         cmStrCat("compression level ", parsedArgs.CompressionLevel, " for ",
                  parsedArgs.Compression, " should be in range ",
@@ -3717,9 +3788,30 @@
       return false;
     }
     if (compress == cmSystemTools::TarCompressNone) {
-      status.SetError(cmStrCat("compression level is not supported for "
-                               "compression \"None\"",
-                               parsedArgs.Compression));
+      status.SetError(
+        cmStrCat("compression level is not supported for "
+                 "compression \"None\". Provided compression level: ",
+                 parsedArgs.CompressionLevel));
+      cmSystemTools::SetFatalErrorOccurred();
+      return false;
+    }
+  }
+
+  // Use the single thread by default for backward compatibility
+  int threads = 1;
+  constexpr int minThreads = 0;
+  if (!parsedArgs.Threads.empty()) {
+    if (parsedArgs.Threads.size() != 1 &&
+        !cmsysString_isdigit(parsedArgs.Threads[0])) {
+      status.SetError(cmStrCat("number of threads ", parsedArgs.Threads,
+                               " should be at least ", minThreads));
+      cmSystemTools::SetFatalErrorOccurred();
+      return false;
+    }
+    threads = std::stoi(parsedArgs.Threads);
+    if (threads < minThreads) {
+      status.SetError(cmStrCat("number of threads ", parsedArgs.Threads,
+                               " should be at least ", minThreads));
       cmSystemTools::SetFatalErrorOccurred();
       return false;
     }
@@ -3731,10 +3823,10 @@
     return false;
   }
 
-  if (!cmSystemTools::CreateTar(parsedArgs.Output, parsedArgs.Paths,
-                                parsedArgs.WorkingDirectory, compress,
-                                parsedArgs.Verbose, parsedArgs.MTime,
-                                parsedArgs.Format, compressionLevel)) {
+  if (!cmSystemTools::CreateTar(
+        parsedArgs.Output, parsedArgs.Paths, parsedArgs.WorkingDirectory,
+        compress, parsedArgs.Verbose, parsedArgs.MTime, parsedArgs.Format,
+        compressionLevel, threads)) {
     status.SetError(cmStrCat("failed to compress: ", parsedArgs.Output));
     cmSystemTools::SetFatalErrorOccurred();
     return false;
@@ -3821,7 +3913,7 @@
           parsedArgs.Touch ? cmSystemTools::cmTarExtractTimestamps::No
                            : cmSystemTools::cmTarExtractTimestamps::Yes,
           parsedArgs.Verbose)) {
-      status.SetError(cmStrCat("failed to extract: ", inFile));
+      status.SetError(cmStrCat("failed to extract:\n  ", inFile));
       cmSystemTools::SetFatalErrorOccurred();
       return false;
     }
diff --git a/Source/cmFileInstaller.cxx b/Source/cmFileInstaller.cxx
index e95e694..c03bc68 100644
--- a/Source/cmFileInstaller.cxx
+++ b/Source/cmFileInstaller.cxx
@@ -455,7 +455,7 @@
     }
     if (!cmSystemTools::FileIsDirectory(destination)) {
       std::string errstring =
-        "INSTALL destination: " + destination + " is not a directory.";
+        cmStrCat("INSTALL destination: ", destination, " is not a directory.");
       this->Status.SetError(errstring);
       return false;
     }
diff --git a/Source/cmFileSet.cxx b/Source/cmFileSet.cxx
index 3861d61..ccb7681 100644
--- a/Source/cmFileSet.cxx
+++ b/Source/cmFileSet.cxx
@@ -88,9 +88,9 @@
   return type == "HEADERS"_s;
 }
 
-cmFileSet::cmFileSet(cmake& cmakeInstance, std::string name, std::string type,
+cmFileSet::cmFileSet(cmMakefile* makefile, std::string name, std::string type,
                      cmFileSetVisibility visibility)
-  : CMakeInstance(cmakeInstance)
+  : Makefile(makefile)
   , Name(std::move(name))
   , Type(std::move(type))
   , Visibility(visibility)
@@ -130,7 +130,8 @@
 
   for (auto const& entry : this->FileEntries) {
     for (auto const& ex : cmList{ entry.Value }) {
-      cmGeneratorExpression ge(this->CMakeInstance, entry.Backtrace);
+      cmGeneratorExpression ge(*this->GetMakefile()->GetCMakeInstance(),
+                               entry.Backtrace);
       auto cge = ge.Parse(ex);
       result.push_back(std::move(cge));
     }
@@ -146,7 +147,8 @@
 
   for (auto const& entry : this->DirectoryEntries) {
     for (auto const& ex : cmList{ entry.Value }) {
-      cmGeneratorExpression ge(this->CMakeInstance, entry.Backtrace);
+      cmGeneratorExpression ge(*this->GetMakefile()->GetCMakeInstance(),
+                               entry.Backtrace);
       auto cge = ge.Parse(ex);
       result.push_back(std::move(cge));
     }
@@ -261,3 +263,91 @@
   cmsys::RegularExpressionMatch match;
   return regex.find(name.c_str(), match);
 }
+
+std::string const cmFileSet::propCOMPILE_DEFINITIONS = "COMPILE_DEFINITIONS";
+std::string const cmFileSet::propCOMPILE_OPTIONS = "COMPILE_OPTIONS";
+std::string const cmFileSet::propINCLUDE_DIRECTORIES = "INCLUDE_DIRECTORIES";
+
+void cmFileSet::SetProperty(std::string const& prop, cmValue value)
+{
+  if (prop == propINCLUDE_DIRECTORIES) {
+    this->IncludeDirectories.clear();
+    if (value) {
+      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
+      this->IncludeDirectories.emplace_back(value, lfbt);
+    }
+  } else if (prop == propCOMPILE_OPTIONS) {
+    this->CompileOptions.clear();
+    if (value) {
+      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
+      this->CompileOptions.emplace_back(value, lfbt);
+    }
+  } else if (prop == propCOMPILE_DEFINITIONS) {
+    this->CompileDefinitions.clear();
+    if (value) {
+      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
+      this->CompileDefinitions.emplace_back(value, lfbt);
+    }
+  } else {
+    this->Properties.SetProperty(prop, value);
+  }
+}
+
+void cmFileSet::AppendProperty(std::string const& prop,
+                               std::string const& value, bool asString)
+{
+  if (prop == propINCLUDE_DIRECTORIES) {
+    if (!value.empty()) {
+      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
+      this->IncludeDirectories.emplace_back(value, lfbt);
+    }
+  } else if (prop == propCOMPILE_OPTIONS) {
+    if (!value.empty()) {
+      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
+      this->CompileOptions.emplace_back(value, lfbt);
+    }
+  } else if (prop == propCOMPILE_DEFINITIONS) {
+    if (!value.empty()) {
+      cmListFileBacktrace lfbt = this->GetMakefile()->GetBacktrace();
+      this->CompileDefinitions.emplace_back(value, lfbt);
+    }
+  } else {
+    this->Properties.AppendProperty(prop, value, asString);
+  }
+}
+
+cmValue cmFileSet::GetProperty(std::string const& prop) const
+{
+  // Check for the properties with backtraces.
+  if (prop == propINCLUDE_DIRECTORIES) {
+    if (this->IncludeDirectories.empty()) {
+      return nullptr;
+    }
+
+    static std::string output;
+    output = cmList::to_string(this->IncludeDirectories);
+    return cmValue(output);
+  }
+
+  if (prop == propCOMPILE_OPTIONS) {
+    if (this->CompileOptions.empty()) {
+      return nullptr;
+    }
+
+    static std::string output;
+    output = cmList::to_string(this->CompileOptions);
+    return cmValue(output);
+  }
+
+  if (prop == propCOMPILE_DEFINITIONS) {
+    if (this->CompileDefinitions.empty()) {
+      return nullptr;
+    }
+
+    static std::string output;
+    output = cmList::to_string(this->CompileDefinitions);
+    return cmValue(output);
+  }
+
+  return this->Properties.GetPropertyValue(prop);
+}
diff --git a/Source/cmFileSet.h b/Source/cmFileSet.h
index 3b37bf8..598e832 100644
--- a/Source/cmFileSet.h
+++ b/Source/cmFileSet.h
@@ -2,6 +2,7 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #pragma once
 
+#include <cstddef>
 #include <map>
 #include <memory>
 #include <string>
@@ -11,6 +12,8 @@
 #include <cmext/string_view>
 
 #include "cmListFileCache.h"
+#include "cmPropertyMap.h"
+#include "cmValue.h"
 
 namespace cm {
 namespace GenEx {
@@ -22,7 +25,6 @@
 struct cmGeneratorExpressionDAGChecker;
 class cmGeneratorTarget;
 class cmMakefile;
-class cmake;
 
 enum class cmFileSetVisibility
 {
@@ -41,13 +43,15 @@
 class cmFileSet
 {
 public:
-  cmFileSet(cmake& cmakeInstance, std::string name, std::string type,
+  cmFileSet(cmMakefile* makefile, std::string name, std::string type,
             cmFileSetVisibility visibility);
 
   std::string const& GetName() const { return this->Name; }
   std::string const& GetType() const { return this->Type; }
   cmFileSetVisibility GetVisibility() const { return this->Visibility; }
 
+  cmMakefile* GetMakefile() const { return this->Makefile; }
+
   void CopyEntries(cmFileSet const* fs);
 
   void ClearDirectoryEntries();
@@ -84,11 +88,37 @@
 
   static bool IsValidName(std::string const& name);
 
+  //! Set/Get a property of this file set
+  void SetProperty(std::string const& prop, cmValue value);
+  void SetProperty(std::string const& prop, std::nullptr_t)
+  {
+    this->SetProperty(prop, cmValue{ nullptr });
+  }
+  void RemoveProperty(std::string const& prop)
+  {
+    this->SetProperty(prop, cmValue{ nullptr });
+  }
+  void SetProperty(std::string const& prop, std::string const& value)
+  {
+    this->SetProperty(prop, cmValue{ value });
+  }
+  void AppendProperty(std::string const& prop, std::string const& value,
+                      bool asString = false);
+  cmValue GetProperty(std::string const& prop) const;
+
 private:
-  cmake& CMakeInstance;
+  cmMakefile* Makefile;
   std::string Name;
   std::string Type;
   cmFileSetVisibility Visibility;
   std::vector<BT<std::string>> DirectoryEntries;
   std::vector<BT<std::string>> FileEntries;
+  cmPropertyMap Properties;
+  std::vector<BT<std::string>> CompileOptions;
+  std::vector<BT<std::string>> CompileDefinitions;
+  std::vector<BT<std::string>> IncludeDirectories;
+
+  static std::string const propCOMPILE_DEFINITIONS;
+  static std::string const propCOMPILE_OPTIONS;
+  static std::string const propINCLUDE_DIRECTORIES;
 };
diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx
index b8d4765..3e98e3f 100644
--- a/Source/cmFindBase.cxx
+++ b/Source/cmFindBase.cxx
@@ -224,13 +224,11 @@
       this->VariableDocumentation += "the (unknown) library be found";
     } else if (this->Names.size() == 1) {
       this->VariableDocumentation +=
-        "the " + this->Names.front() + " library be found";
+        cmStrCat("the ", this->Names.front(), " library be found");
     } else {
-      this->VariableDocumentation += "one of the ";
-      this->VariableDocumentation +=
-        cmJoin(cmMakeRange(this->Names).retreat(1), ", ");
-      this->VariableDocumentation +=
-        " or " + this->Names.back() + " libraries be found";
+      this->VariableDocumentation += cmStrCat(
+        "one of the ", cmJoin(cmMakeRange(this->Names).retreat(1), ", "),
+        " or ", this->Names.back(), " libraries be found");
     }
   }
 
diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx
index fb7cc9f..444c040 100644
--- a/Source/cmFindCommon.cxx
+++ b/Source/cmFindCommon.cxx
@@ -301,8 +301,9 @@
 
   auto isSameDirectoryOrSubDirectory = [](std::string const& l,
                                           std::string const& r) {
-    return (cmSystemTools::GetRealPath(l) == cmSystemTools::GetRealPath(r)) ||
-      cmSystemTools::IsSubDirectory(l, r);
+    std::string const lReal = cmSystemTools::GetRealPath(l);
+    std::string const rReal = cmSystemTools::GetRealPath(r);
+    return (lReal == rReal) || cmSystemTools::IsSubDirectory(lReal, rReal);
   };
 
   for (auto const& r : roots) {
diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx
index f7da32e..57d2a41 100644
--- a/Source/cmFindLibraryCommand.cxx
+++ b/Source/cmFindLibraryCommand.cxx
@@ -3,7 +3,6 @@
 #include "cmFindLibraryCommand.h"
 
 #include <algorithm>
-#include <cctype>
 #include <cstdio>
 #include <cstring>
 #include <set>
@@ -13,6 +12,7 @@
 #include <cm/optional>
 
 #include "cmsys/RegularExpression.hxx"
+#include "cmsys/String.h"
 
 #include "cmFindCommon.h"
 #include "cmGlobalGenerator.h"
@@ -349,7 +349,7 @@
       out += "\\";
     }
     if (dirCase == cmSystemTools::DirCase::Insensitive) {
-      out += static_cast<char>(tolower(ch));
+      out += static_cast<char>(cmsysString_tolower(ch));
     } else {
       out += ch;
     }
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index acdfa67..f0d784a 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -27,7 +27,6 @@
 #include "cmConfigureLog.h"
 #include "cmDependencyProvider.h"
 #include "cmExecutionStatus.h"
-#include "cmExperimental.h"
 #include "cmFindPackageStack.h"
 #include "cmList.h"
 #include "cmListFileCache.h"
@@ -86,7 +85,7 @@
     return 0;
   }
   for (auto i = startIndex; i < paths.size(); i++) {
-    buffer += "  " + paths[i].Path + "\n";
+    buffer += cmStrCat("  ", paths[i].Path, '\n');
   }
   return paths.size();
 }
@@ -881,7 +880,7 @@
       this->AddPathSuffix(args[i]);
     } else if (doing == DoingConfigs) {
       if (args[i].find_first_of(":/\\") != std::string::npos ||
-          cmSystemTools::GetFilenameLastExtension(args[i]) != ".cmake") {
+          !cmHasSuffix(args[i], ".cmake"_s)) {
         this->SetError(cmStrCat(
           "given CONFIGS option followed by invalid file name \"", args[i],
           "\".  The names given must be file names without "
@@ -926,9 +925,7 @@
   // Check and eliminate search modes not allowed by the args provided
   this->UseFindModules = configArgs.empty();
   this->UseConfigFiles = moduleArgs.empty();
-  if (this->UseConfigFiles &&
-      cmExperimental::HasSupportEnabled(
-        *this->Makefile, cmExperimental::Feature::ImportPackageInfo)) {
+  if (this->UseConfigFiles) {
     this->UseCpsFiles = this->Configs.empty();
   } else {
     this->UseCpsFiles = false;
@@ -2244,7 +2241,7 @@
   }
 
   // Import base file.
-  if (!reader.ImportTargets(this->Makefile, this->Status)) {
+  if (!reader.ImportTargets(this->Makefile, this->Status, this->GlobalScope)) {
     return false;
   }
 
diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx
index df8cb02..a3e17eb 100644
--- a/Source/cmFindProgramCommand.cxx
+++ b/Source/cmFindProgramCommand.cxx
@@ -338,8 +338,8 @@
 
     if (CFURLGetFileSystemRepresentation(executableURL, false, buffer,
                                          MAX_OSX_PATH_SIZE)) {
-      executable = bundlePath + "/Contents/MacOS/" +
-        std::string(reinterpret_cast<char*>(buffer));
+      executable = cmStrCat(bundlePath, "/Contents/MacOS/",
+                            reinterpret_cast<char const*>(buffer));
     }
     // Only release CFURLRef if it's not null
     CFRelease(executableURL);
diff --git a/Source/cmFunctionBlocker.cxx b/Source/cmFunctionBlocker.cxx
index 7fc6ffb..a41c773 100644
--- a/Source/cmFunctionBlocker.cxx
+++ b/Source/cmFunctionBlocker.cxx
@@ -11,6 +11,7 @@
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmake.h"
 
 bool cmFunctionBlocker::IsFunctionBlocked(cmListFileFunction const& lff,
                                           cmExecutionStatus& status)
@@ -49,7 +50,15 @@
         mf.IssueMessage(MessageType::AUTHOR_WARNING, e.str());
       }
 
-      return this->Replay(std::move(this->Functions), status);
+      bool replayResult = this->Replay(std::move(this->Functions), status);
+      cmListFileBacktrace endCommandBT =
+        mf.GetBacktrace().Push(closingContext);
+      // if trace is enabled, print a (trivially) evaluated "end" statement
+      if (mf.GetCMakeInstance()->GetTrace()) {
+        mf.PrintCommandTrace(lff, endCommandBT,
+                             cmMakefile::CommandMissingFromStack::Yes);
+      }
+      return replayResult;
     }
   }
 
diff --git a/Source/cmGccDepfileLexerHelper.cxx b/Source/cmGccDepfileLexerHelper.cxx
index 56f0950..478a93d 100644
--- a/Source/cmGccDepfileLexerHelper.cxx
+++ b/Source/cmGccDepfileLexerHelper.cxx
@@ -12,9 +12,8 @@
 #include "LexerParser/cmGccDepfileLexer.h"
 
 #ifdef _WIN32
-#  include <cctype>
-
 #  include "cmsys/Encoding.h"
+#  include "cmsys/String.h"
 #endif
 
 bool cmGccDepfileLexerHelper::readFile(char const* filePath)
@@ -127,10 +126,12 @@
         // Unescape the colon following the drive letter.
         // Some versions of GNU compilers can escape this character.
         // c\:\path must be transformed to c:\path
-        if (pit->size() >= 3 && std::toupper((*pit)[0]) >= 'A' &&
-            std::toupper((*pit)[0]) <= 'Z' && (*pit)[1] == '\\' &&
-            (*pit)[2] == ':') {
-          pit->erase(1, 1);
+        if (pit->size() >= 3) {
+          auto pit0 = static_cast<char>(cmsysString_toupper((*pit)[0]));
+          if (pit0 >= 'A' && pit0 <= 'Z' && (*pit)[1] == '\\' &&
+              (*pit)[2] == ':') {
+            pit->erase(1, 1);
+          }
         }
 #endif
         ++pit;
diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx
index b3ae9d7..c7fffb4 100644
--- a/Source/cmGeneratorExpression.cxx
+++ b/Source/cmGeneratorExpression.cxx
@@ -4,6 +4,7 @@
 
 #include <algorithm>
 #include <cassert>
+#include <cstddef>
 #include <memory>
 #include <stack>
 #include <utility>
@@ -18,8 +19,11 @@
 #include "cmGeneratorExpressionEvaluator.h"
 #include "cmGeneratorExpressionLexer.h"
 #include "cmGeneratorExpressionParser.h"
+#include "cmGeneratorTarget.h"
 #include "cmList.h"
 #include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmake.h"
@@ -166,7 +170,7 @@
 }
 
 static std::string extractAllGeneratorExpressions(
-  std::string const& input,
+  cm::string_view input,
   std::map<std::string, std::vector<std::string>>* collected)
 {
   std::string result;
@@ -176,9 +180,9 @@
   std::stack<char const*> colons; // indices of ":"
   while ((pos = input.find("$<", lastPos)) != std::string::npos) {
     result += input.substr(lastPos, pos - lastPos);
-    starts.push(input.c_str() + pos);
+    starts.push(input.data() + pos);
     pos += 2;
-    char const* c = input.c_str() + pos;
+    char const* c = input.data() + pos;
     char const* const cStart = c;
     for (; *c; ++c) {
       if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) {
@@ -209,7 +213,7 @@
     }
     std::string::size_type const traversed = (c - cStart) + 1;
     if (!*c) {
-      result += "$<" + input.substr(pos, traversed);
+      result += cmStrCat("$<", input.substr(pos, traversed));
     }
     pos += traversed;
     lastPos = pos;
@@ -220,7 +224,7 @@
   return cmGeneratorExpression::StripEmptyListElements(result);
 }
 
-static std::string stripAllGeneratorExpressions(std::string const& input)
+static std::string stripAllGeneratorExpressions(cm::string_view input)
 {
   return extractAllGeneratorExpressions(input, nullptr);
 }
@@ -243,7 +247,7 @@
 }
 
 static std::string stripExportInterface(
-  std::string const& input, cmGeneratorExpression::PreprocessContext context,
+  cm::string_view input, cmGeneratorExpression::PreprocessContext context,
   cm::string_view importPrefix)
 {
   std::string result;
@@ -282,7 +286,7 @@
       assert(false && "Invalid position found");
     }
     nestingLevel = 1;
-    char const* c = input.c_str() + pos;
+    char const* c = input.data() + pos;
     char const* const cStart = c;
     for (; *c; ++c) {
       if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) {
@@ -300,7 +304,8 @@
           result += input.substr(pos, c - cStart);
         } else if (context == cmGeneratorExpression::InstallInterface &&
                    foundGenex == FoundGenex::InstallInterface) {
-          std::string const content = input.substr(pos, c - cStart);
+          std::string const content =
+            static_cast<std::string>(input.substr(pos, c - cStart));
           if (!importPrefix.empty()) {
             prefixItems(content, result, importPrefix);
           } else {
@@ -381,7 +386,7 @@
       }
     }
     std::string::size_type const traversed = (c - cStart) + 1;
-    output.push_back(preGenex + "$<" + input.substr(pos, traversed));
+    output.push_back(cmStrCat(preGenex, "$<", input.substr(pos, traversed)));
     pos += traversed;
     lastPos = pos;
   }
@@ -390,7 +395,7 @@
   }
 }
 
-std::string cmGeneratorExpression::Preprocess(std::string const& input,
+std::string cmGeneratorExpression::Preprocess(cm::string_view input,
                                               PreprocessContext context,
                                               cm::string_view importPrefix)
 {
@@ -413,6 +418,50 @@
   return extractAllGeneratorExpressions(input, &collected);
 }
 
+bool cmGeneratorExpression::ForbidGeneratorExpressions(
+  cmGeneratorTarget const* target, std::string const& propertyName,
+  std::string const& propertyValue)
+{
+  std::map<std::string, std::vector<std::string>> allowList;
+  std::string evaluatedValue;
+  return ForbidGeneratorExpressions(target, propertyName, propertyValue,
+                                    evaluatedValue, allowList);
+}
+
+bool cmGeneratorExpression::ForbidGeneratorExpressions(
+  cmGeneratorTarget const* target, std::string const& propertyName,
+  std::string const& propertyValue, std::string& evaluatedValue,
+  std::map<std::string, std::vector<std::string>>& allowList)
+{
+  size_t const initialAllowedGenExps = allowList.size();
+  evaluatedValue = Collect(propertyValue, allowList);
+  if (evaluatedValue != propertyValue &&
+      allowList.size() > initialAllowedGenExps) {
+    target->Makefile->IssueMessage(
+      MessageType::FATAL_ERROR,
+      cmStrCat("Property \"", propertyName, "\" of target \"",
+               target->GetName(),
+               "\" contains a generator expression. This is not allowed."));
+    return false;
+  }
+
+  // Check for nested generator expressions (e.g., $<LINK_ONLY:$<...>>).
+  for (auto const& genexp : allowList) {
+    for (auto const& value : genexp.second) {
+      if (value.find("$<") != std::string::npos) {
+        target->Makefile->IssueMessage(
+          MessageType::FATAL_ERROR,
+          cmStrCat("$<", genexp.first, ":...> expression in \"", propertyName,
+                   "\" of target \"", target->GetName(),
+                   "\" contains a generator expression. This is not "
+                   "allowed."));
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
 cm::string_view::size_type cmGeneratorExpression::Find(cm::string_view input)
 {
   cm::string_view::size_type const openpos = input.find("$<");
diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h
index 3897e67..210cd0a 100644
--- a/Source/cmGeneratorExpression.h
+++ b/Source/cmGeneratorExpression.h
@@ -58,6 +58,15 @@
     cmGeneratorTarget const* currentTarget = nullptr,
     std::string const& language = std::string());
 
+  static bool ForbidGeneratorExpressions(
+    cmGeneratorTarget const* target, std::string const& propertyName,
+    std::string const& propertyValue, std::string& evaluatedValue,
+    std::map<std::string, std::vector<std::string>>& allowList);
+
+  static bool ForbidGeneratorExpressions(cmGeneratorTarget const* target,
+                                         std::string const& propertyName,
+                                         std::string const& propertyValue);
+
   enum PreprocessContext
   {
     StripAllGeneratorExpressions,
@@ -65,7 +74,7 @@
     InstallInterface
   };
 
-  static std::string Preprocess(std::string const& input,
+  static std::string Preprocess(cm::string_view input,
                                 PreprocessContext context,
                                 cm::string_view importPrefix = {});
 
diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx
index 8ad2be5..6c576c4 100644
--- a/Source/cmGeneratorExpressionEvaluator.cxx
+++ b/Source/cmGeneratorExpressionEvaluator.cxx
@@ -2,16 +2,14 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "cmGeneratorExpressionEvaluator.h"
 
-#include <sstream>
-
 #ifndef CMAKE_BOOTSTRAP
 #  include <cm3p/json/value.h>
 #endif
-
 #include "cmGenExContext.h"
 #include "cmGenExEvaluation.h"
 #include "cmGeneratorExpressionNode.h"
 #include "cmLocalGenerator.h"
+#include "cmStringAlgorithms.h"
 #include "cmake.h"
 
 GeneratorExpressionContent::GeneratorExpressionContent(
@@ -96,8 +94,9 @@
     if (node->NumExpectedParameters() == 1 &&
         node->AcceptsArbitraryContentParameter()) {
       if (this->ParamChildren.empty()) {
-        reportError(eval, this->GetOriginalExpression(),
-                    "$<" + identifier + "> expression requires a parameter.");
+        reportError(
+          eval, this->GetOriginalExpression(),
+          cmStrCat("$<", identifier, "> expression requires a parameter."));
       }
     } else {
       std::vector<std::string> parameters;
@@ -166,19 +165,20 @@
   if ((numExpected > cmGeneratorExpressionNode::DynamicParameters &&
        static_cast<unsigned int>(numExpected) != parameters.size())) {
     if (numExpected == 0) {
-      reportError(eval, this->GetOriginalExpression(),
-                  "$<" + identifier + "> expression requires no parameters.");
+      reportError(
+        eval, this->GetOriginalExpression(),
+        cmStrCat("$<", identifier, "> expression requires no parameters."));
     } else if (numExpected == 1) {
       reportError(eval, this->GetOriginalExpression(),
-                  "$<" + identifier +
-                    "> expression requires "
-                    "exactly one parameter.");
+                  cmStrCat("$<", identifier,
+                           "> expression requires "
+                           "exactly one parameter."));
     } else {
-      std::ostringstream e;
-      e << "$<" + identifier + "> expression requires " << numExpected
-        << " comma separated parameters, but got " << parameters.size()
-        << " instead.";
-      reportError(eval, this->GetOriginalExpression(), e.str());
+      std::string e =
+        cmStrCat("$<", identifier, "> expression requires ", numExpected,
+                 " comma separated parameters, but got ", parameters.size(),
+                 " instead.");
+      reportError(eval, this->GetOriginalExpression(), e);
     }
     return std::string();
   }
@@ -186,18 +186,18 @@
   if (numExpected == cmGeneratorExpressionNode::OneOrMoreParameters &&
       parameters.empty()) {
     reportError(eval, this->GetOriginalExpression(),
-                "$<" + identifier +
-                  "> expression requires at least one parameter.");
+                cmStrCat("$<", identifier,
+                         "> expression requires at least one parameter."));
   } else if (numExpected == cmGeneratorExpressionNode::TwoOrMoreParameters &&
              parameters.size() < 2) {
     reportError(eval, this->GetOriginalExpression(),
-                "$<" + identifier +
-                  "> expression requires at least two parameters.");
+                cmStrCat("$<", identifier,
+                         "> expression requires at least two parameters."));
   } else if (numExpected == cmGeneratorExpressionNode::OneOrZeroParameters &&
              parameters.size() > 1) {
     reportError(eval, this->GetOriginalExpression(),
-                "$<" + identifier +
-                  "> expression requires one or zero parameters.");
+                cmStrCat("$<", identifier,
+                         "> expression requires one or zero parameters."));
   }
   return std::string();
 }
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 9230746..b938329 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -7,6 +7,7 @@
 #include <cerrno>
 #include <cstdlib>
 #include <cstring>
+#include <exception>
 #include <functional>
 #include <map>
 #include <memory>
@@ -26,7 +27,9 @@
 #include "cmsys/String.h"
 
 #include "cmCMakePath.h"
+#include "cmCMakeString.hxx"
 #include "cmComputeLinkInformation.h"
+#include "cmFileSet.h"
 #include "cmGenExContext.h"
 #include "cmGenExEvaluation.h"
 #include "cmGeneratorExpression.h"
@@ -43,6 +46,7 @@
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
 #include "cmRange.h"
+#include "cmSourceFile.h"
 #include "cmStandardLevelResolver.h"
 #include "cmState.h"
 #include "cmStateSnapshot.h"
@@ -265,9 +269,84 @@
     GeneratorExpressionContent const* /*content*/,
     cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
   {
-    return parameters.front() == parameters[1] ? "1" : "0";
+    return cm::CMakeString{ parameters.front() }.Compare(
+             cm::CMakeString::CompOperator::EQUAL, parameters[1])
+      ? "1"
+      : "0";
   }
 } strEqualNode;
+static const struct StrLessNode : public cmGeneratorExpressionNode
+{
+  StrLessNode() {} // NOLINT(modernize-use-equals-default)
+
+  int NumExpectedParameters() const override { return 2; }
+
+  std::string Evaluate(
+    std::vector<std::string> const& parameters,
+    cm::GenEx::Evaluation* /*eval*/,
+    GeneratorExpressionContent const* /*content*/,
+    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+  {
+    return cm::CMakeString{ parameters.front() }.Compare(
+             cm::CMakeString::CompOperator::LESS, parameters[1])
+      ? "1"
+      : "0";
+  }
+} strLessNode;
+static const struct StrLessEqualNode : public cmGeneratorExpressionNode
+{
+  StrLessEqualNode() {} // NOLINT(modernize-use-equals-default)
+
+  int NumExpectedParameters() const override { return 2; }
+
+  std::string Evaluate(
+    std::vector<std::string> const& parameters,
+    cm::GenEx::Evaluation* /*eval*/,
+    GeneratorExpressionContent const* /*content*/,
+    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+  {
+    return cm::CMakeString{ parameters.front() }.Compare(
+             cm::CMakeString::CompOperator::LESS_EQUAL, parameters[1])
+      ? "1"
+      : "0";
+  }
+} strLessEqualNode;
+static const struct StrGreaterNode : public cmGeneratorExpressionNode
+{
+  StrGreaterNode() {} // NOLINT(modernize-use-equals-default)
+
+  int NumExpectedParameters() const override { return 2; }
+
+  std::string Evaluate(
+    std::vector<std::string> const& parameters,
+    cm::GenEx::Evaluation* /*eval*/,
+    GeneratorExpressionContent const* /*content*/,
+    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+  {
+    return cm::CMakeString{ parameters.front() }.Compare(
+             cm::CMakeString::CompOperator::GREATER, parameters[1])
+      ? "1"
+      : "0";
+  }
+} strGreaterNode;
+static const struct StrGreaterEqualNode : public cmGeneratorExpressionNode
+{
+  StrGreaterEqualNode() {} // NOLINT(modernize-use-equals-default)
+
+  int NumExpectedParameters() const override { return 2; }
+
+  std::string Evaluate(
+    std::vector<std::string> const& parameters,
+    cm::GenEx::Evaluation* /*eval*/,
+    GeneratorExpressionContent const* /*content*/,
+    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+  {
+    return cm::CMakeString{ parameters.front() }.Compare(
+             cm::CMakeString::CompOperator::GREATER_EQUAL, parameters[1])
+      ? "1"
+      : "0";
+  }
+} strGreaterEqualNode;
 
 static const struct EqualNode : public cmGeneratorExpressionNode
 {
@@ -504,7 +583,7 @@
   {
     if (eval->HeadTarget) {
       cmGeneratorExpressionDAGChecker dagChecker{
-        eval->HeadTarget, genexOperator + ":" + expression,
+        eval->HeadTarget, cmStrCat(genexOperator, ':', expression),
         content,          dagCheckerParent,
         eval->Context,    eval->Backtrace,
       };
@@ -706,6 +785,55 @@
   return true;
 };
 
+template <typename IndexType>
+bool GetNumericArgument(std::string const& arg, IndexType& value)
+{
+  try {
+    std::size_t pos;
+
+    if (sizeof(IndexType) == sizeof(long)) {
+      value = std::stol(arg, &pos);
+    } else {
+      value = std::stoll(arg, &pos);
+    }
+
+    if (pos != arg.length()) {
+      // this is not a number
+      return false;
+    }
+  } catch (std::invalid_argument const&) {
+    return false;
+  }
+
+  return true;
+}
+
+template <typename IndexType>
+bool GetNumericArguments(
+  cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* cnt,
+  Arguments args, std::vector<IndexType>& indexes,
+  cmList::ExpandElements expandElements = cmList::ExpandElements::No)
+{
+  using IndexRange = cmRange<Arguments::const_iterator>;
+  IndexRange arguments(args.begin(), args.end());
+  cmList list;
+  if (expandElements == cmList::ExpandElements::Yes) {
+    list = cmList{ args.begin(), args.end(), expandElements };
+    arguments = IndexRange{ list.begin(), list.end() };
+  }
+
+  for (auto const& value : arguments) {
+    IndexType index;
+    if (!GetNumericArgument(value, index)) {
+      reportError(eval, cnt->GetOriginalExpression(),
+                  cmStrCat("index: \"", value, "\" is not a valid index"));
+      return false;
+    }
+    indexes.push_back(index);
+  }
+  return true;
+}
+
 bool CheckPathParametersEx(cm::GenEx::Evaluation* eval,
                            GeneratorExpressionContent const* cnt,
                            cm::string_view option, std::size_t count,
@@ -1163,6 +1291,553 @@
 } pathEqualNode;
 
 namespace {
+inline bool CheckStringParametersEx(cm::GenEx::Evaluation* eval,
+                                    GeneratorExpressionContent const* cnt,
+                                    cm::string_view option, std::size_t count,
+                                    int required = 1, bool exactly = true)
+{
+  return CheckGenExParameters(eval, cnt, "STRING"_s, option, count, required,
+                              exactly);
+}
+inline bool CheckStringParameters(cm::GenEx::Evaluation* eval,
+                                  GeneratorExpressionContent const* cnt,
+                                  cm::string_view option, Arguments args,
+                                  int required = 1)
+{
+  return CheckStringParametersEx(eval, cnt, option, args.size(), required);
+};
+}
+
+static const struct StringNode : public cmGeneratorExpressionNode
+{
+  StringNode() {} // NOLINT(modernize-use-equals-default)
+
+  int NumExpectedParameters() const override { return OneOrMoreParameters; }
+
+  bool AcceptsArbitraryContentParameter() const override { return true; }
+
+  std::string Evaluate(
+    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
+    GeneratorExpressionContent const* content,
+    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+  {
+    static std::unordered_map<
+      cm::string_view,
+      std::function<std::string(cm::GenEx::Evaluation*,
+                                GeneratorExpressionContent const*,
+                                Arguments&)>>
+      stringCommands{
+        { "LENGTH"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            if (CheckStringParameters(ev, cnt, "LENGTH"_s, args)) {
+              return std::to_string(cm::CMakeString{ args.front() }.Length());
+            }
+            return std::string{};
+          } },
+        { "SUBSTRING"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            if (CheckStringParameters(ev, cnt, "SUBSTRING"_s, args, 3)) {
+              cm::CMakeString str{ args.front() };
+              std::vector<long> indexes;
+              if (GetNumericArguments(ev, cnt, args.advance(1), indexes)) {
+                try {
+                  return str.Substring(indexes.front(), indexes.back());
+                } catch (std::out_of_range const& e) {
+                  reportError(ev, cnt->GetOriginalExpression(), e.what());
+                  return std::string{};
+                }
+              }
+            }
+            return std::string{};
+          } },
+        { "FIND"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            if (CheckStringParametersEx(ev, cnt, "FIND"_s, args.size(), 2,
+                                        false)) {
+              if (args.size() > 3) {
+                reportError(ev, cnt->GetOriginalExpression(),
+                            "$<STRING:FIND> expression expects at "
+                            "most three parameters.");
+                return std::string{};
+              }
+
+              auto const FROM = "FROM:"_s;
+
+              cm::CMakeString str{ args.front() };
+              cm::CMakeString::FindFrom from =
+                cm::CMakeString::FindFrom::Begin;
+              cm::string_view substring;
+
+              args.advance(1);
+              if (args.size() == 2) {
+                cm::CMakeString::FindFrom opt =
+                  static_cast<cm::CMakeString::FindFrom>(-1);
+
+                for (auto const& arg : args) {
+                  if (cmHasPrefix(arg, FROM)) {
+                    if (arg != "FROM:BEGIN"_s && arg != "FROM:END"_s) {
+                      reportError(
+                        ev, cnt->GetOriginalExpression(),
+                        cmStrCat("Invalid value for '", FROM,
+                                 "' option. 'BEGIN' or 'END' expected."));
+                      return std::string{};
+                    }
+                    opt = arg == "FROM:BEGIN"_s
+                      ? cm::CMakeString::FindFrom::Begin
+                      : cm::CMakeString::FindFrom::End;
+                  } else {
+                    substring = arg;
+                  }
+                }
+                if (opt == static_cast<cm::CMakeString::FindFrom>(-1)) {
+                  reportError(
+                    ev, cnt->GetOriginalExpression(),
+                    cmStrCat("Expected option '", FROM, "' is missing."));
+                  return std::string{};
+                }
+                from = opt;
+              } else {
+                substring = args.front();
+              }
+              auto pos = str.Find(substring, from);
+              return pos == cm::CMakeString::npos ? "-1" : std::to_string(pos);
+            }
+            return std::string{};
+          } },
+        { "MATCH"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            if (CheckStringParametersEx(ev, cnt, "MATCH"_s, args.size(), 2,
+                                        false)) {
+              if (args.size() > 3) {
+                reportError(ev, cnt->GetOriginalExpression(),
+                            "$<STRING:MATCH> expression expects at "
+                            "most three parameters.");
+                return std::string{};
+              }
+
+              auto const SEEK = "SEEK:"_s;
+
+              cm::CMakeString str{ args.front() };
+              cm::CMakeString::MatchItems seek =
+                cm::CMakeString::MatchItems::Once;
+              auto const* regex = &args[1];
+
+              args.advance(1);
+              if (args.size() == 2) {
+                cm::CMakeString::MatchItems opt =
+                  static_cast<cm::CMakeString::MatchItems>(-1);
+
+                for (auto const& arg : args) {
+                  if (cmHasPrefix(arg, SEEK)) {
+                    if (arg != "SEEK:ONCE"_s && arg != "SEEK:ALL"_s) {
+                      reportError(
+                        ev, cnt->GetOriginalExpression(),
+                        cmStrCat("Invalid value for '", SEEK,
+                                 "' option. 'ONCE' or 'ALL' expected."));
+                      return std::string{};
+                    }
+                    opt = arg == "SEEK:ONCE"_s
+                      ? cm::CMakeString::MatchItems::Once
+                      : cm::CMakeString::MatchItems::All;
+                  } else {
+                    regex = &arg;
+                  }
+                }
+                if (opt == static_cast<cm::CMakeString::MatchItems>(-1)) {
+                  reportError(
+                    ev, cnt->GetOriginalExpression(),
+                    cmStrCat("Expected option '", SEEK, "' is missing."));
+                  return std::string{};
+                }
+                seek = opt;
+              }
+
+              try {
+                return str.Match(*regex, seek).to_string();
+              } catch (std::invalid_argument const& e) {
+                reportError(ev, cnt->GetOriginalExpression(), e.what());
+                return std::string{};
+              }
+            }
+            return std::string{};
+          } },
+        { "JOIN"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            if (CheckStringParametersEx(ev, cnt, "JOIN"_s, args.size(), 2,
+                                        false)) {
+              auto const& glue = args.front();
+              return cm::CMakeString{ args.advance(1), glue };
+            }
+            return std::string{};
+          } },
+        { "ASCII"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            if (CheckStringParametersEx(ev, cnt, "ASCII"_s, args.size(), 1,
+                                        false)) {
+              try {
+                return cm::CMakeString{}.FromASCII(args);
+              } catch (std::invalid_argument const& e) {
+                reportError(ev, cnt->GetOriginalExpression(), e.what());
+                return std::string{};
+              }
+            }
+            return std::string{};
+          } },
+        { "TIMESTAMP"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            cm::string_view format;
+            cm::CMakeString::UTC utc = cm::CMakeString::UTC::No;
+
+            if (args.size() == 2 && args.front() != "UTC"_s &&
+                args.back() != "UTC"_s) {
+              reportError(ev, cnt->GetOriginalExpression(),
+                          "'UTC' option is expected.");
+              return std::string{};
+            }
+            if (args.size() > 2) {
+              reportError(ev, cnt->GetOriginalExpression(),
+                          "$<STRING:TIMESTAMP> expression expects at most two "
+                          "parameters.");
+              return std::string{};
+            }
+
+            for (auto const& arg : args) {
+              if (arg == "UTC"_s) {
+                utc = cm::CMakeString::UTC::Yes;
+              } else {
+                format = arg;
+              }
+            }
+            return cm::CMakeString{}.Timestamp(format, utc);
+          } },
+        { "RANDOM"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            auto const ALPHABET = "ALPHABET:"_s;
+            auto const LENGTH = "LENGTH:"_s;
+            auto const RANDOM_SEED = "RANDOM_SEED:"_s;
+
+            if (args.size() > 3) {
+              reportError(ev, cnt->GetOriginalExpression(),
+                          "$<STRING:RANDOM> expression expects at most three "
+                          "parameters.");
+              return std::string{};
+            }
+
+            cm::string_view alphabet;
+            std::size_t length = 5;
+            bool seed_specified = false;
+            unsigned int seed = 0;
+            for (auto const& arg : args) {
+              if (cmHasPrefix(arg, ALPHABET)) {
+                alphabet = cm::string_view{ arg.c_str() + ALPHABET.length() };
+                continue;
+              }
+              if (cmHasPrefix(arg, LENGTH)) {
+                try {
+                  length = std::stoul(arg.substr(LENGTH.size()));
+                } catch (std::exception const&) {
+                  reportError(ev, cnt->GetOriginalExpression(),
+                              cmStrCat(arg, ": invalid numeric value for '",
+                                       LENGTH, "' option."));
+                  return std::string{};
+                }
+                continue;
+              }
+              if (cmHasPrefix(arg, RANDOM_SEED)) {
+                try {
+                  seed_specified = true;
+                  seed = static_cast<unsigned int>(
+                    std::stoul(arg.substr(RANDOM_SEED.size())));
+                } catch (std::exception const&) {
+                  reportError(ev, cnt->GetOriginalExpression(),
+                              cmStrCat(arg, ": invalid numeric value for '",
+                                       RANDOM_SEED, "' option."));
+                  return std::string{};
+                }
+                continue;
+              }
+              reportError(ev, cnt->GetOriginalExpression(),
+                          cmStrCat(arg, ": invalid parameter."));
+              return std::string{};
+            }
+
+            try {
+              if (seed_specified) {
+                return cm::CMakeString{}.Random(seed, length, alphabet);
+              }
+              return cm::CMakeString{}.Random(length, alphabet);
+            } catch (std::exception const& e) {
+              reportError(ev, cnt->GetOriginalExpression(), e.what());
+              return std::string{};
+            }
+          } },
+        { "UUID"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            if (CheckStringParametersEx(ev, cnt, "UUID"_s, args.size(), 2,
+                                        false)) {
+              auto const NAMESPACE = "NAMESPACE:"_s;
+              auto const NAME = "NAME:"_s;
+              auto const TYPE = "TYPE:"_s;
+              auto const CASE = "CASE:"_s;
+
+              if (args.size() > 4) {
+                reportError(ev, cnt->GetOriginalExpression(),
+                            "$<STRING:UUID> expression expects at most four "
+                            "parameters.");
+                return std::string{};
+              }
+
+              cm::string_view nameSpace;
+              cm::string_view name;
+              cm::CMakeString::UUIDType type =
+                static_cast<cm::CMakeString::UUIDType>(-1);
+              cm::CMakeString::Case uuidCase = cm::CMakeString::Case::Lower;
+              for (auto const& arg : args) {
+                if (cmHasPrefix(arg, NAMESPACE)) {
+                  nameSpace =
+                    cm::string_view{ arg.c_str() + NAMESPACE.length() };
+                  if (nameSpace.empty()) {
+                    reportError(
+                      ev, cnt->GetOriginalExpression(),
+                      cmStrCat("Invalid value for '", NAMESPACE, "' option."));
+                    return std::string{};
+                  }
+                  continue;
+                }
+                if (cmHasPrefix(arg, NAME)) {
+                  name = cm::string_view{ arg.c_str() + NAME.length() };
+                  continue;
+                }
+                if (cmHasPrefix(arg, TYPE)) {
+                  auto value = cm::string_view{ arg.c_str() + TYPE.length() };
+                  if (value != "MD5"_s && value != "SHA1"_s) {
+                    reportError(
+                      ev, cnt->GetOriginalExpression(),
+                      cmStrCat("Invalid value for '", TYPE,
+                               "' option. 'MD5' or 'SHA1' expected."));
+                    return std::string{};
+                  }
+                  type = value == "MD5"_s ? cm::CMakeString::UUIDType::MD5
+                                          : cm::CMakeString::UUIDType::SHA1;
+                  continue;
+                }
+                if (cmHasPrefix(arg, CASE)) {
+                  auto value = cm::string_view{ arg.c_str() + CASE.length() };
+                  if (value != "UPPER"_s && value != "LOWER"_s) {
+                    reportError(
+                      ev, cnt->GetOriginalExpression(),
+                      cmStrCat("Invalid value for '", CASE,
+                               "' option. 'UPPER' or 'LOWER' expected."));
+                    return std::string{};
+                  }
+                  uuidCase = value == "UPPER"_s ? cm::CMakeString::Case::Upper
+                                                : cm::CMakeString::Case::Lower;
+                  continue;
+                }
+                reportError(ev, cnt->GetOriginalExpression(),
+                            cmStrCat(arg, ": invalid parameter."));
+                return std::string{};
+              }
+              if (nameSpace.empty()) {
+                reportError(
+                  ev, cnt->GetOriginalExpression(),
+                  cmStrCat("Required option '", NAMESPACE, "' is missing."));
+                return std::string{};
+              }
+              if (type == static_cast<cm::CMakeString::UUIDType>(-1)) {
+                reportError(
+                  ev, cnt->GetOriginalExpression(),
+                  cmStrCat("Required option '", TYPE, "' is missing."));
+                return std::string{};
+              }
+
+              try {
+                return cm::CMakeString{}.UUID(nameSpace, name, type, uuidCase);
+              } catch (std::exception const& e) {
+                reportError(ev, cnt->GetOriginalExpression(), e.what());
+                return std::string{};
+              }
+            }
+            return std::string{};
+          } },
+        { "REPLACE"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            if (CheckStringParametersEx(ev, cnt, "REPLACE"_s, args.size(), 3,
+                                        false)) {
+              if (args.size() > 4) {
+                reportError(ev, cnt->GetOriginalExpression(),
+                            "$<STRING:REPLACE> expression expects at "
+                            "most four parameters.");
+                return std::string{};
+              }
+
+              cm::CMakeString::Regex isRegex = cm::CMakeString::Regex::No;
+              if (args.size() == 4) {
+                cm::string_view type = args.front();
+                if (type != "STRING"_s && type != "REGEX"_s) {
+                  reportError(
+                    ev, cnt->GetOriginalExpression(),
+                    cmStrCat(
+                      '\'', type,
+                      "' is unexpected. 'STRING' or 'REGEX' expected."));
+                  return std::string{};
+                }
+                isRegex = type == "STRING"_s ? cm::CMakeString::Regex::No
+                                             : cm::CMakeString::Regex::Yes;
+                args.advance(1);
+              }
+
+              try {
+                return cm::CMakeString{ args.front() }.Replace(
+                  args[1], args[2], isRegex);
+              } catch (std::invalid_argument const& e) {
+                reportError(ev, cnt->GetOriginalExpression(), e.what());
+                return std::string{};
+              }
+            }
+            return std::string{};
+          } },
+        { "APPEND"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            if (CheckStringParametersEx(ev, cnt, "APPEND"_s, args.size(), 2,
+                                        false)) {
+              cm::CMakeString data{ args.front() };
+              return data.Append(args.advance(1));
+            }
+            return std::string{};
+          } },
+        { "PREPEND"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            if (CheckStringParametersEx(ev, cnt, "PREPEND "_s, args.size(), 2,
+                                        false)) {
+              cm::CMakeString data{ args.front() };
+              return data.Prepend(args.advance(1));
+            }
+            return std::string{};
+          } },
+        { "TOLOWER"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            if (CheckStringParameters(ev, cnt, "TOLOWER"_s, args, 1)) {
+              return cm::CMakeString{}.ToLower(args.front());
+            }
+            return std::string{};
+          } },
+        { "TOUPPER"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            if (CheckStringParameters(ev, cnt, "TOUPPER"_s, args, 1)) {
+              return cm::CMakeString{}.ToUpper(args.front());
+            }
+            return std::string{};
+          } },
+        { "STRIP"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            if (CheckStringParameters(ev, cnt, "STRIP"_s, args, 2)) {
+              if (args.front() != "SPACES"_s) {
+                reportError(ev, cnt->GetOriginalExpression(),
+                            cmStrCat('\'', args.front(),
+                                     "' is unexpected. 'SPACES' expected."));
+                return std::string{};
+              }
+
+              return cm::CMakeString{ args[1] }.Strip();
+            }
+            return std::string{};
+          } },
+        { "QUOTE"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            if (CheckStringParameters(ev, cnt, "QUOTE"_s, args, 2)) {
+              if (args.front() != "REGEX"_s) {
+                reportError(ev, cnt->GetOriginalExpression(),
+                            cmStrCat('\'', args.front(),
+                                     "' is unexpected. 'REGEX' expected."));
+                return std::string{};
+              }
+
+              return cm::CMakeString{ args[1] }.Quote();
+            }
+            return std::string{};
+          } },
+        { "HEX"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            if (CheckStringParameters(ev, cnt, "HEX"_s, args, 1)) {
+              return cm::CMakeString{ args.front() }.ToHexadecimal();
+            }
+            return std::string{};
+          } },
+        { "HASH"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            if (CheckStringParameters(ev, cnt, "HASH"_s, args, 2)) {
+              auto const ALGORITHM = "ALGORITHM:"_s;
+
+              if (cmHasPrefix(args[1], ALGORITHM)) {
+                try {
+                  auto const algo =
+                    cm::string_view{ args[1].c_str() + ALGORITHM.length() };
+                  if (algo.empty()) {
+                    reportError(
+                      ev, cnt->GetOriginalExpression(),
+                      cmStrCat("Missing value for '", ALGORITHM, "' option."));
+                    return std::string{};
+                  }
+                  return cm::CMakeString{ args.front() }.Hash(algo);
+                } catch (std::exception const& e) {
+                  reportError(ev, cnt->GetOriginalExpression(), e.what());
+                  return std::string{};
+                }
+              }
+              reportError(ev, cnt->GetOriginalExpression(),
+                          cmStrCat(args[1], ": invalid parameter. Option '",
+                                   ALGORITHM, "' expected."));
+            }
+            return std::string{};
+          } },
+        { "MAKE_C_IDENTIFIER"_s,
+          [](cm::GenEx::Evaluation* ev, GeneratorExpressionContent const* cnt,
+             Arguments& args) -> std::string {
+            if (CheckStringParameters(ev, cnt, "MAKE_C_IDENTIFIER"_s, args,
+                                      1)) {
+              return cm::CMakeString{ args.front() }.MakeCIdentifier();
+            }
+            return std::string{};
+          } }
+      };
+
+    if (parameters.front().empty()) {
+      reportError(eval, content->GetOriginalExpression(),
+                  "$<STRING> expression requires at least one parameter.");
+      return std::string{};
+    }
+
+    if (cm::contains(stringCommands, parameters.front())) {
+      auto args = Arguments{ parameters }.advance(1);
+      return stringCommands[parameters.front()](eval, content, args);
+    }
+
+    reportError(eval, content->GetOriginalExpression(),
+                cmStrCat(parameters.front(), ": invalid option."));
+    return std::string{};
+  }
+} stringNode;
+
+namespace {
 inline bool CheckListParametersEx(cm::GenEx::Evaluation* eval,
                                   GeneratorExpressionContent const* cnt,
                                   cm::string_view option, std::size_t count,
@@ -1183,53 +1858,6 @@
 {
   return list.empty() ? cmList{} : cmList{ list, cmList::EmptyElements::Yes };
 }
-
-bool GetNumericArgument(std::string const& arg, cmList::index_type& value)
-{
-  try {
-    std::size_t pos;
-
-    if (sizeof(cmList::index_type) == sizeof(long)) {
-      value = std::stol(arg, &pos);
-    } else {
-      value = std::stoll(arg, &pos);
-    }
-
-    if (pos != arg.length()) {
-      // this is not a number
-      return false;
-    }
-  } catch (std::invalid_argument const&) {
-    return false;
-  }
-
-  return true;
-}
-
-bool GetNumericArguments(
-  cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* cnt,
-  Arguments args, std::vector<cmList::index_type>& indexes,
-  cmList::ExpandElements expandElements = cmList::ExpandElements::No)
-{
-  using IndexRange = cmRange<Arguments::const_iterator>;
-  IndexRange arguments(args.begin(), args.end());
-  cmList list;
-  if (expandElements == cmList::ExpandElements::Yes) {
-    list = cmList{ args.begin(), args.end(), expandElements };
-    arguments = IndexRange{ list.begin(), list.end() };
-  }
-
-  for (auto const& value : arguments) {
-    cmList::index_type index;
-    if (!GetNumericArgument(value, index)) {
-      reportError(eval, cnt->GetOriginalExpression(),
-                  cmStrCat("index: \"", value, "\" is not a valid index"));
-      return false;
-    }
-    indexes.push_back(index);
-  }
-  return true;
-}
 }
 
 static const struct ListNode : public cmGeneratorExpressionNode
@@ -2020,7 +2648,7 @@
   {
     std::string const& compilerFrontendVariant =
       eval->Context.LG->GetMakefile()->GetSafeDefinition(
-        "CMAKE_" + lang + "_COMPILER_FRONTEND_VARIANT");
+        cmStrCat("CMAKE_", lang, "_COMPILER_FRONTEND_VARIANT"));
     if (parameters.empty()) {
       return compilerFrontendVariant;
     }
@@ -2951,6 +3579,291 @@
   }
 } deviceLinkNode;
 
+namespace {
+bool GetFileSet(std::vector<std::string> const& parameters,
+                cm::GenEx::Evaluation* eval,
+                GeneratorExpressionContent const* content, cmFileSet*& fileSet)
+{
+  auto const& fileSetName = parameters[0];
+  auto targetName = parameters[1];
+  auto* makefile = eval->Context.LG->GetMakefile();
+  fileSet = nullptr;
+
+  auto const TARGET = "TARGET:"_s;
+
+  if (cmHasPrefix(targetName, TARGET)) {
+    targetName = targetName.substr(TARGET.length());
+    if (targetName.empty()) {
+      reportError(eval, content->GetOriginalExpression(),
+                  cmStrCat("No value provided for the ", TARGET, " option."));
+      return false;
+    }
+    auto* target = makefile->FindTargetToUse(targetName);
+    if (!target) {
+      reportError(eval, content->GetOriginalExpression(),
+                  cmStrCat("Non-existent target: ", targetName));
+      return false;
+    }
+    fileSet = target->GetFileSet(fileSetName);
+  } else {
+    reportError(eval, content->GetOriginalExpression(),
+                cmStrCat("Invalid option. ", TARGET, " expected."));
+    return false;
+  }
+  return true;
+}
+}
+
+static const struct FileSetExistsNode : public cmGeneratorExpressionNode
+{
+  FileSetExistsNode() {} // NOLINT(modernize-use-equals-default)
+
+  // This node handles errors on parameter count itself.
+  int NumExpectedParameters() const override { return 2; }
+
+  std::string Evaluate(
+    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
+    GeneratorExpressionContent const* content,
+    cmGeneratorExpressionDAGChecker* /*dagCheckerParent*/) const override
+  {
+    if (parameters[0].empty()) {
+      reportError(
+        eval, content->GetOriginalExpression(),
+        "$<FILE_SET_EXISTS:fileset,TARGET:tgt> expression requires a "
+        "non-empty FILE_SET name.");
+      return std::string{};
+    }
+
+    cmFileSet* fileSet = nullptr;
+    if (!GetFileSet(parameters, eval, content, fileSet)) {
+      return std::string{};
+    }
+
+    return fileSet ? "1" : "0";
+  }
+} fileSetExistsNode;
+
+static const struct FileSetPropertyNode : public cmGeneratorExpressionNode
+{
+  FileSetPropertyNode() {} // NOLINT(modernize-use-equals-default)
+
+  // This node handles errors on parameter count itself.
+  int NumExpectedParameters() const override { return 3; }
+
+  std::string Evaluate(
+    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
+    GeneratorExpressionContent const* content,
+    cmGeneratorExpressionDAGChecker* /*dagCheckerParent*/) const override
+  {
+    static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
+
+    std::string const& fileSetName = parameters.front();
+    std::string const& propertyName = parameters.back();
+
+    if (fileSetName.empty() && propertyName.empty()) {
+      reportError(eval, content->GetOriginalExpression(),
+                  "$<FILE_SET_PROPERTY:fileset,TARGET:tgt,prop> expression "
+                  "requires a non-empty FILE_SET name and property name.");
+      return std::string{};
+    }
+    if (fileSetName.empty()) {
+      reportError(
+        eval, content->GetOriginalExpression(),
+        "$<FILE_SET_PROPERTY:fileset,TARGET:tgt,prop> expression requires a "
+        "non-empty FILE_SET name.");
+      return std::string{};
+    }
+    if (propertyName.empty()) {
+      reportError(
+        eval, content->GetOriginalExpression(),
+        "$<FILE_SET_PROPERTY:fileset,TARGET:tgt,prop> expression requires a "
+        "non-empty property name.");
+      return std::string{};
+    }
+    if (!propertyNameValidator.find(propertyName)) {
+      reportError(eval, content->GetOriginalExpression(),
+                  "Property name not supported.");
+      return std::string{};
+    }
+
+    cmFileSet* fileSet = nullptr;
+    if (!GetFileSet(parameters, eval, content, fileSet)) {
+      return std::string{};
+    }
+    if (!fileSet) {
+      reportError(
+        eval, content->GetOriginalExpression(),
+        cmStrCat("FILE_SET \"", fileSetName, "\" is not known from CMake."));
+      return std::string{};
+    }
+
+    return fileSet->GetProperty(propertyName);
+  }
+} fileSetPropertyNode;
+
+namespace {
+bool GetSourceFile(
+  cmRange<std::vector<std::string>::const_iterator> parameters,
+  cm::GenEx::Evaluation* eval, GeneratorExpressionContent const* content,
+  cmSourceFile*& sourceFile)
+{
+  auto sourceName = *parameters.begin();
+  auto* makefile = eval->Context.LG->GetMakefile();
+  sourceFile = nullptr;
+
+  if (parameters.size() == 2) {
+    auto const& option = *parameters.advance(1).begin();
+    auto const DIRECTORY = "DIRECTORY:"_s;
+    auto const TARGET_DIRECTORY = "TARGET_DIRECTORY:"_s;
+    if (cmHasPrefix(option, DIRECTORY)) {
+      auto dir = option.substr(DIRECTORY.length());
+      if (dir.empty()) {
+        reportError(
+          eval, content->GetOriginalExpression(),
+          cmStrCat("No value provided for the ", DIRECTORY, " option."));
+        return false;
+      }
+      dir = cmSystemTools::CollapseFullPath(
+        dir, makefile->GetCurrentSourceDirectory());
+      makefile = makefile->GetGlobalGenerator()->FindMakefile(dir);
+      if (!makefile) {
+        reportError(
+          eval, content->GetOriginalExpression(),
+          cmStrCat("Directory \"", dir, "\" is not known from CMake."));
+        return false;
+      }
+    } else if (cmHasPrefix(option, TARGET_DIRECTORY)) {
+      auto targetName = option.substr(TARGET_DIRECTORY.length());
+      if (targetName.empty()) {
+        reportError(eval, content->GetOriginalExpression(),
+                    cmStrCat("No value provided for the ", TARGET_DIRECTORY,
+                             " option."));
+        return false;
+      }
+      auto* target = makefile->FindTargetToUse(targetName);
+      if (!target) {
+        reportError(eval, content->GetOriginalExpression(),
+                    cmStrCat("Non-existent target: ", targetName));
+        return false;
+      }
+      makefile = makefile->GetGlobalGenerator()->FindMakefile(
+        target->GetProperty("BINARY_DIR"));
+    } else {
+      reportError(eval, content->GetOriginalExpression(),
+                  cmStrCat("Invalid option. ", DIRECTORY, " or ",
+                           TARGET_DIRECTORY, " expected."));
+      return false;
+    }
+
+    sourceName = cmSystemTools::CollapseFullPath(
+      sourceName,
+      eval->Context.LG->GetMakefile()->GetCurrentSourceDirectory());
+  }
+
+  sourceFile = makefile->GetSource(sourceName);
+  return true;
+}
+}
+
+static const struct SourceExistsNode : public cmGeneratorExpressionNode
+{
+  SourceExistsNode() {} // NOLINT(modernize-use-equals-default)
+
+  // This node handles errors on parameter count itself.
+  int NumExpectedParameters() const override { return OneOrMoreParameters; }
+
+  std::string Evaluate(
+    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
+    GeneratorExpressionContent const* content,
+    cmGeneratorExpressionDAGChecker* /*dagCheckerParent*/) const override
+  {
+    if (parameters.size() > 2) {
+      reportError(eval, content->GetOriginalExpression(),
+                  "$<SOURCE_EXISTS:...> expression requires at most two "
+                  "parameters.");
+      return std::string{};
+    }
+
+    if (parameters[0].empty()) {
+      reportError(eval, content->GetOriginalExpression(),
+                  "$<SOURCE_EXISTS:src> expression requires a "
+                  "non-empty source name.");
+      return std::string{};
+    }
+
+    cmSourceFile* sourceFile = nullptr;
+    if (!GetSourceFile(cmMakeRange(parameters), eval, content, sourceFile)) {
+      return std::string{};
+    }
+
+    return sourceFile ? "1" : "0";
+  }
+} sourceExistsNode;
+
+static const struct SourcePropertyNode : public cmGeneratorExpressionNode
+{
+  SourcePropertyNode() {} // NOLINT(modernize-use-equals-default)
+
+  // This node handles errors on parameter count itself.
+  int NumExpectedParameters() const override { return TwoOrMoreParameters; }
+
+  std::string Evaluate(
+    std::vector<std::string> const& parameters, cm::GenEx::Evaluation* eval,
+    GeneratorExpressionContent const* content,
+    cmGeneratorExpressionDAGChecker* /*dagCheckerParent*/) const override
+  {
+    static cmsys::RegularExpression propertyNameValidator("^[A-Za-z0-9_]+$");
+
+    if (parameters.size() > 3) {
+      reportError(eval, content->GetOriginalExpression(),
+                  "$<SOURCE_PROPERTY:...> expression requires at most three "
+                  "parameters.");
+      return std::string{};
+    }
+
+    std::string sourceName = parameters.front();
+    std::string const& propertyName = parameters.back();
+
+    if (sourceName.empty() && propertyName.empty()) {
+      reportError(eval, content->GetOriginalExpression(),
+                  "$<SOURCE_PROPERTY:src,prop> expression requires a "
+                  "non-empty source name and property name.");
+      return std::string{};
+    }
+    if (sourceName.empty()) {
+      reportError(eval, content->GetOriginalExpression(),
+                  "$<SOURCE_PROPERTY:src,prop> expression requires a "
+                  "non-empty source name.");
+      return std::string{};
+    }
+    if (propertyName.empty()) {
+      reportError(eval, content->GetOriginalExpression(),
+                  "$<SOURCE_PROPERTY:src,prop> expression requires a "
+                  "non-empty property name.");
+      return std::string{};
+    }
+    if (!propertyNameValidator.find(propertyName)) {
+      reportError(eval, content->GetOriginalExpression(),
+                  "Property name not supported.");
+      return std::string{};
+    }
+
+    cmSourceFile* sourceFile = nullptr;
+    if (!GetSourceFile(cmMakeRange(parameters).retreat(1), eval, content,
+                       sourceFile)) {
+      return std::string{};
+    }
+    if (!sourceFile) {
+      reportError(
+        eval, content->GetOriginalExpression(),
+        cmStrCat("Source file \"", sourceName, "\" is not known from CMake."));
+      return std::string{};
+    }
+
+    return sourceFile->GetPropertyForUser(propertyName);
+  }
+} sourcePropertyNode;
+
 static std::string getLinkedTargetsContent(
   cmGeneratorTarget const* target, std::string const& prop,
   cm::GenEx::Evaluation* eval, cmGeneratorExpressionDAGChecker* dagChecker,
@@ -3564,7 +4477,7 @@
       std::vector<std::string> const& langAvailable =
         availableFeatures[lit.first];
       cmValue standardDefault = eval->Context.LG->GetMakefile()->GetDefinition(
-        "CMAKE_" + lit.first + "_STANDARD_DEFAULT");
+        cmStrCat("CMAKE_", lit.first, "_STANDARD_DEFAULT"));
       for (std::string const& it : lit.second) {
         if (!cm::contains(langAvailable, it)) {
           return "0";
@@ -3889,7 +4802,8 @@
 
     std::string language = target->GetLinkerLanguage(eval->Context.Config);
 
-    std::string pdbSupportVar = "CMAKE_" + language + "_LINKER_SUPPORTS_PDB";
+    std::string pdbSupportVar =
+      cmStrCat("CMAKE_", language, "_LINKER_SUPPORTS_PDB");
 
     if (!eval->Context.LG->GetMakefile()->IsOn(pdbSupportVar)) {
       ::reportError(eval, content->GetOriginalExpression(),
@@ -4151,14 +5065,14 @@
       eval->Context.LG->FindGeneratorTargetToUse(name);
     if (!target) {
       ::reportError(eval, content->GetOriginalExpression(),
-                    "No target \"" + name + "\"");
+                    cmStrCat("No target \"", name, '"'));
       return nullptr;
     }
     if (target->GetType() >= cmStateEnums::OBJECT_LIBRARY &&
         target->GetType() != cmStateEnums::UNKNOWN_LIBRARY) {
-      ::reportError(eval, content->GetOriginalExpression(),
-                    "Target \"" + name +
-                      "\" is not an executable or library.");
+      ::reportError(
+        eval, content->GetOriginalExpression(),
+        cmStrCat("Target \"", name, "\" is not an executable or library."));
       return nullptr;
     }
     if (dagChecker &&
@@ -4408,7 +5322,8 @@
 
     std::string language = target->GetLinkerLanguage(eval->Context.Config);
 
-    std::string pdbSupportVar = "CMAKE_" + language + "_LINKER_SUPPORTS_PDB";
+    std::string pdbSupportVar =
+      cmStrCat("CMAKE_", language, "_LINKER_SUPPORTS_PDB");
 
     if (!eval->Context.LG->GetMakefile()->IsOn(pdbSupportVar)) {
       ::reportError(
@@ -4440,7 +5355,8 @@
         postfix != Postfix::Unspecified) {
       eval->Context.LG->GetCMakeInstance()->IssueMessage(
         MessageType::AUTHOR_WARNING,
-        cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0202), '\n',
+        cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0202),
+                 "\n"
                  "\"POSTFIX\" option is recognized only when the policy is "
                  "set to NEW. Since the policy is not set, the OLD behavior "
                  "will be used."),
@@ -4784,7 +5700,7 @@
     for (auto const& in : list_in) {
       if (!cmSystemTools::FileIsFullPath(in)) {
         reportError(eval, content->GetOriginalExpression(),
-                    "\"" + in + "\" is not an absolute path.");
+                    cmStrCat('"', in, "\" is not an absolute path."));
         return std::string();
       }
       list_out.emplace_back(converter.ConvertDirectorySeparatorsForShell(in));
@@ -4885,6 +5801,11 @@
     { "TARGET_BUNDLE_DIR_NAME", &targetBundleDirNameNode },
     { "TARGET_BUNDLE_CONTENT_DIR", &targetBundleContentDirNode },
     { "STREQUAL", &strEqualNode },
+    { "STRLESS", &strLessNode },
+    { "STRLESS_EQUAL", &strLessEqualNode },
+    { "STRGREATER", &strGreaterNode },
+    { "STRGREATER_EQUAL", &strGreaterEqualNode },
+    { "STRING", &stringNode },
     { "EQUAL", &equalNode },
     { "IN_LIST", &inListNode },
     { "FILTER", &filterNode },
@@ -4901,6 +5822,10 @@
     { "COMMA", &commaNode },
     { "SEMICOLON", &semicolonNode },
     { "QUOTE", &quoteNode },
+    { "SOURCE_EXISTS", &sourceExistsNode },
+    { "SOURCE_PROPERTY", &sourcePropertyNode },
+    { "FILE_SET_EXISTS", &fileSetExistsNode },
+    { "FILE_SET_PROPERTY", &fileSetPropertyNode },
     { "TARGET_PROPERTY", &targetPropertyNode },
     { "TARGET_INTERMEDIATE_DIR", &targetIntermediateDirNode },
     { "TARGET_NAME", &targetNameNode },
diff --git a/Source/cmGeneratorExpressionParser.cxx b/Source/cmGeneratorExpressionParser.cxx
index c47de3b..6975642 100644
--- a/Source/cmGeneratorExpressionParser.cxx
+++ b/Source/cmGeneratorExpressionParser.cxx
@@ -115,31 +115,9 @@
       emptyParamTermination = true;
     }
 
-    while (this->it != this->Tokens.end() &&
-           this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) {
-      commaTokens.push_back(this->it);
-      parameters.resize(parameters.size() + 1);
-      assert(this->it != this->Tokens.end());
-      ++this->it;
-      if (this->it == this->Tokens.end()) {
-        emptyParamTermination = true;
-      }
-    }
-    while (this->it != this->Tokens.end() &&
-           this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator) {
-      extendText(*(parameters.end() - 1), this->it);
-      assert(this->it != this->Tokens.end());
-      ++this->it;
-    }
-    while (this->it != this->Tokens.end() &&
-           this->it->TokenType != cmGeneratorExpressionToken::EndExpression) {
-      this->ParseContent(*(parameters.end() - 1));
-      if (this->it == this->Tokens.end()) {
-        break;
-      }
-      while (this->it != this->Tokens.end() &&
-             this->it->TokenType ==
-               cmGeneratorExpressionToken::CommaSeparator) {
+    auto handleCommaOrColon = [this, &commaTokens, &parameters,
+                               &emptyParamTermination]() -> void {
+      if (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator) {
         commaTokens.push_back(this->it);
         parameters.resize(parameters.size() + 1);
         assert(this->it != this->Tokens.end());
@@ -147,14 +125,32 @@
         if (this->it == this->Tokens.end()) {
           emptyParamTermination = true;
         }
-      }
-      while (this->it != this->Tokens.end() &&
-             this->it->TokenType ==
-               cmGeneratorExpressionToken::ColonSeparator) {
+      } else if (this->it->TokenType ==
+                 cmGeneratorExpressionToken::ColonSeparator) {
         extendText(*(parameters.end() - 1), this->it);
         assert(this->it != this->Tokens.end());
         ++this->it;
       }
+    };
+
+    while (
+      this->it != this->Tokens.end() &&
+      (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator ||
+       this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)) {
+      handleCommaOrColon();
+    }
+    while (this->it != this->Tokens.end() &&
+           this->it->TokenType != cmGeneratorExpressionToken::EndExpression) {
+      this->ParseContent(*(parameters.end() - 1));
+      if (this->it == this->Tokens.end()) {
+        break;
+      }
+      while (
+        this->it != this->Tokens.end() &&
+        (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator ||
+         this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)) {
+        handleCommaOrColon();
+      }
     }
     if (this->it != this->Tokens.end() &&
         this->it->TokenType == cmGeneratorExpressionToken::EndExpression) {
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 22f1e17..d44d4bd 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -5,10 +5,10 @@
 #include <algorithm>
 #include <array>
 #include <cassert>
-#include <cctype>
 #include <cstddef>
 #include <cstdio>
 #include <cstring>
+#include <initializer_list>
 #include <sstream>
 #include <unordered_set>
 #include <utility>
@@ -19,9 +19,12 @@
 #include <cmext/algorithm>
 #include <cmext/string_view>
 
+#include "cmsys/String.h"
+
 #include "cmAlgorithms.h"
 #include "cmComputeLinkInformation.h" // IWYU pragma: keep
 #include "cmCryptoHash.h"
+#include "cmCxxModuleMetadata.h"
 #include "cmCxxModuleUsageEffects.h"
 #include "cmExperimental.h"
 #include "cmFileSet.h"
@@ -321,7 +324,7 @@
     std::string configUpper = cmSystemTools::UpperCase(config);
     if (!type.empty() && !configUpper.empty()) {
       // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME_<CONFIG>
-      props.push_back(type + "_OUTPUT_NAME_" + configUpper);
+      props.push_back(cmStrCat(type, "_OUTPUT_NAME_", configUpper));
     }
     if (!type.empty()) {
       // <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_NAME
@@ -356,7 +359,8 @@
     // from the above block.
     this->LocalGenerator->GetCMakeInstance()->IssueMessage(
       MessageType::FATAL_ERROR,
-      "Target '" + this->GetName() + "' OUTPUT_NAME depends on itself.",
+      cmStrCat("Target '", this->GetName(),
+               "' OUTPUT_NAME depends on itself."),
       this->GetBacktrace());
   }
   return i->second;
@@ -530,6 +534,7 @@
 void cmGeneratorTarget::ClearSourcesCache()
 {
   this->AllConfigSources.clear();
+  this->AllConfigCompileLanguages.clear();
   this->KindedSourcesMap.clear();
   this->SourcesAreContextDependent = Tribool::Indeterminate;
   this->Objects.clear();
@@ -805,7 +810,8 @@
   cmPolicies::PolicyStatus cmp0069 = this->GetPolicyStatusCMP0069();
 
   if (cmp0069 == cmPolicies::OLD || cmp0069 == cmPolicies::WARN) {
-    if (this->Makefile->IsOn("_CMAKE_" + lang + "_IPO_LEGACY_BEHAVIOR")) {
+    if (this->Makefile->IsOn(
+          cmStrCat("_CMAKE_", lang, "_IPO_LEGACY_BEHAVIOR"))) {
       return true;
     }
     if (this->PolicyReportedCMP0069) {
@@ -2329,6 +2335,7 @@
   }
 
   // C++ module flags.
+  bool useBmiTemplate = false;
   if (lang == "CXX"_s) {
     FlagClassification cls = FlagClassification::LocationFlag;
     FlagKind kind = FlagKind::BuildSystem;
@@ -2347,13 +2354,18 @@
       }
 
       if (!this->Target->IsNormal()) {
-        auto flag = mf->GetSafeDefinition("CMAKE_CXX_MODULE_BMI_ONLY_FLAG");
-        cmRulePlaceholderExpander::RuleVariables compileObjectVars;
-        compileObjectVars.Object = sfVars.ObjectFileDir.c_str();
-        auto rulePlaceholderExpander = lg->CreateRulePlaceholderExpander();
-        rulePlaceholderExpander->ExpandRuleVariables(lg, flag,
-                                                     compileObjectVars);
-        lg->AppendCompileOptions(bmiFlags, flag);
+        if (!mf->GetDefinition("CMAKE_CXX_COMPILE_BMI").IsEmpty()) {
+          useBmiTemplate = true;
+        } else {
+          std::string flag =
+            mf->GetSafeDefinition("CMAKE_CXX_MODULE_BMI_ONLY_FLAG");
+          cmRulePlaceholderExpander::RuleVariables compileObjectVars;
+          compileObjectVars.Object = sfVars.ObjectFileDir.c_str();
+          auto rulePlaceholderExpander = lg->CreateRulePlaceholderExpander();
+          rulePlaceholderExpander->ExpandRuleVariables(lg, flag,
+                                                       compileObjectVars);
+          lg->AppendCompileOptions(bmiFlags, flag);
+        }
       }
     }
 
@@ -2376,7 +2388,8 @@
     FlagClassification cls = FlagClassification::ExecutionFlag;
     FlagKind kind = FlagKind::NotAFlag;
 
-    std::string const cmdVar = cmStrCat("CMAKE_", lang, "_COMPILE_OBJECT");
+    std::string const cmdVar =
+      cmStrCat("CMAKE_", lang, "_COMPILE_", useBmiTemplate ? "BMI" : "OBJECT");
     std::string const& compileCmd = mf->GetRequiredDefinition(cmdVar);
     cmList compileCmds(compileCmd); // FIXME: which command to use?
     std::string& cmd = compileCmds[0];
@@ -2682,32 +2695,33 @@
     }
 
     for (CudaArchitecture& architecture : architectures) {
-      flags +=
-        " \"--generate-code=arch=compute_" + architecture.name + ",code=[";
+      flags = cmStrCat(std::move(flags), " \"--generate-code=arch=compute_",
+                       architecture.name, ",code=[");
 
       if (architecture.virtual_) {
-        flags += "compute_" + architecture.name;
+        flags = cmStrCat(std::move(flags), "compute_", architecture.name);
 
         if (ipoEnabled || architecture.real) {
-          flags += ",";
+          flags += ',';
         }
       }
 
       if (ipoEnabled) {
         if (compileOrLink == cmBuildStep::Compile) {
-          flags += "lto_" + architecture.name;
+          flags = cmStrCat(std::move(flags), "lto_", architecture.name);
         } else if (compileOrLink == cmBuildStep::Link) {
-          flags += "sm_" + architecture.name;
+          flags = cmStrCat(std::move(flags), "sm_", architecture.name);
         }
       } else if (architecture.real) {
-        flags += "sm_" + architecture.name;
+        flags = cmStrCat(std::move(flags), "sm_", architecture.name);
       }
 
       flags += "]\"";
     }
   } else if (compiler == "Clang" && compileOrLink == cmBuildStep::Compile) {
     for (CudaArchitecture& architecture : architectures) {
-      flags += " --cuda-gpu-arch=sm_" + architecture.name;
+      flags =
+        cmStrCat(std::move(flags), " --cuda-gpu-arch=sm_", architecture.name);
 
       if (!architecture.real) {
         this->Makefile->IssueMessage(
@@ -2716,7 +2730,8 @@
       }
 
       if (!architecture.virtual_) {
-        flags += " --no-cuda-include-ptx=sm_" + architecture.name;
+        flags = cmStrCat(std::move(flags), " --no-cuda-include-ptx=sm_",
+                         architecture.name);
       }
     }
   }
@@ -2749,9 +2764,10 @@
   std::string arch = this->GetSafeProperty("HIP_ARCHITECTURES");
 
   if (arch.empty()) {
-    this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
-                                 "HIP_ARCHITECTURES is empty for target \"" +
-                                   this->GetName() + "\".");
+    this->Makefile->IssueMessage(
+      MessageType::FATAL_ERROR,
+      cmStrCat("HIP_ARCHITECTURES is empty for target \"", this->GetName(),
+               "\"."));
   }
 
   // If HIP_ARCHITECTURES is false we don't add any architectures.
@@ -2765,6 +2781,11 @@
     return;
   }
 
+  // For spirv platform, chipStar handles targeting via the hip package
+  if (this->Makefile->GetSafeDefinition("CMAKE_HIP_PLATFORM") == "spirv") {
+    return;
+  }
+
   cmList options(arch);
 
   for (std::string& option : options) {
@@ -2815,29 +2836,29 @@
 {
   switch (this->GetType()) {
     case cmStateEnums::STATIC_LIBRARY: {
-      std::string var = "CMAKE_" + lang + "_CREATE_STATIC_LIBRARY";
+      std::string var = cmStrCat("CMAKE_", lang, "_CREATE_STATIC_LIBRARY");
       return this->GetFeatureSpecificLinkRuleVariable(var, lang, config);
     }
     case cmStateEnums::SHARED_LIBRARY:
       if (this->IsArchivedAIXSharedLibrary()) {
-        return "CMAKE_" + lang + "_CREATE_SHARED_LIBRARY_ARCHIVE";
+        return cmStrCat("CMAKE_", lang, "_CREATE_SHARED_LIBRARY_ARCHIVE");
       }
-      return "CMAKE_" + lang + "_CREATE_SHARED_LIBRARY";
+      return cmStrCat("CMAKE_", lang, "_CREATE_SHARED_LIBRARY");
     case cmStateEnums::MODULE_LIBRARY:
-      return "CMAKE_" + lang + "_CREATE_SHARED_MODULE";
+      return cmStrCat("CMAKE_", lang, "_CREATE_SHARED_MODULE");
     case cmStateEnums::EXECUTABLE:
       if (this->IsExecutableWithExports()) {
         std::string linkExeWithExports =
-          "CMAKE_" + lang + "_LINK_EXECUTABLE_WITH_EXPORTS";
+          cmStrCat("CMAKE_", lang, "_LINK_EXECUTABLE_WITH_EXPORTS");
         if (this->Makefile->IsDefinitionSet(linkExeWithExports)) {
           return linkExeWithExports;
         }
       }
-      return "CMAKE_" + lang + "_LINK_EXECUTABLE";
+      return cmStrCat("CMAKE_", lang, "_LINK_EXECUTABLE");
     default:
       break;
   }
-  return "";
+  return {};
 }
 
 //----------------------------------------------------------------------------
@@ -3275,9 +3296,9 @@
     if (GlobalGenerator->IsFastbuild()) {
       // Account for potential spaces in a shell-friendly way.
       cmSystemTools::ReplaceString(createOptionList, "<PCH_HEADER>",
-                                   '"' + pchHeader + '"');
+                                   cmStrCat('"', pchHeader, '"'));
       cmSystemTools::ReplaceString(createOptionList, "<PCH_FILE>",
-                                   '"' + pchFile + '"');
+                                   cmStrCat('"', pchFile, '"'));
     } else {
       cmSystemTools::ReplaceString(createOptionList, "<PCH_HEADER>",
                                    pchHeader);
@@ -3319,9 +3340,9 @@
     if (GlobalGenerator->IsFastbuild()) {
       // Account for potential spaces in a shell-friendly way.
       cmSystemTools::ReplaceString(useOptionList, "<PCH_HEADER>",
-                                   '"' + pchHeader + '"');
+                                   cmStrCat('"', pchHeader, '"'));
       cmSystemTools::ReplaceString(useOptionList, "<PCH_FILE>",
-                                   '"' + pchFile + '"');
+                                   cmStrCat('"', pchFile, '"'));
     } else {
       cmSystemTools::ReplaceString(useOptionList, "<PCH_HEADER>", pchHeader);
       cmSystemTools::ReplaceString(useOptionList, "<PCH_FILE>", pchFile);
@@ -3940,8 +3961,7 @@
 
     if (linkerType != "DEFAULT"_s) {
       auto isCMakeLinkerType = [](std::string const& type) -> bool {
-        return std::all_of(type.cbegin(), type.cend(),
-                           [](char c) { return std::isupper(c); });
+        return std::all_of(type.cbegin(), type.cend(), cmsysString_isupper);
       };
       if (isCMakeLinkerType(linkerType)) {
         this->LocalGenerator->IssueMessage(
@@ -4020,7 +4040,7 @@
     // from the above block.
     this->LocalGenerator->GetCMakeInstance()->IssueMessage(
       MessageType::FATAL_ERROR,
-      "Target '" + this->GetName() + "' PDB_NAME depends on itself.",
+      cmStrCat("Target '", this->GetName(), "' PDB_NAME depends on itself."),
       this->GetBacktrace());
   }
   return i->second;
@@ -4540,7 +4560,8 @@
     // from the above block.
     this->LocalGenerator->GetCMakeInstance()->IssueMessage(
       MessageType::FATAL_ERROR,
-      "Target '" + this->GetName() + "' OUTPUT_DIRECTORY depends on itself.",
+      cmStrCat("Target '", this->GetName(),
+               "' OUTPUT_DIRECTORY depends on itself."),
       this->GetBacktrace());
     return nullptr;
   }
@@ -5130,6 +5151,77 @@
   return cm::contains(this->LinkImplicitNullProperties, p);
 }
 
+namespace {
+bool CreateCxxStdlibTarget(cmMakefile* makefile, cmLocalGenerator* lg,
+                           std::string const& targetName,
+                           std::string const& cxxTargetName,
+                           std::string const& stdLevel,
+                           std::vector<std::string> const& configs)
+{
+#ifndef CMAKE_BOOTSTRAP
+
+  static cm::optional<cmCxxModuleMetadata> metadata;
+
+  // Load metadata only when we need to create a target
+  if (!metadata) {
+    auto errorMessage =
+      makefile->GetDefinition("CMAKE_CXX_COMPILER_IMPORT_STD_ERROR_MESSAGE");
+    if (!errorMessage.IsEmpty()) {
+      makefile->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat(R"(The "CXX_MODULE_STD" property on target ")", targetName,
+                 "\" requires toolchain support, but it was not provided.  "
+                 "Reason:\n  ",
+                 *errorMessage));
+      return false;
+    }
+
+    auto metadataPath =
+      makefile->GetDefinition("CMAKE_CXX_STDLIB_MODULES_JSON");
+    if (metadataPath.IsEmpty()) {
+      makefile->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat(
+          R"("The "CXX_MODULE_STD" property on target ")", targetName,
+          "\" requires CMAKE_CXX_STDLIB_MODULES_JSON be set, but it was not "
+          "provided by the toolchain."));
+      return false;
+    }
+
+    auto parseResult = cmCxxModuleMetadata::LoadFromFile(*metadataPath);
+    if (!parseResult) {
+      makefile->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat("Failed to load C++ standard library modules metadata "
+                 "from \"",
+                 *metadataPath, "\": ", parseResult.Error));
+      return false;
+    }
+
+    metadata = std::move(*parseResult.Meta);
+  }
+
+  auto const localTargetName = cmStrCat("__cmake_cxx_std_", stdLevel);
+  cmStandardLevelResolver standardResolver(makefile);
+  auto* stdlibTgt = makefile->AddLibrary(
+    localTargetName, cmStateEnums::STATIC_LIBRARY, {}, true);
+  cmCxxModuleMetadata::PopulateTarget(*stdlibTgt, *metadata, configs);
+  standardResolver.AddRequiredTargetFeature(stdlibTgt,
+                                            cmStrCat("cxx_std_", stdLevel));
+  auto gt = cm::make_unique<cmGeneratorTarget>(stdlibTgt, lg);
+  for (auto const& config : configs) {
+    gt->ComputeCompileFeatures(config);
+  }
+
+  lg->AddGeneratorTarget(std::move(gt));
+  makefile->AddAlias(cxxTargetName, localTargetName);
+
+#endif // CMAKE_BOOTSTRAP
+
+  return true;
+}
+} // namespace
+
 bool cmGeneratorTarget::ApplyCXXStdTargets()
 {
   cmStandardLevelResolver standardResolver(this->Makefile);
@@ -5211,35 +5303,32 @@
 
     auto const stdLevel =
       standardResolver.GetLevelString("CXX", *explicitLevel);
-    auto const targetName = cmStrCat("__CMAKE::CXX", stdLevel);
-    if (!this->Makefile->FindTargetToUse(targetName)) {
-      auto basicReason = this->Makefile->GetDefinition(cmStrCat(
-        "CMAKE_CXX", stdLevel, "_COMPILER_IMPORT_STD_NOT_FOUND_MESSAGE"));
-      std::string reason;
-      if (!basicReason.IsEmpty()) {
-        reason = cmStrCat("  Reason:\n  ", basicReason);
-      }
-      this->Makefile->IssueMessage(
-        MessageType::FATAL_ERROR,
-        cmStrCat(R"(The "CXX_MODULE_STD" property on the target ")",
-                 this->GetName(), "\" requires that the \"", targetName,
-                 "\" target exist, but it was not provided by the toolchain.",
-                 reason));
-      break;
-    }
+    auto const cxxTargetName = cmStrCat("__CMAKE::CXX", stdLevel);
 
-    // Check the experimental feature here as well. A toolchain may have
-    // provided the target and skipped the check in the toolchain preparation
-    // logic.
-    if (!cmExperimental::HasSupportEnabled(
-          *this->Makefile, cmExperimental::Feature::CxxImportStd)) {
-      break;
+    // Create the __CMAKE::CXX## target if it doesn't already exist
+    if (!this->Makefile->FindTargetToUse(cxxTargetName) &&
+        !CreateCxxStdlibTarget(this->Makefile, this->LocalGenerator,
+                               this->GetName(), cxxTargetName, stdLevel,
+                               configs)) {
+      return false;
     }
 
     this->Target->AppendProperty(
       "LINK_LIBRARIES",
-      cmStrCat("$<BUILD_LOCAL_INTERFACE:$<$<CONFIG:", config, ">:", targetName,
-               ">>"));
+      cmStrCat("$<BUILD_LOCAL_INTERFACE:$<$<CONFIG:", config,
+               ">:", cxxTargetName, ">>"));
+  }
+
+  // Check the experimental feature here. A toolchain may have
+  // skipped the check in the toolchain preparation logic.
+  if (!cmExperimental::HasSupportEnabled(
+        *this->Makefile, cmExperimental::Feature::CxxImportStd)) {
+    this->Makefile->IssueMessage(
+      MessageType::FATAL_ERROR,
+      "Experimental `import std` support not enabled when detecting "
+      "toolchain; it must be set before `CXX` is enabled (usually a "
+      "`project()` call).");
+    return false;
   }
 
   return true;
@@ -5339,7 +5428,9 @@
         }
         // See `cmGlobalGenerator::ApplyCXXStdTargets` in
         // `cmGlobalGenerator::Compute` for non-synthetic target resolutions.
-        gtp->ApplyCXXStdTargets();
+        if (!gtp->ApplyCXXStdTargets()) {
+          return false;
+        }
 
         gtp->DiscoverSyntheticTargets(cache, config);
 
@@ -5657,145 +5748,236 @@
 
 bool cmGeneratorTarget::AddHeaderSetVerification()
 {
-  if (!this->GetPropertyAsBool("VERIFY_INTERFACE_HEADER_SETS")) {
-    return true;
-  }
-
-  if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
-      this->GetType() != cmStateEnums::SHARED_LIBRARY &&
-      this->GetType() != cmStateEnums::UNKNOWN_LIBRARY &&
-      this->GetType() != cmStateEnums::OBJECT_LIBRARY &&
-      this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
-      !this->IsExecutableWithExports()) {
-    return true;
-  }
-
-  auto verifyValue = this->GetProperty("INTERFACE_HEADER_SETS_TO_VERIFY");
-  bool const all = verifyValue.IsEmpty();
-  std::set<std::string> verifySet;
-  if (!all) {
-    cmList verifyList{ verifyValue };
-    verifySet.insert(verifyList.begin(), verifyList.end());
-  }
-
-  cmTarget* verifyTarget = nullptr;
-  cmTarget* allVerifyTarget =
-    this->GlobalGenerator->GetMakefiles().front()->FindTargetToUse(
-      "all_verify_interface_header_sets",
-      { cmStateEnums::TargetDomain::NATIVE });
-
-  auto interfaceFileSetEntries = this->Target->GetInterfaceHeaderSetsEntries();
-
-  std::set<cmFileSet*> fileSets;
-  for (auto const& entry : interfaceFileSetEntries) {
-    for (auto const& name : cmList{ entry.Value }) {
-      if (all || verifySet.count(name)) {
-        fileSets.insert(this->Target->GetFileSet(name));
-        verifySet.erase(name);
-      }
+  for (bool const isInterface : { false, true }) {
+    if (!this->GetPropertyAsBool(isInterface ? "VERIFY_INTERFACE_HEADER_SETS"
+                                             : "VERIFY_PRIVATE_HEADER_SETS")) {
+      continue;
     }
-  }
-  if (!verifySet.empty()) {
-    this->Makefile->IssueMessage(
-      MessageType::FATAL_ERROR,
-      cmStrCat("Property INTERFACE_HEADER_SETS_TO_VERIFY of target \"",
-               this->GetName(),
-               "\" contained the following header sets that are nonexistent "
-               "or not INTERFACE:\n  ",
-               cmJoin(verifySet, "\n  ")));
-    return false;
-  }
 
-  cm::optional<std::set<std::string>> languages;
-  for (auto* fileSet : fileSets) {
-    auto dirCges = fileSet->CompileDirectoryEntries();
-    auto fileCges = fileSet->CompileFileEntries();
+    if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
+        this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+        (this->GetType() != cmStateEnums::MODULE_LIBRARY || isInterface) &&
+        this->GetType() != cmStateEnums::UNKNOWN_LIBRARY &&
+        this->GetType() != cmStateEnums::OBJECT_LIBRARY &&
+        this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
+        this->GetType() != cmStateEnums::EXECUTABLE) {
+      continue;
+    }
 
-    static auto const contextSensitive =
-      [](std::unique_ptr<cmCompiledGeneratorExpression> const& cge) {
-        return cge->GetHadContextSensitiveCondition();
-      };
-    bool dirCgesContextSensitive = false;
-    bool fileCgesContextSensitive = false;
+    char const* headerSetsProperty = isInterface
+      ? "INTERFACE_HEADER_SETS_TO_VERIFY"
+      : "PRIVATE_HEADER_SETS_TO_VERIFY";
 
-    std::vector<std::string> dirs;
-    std::map<std::string, std::vector<std::string>> filesPerDir;
-    bool first = true;
-    for (auto const& config : this->Makefile->GetGeneratorConfigs(
-           cmMakefile::GeneratorConfigQuery::IncludeEmptyConfig)) {
-      cm::GenEx::Context context(this->LocalGenerator, config);
-      if (first || dirCgesContextSensitive) {
-        dirs = fileSet->EvaluateDirectoryEntries(dirCges, context, this);
-        dirCgesContextSensitive =
-          std::any_of(dirCges.begin(), dirCges.end(), contextSensitive);
-      }
-      if (first || fileCgesContextSensitive) {
-        filesPerDir.clear();
-        for (auto const& fileCge : fileCges) {
-          fileSet->EvaluateFileEntry(dirs, filesPerDir, fileCge, context,
-                                     this);
-          if (fileCge->GetHadContextSensitiveCondition()) {
-            fileCgesContextSensitive = true;
-          }
+    auto verifyValue = this->GetProperty(headerSetsProperty);
+    bool const all = verifyValue.IsEmpty();
+    std::set<std::string> verifySet;
+    if (!all) {
+      cmList verifyList{ verifyValue };
+      verifySet.insert(verifyList.begin(), verifyList.end());
+    }
+
+    cmTarget* verifyTarget = nullptr;
+    std::string const verifyTargetName =
+      cmStrCat(this->GetName(),
+               isInterface ? "_verify_interface_header_sets"
+                           : "_verify_private_header_sets");
+
+    char const* allVerifyTargetName = isInterface
+      ? "all_verify_interface_header_sets"
+      : "all_verify_private_header_sets";
+    cmTarget* allVerifyTarget =
+      this->GlobalGenerator->GetMakefiles().front()->FindTargetToUse(
+        allVerifyTargetName, { cmStateEnums::TargetDomain::NATIVE });
+
+    auto fileSetEntries = isInterface
+      ? this->Target->GetInterfaceHeaderSetsEntries()
+      : this->Target->GetHeaderSetsEntries();
+
+    std::set<cmFileSet*> fileSets;
+    for (auto const& entry : fileSetEntries) {
+      for (auto const& name : cmList{ entry.Value }) {
+        if (all || verifySet.count(name)) {
+          fileSets.insert(this->Target->GetFileSet(name));
+          verifySet.erase(name);
         }
       }
-
-      for (auto const& files : filesPerDir) {
-        for (auto const& file : files.second) {
-          std::string filename = this->GenerateHeaderSetVerificationFile(
-            *this->Makefile->GetOrCreateSource(file), files.first, languages);
-          if (filename.empty()) {
-            continue;
-          }
-
-          if (!verifyTarget) {
-            {
-              cmMakefile::PolicyPushPop polScope(this->Makefile);
-              this->Makefile->SetPolicy(cmPolicies::CMP0119, cmPolicies::NEW);
-              verifyTarget = this->Makefile->AddLibrary(
-                cmStrCat(this->GetName(), "_verify_interface_header_sets"),
-                cmStateEnums::OBJECT_LIBRARY, {}, true);
-            }
-
-            verifyTarget->AddLinkLibrary(
-              *this->Makefile, this->GetName(),
-              cmTargetLinkLibraryType::GENERAL_LibraryType);
-            verifyTarget->SetProperty("AUTOMOC", "OFF");
-            verifyTarget->SetProperty("AUTORCC", "OFF");
-            verifyTarget->SetProperty("AUTOUIC", "OFF");
-            verifyTarget->SetProperty("DISABLE_PRECOMPILE_HEADERS", "ON");
-            verifyTarget->SetProperty("UNITY_BUILD", "OFF");
-            verifyTarget->SetProperty("CXX_SCAN_FOR_MODULES", "OFF");
-            verifyTarget->FinalizeTargetConfiguration(
-              this->Makefile->GetCompileDefinitionsEntries());
-
-            if (!allVerifyTarget) {
-              allVerifyTarget = this->GlobalGenerator->GetMakefiles()
-                                  .front()
-                                  ->AddNewUtilityTarget(
-                                    "all_verify_interface_header_sets", true);
-            }
-
-            allVerifyTarget->AddUtility(verifyTarget->GetName(), false);
-          }
-
-          if (fileCgesContextSensitive) {
-            filename = cmStrCat("$<$<CONFIG:", config, ">:", filename, '>');
-          }
-          verifyTarget->AddSource(filename);
-        }
-      }
-
-      if (!dirCgesContextSensitive && !fileCgesContextSensitive) {
-        break;
-      }
-      first = false;
     }
-  }
 
-  if (verifyTarget) {
-    this->LocalGenerator->AddGeneratorTarget(
-      cm::make_unique<cmGeneratorTarget>(verifyTarget, this->LocalGenerator));
+    if (isInterface) {
+      cmPolicies::PolicyStatus const cmp0209 = this->GetPolicyStatusCMP0209();
+      if (cmp0209 != cmPolicies::NEW &&
+          this->GetType() == cmStateEnums::EXECUTABLE &&
+          !this->GetPropertyAsBool("ENABLE_EXPORTS")) {
+        if (cmp0209 == cmPolicies::WARN && !fileSets.empty()) {
+          this->Makefile->IssueMessage(
+            MessageType::AUTHOR_WARNING,
+            cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0209),
+                     "\n"
+                     "Executable target \"",
+                     this->GetName(),
+                     "\" has interface header file sets, but it does not "
+                     "enable exports. Those headers would be verified under "
+                     "CMP0209 NEW behavior.\n"));
+        }
+        continue;
+      }
+    }
+
+    if (!verifySet.empty()) {
+      this->Makefile->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat("Property ", headerSetsProperty, " of target \"",
+                 this->GetName(),
+                 "\" contained the following header sets that are nonexistent "
+                 "or not ",
+                 isInterface ? "INTERFACE" : "PRIVATE", ":\n  ",
+                 cmJoin(verifySet, "\n  ")));
+      return false;
+    }
+
+    cm::optional<std::set<std::string>> languages;
+    for (auto* fileSet : fileSets) {
+      auto dirCges = fileSet->CompileDirectoryEntries();
+      auto fileCges = fileSet->CompileFileEntries();
+
+      static auto const contextSensitive =
+        [](std::unique_ptr<cmCompiledGeneratorExpression> const& cge) {
+          return cge->GetHadContextSensitiveCondition();
+        };
+      bool dirCgesContextSensitive = false;
+      bool fileCgesContextSensitive = false;
+
+      std::vector<std::string> dirs;
+      std::map<std::string, std::vector<std::string>> filesPerDir;
+      bool first = true;
+      for (auto const& config : this->Makefile->GetGeneratorConfigs(
+             cmMakefile::GeneratorConfigQuery::IncludeEmptyConfig)) {
+        cm::GenEx::Context context(this->LocalGenerator, config);
+        if (first || dirCgesContextSensitive) {
+          dirs = fileSet->EvaluateDirectoryEntries(dirCges, context, this);
+          dirCgesContextSensitive =
+            std::any_of(dirCges.begin(), dirCges.end(), contextSensitive);
+        }
+        if (first || fileCgesContextSensitive) {
+          filesPerDir.clear();
+          for (auto const& fileCge : fileCges) {
+            fileSet->EvaluateFileEntry(dirs, filesPerDir, fileCge, context,
+                                       this);
+            if (fileCge->GetHadContextSensitiveCondition()) {
+              fileCgesContextSensitive = true;
+            }
+          }
+        }
+
+        for (auto const& files : filesPerDir) {
+          for (auto const& file : files.second) {
+            std::string filename = this->GenerateHeaderSetVerificationFile(
+              *this->Makefile->GetOrCreateSource(file), files.first,
+              verifyTargetName, languages);
+            if (filename.empty()) {
+              continue;
+            }
+
+            if (!verifyTarget) {
+              {
+                cmMakefile::PolicyPushPop polScope(this->Makefile);
+                this->Makefile->SetPolicy(cmPolicies::CMP0119,
+                                          cmPolicies::NEW);
+                verifyTarget = this->Makefile->AddLibrary(
+                  verifyTargetName, cmStateEnums::OBJECT_LIBRARY, {}, true);
+              }
+
+              if (isInterface) {
+                // Link to the original target so that we pick up its
+                // interface compile options just like a consumer would.
+                // This also ensures any generated headers in the original
+                // target will be created.
+                verifyTarget->AddLinkLibrary(
+                  *this->Makefile, this->GetName(),
+                  cmTargetLinkLibraryType::GENERAL_LibraryType);
+              } else {
+                // For private file sets, we need to simulate compiling the
+                // same way as the original target. That includes linking to
+                // the same things so we pick up the same transitive
+                // properties. For the <LANG>_... properties, we don't care if
+                // we set them for languages this target won't eventually use.
+                // The verify header sets feature currently only supports the
+                // C and C++ languages, so we just always set those here for
+                // simplicity rather than working out all languages the target
+                // has to compile for.
+                static std::vector<std::string> propertiesToCopy = {
+                  "COMPILE_DEFINITIONS", "COMPILE_FEATURES",
+                  "COMPILE_FLAGS",       "COMPILE_OPTIONS",
+                  "DEFINE_SYMBOL",       "INCLUDE_DIRECTORIES",
+                  "LINK_LIBRARIES",      "C_STANDARD",
+                  "C_STANDARD_REQUIRED", "C_EXTENSIONS",
+                  "CXX_STANDARD",        "CXX_STANDARD_REQUIRED",
+                  "CXX_EXTENSIONS"
+                };
+                for (std::string const& prop : propertiesToCopy) {
+                  cmValue propValue = this->Target->GetProperty(prop);
+                  if (propValue.IsSet()) {
+                    verifyTarget->SetProperty(prop, propValue);
+                  }
+                }
+                // The original target might have generated headers. Since
+                // we only link to the original target for compilation,
+                // there's nothing to force such generation to happen yet.
+                // Our verify target must depend on the original target to
+                // ensure such generated files will be created.
+                verifyTarget->AddUtility(this->GetName(), false,
+                                         this->Makefile);
+                verifyTarget->AddCodegenDependency(this->GetName());
+              }
+
+              verifyTarget->SetProperty("AUTOMOC", "OFF");
+              verifyTarget->SetProperty("AUTORCC", "OFF");
+              verifyTarget->SetProperty("AUTOUIC", "OFF");
+              verifyTarget->SetProperty("DISABLE_PRECOMPILE_HEADERS", "ON");
+              verifyTarget->SetProperty("UNITY_BUILD", "OFF");
+              verifyTarget->SetProperty("CXX_SCAN_FOR_MODULES", "OFF");
+
+              if (isInterface) {
+                verifyTarget->FinalizeTargetConfiguration(
+                  this->Makefile->GetCompileDefinitionsEntries());
+              } else {
+                // Private verification only needs to add the directory scope
+                // definitions here
+                for (auto const& def :
+                     this->Makefile->GetCompileDefinitionsEntries()) {
+                  verifyTarget->InsertCompileDefinition(def);
+                }
+              }
+
+              if (!allVerifyTarget) {
+                allVerifyTarget =
+                  this->GlobalGenerator->GetMakefiles()
+                    .front()
+                    ->AddNewUtilityTarget(allVerifyTargetName, true);
+              }
+
+              allVerifyTarget->AddUtility(verifyTargetName, false);
+            }
+
+            if (fileCgesContextSensitive) {
+              filename = cmStrCat("$<$<CONFIG:", config, ">:", filename, '>');
+            }
+            verifyTarget->AddSource(filename);
+          }
+        }
+
+        if (!dirCgesContextSensitive && !fileCgesContextSensitive) {
+          break;
+        }
+        first = false;
+      }
+    }
+
+    if (verifyTarget) {
+      this->LocalGenerator->AddGeneratorTarget(
+        cm::make_unique<cmGeneratorTarget>(verifyTarget,
+                                           this->LocalGenerator));
+    }
   }
 
   return true;
@@ -5803,6 +5985,7 @@
 
 std::string cmGeneratorTarget::GenerateHeaderSetVerificationFile(
   cmSourceFile& source, std::string const& dir,
+  std::string const& verifyTargetName,
   cm::optional<std::set<std::string>>& languages) const
 {
   std::string extension;
@@ -5856,9 +6039,9 @@
   }
   headerFilename += source.GetLocation().GetName();
 
-  auto filename = cmStrCat(
-    this->LocalGenerator->GetCurrentBinaryDirectory(), '/', this->GetName(),
-    "_verify_interface_header_sets/", headerFilename, extension);
+  auto filename =
+    cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
+             verifyTargetName, '/', headerFilename, extension);
   auto* verificationSource = this->Makefile->GetOrCreateSource(filename);
   source.SetSpecialSourceType(
     cmSourceFile::SpecialSourceType::HeaderSetVerificationSource);
@@ -6301,7 +6484,8 @@
   if (this->GetPolicyStatusCMP0195() == cmPolicies::NEW) {
     if (cmValue moduleTriple =
           this->Makefile->GetDefinition("CMAKE_Swift_MODULE_TRIPLE")) {
-      moduleFilename += "/" + *moduleTriple + ".swiftmodule";
+      moduleFilename = cmStrCat(std::move(moduleFilename), '/', *moduleTriple,
+                                ".swiftmodule");
     }
   }
   return moduleFilename;
@@ -6337,8 +6521,8 @@
 std::string cmGeneratorTarget::GetSwiftModulePath(
   std::string const& config) const
 {
-  return this->GetSwiftModuleDirectory(config) + "/" +
-    this->GetSwiftModuleFileName();
+  return cmStrCat(this->GetSwiftModuleDirectory(config), '/',
+                  this->GetSwiftModuleFileName());
 }
 
 std::string cmGeneratorTarget::GetPropertyOrDefault(
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 94c16b5..a32ecba 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -1112,6 +1112,7 @@
   bool AddHeaderSetVerification();
   std::string GenerateHeaderSetVerificationFile(
     cmSourceFile& source, std::string const& dir,
+    std::string const& verifyTargetName,
     cm::optional<std::set<std::string>>& languages) const;
 
   std::string GetImportedXcFrameworkPath(std::string const& config) const;
@@ -1325,6 +1326,9 @@
   mutable std::vector<AllConfigSource> AllConfigSources;
   void ComputeAllConfigSources() const;
 
+  mutable std::set<std::string> AllConfigCompileLanguages;
+  void ComputeAllConfigCompileLanguages() const;
+
   mutable std::unordered_map<std::string, bool> MaybeInterfacePropertyExists;
   bool MaybeHaveInterfaceProperty(std::string const& prop,
                                   cm::GenEx::Evaluation* eval,
diff --git a/Source/cmGeneratorTarget_CompatibleInterface.cxx b/Source/cmGeneratorTarget_CompatibleInterface.cxx
index 1a8a944..2243cdd 100644
--- a/Source/cmGeneratorTarget_CompatibleInterface.cxx
+++ b/Source/cmGeneratorTarget_CompatibleInterface.cxx
@@ -169,7 +169,7 @@
 
   for (std::string const& p : props) {
     std::string pname = cmSystemTools::HelpFileName(p);
-    std::string pfile = pdir + pname + ".rst";
+    std::string pfile = cmStrCat(pdir, pname, ".rst");
     if (cmSystemTools::FileExists(pfile, true)) {
       std::ostringstream e;
       e << "Target \"" << dependee->GetName() << "\" has property \"" << p
@@ -679,8 +679,9 @@
       if (propInitialized) {
         std::pair<bool, PropertyType> consistent =
           consistentProperty(propContent, ifacePropContent, t);
-        report += reportEntry;
-        report += compatibilityAgree(t, propContent != consistent.second);
+        report =
+          cmStrCat(std::move(report), reportEntry,
+                   compatibilityAgree(t, propContent != consistent.second));
         if (!consistent.first) {
           std::ostringstream e;
           e << "The INTERFACE_" << p << " property of \""
@@ -692,7 +693,7 @@
         propContent = consistent.second;
         continue;
       }
-      report += reportEntry + "(Interface set)\n";
+      report = cmStrCat(std::move(report), reportEntry, "(Interface set)\n");
       propContent = ifacePropContent;
       propInitialized = true;
     } else {
diff --git a/Source/cmGeneratorTarget_IncludeDirectories.cxx b/Source/cmGeneratorTarget_IncludeDirectories.cxx
index 1cd101e..c91d25b 100644
--- a/Source/cmGeneratorTarget_IncludeDirectories.cxx
+++ b/Source/cmGeneratorTarget_IncludeDirectories.cxx
@@ -55,7 +55,8 @@
   switch (dagChecker.Check()) {
     case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
       dagChecker.ReportError(
-        nullptr, "$<TARGET_PROPERTY:" + target->GetName() + ",propertyName");
+        nullptr,
+        cmStrCat("$<TARGET_PROPERTY:", target->GetName(), ",propertyName"));
       CM_FALLTHROUGH;
     case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
       // No error. We just skip cyclic references.
@@ -195,15 +196,15 @@
       if (uniqueIncludes.insert(entryInclude).second) {
         includes.emplace_back(entryInclude, entry.Backtrace);
         if (debugIncludes) {
-          usedIncludes += " * " + entryInclude + "\n";
+          usedIncludes += cmStrCat(" * ", entryInclude, "\n");
         }
       }
     }
     if (!usedIncludes.empty()) {
       tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
         MessageType::LOG,
-        std::string("Used includes for target ") + tgt->GetName() + ":\n" +
-          usedIncludes,
+        cmStrCat("Used includes for target ", tgt->GetName(), ":\n",
+                 usedIncludes),
         entry.Backtrace);
     }
   }
diff --git a/Source/cmGeneratorTarget_Link.cxx b/Source/cmGeneratorTarget_Link.cxx
index ddc8e3c..8650b78 100644
--- a/Source/cmGeneratorTarget_Link.cxx
+++ b/Source/cmGeneratorTarget_Link.cxx
@@ -227,7 +227,7 @@
     // Now consider languages that propagate from linked targets.
     for (std::string const& lang : languages) {
       std::string propagates =
-        "CMAKE_" + lang + "_LINKER_PREFERENCE_PROPAGATES";
+        cmStrCat("CMAKE_", lang, "_LINKER_PREFERENCE_PROPAGATES");
       if (this->Makefile->IsOn(propagates)) {
         tsl.Consider(lang);
       }
@@ -823,7 +823,7 @@
   std::string const& runtimeLibrary =
     this->GetRuntimeLinkLibrary(lang, config);
   if (cmValue runtimeLinkOptions = this->Makefile->GetDefinition(
-        "CMAKE_" + lang + "_RUNTIME_LIBRARIES_" + runtimeLibrary)) {
+        cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARIES_", runtimeLibrary))) {
     cmList libsList{ *runtimeLinkOptions };
     result.reserve(libsList.size());
 
diff --git a/Source/cmGeneratorTarget_LinkDirectories.cxx b/Source/cmGeneratorTarget_LinkDirectories.cxx
index d6f1498..8f11a05 100644
--- a/Source/cmGeneratorTarget_LinkDirectories.cxx
+++ b/Source/cmGeneratorTarget_LinkDirectories.cxx
@@ -82,15 +82,15 @@
       if (uniqueDirectories.insert(entryDirectory).second) {
         directories.emplace_back(entryDirectory, entry.Backtrace);
         if (debugDirectories) {
-          usedDirectories += " * " + entryDirectory + "\n";
+          usedDirectories += cmStrCat(" * ", entryDirectory, '\n');
         }
       }
     }
     if (!usedDirectories.empty()) {
       tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
         MessageType::LOG,
-        std::string("Used link directories for target ") + tgt->GetName() +
-          ":\n" + usedDirectories,
+        cmStrCat("Used link directories for target ", tgt->GetName(), ":\n",
+                 usedDirectories),
         entry.Backtrace);
     }
   }
diff --git a/Source/cmGeneratorTarget_Options.cxx b/Source/cmGeneratorTarget_Options.cxx
index 1674e49..2244e46 100644
--- a/Source/cmGeneratorTarget_Options.cxx
+++ b/Source/cmGeneratorTarget_Options.cxx
@@ -522,10 +522,10 @@
   if (this->IsDeviceLink()) {
     // wrap host link options
     std::string const wrapper(this->Makefile->GetSafeDefinition(
-      "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG"));
+      cmStrCat("CMAKE_", language, "_DEVICE_COMPILER_WRAPPER_FLAG")));
     cmList wrapperFlag{ wrapper };
     std::string const wrapperSep(this->Makefile->GetSafeDefinition(
-      "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG_SEP"));
+      cmStrCat("CMAKE_", language, "_DEVICE_COMPILER_WRAPPER_FLAG_SEP")));
     bool concatFlagAndArgs = true;
     if (!wrapperFlag.empty() && wrapperFlag.back() == " ") {
       concatFlagAndArgs = false;
diff --git a/Source/cmGeneratorTarget_Sources.cxx b/Source/cmGeneratorTarget_Sources.cxx
index 4fc05ad..5278408 100644
--- a/Source/cmGeneratorTarget_Sources.cxx
+++ b/Source/cmGeneratorTarget_Sources.cxx
@@ -36,6 +36,7 @@
 #include "cmSourceFileLocation.h"
 #include "cmSourceGroup.h"
 #include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmValue.h"
@@ -59,10 +60,12 @@
         std::string uniqueName =
           headTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely(
             lib.Target);
-        std::string genex = "$<TARGET_OBJECTS:" + std::move(uniqueName) + ">";
+        std::string genex =
+          cmStrCat("$<TARGET_OBJECTS:", std::move(uniqueName), '>');
         cmGeneratorExpression ge(*headTarget->Makefile->GetCMakeInstance(),
                                  lib.Backtrace);
-        std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
+        std::unique_ptr<cmCompiledGeneratorExpression> cge =
+          ge.Parse(std::move(genex));
         cge->SetEvaluateForBuildsystem(true);
 
         EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace);
@@ -122,7 +125,7 @@
       }
       bool found = false;
       for (auto const& sg : headTarget->Makefile->GetSourceGroups()) {
-        if (sg.MatchChildrenFiles(path)) {
+        if (sg->MatchChildrenFiles(path)) {
           found = true;
           break;
         }
@@ -212,15 +215,15 @@
       if (uniqueSrcs.insert(src).second) {
         srcs.emplace_back(src, entry.Backtrace);
         if (debugSources) {
-          usedSources += " * " + src + "\n";
+          usedSources += cmStrCat(" * ", src, '\n');
         }
       }
     }
     if (!usedSources.empty()) {
       tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
         MessageType::LOG,
-        std::string("Used sources for target ") + tgt->GetName() + ":\n" +
-          usedSources,
+        cmStrCat("Used sources for target ", tgt->GetName(), ":\n",
+                 usedSources),
         entry.Backtrace);
     }
   }
@@ -508,7 +511,7 @@
   return result;
 }
 
-std::set<std::string> cmGeneratorTarget::GetAllConfigCompileLanguages() const
+void cmGeneratorTarget::ComputeAllConfigCompileLanguages() const
 {
   std::set<std::string> languages;
   std::vector<AllConfigSource> const& sources = this->GetAllConfigSources();
@@ -518,5 +521,13 @@
       languages.emplace(lang);
     }
   }
-  return languages;
+  this->AllConfigCompileLanguages = languages;
+}
+
+std::set<std::string> cmGeneratorTarget::GetAllConfigCompileLanguages() const
+{
+  if (this->AllConfigCompileLanguages.empty()) {
+    this->ComputeAllConfigCompileLanguages();
+  }
+  return this->AllConfigCompileLanguages;
 }
diff --git a/Source/cmGeneratorTarget_TransitiveProperty.cxx b/Source/cmGeneratorTarget_TransitiveProperty.cxx
index 61e550e..d20819b 100644
--- a/Source/cmGeneratorTarget_TransitiveProperty.cxx
+++ b/Source/cmGeneratorTarget_TransitiveProperty.cxx
@@ -65,7 +65,7 @@
                                                    cm::GenEx::Evaluation* eval,
                                                    UseTo usage) const
 {
-  std::string const key = prop + '@' + eval->Context.Config;
+  std::string const key = cmStrCat(prop, '@', eval->Context.Config);
   auto i = this->MaybeInterfacePropertyExists.find(key);
   if (i == this->MaybeInterfacePropertyExists.end()) {
     // Insert an entry now in case there is a cycle.
@@ -123,7 +123,7 @@
   switch (dagChecker.Check()) {
     case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
       dagChecker.ReportError(
-        eval, "$<TARGET_PROPERTY:" + this->GetName() + "," + prop + ">");
+        eval, cmStrCat("$<TARGET_PROPERTY:", this->GetName(), ',', prop, '>'));
       return result;
     case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
       // No error. We just skip cyclic references.
diff --git a/Source/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx
index c75e331..0e8db4a 100644
--- a/Source/cmGetPropertyCommand.cxx
+++ b/Source/cmGetPropertyCommand.cxx
@@ -9,6 +9,7 @@
 #include <cmext/string_view>
 
 #include "cmExecutionStatus.h"
+#include "cmFileSet.h"
 #include "cmGlobalGenerator.h"
 #include "cmInstalledFile.h"
 #include "cmMakefile.h"
@@ -45,6 +46,9 @@
 bool HandleTargetMode(cmExecutionStatus& status, std::string const& name,
                       OutType infoType, std::string const& variable,
                       std::string const& propertyName);
+bool HandleFileSetMode(cmExecutionStatus& status, std::string const& name,
+                       OutType infoType, std::string const& variable,
+                       std::string const& propertyName, cmTarget* target);
 bool HandleSourceMode(cmExecutionStatus& status, std::string const& name,
                       OutType infoType, std::string const& variable,
                       std::string const& propertyName,
@@ -80,6 +84,9 @@
   std::string name;
   std::string propertyName;
 
+  std::string file_set_target_name;
+  bool file_set_target_option_enabled = false;
+
   std::vector<std::string> source_file_directories;
   std::vector<std::string> source_file_target_directories;
   bool source_file_directory_option_enabled = false;
@@ -96,6 +103,8 @@
     scope = cmProperty::DIRECTORY;
   } else if (args[1] == "TARGET") {
     scope = cmProperty::TARGET;
+  } else if (args[1] == "FILE_SET") {
+    scope = cmProperty::FILE_SET;
   } else if (args[1] == "SOURCE") {
     scope = cmProperty::SOURCE_FILE;
   } else if (args[1] == "TEST") {
@@ -107,11 +116,11 @@
   } else if (args[1] == "INSTALL") {
     scope = cmProperty::INSTALL;
   } else {
-    status.SetError(cmStrCat(
-      "given invalid scope ", args[1],
-      ".  "
-      "Valid scopes are "
-      "GLOBAL, DIRECTORY, TARGET, SOURCE, TEST, VARIABLE, CACHE, INSTALL."));
+    status.SetError(cmStrCat("given invalid scope ", args[1],
+                             ".  "
+                             "Valid scopes are "
+                             "GLOBAL, DIRECTORY, TARGET, FILE_SET, SOURCE, "
+                             "TEST, VARIABLE, CACHE, INSTALL."));
     return false;
   }
 
@@ -122,6 +131,7 @@
     DoingName,
     DoingProperty,
     DoingType,
+    DoingFileSetTarget,
     DoingSourceDirectory,
     DoingSourceTargetDirectory,
     DoingTestDirectory,
@@ -145,6 +155,10 @@
     } else if (doing == DoingName) {
       doing = DoingNone;
       name = args[i];
+    } else if (doing == DoingNone && scope == cmProperty::FILE_SET &&
+               args[i] == "TARGET") {
+      doing = DoingFileSetTarget;
+      file_set_target_option_enabled = true;
     } else if (doing == DoingNone && scope == cmProperty::SOURCE_FILE &&
                args[i] == "DIRECTORY") {
       doing = DoingSourceDirectory;
@@ -157,6 +171,9 @@
                args[i] == "DIRECTORY") {
       doing = DoingTestDirectory;
       test_directory_option_enabled = true;
+    } else if (doing == DoingFileSetTarget) {
+      file_set_target_name = args[i];
+      doing = DoingNone;
     } else if (doing == DoingSourceDirectory) {
       source_file_directories.push_back(args[i]);
       doing = DoingNone;
@@ -181,21 +198,6 @@
     return false;
   }
 
-  std::vector<cmMakefile*> source_file_directory_makefiles;
-  bool source_file_scopes_handled =
-    SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes(
-      status, source_file_directory_option_enabled,
-      source_file_target_option_enabled, source_file_directories,
-      source_file_target_directories, source_file_directory_makefiles);
-  cmMakefile* test_directory_makefile;
-  bool test_scopes_handled =
-    SetPropertyCommand::HandleAndValidateTestDirectoryScopes(
-      status, test_directory_option_enabled, test_directory,
-      test_directory_makefile);
-  if (!(source_file_scopes_handled && test_scopes_handled)) {
-    return false;
-  }
-
   // Compute requested output.
   if (infoType == OutBriefDoc) {
     // Lookup brief documentation.
@@ -231,11 +233,6 @@
     }
   } else {
     // Dispatch property getting.
-    cmMakefile& directory_scope_mf = *(source_file_directory_makefiles[0]);
-    bool source_file_paths_should_be_absolute =
-      source_file_directory_option_enabled ||
-      source_file_target_option_enabled;
-
     switch (scope) {
       case cmProperty::GLOBAL:
         return HandleGlobalMode(status, name, infoType, variable,
@@ -246,13 +243,43 @@
       case cmProperty::TARGET:
         return HandleTargetMode(status, name, infoType, variable,
                                 propertyName);
-      case cmProperty::SOURCE_FILE:
+      case cmProperty::FILE_SET: {
+        cmTarget* file_set_target;
+        if (!SetPropertyCommand::HandleAndValidateFileSetTargetScopes(
+              status, file_set_target_option_enabled, file_set_target_name,
+              file_set_target)) {
+          return false;
+        }
+        return HandleFileSetMode(status, name, infoType, variable,
+                                 propertyName, file_set_target);
+      }
+      case cmProperty::SOURCE_FILE: {
+        std::vector<cmMakefile*> source_file_directory_makefiles;
+        if (!SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes(
+              status, source_file_directory_option_enabled,
+              source_file_target_option_enabled, source_file_directories,
+              source_file_target_directories,
+              source_file_directory_makefiles)) {
+          return false;
+        }
+        bool source_file_paths_should_be_absolute =
+          source_file_directory_option_enabled ||
+          source_file_target_option_enabled;
+        cmMakefile& directory_scope_mf = *(source_file_directory_makefiles[0]);
         return HandleSourceMode(status, name, infoType, variable, propertyName,
                                 directory_scope_mf,
                                 source_file_paths_should_be_absolute);
-      case cmProperty::TEST:
+      }
+      case cmProperty::TEST: {
+        cmMakefile* test_directory_makefile;
+        if (!SetPropertyCommand::HandleAndValidateTestDirectoryScopes(
+              status, test_directory_option_enabled, test_directory,
+              test_directory_makefile)) {
+          return false;
+        }
         return HandleTestMode(status, name, infoType, variable, propertyName,
                               *test_directory_makefile);
+      }
       case cmProperty::VARIABLE:
         return HandleVariableMode(status, name, infoType, variable,
                                   propertyName);
@@ -413,6 +440,25 @@
   return false;
 }
 
+bool HandleFileSetMode(cmExecutionStatus& status, std::string const& name,
+                       OutType infoType, std::string const& variable,
+                       std::string const& propertyName, cmTarget* target)
+{
+  if (name.empty()) {
+    status.SetError("not given name for FILE_SET scope.");
+    return false;
+  }
+
+  if (cmFileSet* fileSet = target->GetFileSet(name)) {
+    cmValue prop = fileSet->GetProperty(propertyName);
+    return StoreResult(infoType, status.GetMakefile(), variable, prop);
+  }
+  status.SetError(cmStrCat("could not find FILE_SET ", name, " for TARGET ",
+                           target->GetName(),
+                           ".  Perhaps it has not yet been created."));
+  return false;
+}
+
 bool HandleSourceMode(cmExecutionStatus& status, std::string const& name,
                       OutType infoType, std::string const& variable,
                       std::string const& propertyName,
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index 7443d11..16e68fd 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -509,17 +509,12 @@
   std::vector<cmSourceFile*> sources;
   this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
 
-  /* vector of all groups defined for this target
-   * -- but the vector is not expanded with sub groups or in any useful order
-   */
-  std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
-
   /* for each source file assign it to its group */
   std::map<std::string, std::vector<cmSourceFile*>> groupFiles;
   std::set<std::string> groupNames;
   for (cmSourceFile* sf : sources) {
     cmSourceGroup* sourceGroup =
-      this->Makefile->FindSourceGroup(sf->ResolveFullPath(), sourceGroups);
+      this->LocalGenerator->FindSourceGroup(sf->ResolveFullPath());
     std::string gn = sourceGroup->GetFullName();
     groupFiles[gn].push_back(sf);
     groupNames.insert(std::move(gn));
@@ -663,8 +658,9 @@
     } else {
       std::vector<cmSourceFile const*> customCommands;
       if (this->ComputeCustomCommandOrder(customCommands)) {
-        std::string message = "The custom commands for target [" +
-          this->GeneratorTarget->GetName() + "] had a cycle.\n";
+        std::string message =
+          cmStrCat("The custom commands for target [",
+                   this->GeneratorTarget->GetName(), "] had a cycle.\n");
         cmSystemTools::Error(message);
       } else {
         /* Custom targets do not have a dependency on SOURCES files.
diff --git a/Source/cmGlobalFastbuildGenerator.cxx b/Source/cmGlobalFastbuildGenerator.cxx
index 95a1f67..9013c5e 100644
--- a/Source/cmGlobalFastbuildGenerator.cxx
+++ b/Source/cmGlobalFastbuildGenerator.cxx
@@ -51,6 +51,7 @@
 // IDE support
 #define FASTBUILD_XCODE_BASE_PATH "XCode/Projects"
 #define FASTBUILD_VS_BASE_PATH "VisualStudio/Projects"
+#define FASTBUILD_VS_PROJECT_SUFFIX "-vcxproj"
 
 #define FASTBUILD_IDE_VS_COMMAND_PREFIX "cd ^$(SolutionDir).. && "
 #define FASTBUILD_DEFAULT_IDE_BUILD_ARGS " -ide -cache -summary -dist "
@@ -699,7 +700,7 @@
 std::string cmGlobalFastbuildGenerator::QuoteIfHasSpaces(std::string str)
 {
   if (str.find(' ') != std::string::npos) {
-    return '"' + str + '"';
+    return cmStrCat('"', str, '"');
   }
   return str;
 }
@@ -903,7 +904,12 @@
       WriteVariable("AllowDistribution", "false", 1);
     }
 
-    if (compilerDef.UseLightCache && compilerDef.CompilerFamily == "msvc") {
+    if (compilerDef.UseLightCache &&
+        (compilerDef.CompilerFamily == "msvc" ||
+         // FASTBuild supports Light Cache for non-MSVC compilers starting from
+         // version 1.19
+         cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL,
+                                       this->FastbuildVersion, "1.19"))) {
       WriteVariable("UseLightCache_Experimental", "true", 1);
     }
     if (compilerDef.UseRelativePaths) {
@@ -976,15 +982,12 @@
   }
 
   // Calculate the root location of the compiler
-  std::string const variableString = "CMAKE_" + language + "_COMPILER";
+  std::string const variableString = cmStrCat("CMAKE_", language, "_COMPILER");
   std::string const compilerLocation = mf->GetSafeDefinition(variableString);
   if (compilerLocation.empty()) {
     return;
   }
 
-  // Calculate the i18n number.
-  std::string i18nNum = "1033";
-
   // Add the language to the compiler's name
   FastbuildCompiler compilerDef;
   compilerDef.ExtraVariables["Root"] =
@@ -992,15 +995,15 @@
   compilerDef.Name = FASTBUILD_COMPILER_PREFIX + language;
   compilerDef.Executable = compilerLocation;
   compilerDef.CmakeCompilerID =
-    mf->GetSafeDefinition("CMAKE_" + language + "_COMPILER_ID");
+    mf->GetSafeDefinition(cmStrCat("CMAKE_", language, "_COMPILER_ID"));
   if (compilerDef.CmakeCompilerID == "Clang" &&
-      mf->GetSafeDefinition("CMAKE_" + language +
-                            "_COMPILER_FRONTEND_VARIANT") == "MSVC") {
+      mf->GetSafeDefinition(cmStrCat(
+        "CMAKE_", language, "_COMPILER_FRONTEND_VARIANT")) == "MSVC") {
     compilerDef.CmakeCompilerID = "Clang-cl";
   }
 
   compilerDef.CmakeCompilerVersion =
-    mf->GetSafeDefinition("CMAKE_" + language + "_COMPILER_VERSION");
+    mf->GetSafeDefinition(cmStrCat("CMAKE_", language, "_COMPILER_VERSION"));
   compilerDef.Language = language;
 
   cmExpandList(mf->GetSafeDefinition(FASTBUILD_COMPILER_EXTRA_FILES),
@@ -1026,6 +1029,10 @@
       compilerDef.CmakeCompilerID == "MSVC") {
     // https://cmake.org/cmake/help/latest/variable/MSVC_VERSION.html
 
+    // Calculate the i18n number.
+    std::string const i18nNum =
+      mf->GetSafeDefinition(cmStrCat("CMAKE_", language, "_MSVC_I18N_DIR"));
+
     // Visual Studio 17 (19.30 to 19.39)
     // TODO
 
@@ -1052,10 +1059,11 @@
       compilerDef.ExtraFiles.push_back("$Root$/vcruntime140.dll");
       compilerDef.ExtraFiles.push_back(
         "$Root$/vcruntime140_1.dll"); // Required as of 16.5.1 (14.25.28610)
-      compilerDef.ExtraFiles.push_back("$Root$/" + i18nNum + "/clui.dll");
       compilerDef.ExtraFiles.push_back(
-        "$Root$/" + i18nNum + "/mspft140ui.dll"); // Localized messages for
-                                                  // static analysis
+        cmStrCat("$Root$/", i18nNum, "/clui.dll"));
+      compilerDef.ExtraFiles.push_back(cmStrCat(
+        "$Root$/", i18nNum, "/mspft140ui.dll")); // Localized messages for
+                                                 // static analysis
     }
     // Visual Studio 15 (19.10 to 19.19)
     else if (cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL,
@@ -1612,12 +1620,23 @@
 void cmGlobalFastbuildGenerator::WriteSolution()
 {
   std::string const solutionName = LocalGenerators[0]->GetProjectName();
-  std::map<std::string /*folder*/, std::vector<std::string>> VSProjects;
+  std::unordered_map<std::string /*folder*/, std::vector<std::string>>
+    VSProjectFolders;
+  std::unordered_map<std::string /*project*/,
+                     std::vector<std::string> /*deps*/>
+    VSProjectDeps;
   std::vector<std::string> VSProjectsWithoutFolder;
 
   for (auto const& IDEProj : IDEProjects) {
     auto const VSProj = IDEProj.second.first;
-    VSProjects[VSProj.folder].emplace_back(VSProj.Alias);
+    VSProjectFolders[VSProj.folder].emplace_back(VSProj.Alias);
+    auto& deps = VSProjectDeps[VSProj.Alias];
+    deps.reserve(VSProj.deps.size());
+    for (auto const& dep : VSProj.deps) {
+      if (dep.Type == FastbuildTargetDepType::REGULAR) {
+        deps.push_back(cmStrCat(dep.Name, FASTBUILD_VS_PROJECT_SUFFIX));
+      }
+    }
   }
 
   WriteCommand("VSSolution", Quote("solution"));
@@ -1631,7 +1650,7 @@
   WriteIDEProjectConfig(configs, "SolutionConfigs");
   int folderNumber = 0;
   std::vector<std::string> folders;
-  for (auto& item : VSProjects) {
+  for (auto& item : VSProjectFolders) {
     auto const& pathToFolder = item.first;
     auto& projectsInFolder = item.second;
     if (pathToFolder.empty()) {
@@ -1643,7 +1662,7 @@
         folderName,
         { { "Path", Quote(pathToFolder) },
           { "Projects",
-            cmStrCat("{", cmJoin(Wrap(projectsInFolder), ","), "}") } },
+            cmStrCat('{', cmJoin(Wrap(projectsInFolder), ","), '}') } },
         1);
       folders.emplace_back(std::move(folderName));
     }
@@ -1651,6 +1670,29 @@
   if (!folders.empty()) {
     WriteArray("SolutionFolders ", Wrap(folders, ".", ""), 1);
   }
+
+  int depNumber = 0;
+  std::vector<std::string> dependencies;
+  for (auto const& dep : VSProjectDeps) {
+    std::string const& projectName = dep.first;
+    std::vector<std::string> const& projectDeps = dep.second;
+    // This project has some deps.
+    if (!projectDeps.empty()) {
+      std::string depName = cmStrCat("Deps_", ++depNumber);
+      WriteStruct(depName,
+                  {
+                    { "Projects", Quote(projectName) },
+                    { "Dependencies",
+                      cmStrCat('{', cmJoin(Wrap(projectDeps), ","), '}') },
+                  },
+                  1);
+      dependencies.emplace_back(std::move(depName));
+    }
+  }
+
+  if (!dependencies.empty()) {
+    WriteArray("SolutionDependencies  ", Wrap(dependencies, ".", ""), 1);
+  }
   if (!VSProjectsWithoutFolder.empty()) {
     WriteArray("SolutionProjects", Wrap(VSProjectsWithoutFolder), 1);
   }
@@ -1871,8 +1913,8 @@
   return cm::nullopt;
 }
 
-void cmGlobalFastbuildGenerator::AddIDEProject(FastbuildTarget const& target,
-                                               std::string const& config)
+void cmGlobalFastbuildGenerator::AddIDEProject(
+  FastbuildTargetBase const& target, std::string const& config)
 {
   auto const& configs = GetConfigNames();
   if (std::find(configs.begin(), configs.end(), config) == configs.end()) {
@@ -1885,11 +1927,12 @@
     this->GetCMakeInstance()->GetHomeDirectory(), target.BasePath);
   // VS
   auto& VSProject = IDEProject.first;
-  VSProject.Alias = target.BaseName + "-vcxproj";
+  VSProject.Alias = cmStrCat(target.BaseName, FASTBUILD_VS_PROJECT_SUFFIX);
   VSProject.ProjectOutput = cmStrCat("VisualStudio/Projects/", relativeSubdir,
                                      '/', target.BaseName + ".vcxproj");
   VSProject.ProjectBasePath = target.BasePath;
   VSProject.folder = relativeSubdir;
+  VSProject.deps = target.PreBuildDependencies;
   // XCode
   auto& XCodeProject = IDEProject.second;
   XCodeProject.Alias = target.BaseName + "-xcodeproj";
diff --git a/Source/cmGlobalFastbuildGenerator.h b/Source/cmGlobalFastbuildGenerator.h
index 0059c93..f2aa938 100644
--- a/Source/cmGlobalFastbuildGenerator.h
+++ b/Source/cmGlobalFastbuildGenerator.h
@@ -96,6 +96,10 @@
   ORDER_ONLY,
   // Regular target dep.
   REGULAR,
+  // Utility target dep.
+  UTIL,
+  // A physical file on disk.
+  ARTIFACT,
 };
 struct FastbuildTargetDep
 {
@@ -135,6 +139,7 @@
   std::set<FastbuildTargetDep> PreBuildDependencies;
   bool Hidden = true;
   FastbuildTargetType Type;
+  bool ExcludeFromAll = false;
   explicit FastbuildTargetBase(FastbuildTargetType TargetType)
     : Type(TargetType)
   {
@@ -144,7 +149,6 @@
 
 struct FastbuildAliasNode : public FastbuildTargetBase
 {
-  bool ExcludeFromAll = false;
   FastbuildAliasNode()
     : FastbuildTargetBase(FastbuildTargetType::ALIAS)
   {
@@ -167,7 +171,6 @@
   FastbuildAliasNode OutputsAlias;
   FastbuildAliasNode ByproductsAlias;
   std::string ConcurrencyGroupName;
-  bool ExcludeFromAll = false;
   FastbuildExecNode()
     : FastbuildTargetBase(FastbuildTargetType::EXEC)
   {
@@ -265,6 +268,7 @@
 struct VCXProject : public IDEProjectCommon
 {
   std::string folder;
+  std::set<FastbuildTargetDep> deps;
 };
 
 struct FastbuildLinkerNode
@@ -328,7 +332,6 @@
   FastbuildExecNodes PreLinkExecNodes;
   FastbuildExecNodes PostBuildExecNodes;
   bool IsGlobal = false;
-  bool ExcludeFromAll = false;
   bool AllowDistribution = true;
   FastbuildTarget()
     : FastbuildTargetBase(FastbuildTargetType::LINK)
@@ -545,7 +548,8 @@
   void AddCompiler(std::string const& lang, cmMakefile* mf);
   void AddLauncher(std::string const& prefix, std::string const& launcher,
                    std::string const& lang, std::string const& args);
-  void AddIDEProject(FastbuildTarget const& target, std::string const& config);
+  void AddIDEProject(FastbuildTargetBase const& target,
+                     std::string const& config);
 
   template <class T>
   void AddTarget(T target)
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 2fa8032..e4f50d3 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -25,6 +25,8 @@
 #include "cm_codecvt_Encoding.hxx"
 
 #include "cmAlgorithms.h"
+#include "cmArgumentParserTypes.h"
+#include "cmBuildArgs.h"
 #include "cmCMakePath.h"
 #include "cmCPackPropertiesGenerator.h"
 #include "cmComputeTargetDepends.h"
@@ -41,6 +43,7 @@
 #include "cmGeneratorTarget.h"
 #include "cmInstallGenerator.h"
 #include "cmInstallRuntimeDependencySet.h"
+#include "cmInstallSbomExportGenerator.h"
 #include "cmLinkLineComputer.h"
 #include "cmList.h"
 #include "cmListFileCache.h"
@@ -51,6 +54,7 @@
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
 #include "cmRange.h"
+#include "cmSbomArguments.h"
 #include "cmSourceFile.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
@@ -729,6 +733,16 @@
 
   for (std::string const& lang : languages) {
     needSetLanguageEnabledMaps[lang] = false;
+
+    if (lang == "Rust" &&
+        !cmExperimental::HasSupportEnabled(*this->Makefiles[0].get(),
+                                           cmExperimental::Feature::Rust)) {
+      mf->IssueMessage(MessageType::FATAL_ERROR,
+                       "Experimental Rust support is not enabled.");
+      cmSystemTools::SetFatalErrorOccurred();
+      return;
+    }
+
     if (lang == "NONE") {
       this->SetLanguageEnabled("NONE", mf);
       continue;
@@ -1096,17 +1110,22 @@
   return "";
 }
 
-std::string cmGlobalGenerator::GetLanguageFromExtension(char const* ext) const
+cm::string_view cmGlobalGenerator::GetLanguageFromExtension(
+  cm::string_view ext) const
 {
   // if there is an extension and it starts with . then move past the
   // . because the extensions are not stored with a .  in the map
-  if (!ext) {
+  if (ext.empty()) {
     return "";
   }
-  if (*ext == '.') {
-    ++ext;
+  if (ext.front() == '.') {
+    ext = ext.substr(1);
   }
+#if __cplusplus >= 201402L || defined(_MSVC_LANG) && _MSVC_LANG >= 201402L
   auto const it = this->ExtensionToLanguage.find(ext);
+#else
+  auto const it = this->ExtensionToLanguage.find(std::string(ext));
+#endif
   if (it != this->ExtensionToLanguage.end()) {
     return it->second;
   }
@@ -1185,7 +1204,7 @@
     std::string outputExtension = *p;
     this->LanguageToOutputExtension[l] = outputExtension;
     this->OutputExtensions[outputExtension] = outputExtension;
-    if (cmHasPrefix(outputExtension, ".")) {
+    if (cmHasPrefix(outputExtension, '.')) {
       outputExtension = outputExtension.substr(1);
       this->OutputExtensions[outputExtension] = outputExtension;
     }
@@ -1235,12 +1254,12 @@
   return this->Makefiles[0]->GetDefinition(name);
 }
 
-bool cmGlobalGenerator::IgnoreFile(char const* ext) const
+bool cmGlobalGenerator::IgnoreFile(cm::string_view ext) const
 {
   if (!this->GetLanguageFromExtension(ext).empty()) {
     return false;
   }
-  return (this->IgnoreExtensions.count(ext) > 0);
+  return (this->IgnoreExtensions.count(std::string(ext)) > 0);
 }
 
 bool cmGlobalGenerator::GetLanguageEnabled(std::string const& l) const
@@ -1367,6 +1386,11 @@
   this->CMP0068WarnTargets.insert(target);
 }
 
+bool cmGlobalGenerator::ShouldWarnCMP0210(std::string const& lang)
+{
+  return this->WarnedCMP0210Languages.insert(lang).second;
+}
+
 bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const
 {
   // If the property is not enabled then okay.
@@ -1568,6 +1592,37 @@
     return false;
   }
 
+#ifndef CMAKE_BOOTSTRAP
+  bool isTryCompile = this->GetGlobalSetting("IN_TRY_COMPILE").IsOn();
+  bool sbomEnabled = cmExperimental::HasSupportEnabled(
+    *this->Makefiles[0], cmExperimental::Feature::GenerateSbom);
+
+  // Automatically generate SBOM files if enabled.
+  cmValue sbomFormat = this->GetGlobalSetting("CMAKE_INSTALL_SBOM_FORMATS");
+  if (sbomFormat.IsSet() && !this->Makefiles[0]->ExplicitlyGeneratesSbom() &&
+      sbomEnabled && !isTryCompile) {
+    std::string location =
+      this->Makefiles[0]->GetSafeDefinition("CMAKE_INSTALL_LIBDIR");
+    if (location.empty()) {
+      location = "lib";
+    }
+
+    std::string projectName = this->LocalGenerators[0]->GetProjectName();
+    cmSbomArguments sbomDefaultArgs;
+    sbomDefaultArgs.ProjectName = projectName;
+    for (auto& exportSet : this->ExportSets) {
+      sbomDefaultArgs.PackageName = exportSet.first;
+      std::string dest = cmStrCat(location, "/sbom/", projectName);
+      this->Makefiles[0]->AddInstallGenerator(
+        cm::make_unique<cmInstallSbomExportGenerator>(
+          &exportSet.second, dest, "", std::vector<std::string>(), "",
+          cmInstallGenerator::SelectMessageLevel(this->Makefiles[0].get()),
+          false, std::move(sbomDefaultArgs), "",
+          this->Makefiles[0]->GetBacktrace()));
+    }
+  }
+#endif
+
   for (auto const& localGen : this->LocalGenerators) {
     cmMakefile* mf = localGen->GetMakefile();
     for (auto const& g : mf->GetInstallGenerators()) {
@@ -1579,6 +1634,12 @@
 
   this->AddExtraIDETargets();
 
+#ifndef CMAKE_BOOTSTRAP
+  for (auto const& localGen : this->LocalGenerators) {
+    localGen->ResolveSourceGroupGenex();
+  }
+#endif
+
   // Trace the dependencies, after that no custom commands should be added
   // because their dependencies might not be handled correctly
   for (auto const& localGen : this->LocalGenerators) {
@@ -1609,6 +1670,7 @@
 
   for (auto const& localGen : this->LocalGenerators) {
     localGen->ComputeHomeRelativeOutputPath();
+    localGen->ComputeSourceGroupSearchIndex();
   }
 
   return true;
@@ -1787,7 +1849,17 @@
 bool cmGlobalGenerator::ApplyCXXStdTargets()
 {
   for (auto const& gen : this->LocalGenerators) {
-    for (auto const& tgt : gen->GetGeneratorTargets()) {
+
+    // tgt->ApplyCXXStd can create targets itself, so we need iterators which
+    // won't be invalidated by that target creation
+    auto const& genTgts = gen->GetGeneratorTargets();
+    std::vector<cmGeneratorTarget*> existingTgts;
+    existingTgts.reserve(genTgts.size());
+    for (auto const& tgt : genTgts) {
+      existingTgts.push_back(tgt.get());
+    }
+
+    for (auto const& tgt : existingTgts) {
       if (!tgt->ApplyCXXStdTargets()) {
         return false;
       }
@@ -1843,13 +1915,36 @@
     }
   }
 
-  cmTarget* allVerifyTarget = this->Makefiles.front()->FindTargetToUse(
-    "all_verify_interface_header_sets",
-    { cmStateEnums::TargetDomain::NATIVE });
-  if (allVerifyTarget) {
+  cmTarget* allVerifyInterfaceTarget =
+    this->Makefiles.front()->FindTargetToUse(
+      "all_verify_interface_header_sets",
+      { cmStateEnums::TargetDomain::NATIVE });
+  if (allVerifyInterfaceTarget) {
+    this->LocalGenerators.front()->AddGeneratorTarget(
+      cm::make_unique<cmGeneratorTarget>(allVerifyInterfaceTarget,
+                                         this->LocalGenerators.front().get()));
+  }
+  cmTarget* allVerifyPrivateTarget = this->Makefiles.front()->FindTargetToUse(
+    "all_verify_private_header_sets", { cmStateEnums::TargetDomain::NATIVE });
+  if (allVerifyPrivateTarget) {
+    this->LocalGenerators.front()->AddGeneratorTarget(
+      cm::make_unique<cmGeneratorTarget>(allVerifyPrivateTarget,
+                                         this->LocalGenerators.front().get()));
+  }
+
+  if (allVerifyInterfaceTarget || allVerifyPrivateTarget) {
+    cmTarget* allVerifyTarget =
+      this->GetMakefiles().front()->AddNewUtilityTarget(
+        "all_verify_header_sets", true);
     this->LocalGenerators.front()->AddGeneratorTarget(
       cm::make_unique<cmGeneratorTarget>(allVerifyTarget,
                                          this->LocalGenerators.front().get()));
+    if (allVerifyInterfaceTarget) {
+      allVerifyTarget->AddUtility(allVerifyInterfaceTarget->GetName(), false);
+    }
+    if (allVerifyPrivateTarget) {
+      allVerifyTarget->AddUtility(allVerifyPrivateTarget->GetName(), false);
+    }
   }
 
   return true;
@@ -2011,6 +2106,7 @@
   this->RuntimeDependencySets.clear();
   this->RuntimeDependencySetsByName.clear();
   this->WarnedExperimental.clear();
+  this->WarnedCMP0210Languages.clear();
 }
 
 bool cmGlobalGenerator::SupportsShortObjectNames() const
@@ -2155,12 +2251,17 @@
   }
 }
 
-int cmGlobalGenerator::TryCompile(int jobs, std::string const& srcdir,
-                                  std::string const& bindir,
+int cmGlobalGenerator::TryCompile(int jobs, std::string const& bindir,
                                   std::string const& projectName,
                                   std::string const& target, bool fast,
                                   std::string& output, cmMakefile* mf)
 {
+  cmBuildArgs buildArgs;
+  buildArgs.jobs = jobs;
+  buildArgs.binaryDir = bindir;
+  buildArgs.projectName = projectName;
+  buildArgs.verbose = true;
+
   // if this is not set, then this is a first time configure
   // and there is a good chance that the try compile stuff will
   // take the bulk of the time, so try and guess some progress
@@ -2188,10 +2289,9 @@
   cmBuildOptions defaultBuildOptions(false, fast, PackageResolveMode::Disable);
 
   std::stringstream ostr;
-  auto ret =
-    this->Build(jobs, srcdir, bindir, projectName, newTarget, ostr, "", config,
-                defaultBuildOptions, true, this->TryCompileTimeout,
-                cmSystemTools::OUTPUT_NONE, {}, BuildTryCompile::Yes);
+  auto ret = this->Build(buildArgs, newTarget, ostr, "", config,
+                         defaultBuildOptions, this->TryCompileTimeout,
+                         cmSystemTools::OUTPUT_NONE, {}, BuildTryCompile::Yes);
   output = ostr.str();
   return ret;
 }
@@ -2216,22 +2316,23 @@
   // they do not support certain build command line options
 }
 
-int cmGlobalGenerator::Build(
-  int jobs, std::string const& /*unused*/, std::string const& bindir,
-  std::string const& projectName, std::vector<std::string> const& targets,
-  std::ostream& ostr, std::string const& makeCommandCSTR,
-  std::string const& config, cmBuildOptions buildOptions, bool verbose,
-  cmDuration timeout, cmSystemTools::OutputOption outputMode,
-  std::vector<std::string> const& nativeOptions,
-  BuildTryCompile isInTryCompile)
+int cmGlobalGenerator::Build(cmBuildArgs const& buildArgs,
+                             std::vector<std::string> const& targets,
+                             std::ostream& ostr,
+                             std::string const& makeCommandCSTR,
+                             std::string const& config,
+                             cmBuildOptions buildOptions, cmDuration timeout,
+                             cmSystemTools::OutputOption outputMode,
+                             std::vector<std::string> const& nativeOptions,
+                             BuildTryCompile isInTryCompile)
 {
   bool hideconsole = cmSystemTools::GetRunCommandHideConsole();
 
   /**
    * Run an executable command and put the stdout in output.
    */
-  cmWorkingDirectory workdir(bindir);
-  ostr << "Change Dir: '" << bindir << '\'' << std::endl;
+  cmWorkingDirectory workdir(buildArgs.binaryDir);
+  ostr << "Change Dir: '" << buildArgs.binaryDir << '\'' << std::endl;
   if (workdir.Failed()) {
     cmSystemTools::SetRunCommandHideConsole(hideconsole);
     std::string const& err = workdir.GetError();
@@ -2251,8 +2352,9 @@
   std::string outputBuf;
 
   std::vector<GeneratedMakeCommand> makeCommand = this->GenerateBuildCommand(
-    makeCommandCSTR, projectName, bindir, targets, realConfig, jobs, verbose,
-    buildOptions, nativeOptions, isInTryCompile);
+    makeCommandCSTR, buildArgs.projectName, buildArgs.binaryDir, targets,
+    realConfig, buildArgs.jobs, buildArgs.verbose, buildOptions, nativeOptions,
+    isInTryCompile);
 
   // Workaround to convince some commands to produce output.
   if (outputMode == cmSystemTools::OUTPUT_PASSTHROUGH &&
@@ -2263,8 +2365,9 @@
   // should we do a clean first?
   if (buildOptions.Clean) {
     std::vector<GeneratedMakeCommand> cleanCommand =
-      this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir,
-                                 { "clean" }, realConfig, jobs, verbose,
+      this->GenerateBuildCommand(makeCommandCSTR, buildArgs.projectName,
+                                 buildArgs.binaryDir, { "clean" }, realConfig,
+                                 buildArgs.jobs, buildArgs.verbose,
                                  buildOptions);
     ostr << "\nRun Clean Command: " << cleanCommand.front().QuotedPrintable()
          << std::endl;
@@ -2739,7 +2842,7 @@
   static cmsys::RegularExpression frameworkPath(
     "((.+)/)?([^/]+)\\.framework(/Versions/([^/]+))?(/(.+))?$");
 
-  auto ext = cmSystemTools::GetFilenameLastExtension(path);
+  auto ext = cmSystemTools::GetFilenameLastExtensionView(path);
   if ((ext.empty() || ext == ".tbd" || ext == ".framework") &&
       frameworkPath.find(path)) {
     auto name = frameworkPath.match(3);
@@ -2764,7 +2867,7 @@
   if (format == FrameworkFormat::Extended) {
     // path format can be more flexible: (/path/to/)?fwName(.framework)?
     auto fwDir = cmSystemTools::GetParentDirectory(path);
-    auto name = cmSystemTools::GetFilenameLastExtension(path) == ".framework"
+    auto name = ext == ".framework"
       ? cmSystemTools::GetFilenameWithoutExtension(path)
       : cmSystemTools::GetFilenameName(path);
 
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 02875b6..7e6e4b4 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -5,6 +5,7 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <cstddef>
+#include <functional>
 #include <iosfwd>
 #include <map>
 #include <memory>
@@ -45,6 +46,7 @@
 enum class cmDepfileFormat;
 enum class codecvt_Encoding;
 
+class cmBuildArgs;
 class cmDirectoryId;
 class cmExportBuildFileGenerator;
 class cmExternalMakefileProjectGenerator;
@@ -247,10 +249,9 @@
    * Try running cmake and building a file. This is used for dynamically
    * loaded commands, not as part of the usual build process.
    */
-  int TryCompile(int jobs, std::string const& srcdir,
-                 std::string const& bindir, std::string const& projectName,
-                 std::string const& targetName, bool fast, std::string& output,
-                 cmMakefile* mf);
+  int TryCompile(int jobs, std::string const& bindir,
+                 std::string const& projectName, std::string const& targetName,
+                 bool fast, std::string& output, cmMakefile* mf);
 
   /**
    * Build a file given the following information. This is a more direct call
@@ -259,11 +260,9 @@
    * done first.
    */
   int Build(
-    int jobs, std::string const& srcdir, std::string const& bindir,
-    std::string const& projectName,
-    std::vector<std::string> const& targetNames, std::ostream& ostr,
-    std::string const& makeProgram, std::string const& config,
-    cmBuildOptions buildOptions, bool verbose, cmDuration timeout,
+    cmBuildArgs const& buildArgs, std::vector<std::string> const& targetNames,
+    std::ostream& ostr, std::string const& makeProgram,
+    std::string const& config, cmBuildOptions buildOptions, cmDuration timeout,
     cmSystemTools::OutputOption outputMode,
     std::vector<std::string> const& nativeOptions = std::vector<std::string>(),
     BuildTryCompile isInTryCompile = BuildTryCompile::No);
@@ -361,9 +360,9 @@
   bool GetToolSupportsColor() const { return this->ToolSupportsColor; }
 
   //! return the language for the given extension
-  std::string GetLanguageFromExtension(char const* ext) const;
+  cm::string_view GetLanguageFromExtension(cm::string_view ext) const;
   //! is an extension to be ignored
-  bool IgnoreFile(char const* ext) const;
+  bool IgnoreFile(cm::string_view ext) const;
   //! What is the preference for linkers and this language (None or Preferred)
   int GetLinkerPreference(std::string const& lang) const;
   //! What is the object file extension for a given source file?
@@ -716,6 +715,8 @@
     return configs;
   }
 
+  bool ShouldWarnCMP0210(std::string const& lang);
+
   bool ShouldWarnExperimental(cm::string_view featureName,
                               cm::string_view featureUuid);
 
@@ -874,7 +875,11 @@
   std::set<std::string> LanguagesInProgress;
   std::map<std::string, std::string> OutputExtensions;
   std::map<std::string, std::string> LanguageToOutputExtension;
+#if __cplusplus >= 201402L || defined(_MSVC_LANG) && _MSVC_LANG >= 201402L
+  std::map<std::string, std::string, std::less<void>> ExtensionToLanguage;
+#else
   std::map<std::string, std::string> ExtensionToLanguage;
+#endif
   std::map<std::string, int> LanguageToLinkerPreference;
 
 #if !defined(CMAKE_BOOTSTRAP)
@@ -964,6 +969,8 @@
   // track targets to issue CMP0068 warning for.
   std::set<std::string> CMP0068WarnTargets;
 
+  std::unordered_set<std::string> WarnedCMP0210Languages;
+
   std::unordered_set<std::string> WarnedExperimental;
 
   mutable std::map<cmSourceFile*, std::set<cmGeneratorTarget const*>>
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index ff4dbc6..b145641 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -4,7 +4,6 @@
 
 #include <algorithm>
 #include <cassert>
-#include <cctype>
 #include <cstdio>
 #include <functional>
 #include <iterator>
@@ -23,6 +22,7 @@
 #include <cm3p/json/writer.h>
 
 #include "cmsys/FStream.hxx"
+#include "cmsys/String.h"
 
 #include "cmCustomCommand.h"
 #include "cmCxxModuleMapper.h"
@@ -172,7 +172,7 @@
   // "." and all invalid characters as hexadecimal.
   std::string encoded;
   for (char i : name) {
-    if (isalnum(i) || i == '_' || i == '-') {
+    if (cmsysString_isalnum(i) || i == '_' || i == '-') {
       encoded += i;
     } else {
       char buf[16];
@@ -2511,7 +2511,7 @@
     }
 
     dir_top_bld = tdi["dir-top-bld"].asString();
-    if (!dir_top_bld.empty() && !cmHasLiteralSuffix(dir_top_bld, "/")) {
+    if (!dir_top_bld.empty() && !cmHasSuffix(dir_top_bld, '/')) {
       dir_top_bld += '/';
     }
 
@@ -2524,7 +2524,7 @@
 
     Json::Value const& tdi_module_dir = tdi["module-dir"];
     module_dir = tdi_module_dir.asString();
-    if (!module_dir.empty() && !cmHasLiteralSuffix(module_dir, "/")) {
+    if (!module_dir.empty() && !cmHasSuffix(module_dir, '/')) {
       module_dir += '/';
     }
 
@@ -2993,11 +2993,35 @@
   }
 
   std::string const dir_cur_bld = tdi["dir-cur-bld"].asString();
+  if (!cmSystemTools::FileIsFullPath(dir_cur_bld)) {
+    cmSystemTools::Error(
+      "-E cmake_ninja_dyndep --tdi= file has no absolute dir-cur-bld");
+    return 1;
+  }
+
   std::string const dir_cur_src = tdi["dir-cur-src"].asString();
+  if (!cmSystemTools::FileIsFullPath(dir_cur_src)) {
+    cmSystemTools::Error(
+      "-E cmake_ninja_dyndep --tdi= file has no absolute dir-cur-src");
+    return 1;
+  }
+
   std::string const dir_top_bld = tdi["dir-top-bld"].asString();
+  if (!cmSystemTools::FileIsFullPath(dir_top_bld)) {
+    cmSystemTools::Error(
+      "-E cmake_ninja_dyndep --tdi= file has no absolute dir-top-bld");
+    return 1;
+  }
+
   std::string const dir_top_src = tdi["dir-top-src"].asString();
+  if (!cmSystemTools::FileIsFullPath(dir_top_src)) {
+    cmSystemTools::Error(
+      "-E cmake_ninja_dyndep --tdi= file has no absolute dir-top-src");
+    return 1;
+  }
+
   std::string module_dir = tdi["module-dir"].asString();
-  if (!module_dir.empty() && !cmHasLiteralSuffix(module_dir, "/")) {
+  if (!module_dir.empty() && !cmHasSuffix(module_dir, '/')) {
     module_dir += '/';
   }
   std::vector<std::string> linked_target_dirs;
@@ -3024,7 +3048,7 @@
 
   auto export_info = cmDyndepCollation::ParseExportInfo(tdi);
 
-  cmake cm(cmake::RoleInternal, cmState::Unknown);
+  cmake cm(cmState::Role::Internal);
   cm.SetHomeDirectory(dir_top_src);
   cm.SetHomeOutputDirectory(dir_top_bld);
   auto ggd = cm.CreateGlobalGenerator("Ninja");
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index 9489cde..bd0a3e8 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -1263,8 +1263,8 @@
   std::string ruleDir = cmStrCat(
     this->GetCMakeInstance()->GetHomeOutputDirectory(), "/CMakeFiles/",
     hasher.HashString(cmSystemTools::GetFilenamePath(output)));
-  std::string ruleFile =
-    cmStrCat(ruleDir, '/', cmSystemTools::GetFilenameName(output), ".rule");
+  std::string ruleFile = cmStrCat(
+    ruleDir, '/', cmSystemTools::GetFilenameNameView(output), ".rule");
   return ruleFile;
 }
 
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index 6105ee5..074caea 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -1002,7 +1002,7 @@
         root->MaybeRelativeToCurBinDir(lg->GetCurrentBinaryDirectory());
       if (dir == "."_s) {
         dir.clear();
-      } else if (!cmHasLiteralSuffix(dir, "/")) {
+      } else if (!cmHasSuffix(dir, '/')) {
         dir += "/";
       }
 
@@ -1055,9 +1055,6 @@
   }
 
   cmMakefile* mf = root->GetMakefile();
-  // Unfortunately we have to copy the source groups because
-  // FindSourceGroup uses a regex which is modifying the group.
-  std::vector<cmSourceGroup> sourceGroups = mf->GetSourceGroups();
   std::vector<std::string> items =
     cmList{ root->GetMakefile()->GetProperty("VS_SOLUTION_ITEMS") };
   for (std::string item : items) {
@@ -1065,7 +1062,8 @@
       item =
         cmSystemTools::CollapseFullPath(item, mf->GetCurrentSourceDirectory());
     }
-    cmSourceGroup* sg = mf->FindSourceGroup(item, sourceGroups);
+    cmSourceGroup* sg =
+      cmSourceGroup::FindSourceGroup(item, mf->GetSourceGroups());
     std::string folderName = sg->GetFullName();
     if (folderName.empty()) {
       folderName = "Solution Items";
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 2f5df55..68614bb 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -491,6 +491,29 @@
   return false;
 }
 
+bool cmGlobalXCodeGenerator::ParseKnownAttributes(
+  cm::string_view attribute, cm::string_view attributeValue)
+{
+  static std::string const knownRegions{ "knownRegions"_s };
+  if (attribute == knownRegions) {
+    std::vector<std::string> regionsVec(cmTokenize(attributeValue, ','));
+    cmXCodeObject* allLangs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+    for (auto const& region : regionsVec) {
+      allLangs->AddObject(this->CreateString(cmTrimWhitespace(region)));
+    }
+    this->RootObject->AddAttribute(knownRegions, allLangs);
+    return true;
+  }
+
+  static std::string const developmentRegion{ "developmentRegion"_s };
+  if (attribute == developmentRegion) {
+    this->RootObject->AddAttribute(
+      developmentRegion, this->CreateString(cmTrimWhitespace(attributeValue)));
+    return true;
+  }
+  return false;
+};
+
 void cmGlobalXCodeGenerator::EnableLanguage(
   std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
 {
@@ -1340,14 +1363,10 @@
   }
   // Make a copy so that we can override it later
   std::string path = cmSystemTools::CollapseFullPath(fullpath);
-  // Compute the extension without leading '.'.
-  std::string ext = cmSystemTools::GetFilenameLastExtension(path);
-  if (!ext.empty()) {
-    ext = ext.substr(1);
-  }
   if (fileType.empty()) {
     path = this->GetLibraryOrFrameworkPath(path);
-    ext = cmSystemTools::GetFilenameLastExtension(path);
+    // Compute the extension without leading '.'.
+    std::string ext = cmSystemTools::GetFilenameLastExtension(path);
     if (!ext.empty()) {
       ext = ext.substr(1);
     }
@@ -2668,43 +2687,25 @@
     }
   }
 
-  std::string extraLinkOptionsVar;
   std::string extraLinkOptions;
-  if (gtgt->GetType() == cmStateEnums::EXECUTABLE) {
-    extraLinkOptionsVar = "CMAKE_EXE_LINKER_FLAGS";
-  } else if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) {
-    extraLinkOptionsVar = "CMAKE_SHARED_LINKER_FLAGS";
-  } else if (gtgt->GetType() == cmStateEnums::MODULE_LIBRARY) {
-    extraLinkOptionsVar = "CMAKE_MODULE_LINKER_FLAGS";
-  }
-  if (!extraLinkOptionsVar.empty()) {
-    this->CurrentLocalGenerator->AddConfigVariableFlags(
-      extraLinkOptions, extraLinkOptionsVar, gtgt, cmBuildStep::Link, llang,
-      configName);
-  }
 
   if (gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY ||
       gtgt->GetType() == cmStateEnums::STATIC_LIBRARY) {
     this->CurrentLocalGenerator->GetStaticLibraryFlags(
       extraLinkOptions, configName, llang, gtgt);
   } else {
+    this->CurrentLocalGenerator->AddTargetTypeLinkerFlags(
+      extraLinkOptions, gtgt, llang, configName);
+    this->CurrentLocalGenerator->AddPerLanguageLinkFlags(
+      extraLinkOptions, gtgt, llang, configName);
     this->CurrentLocalGenerator->AppendLinkerTypeFlags(extraLinkOptions, gtgt,
                                                        configName, llang);
     this->CurrentLocalGenerator->AppendWarningAsErrorLinkerFlags(
       extraLinkOptions, gtgt, llang);
 
-    cmValue targetLinkFlags = gtgt->GetProperty("LINK_FLAGS");
-    if (targetLinkFlags) {
-      this->CurrentLocalGenerator->AppendFlags(extraLinkOptions,
-                                               *targetLinkFlags);
-    }
-    if (!configName.empty()) {
-      std::string linkFlagsVar =
-        cmStrCat("LINK_FLAGS_", cmSystemTools::UpperCase(configName));
-      if (cmValue linkFlags = gtgt->GetProperty(linkFlagsVar)) {
-        this->CurrentLocalGenerator->AppendFlags(extraLinkOptions, *linkFlags);
-      }
-    }
+    this->CurrentLocalGenerator->AddTargetPropertyLinkFlags(extraLinkOptions,
+                                                            gtgt, configName);
+
     std::vector<std::string> opts;
     gtgt->GetLinkOptions(opts, configName, llang);
     // LINK_OPTIONS are escaped.
@@ -2833,8 +2834,9 @@
       buildSettings->AddAttribute("LIBRARY_STYLE",
                                   this->CreateString("BUNDLE"));
       // Add the flags to create a module library (bundle).
-      std::string createFlags = this->LookupFlags(
-        "CMAKE_SHARED_MODULE_CREATE_", llang, "_FLAGS", gtgt);
+      std::string createFlags;
+      this->CurrentLocalGenerator->AppendTargetCreationLinkFlags(createFlags,
+                                                                 gtgt, llang);
       if (this->GetTargetProductType(gtgt) !=
           "com.apple.product-type.app-extension"_s) {
         // Xcode passes -bundle automatically.
@@ -2889,8 +2891,9 @@
                                     this->CreateString(plist));
       } else {
         // Add the flags to create a shared library.
-        std::string createFlags = this->LookupFlags(
-          "CMAKE_SHARED_LIBRARY_CREATE_", llang, "_FLAGS", gtgt);
+        std::string createFlags;
+        this->CurrentLocalGenerator->AppendTargetCreationLinkFlags(
+          createFlags, gtgt, llang);
         // Xcode passes -dynamiclib automatically.
         cmSystemTools::ReplaceString(createFlags, "-dynamiclib", "");
         createFlags = cmTrimWhitespace(createFlags);
@@ -2912,8 +2915,9 @@
     }
     case cmStateEnums::EXECUTABLE: {
       // Add the flags to create an executable.
-      std::string createFlags =
-        this->LookupFlags("CMAKE_", llang, "_LINK_FLAGS", gtgt);
+      std::string createFlags;
+      this->CurrentLocalGenerator->AppendTargetCreationLinkFlags(createFlags,
+                                                                 gtgt, llang);
       if (!createFlags.empty()) {
         extraLinkOptions += ' ';
         extraLinkOptions += createFlags;
@@ -4499,8 +4503,6 @@
   std::vector<cmLocalGenerator*>& generators)
 {
   for (auto& generator : generators) {
-    cmMakefile* mf = generator->GetMakefile();
-    std::vector<cmSourceGroup> sourceGroups = mf->GetSourceGroups();
     for (auto const& gtgt : generator->GetGeneratorTargets()) {
       // Same skipping logic here as in CreateXCodeTargets so that we do not
       // end up with (empty anyhow) ZERO_CHECK, install, or test source
@@ -4512,9 +4514,9 @@
         continue;
       }
 
-      auto addSourceToGroup = [this, mf, &gtgt,
-                               &sourceGroups](std::string const& source) {
-        cmSourceGroup* sourceGroup = mf->FindSourceGroup(source, sourceGroups);
+      auto addSourceToGroup = [this, &gtgt,
+                               &generator](std::string const& source) {
+        cmSourceGroup* sourceGroup = generator->FindSourceGroup(source);
         cmXCodeObject* pbxgroup =
           this->CreateOrGetPBXGroup(gtgt.get(), sourceGroup);
         std::string key = GetGroupMapKeyFromPath(gtgt.get(), source);
@@ -4873,9 +4875,14 @@
         std::string attribute = var.substr(22);
         this->FilterConfigurationAttribute(config.first, attribute);
         if (!attribute.empty()) {
+          std::string const attributeValue =
+            this->CurrentMakefile->GetSafeDefinition(var);
+          if (this->ParseKnownAttributes(attribute, attributeValue)) {
+            continue;
+          }
+
           std::string processed = cmGeneratorExpression::Evaluate(
-            this->CurrentMakefile->GetSafeDefinition(var),
-            this->CurrentLocalGenerator, config.first);
+            attributeValue, this->CurrentLocalGenerator, config.first);
           buildSettingsForCfg->AddAttribute(attribute,
                                             this->CreateString(processed));
         }
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index 266a9a9..82bb9d5 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -157,6 +157,8 @@
   bool ParseGeneratorToolset(std::string const& ts, cmMakefile* mf);
   bool ProcessGeneratorToolsetField(std::string const& key,
                                     std::string const& value, cmMakefile* mf);
+  bool ParseKnownAttributes(cm::string_view attribute,
+                            cm::string_view attributeValue);
 
   cmXCodeObject* CreateOrGetPBXGroup(cmGeneratorTarget* gtgt,
                                      cmSourceGroup* sg);
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx
index 65036fd..baba225 100644
--- a/Source/cmGraphVizWriter.cxx
+++ b/Source/cmGraphVizWriter.cxx
@@ -3,15 +3,16 @@
 #include "cmGraphVizWriter.h"
 
 #include <algorithm>
-#include <cctype>
 #include <iostream>
 #include <memory>
 #include <set>
+#include <unordered_set>
 #include <utility>
 
 #include <cm/memory>
 
 #include "cmsys/RegularExpression.hxx"
+#include "cmsys/String.h"
 
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
@@ -197,9 +198,7 @@
   std::string const& settingsFileName,
   std::string const& fallbackSettingsFileName)
 {
-  cmake cm(cmake::RoleScript, cmState::Unknown);
-  cm.SetHomeDirectory("");
-  cm.SetHomeOutputDirectory("");
+  cmake cm(cmState::Role::Script);
   cm.GetCurrentSnapshot().SetDefaultDefinitions();
   cmGlobalGenerator ggi(&cm);
   cmMakefile mf(&ggi, cm.GetCurrentSnapshot());
@@ -369,10 +368,14 @@
     std::unique_ptr<cmGeneratedFileStream> fileStream =
       this->CreateTargetFile(rootItem, fileNameSuffix);
 
+    // avoid write same node multiple times
+    std::unordered_set<std::string> writtenNodes = { rootItem.AsStr() };
     for (Connection const& con : cons) {
       cmLinkItem const& src = DirFunc::src(con);
       cmLinkItem const& dst = DirFunc::dst(con);
-      this->WriteNode(*fileStream, con.dst);
+      if (writtenNodes.emplace(con.dst.AsStr()).second) {
+        this->WriteNode(*fileStream, con.dst);
+      }
       this->WriteConnection(*fileStream, src, dst, con.scopeType);
     }
 
@@ -599,7 +602,7 @@
   auto const extra_chars = std::set<char>{ '.', '-', '_' };
 
   for (char c : str) {
-    if (std::isalnum(c) || extra_chars.find(c) != extra_chars.cend()) {
+    if (cmsysString_isalnum(c) || extra_chars.find(c) != extra_chars.cend()) {
       pathSafeStr += c;
     }
   }
diff --git a/Source/cmHexFileConverter.cxx b/Source/cmHexFileConverter.cxx
index a028bb4..3036473 100644
--- a/Source/cmHexFileConverter.cxx
+++ b/Source/cmHexFileConverter.cxx
@@ -2,10 +2,11 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "cmHexFileConverter.h"
 
-#include <cctype>
 #include <cstdio>
 #include <cstring>
 
+#include "cmsys/String.h"
+
 #include "cmSystemTools.h"
 
 #define INTEL_HEX_MIN_LINE_LENGTH (1 + 8 + 2)
@@ -163,7 +164,7 @@
   }
 
   for (unsigned int i = 1; i < slen; i++) {
-    if (!isxdigit(buf[i])) {
+    if (!cmsysString_isxdigit(buf[i])) {
       return Binary;
     }
   }
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index b9080bd..1d37546 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -39,6 +39,7 @@
 #include "cmInstallPackageInfoExportGenerator.h"
 #include "cmInstallRuntimeDependencySet.h"
 #include "cmInstallRuntimeDependencySetGenerator.h"
+#include "cmInstallSbomExportGenerator.h"
 #include "cmInstallScriptGenerator.h"
 #include "cmInstallTargetGenerator.h"
 #include "cmList.h"
@@ -48,6 +49,7 @@
 #include "cmPolicies.h"
 #include "cmRange.h"
 #include "cmRuntimeDependencyArchive.h"
+#include "cmSbomArguments.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSubcommandTable.h"
@@ -247,7 +249,8 @@
       cmInstallGenerator::SelectMessageLevel(helper.Makefile),
       runtimeDependenciesArgsRef.GetExcludeFromAll() &&
         (apple ? frameworkArgs.GetExcludeFromAll() : true),
-      helper.Makefile->GetBacktrace());
+      helper.Makefile->GetBacktrace(),
+      helper.Makefile->GetPolicyStatus(cmPolicies::CMP0207));
   helper.Makefile->AddInstallGenerator(
     std::move(getRuntimeDependenciesGenerator));
 
@@ -1788,10 +1791,11 @@
       exclude_from_all = true;
       doing = DoingNone;
     } else if (doing == DoingDirs) {
-      // Convert this directory to a full path.
+      // If the given directory is not a full path, convert it to one by
+      // assuming it's relative to the current source directory.
       std::string dir = args[i];
       std::string::size_type gpos = cmGeneratorExpression::Find(dir);
-      if (gpos != 0 && !cmSystemTools::FileIsFullPath(dir)) {
+      if (!dir.empty() && gpos != 0 && !cmSystemTools::FileIsFullPath(dir)) {
         dir =
           cmStrCat(helper.Makefile->GetCurrentSourceDirectory(), '/', args[i]);
       }
@@ -1987,8 +1991,7 @@
   }
 
   // Check the file extension.
-  if (!fname.empty() &&
-      cmSystemTools::GetFilenameLastExtension(fname) != ".mk") {
+  if (!fname.empty() && !cmHasSuffix(fname, ".mk"_s)) {
     status.SetError(cmStrCat(
       args[0], " given invalid export file name \"", fname,
       R"(".  The FILE argument must specify a name ending in ".mk".)"));
@@ -2035,6 +2038,152 @@
 #endif
 }
 
+#ifndef CMAKE_BOOTSTRAP
+cm::optional<cm::string_view> MatchExport(cm::string_view directive,
+                                          std::string const& exportName)
+{
+  std::string::size_type const l = exportName.size();
+  if (directive.substr(0, l) == exportName) {
+    if (directive.size() > l && directive[l] == ':') {
+      return directive.substr(l + 1);
+    }
+  }
+  return cm::nullopt;
+}
+
+void AssignValue(std::string& dest, std::string const& value)
+{
+  dest = value;
+}
+
+void AssignValue(std::vector<std::string>& dest, std::string const& value)
+{
+  dest = cmList{ value }.data();
+}
+
+template <typename T>
+void GetExportArgumentFromVariable(cmMakefile const* makefile,
+                                   cmExportSet const& exportSet,
+                                   cm::string_view suffix, T& variable)
+{
+  std::string const& name =
+    cmStrCat(exportSet.GetName(), "_EXPORT_PACKAGE_INFO_"_s, suffix);
+  if (cmValue const& value = makefile->GetDefinition(name)) {
+    std::string realValue;
+    makefile->ConfigureString(value, realValue, true, false);
+    AssignValue(variable, realValue);
+  }
+}
+
+bool HandleMappedPackageInfo(
+  cmExportSet& exportSet, cm::string_view directive, Helper& helper,
+  cmInstallCommandArguments const& installCommandArgs,
+  cmExecutionStatus& status, cmInstallGenerator::MessageLevel message,
+  std::string const& cxxModulesDirectory)
+{
+  cmPackageInfoArguments arguments;
+
+  // Extract information from the directive.
+  std::string::size_type const n = directive.find('/');
+  if (n != std::string::npos) {
+    arguments.PackageName = std::string{ directive.substr(0, n) };
+    directive = directive.substr(n + 1);
+
+    if (!directive.empty() && directive[0] == 'l') {
+      arguments.LowerCase = true;
+      directive = directive.substr(1);
+    }
+
+    if (!directive.empty() && directive[0] == 'a') {
+      std::string::size_type const d = directive.find('/');
+      if (d != std::string::npos) {
+        arguments.Appendix = std::string{ directive.substr(1, d - 1) };
+        directive = directive.substr(d);
+      } else {
+        arguments.Appendix = std::string{ directive.substr(1) };
+        directive = {};
+      }
+
+      if (arguments.Appendix.empty()) {
+        status.SetError(cmStrCat(
+          "CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO given APPENDIX "
+          R"(directive for export ")"_s,
+          exportSet.GetName(), R"(", but no appendix name was provided.)"_s));
+        return false;
+      }
+    }
+
+    if (!directive.empty()) {
+      if (directive[0] != '/') {
+        status.SetError(
+          cmStrCat("CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO given unrecognized "
+                   R"(directive  ")"_s,
+                   directive, R"(".)"_s));
+        return false;
+      }
+
+      directive = directive.substr(1);
+    }
+  } else {
+    arguments.PackageName = std::string{ directive };
+    directive = {};
+  }
+
+  if (arguments.PackageName.empty()) {
+    status.SetError(
+      cmStrCat("CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO missing package name "
+               R"(for export ")"_s,
+               exportSet.GetName(), R"(".)"_s));
+    return false;
+  }
+
+  // Build destination.
+  std::string dest = std::string{ directive };
+  if (dest.empty()) {
+    if (helper.Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Windows") {
+      dest = std::string{ "cps"_s };
+    } else {
+      dest = cmStrCat(helper.GetLibraryDestination(nullptr), "/cps/",
+                      arguments.GetPackageDirName());
+    }
+  }
+
+  if (arguments.Appendix.empty()) {
+    // Get additional export information from variables.
+    GetExportArgumentFromVariable( // BR
+      helper.Makefile, exportSet, "VERSION"_s, arguments.Version);
+    GetExportArgumentFromVariable( // BR
+      helper.Makefile, exportSet, "COMPAT_VERSION"_s, arguments.VersionCompat);
+    GetExportArgumentFromVariable( // BR
+      helper.Makefile, exportSet, "VERSION_SCHEMA"_s, arguments.VersionSchema);
+    GetExportArgumentFromVariable( // BR
+      helper.Makefile, exportSet, "LICENSE"_s, arguments.License);
+    GetExportArgumentFromVariable( // BR
+      helper.Makefile, exportSet, "DEFAULT_LICENSE"_s,
+      arguments.DefaultLicense);
+    GetExportArgumentFromVariable( // BR
+      helper.Makefile, exportSet, "DEFAULT_CONFIGURATIONS"_s,
+      arguments.DefaultConfigs);
+  }
+
+  // Sanity-check export information.
+  if (!arguments.Check(status)) {
+    return false;
+  }
+
+  // Create the package info generator.
+  helper.Makefile->AddInstallGenerator(
+    cm::make_unique<cmInstallPackageInfoExportGenerator>(
+      &exportSet, dest, installCommandArgs.GetPermissions(),
+      installCommandArgs.GetConfigurations(),
+      installCommandArgs.GetComponent(), message,
+      installCommandArgs.GetExcludeFromAll(), std::move(arguments),
+      cxxModulesDirectory, helper.Makefile->GetBacktrace()));
+
+  return true;
+}
+#endif
+
 bool HandleExportMode(std::vector<std::string> const& args,
                       cmExecutionStatus& status)
 {
@@ -2100,8 +2249,7 @@
   }
 
   // Check the file extension.
-  if (!fname.empty() &&
-      cmSystemTools::GetFilenameLastExtension(fname) != ".cmake") {
+  if (!fname.empty() && !cmHasSuffix(fname, ".cmake"_s)) {
     status.SetError(
       cmStrCat(args[0], " given invalid export file name \"", fname,
                "\".  "
@@ -2135,6 +2283,26 @@
   helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
     ica.GetComponent());
 
+#ifndef CMAKE_BOOTSTRAP
+  // Check if PACKAGE_INFO export has been requested for this export set.
+  if (cmExperimental::HasSupportEnabled(
+        status.GetMakefile(), cmExperimental::Feature::MappedPackageInfo)) {
+    if (cmValue const& piExports = helper.Makefile->GetDefinition(
+          "CMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFO")) {
+      for (auto const& pie : cmList{ piExports }) {
+        cm::optional<cm::string_view> const directive = MatchExport(pie, exp);
+        if (directive) {
+          if (!HandleMappedPackageInfo(exportSet, *directive, helper, ica,
+                                       status, message,
+                                       cxx_modules_directory)) {
+            return false;
+          }
+        }
+      }
+    }
+  }
+#endif
+
   // Create the export install generator.
   helper.Makefile->AddInstallGenerator(
     cm::make_unique<cmInstallCMakeConfigExportGenerator>(
@@ -2151,12 +2319,6 @@
                            cmExecutionStatus& status)
 {
 #ifndef CMAKE_BOOTSTRAP
-  if (!cmExperimental::HasSupportEnabled(
-        status.GetMakefile(), cmExperimental::Feature::ExportPackageInfo)) {
-    status.SetError("does not recognize sub-command PACKAGE_INFO");
-    return false;
-  }
-
   Helper helper(status);
 
   // This is the PACKAGE_INFO mode.
@@ -2168,15 +2330,12 @@
 
   arguments.Bind(ica);
   ica.Bind("EXPORT"_s, exportName);
-  // ica.Bind("CXX_MODULES_DIRECTORY"_s, cxxModulesDirectory); TODO?
+  ica.Bind("CXX_MODULES_DIRECTORY"_s, cxxModulesDirectory);
 
   std::vector<std::string> unknownArgs;
-  ica.Parse(args, &unknownArgs);
+  ArgumentParser::ParseResult result = ica.Parse(args, &unknownArgs);
 
-  if (!unknownArgs.empty()) {
-    // Unknown argument.
-    status.SetError(
-      cmStrCat(args[0], " given unknown argument \"", unknownArgs[0], "\"."));
+  if (!result.Check(args[0], &unknownArgs, status)) {
     return false;
   }
 
@@ -2184,12 +2343,6 @@
     return false;
   }
 
-  if (arguments.PackageName.empty()) {
-    // TODO: Fix our use of the parser to enforce this.
-    status.SetError(cmStrCat(args[0], " missing package name."));
-    return false;
-  }
-
   if (exportName.empty()) {
     status.SetError(cmStrCat(args[0], " missing EXPORT."));
     return false;
@@ -2353,6 +2506,93 @@
   return true;
 }
 
+bool HandleSbomMode(std::vector<std::string> const& args,
+                    cmExecutionStatus& status)
+{
+#ifndef CMAKE_BOOTSTRAP
+  if (!cmExperimental::HasSupportEnabled(
+        status.GetMakefile(), cmExperimental::Feature::GenerateSbom)) {
+    status.SetError("does not recognize sub-command SBOM");
+    return false;
+  }
+
+  Helper helper(status);
+  cmInstallCommandArguments ica(helper.DefaultComponentName, *helper.Makefile);
+
+  cmSbomArguments arguments;
+  ArgumentParser::NonEmpty<std::string> exportName;
+  ArgumentParser::NonEmpty<std::string> cxxModulesDirectory;
+
+  arguments.Bind(ica);
+  ica.Bind("EXPORT"_s, exportName);
+  // ica.Bind("CXX_MODULES_DIRECTORY"_s, cxxModulesDirectory); TODO?
+
+  std::vector<std::string> unknownArgs;
+  ica.Parse(args, &unknownArgs);
+
+  ArgumentParser::ParseResult result = ica.Parse(args, &unknownArgs);
+  if (!result.Check(args[0], &unknownArgs, status)) {
+    return false;
+  }
+
+  if (!ica.Finalize()) {
+    return false;
+  }
+
+  if (arguments.PackageName.empty()) {
+    // TODO: Fix our use of the parser to enforce this.
+    status.SetError(cmStrCat(args[0], " missing SBOM name."));
+    return false;
+  }
+
+  if (exportName.empty()) {
+    status.SetError(cmStrCat(args[0], " missing EXPORT."));
+    return false;
+  }
+
+  if (!arguments.Check(status) || !arguments.SetMetadataFromProject(status)) {
+    return false;
+  }
+
+  // Get or construct the destination path.
+  std::string dest = ica.GetDestination();
+  if (dest.empty()) {
+    if (helper.Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Windows") {
+      dest = std::string{ "/sbom/"_s };
+    } else {
+      dest = cmStrCat(helper.GetLibraryDestination(nullptr), "/sbom/",
+                      arguments.GetPackageDirName());
+    }
+  }
+
+  cmExportSet& exportSet =
+    helper.Makefile->GetGlobalGenerator()->GetExportSets()[exportName];
+
+  cmInstallGenerator::MessageLevel message =
+    cmInstallGenerator::SelectMessageLevel(helper.Makefile);
+
+  // Tell the global generator about any installation component names
+  // specified
+  helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+    ica.GetComponent());
+  helper.Makefile->SetExplicitlyGeneratesSbom(true);
+
+  // Create the export install generator.
+  helper.Makefile->AddInstallGenerator(
+    cm::make_unique<cmInstallSbomExportGenerator>(
+      &exportSet, dest, ica.GetPermissions(), ica.GetConfigurations(),
+      ica.GetComponent(), message, ica.GetExcludeFromAll(),
+      std::move(arguments), std::move(cxxModulesDirectory),
+      helper.Makefile->GetBacktrace()));
+
+  return true;
+#else
+  static_cast<void>(args);
+  status.SetError("SBOM not supported in bootstrap cmake");
+  return false;
+#endif
+}
+
 bool Helper::MakeFilesFullPath(char const* modeName,
                                std::vector<std::string> const& relFiles,
                                std::vector<std::string>& absFiles)
@@ -2590,6 +2830,7 @@
     { "EXPORT_ANDROID_MK"_s, HandleExportAndroidMKMode },
     { "PACKAGE_INFO"_s, HandlePackageInfoMode },
     { "RUNTIME_DEPENDENCY_SET"_s, HandleRuntimeDependencySetMode },
+    { "SBOM"_s, HandleSbomMode }
   };
 
   return subcommand(args[0], args, status);
diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx
index a388d91..cf1fac9 100644
--- a/Source/cmInstallDirectoryGenerator.cxx
+++ b/Source/cmInstallDirectoryGenerator.cxx
@@ -2,6 +2,7 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "cmInstallDirectoryGenerator.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "cmGeneratorExpression.h"
@@ -54,6 +55,13 @@
 std::vector<std::string> cmInstallDirectoryGenerator::GetDirectories(
   std::string const& config) const
 {
+  // If given only empty directories, collapse into a single specification to
+  // avoid redundant calls. This supports the use case of installing an empty
+  // directory into a destination when a directory is not specified.
+  if (std::all_of(this->Directories.begin(), this->Directories.end(),
+                  [](std::string const& d) { return d.empty(); })) {
+    return std::vector<std::string>{ "" };
+  }
   cmList directories;
   if (this->ActionsPerConfig) {
     for (std::string const& f : this->Directories) {
@@ -81,11 +89,13 @@
 {
   std::vector<std::string> dirs = this->GetDirectories(config);
 
-  // Make sure all dirs have absolute paths.
-  cmMakefile const& mf = *this->LocalGenerator->GetMakefile();
-  for (std::string& d : dirs) {
-    if (!cmSystemTools::FileIsFullPath(d)) {
-      d = cmStrCat(mf.GetCurrentSourceDirectory(), '/', d);
+  if (!(dirs.size() == 1 && dirs[0].empty())) {
+    // Make sure all dirs have absolute paths.
+    cmMakefile const& mf = *this->LocalGenerator->GetMakefile();
+    for (std::string& d : dirs) {
+      if (!cmSystemTools::FileIsFullPath(d)) {
+        d = cmStrCat(mf.GetCurrentSourceDirectory(), '/', d);
+      }
     }
   }
 
diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx
index 4ba3f01..8886439 100644
--- a/Source/cmInstallExportGenerator.cxx
+++ b/Source/cmInstallExportGenerator.cxx
@@ -246,5 +246,5 @@
 
 std::string cmInstallExportGenerator::GetDestinationFile() const
 {
-  return this->Destination + '/' + this->FileName;
+  return cmStrCat(this->Destination, '/', this->FileName);
 }
diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx
index b49b0ea..cc9fd8a 100644
--- a/Source/cmInstallGenerator.cxx
+++ b/Source/cmInstallGenerator.cxx
@@ -5,6 +5,8 @@
 #include <sstream>
 #include <utility>
 
+#include <cm/string_view>
+
 #include "cmMakefile.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
@@ -84,7 +86,7 @@
         if (rename && *rename) {
           os << rename;
         } else {
-          os << cmSystemTools::GetFilenameName(file);
+          os << cmSystemTools::GetFilenameNameView(file);
         }
         firstIteration = false;
       }
diff --git a/Source/cmInstallGetRuntimeDependenciesGenerator.cxx b/Source/cmInstallGetRuntimeDependenciesGenerator.cxx
index 0ba9f14..4292f8f 100644
--- a/Source/cmInstallGetRuntimeDependenciesGenerator.cxx
+++ b/Source/cmInstallGetRuntimeDependenciesGenerator.cxx
@@ -19,6 +19,7 @@
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmOutputConverter.h"
+#include "cmPolicies.h"
 #include "cmScriptGenerator.h"
 #include "cmStringAlgorithms.h"
 
@@ -83,7 +84,8 @@
     std::vector<std::string> postExcludeFiles, std::string libraryComponent,
     std::string frameworkComponent, bool noInstallRPath, char const* depsVar,
     char const* rpathPrefix, std::vector<std::string> const& configurations,
-    MessageLevel message, bool exclude_from_all, cmListFileBacktrace backtrace)
+    MessageLevel message, bool exclude_from_all, cmListFileBacktrace backtrace,
+    cmPolicies::PolicyStatus policyStatusCMP0207)
   : cmInstallGenerator("", configurations, "", message, exclude_from_all,
                        false, std::move(backtrace))
   , RuntimeDependencySet(runtimeDependencySet)
@@ -96,6 +98,7 @@
   , PostExcludeFiles(std::move(postExcludeFiles))
   , LibraryComponent(std::move(libraryComponent))
   , FrameworkComponent(std::move(frameworkComponent))
+  , PolicyStatusCMP0207(policyStatusCMP0207)
   , NoInstallRPath(noInstallRPath)
   , DepsVar(depsVar)
   , RPathPrefix(rpathPrefix)
@@ -141,6 +144,14 @@
     this->LocalGenerator->GetMakefile()->GetSafeDefinition(
       "CMAKE_INSTALL_NAME_TOOL");
 
+  Indent inputIndent = indent;
+  if (this->PolicyStatusCMP0207 != cmPolicies::WARN) {
+    indent = indent.Next();
+    os << inputIndent << "block(SCOPE_FOR POLICIES)\n"
+       << indent << "cmake_policy(SET CMP0207 "
+       << (this->PolicyStatusCMP0207 == cmPolicies::NEW ? "NEW" : "OLD")
+       << ")\n";
+  }
   os << indent << "file(GET_RUNTIME_DEPENDENCIES\n"
      << indent << "  RESOLVED_DEPENDENCIES_VAR " << this->DepsVar << '\n';
   WriteFilesArgument(os, "EXECUTABLES"_s,
@@ -204,4 +215,8 @@
     os << indent << "  RPATH_PREFIX " << this->RPathPrefix << '\n';
   }
   os << indent << "  )\n";
+
+  if (this->PolicyStatusCMP0207 != cmPolicies::WARN) {
+    os << inputIndent << "endblock()\n";
+  }
 }
diff --git a/Source/cmInstallGetRuntimeDependenciesGenerator.h b/Source/cmInstallGetRuntimeDependenciesGenerator.h
index 11b6d87..9670dcf 100644
--- a/Source/cmInstallGetRuntimeDependenciesGenerator.h
+++ b/Source/cmInstallGetRuntimeDependenciesGenerator.h
@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "cmInstallGenerator.h"
+#include "cmPolicies.h"
 
 class cmListFileBacktrace;
 class cmLocalGenerator;
@@ -26,8 +27,8 @@
     std::vector<std::string> postExcludeFiles, std::string libraryComponent,
     std::string frameworkComponent, bool noInstallRPath, char const* depsVar,
     char const* rpathPrefix, std::vector<std::string> const& configurations,
-    MessageLevel message, bool exclude_from_all,
-    cmListFileBacktrace backtrace);
+    MessageLevel message, bool exclude_from_all, cmListFileBacktrace backtrace,
+    cmPolicies::PolicyStatus policyStatusCMP0207);
 
   bool Compute(cmLocalGenerator* lg) override;
 
@@ -48,6 +49,7 @@
   std::vector<std::string> PostExcludeFiles;
   std::string LibraryComponent;
   std::string FrameworkComponent;
+  cmPolicies::PolicyStatus PolicyStatusCMP0207;
   bool NoInstallRPath;
   char const* DepsVar;
   char const* RPathPrefix;
diff --git a/Source/cmInstallSbomExportGenerator.cxx b/Source/cmInstallSbomExportGenerator.cxx
new file mode 100644
index 0000000..01af7ed
--- /dev/null
+++ b/Source/cmInstallSbomExportGenerator.cxx
@@ -0,0 +1,30 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+file LICENSE.rst or https://cmake.org/licensing for details.  */
+#include "cmInstallSbomExportGenerator.h"
+
+#include <utility>
+
+#include <cm/memory>
+
+#include "cmExportInstallFileGenerator.h"
+#include "cmExportInstallSbomGenerator.h"
+#include "cmListFileCache.h"
+#include "cmSbomArguments.h"
+
+class cmExportSet;
+
+cmInstallSbomExportGenerator::cmInstallSbomExportGenerator(
+  cmExportSet* exportSet, std::string destination, std::string filePermissions,
+  std::vector<std::string> const& configurations, std::string component,
+  MessageLevel message, bool excludeFromAll, cmSbomArguments args,
+  std::string cxxModulesDirectory, cmListFileBacktrace backtrace)
+  : cmInstallExportGenerator(
+      exportSet, std::move(destination), std::move(filePermissions),
+      configurations, std::move(component), message, excludeFromAll,
+      args.GetPackageFileName(), args.GetNamespace(),
+      std::move(cxxModulesDirectory), std::move(backtrace))
+{
+  this->EFGen = cm::make_unique<cmExportInstallSbomGenerator>(this, args);
+}
+
+cmInstallSbomExportGenerator::~cmInstallSbomExportGenerator() = default;
diff --git a/Source/cmInstallSbomExportGenerator.h b/Source/cmInstallSbomExportGenerator.h
new file mode 100644
index 0000000..23d7318
--- /dev/null
+++ b/Source/cmInstallSbomExportGenerator.h
@@ -0,0 +1,31 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "cmInstallExportGenerator.h"
+
+class cmExportSet;
+class cmListFileBacktrace;
+class cmSbomArguments;
+
+class cmInstallSbomExportGenerator final : public cmInstallExportGenerator
+{
+public:
+  cmInstallSbomExportGenerator(cmExportSet* exportSet, std::string destination,
+                               std::string filePermissions,
+                               std::vector<std::string> const& configurations,
+                               std::string component, MessageLevel message,
+                               bool excludeFromAll, cmSbomArguments arguments,
+                               std::string cxxModulesDirectory,
+                               cmListFileBacktrace backtrace);
+  cmInstallSbomExportGenerator(cmInstallSbomExportGenerator const&) = delete;
+  ~cmInstallSbomExportGenerator() override;
+
+  cmInstallSbomExportGenerator& operator=(
+    cmInstallSbomExportGenerator const&) = delete;
+
+  char const* InstallSubcommand() const override { return "SBOM"; }
+};
diff --git a/Source/cmInstallScriptHandler.cxx b/Source/cmInstallScriptHandler.cxx
index 5fc2b35..10f795b 100644
--- a/Source/cmInstallScriptHandler.cxx
+++ b/Source/cmInstallScriptHandler.cxx
@@ -201,10 +201,8 @@
     .SetExternalLoop(*loop)
     .SetMergedBuiltinStreams();
   this->chain = cm::make_unique<cmUVProcessChain>(builder.Start());
-  this->pipe.init(this->chain->GetLoop(), 0);
-  uv_pipe_open(this->pipe, this->chain->OutputStream());
   this->streamHandler = cmUVStreamRead(
-    this->pipe,
+    this->chain->OutputStream(),
     [this](std::vector<char> data) {
       std::string strdata;
       cmProcessOutput(cmProcessOutput::Auto)
diff --git a/Source/cmInstallScriptHandler.h b/Source/cmInstallScriptHandler.h
index f35adb0..6f2a7d7 100644
--- a/Source/cmInstallScriptHandler.h
+++ b/Source/cmInstallScriptHandler.h
@@ -8,10 +8,13 @@
 #include <string>
 #include <vector>
 
-#include "cmUVHandlePtr.h"
 #include "cmUVProcessChain.h"
 #include "cmUVStream.h"
 
+namespace cm {
+class uv_loop_ptr;
+}
+
 class cmInstrumentation;
 
 class cmInstallScriptHandler
@@ -42,7 +45,6 @@
     std::string name;
     std::unique_ptr<cmUVProcessChain> chain;
     std::unique_ptr<cmUVStreamReadHandle> streamHandler;
-    cm::uv_pipe_ptr pipe;
   };
 
 private:
diff --git a/Source/cmInstrumentation.cxx b/Source/cmInstrumentation.cxx
index 6ccf01d..d866c73 100644
--- a/Source/cmInstrumentation.cxx
+++ b/Source/cmInstrumentation.cxx
@@ -4,6 +4,7 @@
 #include <chrono>
 #include <ctime>
 #include <iomanip>
+#include <iterator>
 #include <set>
 #include <sstream>
 #include <stdexcept>
@@ -25,7 +26,6 @@
 
 #include "cmCMakePath.h"
 #include "cmCryptoHash.h"
-#include "cmExperimental.h"
 #include "cmFileLock.h"
 #include "cmFileLockResult.h"
 #include "cmGeneratorTarget.h"
@@ -40,6 +40,7 @@
 #include "cmTimestamp.h"
 #include "cmUVProcessChain.h"
 #include "cmValue.h"
+#include "cmake.h"
 
 using LoadQueriesAfter = cmInstrumentation::LoadQueriesAfter;
 
@@ -93,18 +94,13 @@
 cmInstrumentation::cmInstrumentation(std::string const& binary_dir,
                                      LoadQueriesAfter loadQueries)
 {
-  std::string const uuid =
-    cmExperimental::DataForFeature(cmExperimental::Feature::Instrumentation)
-      .Uuid;
   this->binaryDir = binary_dir;
-  this->timingDirv1 =
-    cmStrCat(this->binaryDir, "/.cmake/instrumentation-", uuid, "/v1");
+  this->timingDirv1 = cmStrCat(this->binaryDir, "/.cmake/instrumentation/v1");
   this->cdashDir = cmStrCat(this->timingDirv1, "/cdash");
   this->dataDir = cmStrCat(this->timingDirv1, "/data");
   if (cm::optional<std::string> configDir =
         cmSystemTools::GetCMakeConfigDirectory()) {
-    this->userTimingDirv1 =
-      cmStrCat(configDir.value(), "/instrumentation-", uuid, "/v1");
+    this->userTimingDirv1 = cmStrCat(configDir.value(), "/instrumentation/v1");
   }
   if (loadQueries == LoadQueriesAfter::Yes) {
     this->LoadQueries();
@@ -113,6 +109,7 @@
 
 void cmInstrumentation::LoadQueries()
 {
+  this->ResetQueries();
   auto const readJSONQueries = [this](std::string const& dir) {
     if (cmSystemTools::FileIsDirectory(dir) && this->ReadJSONQueries(dir)) {
       this->hasQuery = true;
@@ -125,35 +122,30 @@
   }
 }
 
+void cmInstrumentation::ResetQueries()
+{
+  this->hasQuery = false;
+  this->options.clear();
+  this->hooks.clear();
+  this->callbacks.clear();
+  this->queryFiles.clear();
+  this->errorMsg.clear();
+}
+
 void cmInstrumentation::CheckCDashVariable()
 {
   std::string envVal;
   if (cmSystemTools::GetEnv("CTEST_USE_INSTRUMENTATION", envVal) &&
       !cmIsOff(envVal)) {
-    if (cmSystemTools::GetEnv("CTEST_EXPERIMENTAL_INSTRUMENTATION", envVal)) {
-      std::string const uuid = cmExperimental::DataForFeature(
-                                 cmExperimental::Feature::Instrumentation)
-                                 .Uuid;
-      if (envVal == uuid) {
-        std::set<cmInstrumentationQuery::Option> options_ = {
-          cmInstrumentationQuery::Option::CDashSubmit,
-          cmInstrumentationQuery::Option::DynamicSystemInformation
-        };
-        if (cmSystemTools::GetEnv("CTEST_USE_VERBOSE_INSTRUMENTATION",
-                                  envVal) &&
-            !cmIsOff(envVal)) {
-          options_.insert(cmInstrumentationQuery::Option::CDashVerbose);
-        }
-        for (auto const& option : options_) {
-          this->AddOption(option);
-        }
-        std::set<cmInstrumentationQuery::Hook> hooks_ = {
-          cmInstrumentationQuery::Hook::PrepareForCDash
-        };
-        this->AddHook(cmInstrumentationQuery::Hook::PrepareForCDash);
-        this->WriteJSONQuery(options_, hooks_, {});
-      }
+    std::set<cmInstrumentationQuery::Option> options_ = {
+      cmInstrumentationQuery::Option::CDashSubmit
+    };
+    if (cmSystemTools::GetEnv("CTEST_USE_VERBOSE_INSTRUMENTATION", envVal) &&
+        !cmIsOff(envVal)) {
+      options_.insert(cmInstrumentationQuery::Option::CDashVerbose);
     }
+    std::set<cmInstrumentationQuery::Hook> hooks_;
+    this->WriteJSONQuery(options_, hooks_, {});
   }
 }
 
@@ -186,6 +178,13 @@
   auto query = cmInstrumentationQuery();
   query.ReadJSON(file, this->errorMsg, this->options, this->hooks,
                  this->callbacks);
+  if (this->HasOption(cmInstrumentationQuery::Option::CDashVerbose)) {
+    this->AddOption(cmInstrumentationQuery::Option::CDashSubmit);
+  }
+  if (this->HasOption(cmInstrumentationQuery::Option::CDashSubmit)) {
+    this->AddHook(cmInstrumentationQuery::Hook::PrepareForCDash);
+    this->AddOption(cmInstrumentationQuery::Option::DynamicSystemInformation);
+  }
   if (!this->errorMsg.empty()) {
     cmSystemTools::Error(cmStrCat(
       "Could not load instrumentation queries from ",
@@ -234,6 +233,8 @@
   Json::Value root;
   root["targets"] = this->DumpTargets(gg);
   root["custom"] = this->customContent;
+  root["project"] =
+    gg->GetCMakeInstance()->GetCacheDefinition("CMAKE_PROJECT_NAME").GetCStr();
   this->WriteInstrumentationJson(
     root, "data/content",
     cmStrCat("cmake-", this->ComputeSuffixTime(), ".json"));
@@ -322,6 +323,7 @@
   if (cmSystemTools::FileIsDirectory(dir)) {
     cmSystemTools::RemoveADirectory(dir);
   }
+  this->writtenJsonQueries = 0;
 }
 
 bool cmInstrumentation::HasQuery() const
@@ -346,6 +348,8 @@
     return 0;
   }
 
+  this->LockIndexing();
+
   // Touch index file immediately to claim snippets
   std::string suffix_time = ComputeSuffixTime();
   std::string const& index_name = cmStrCat("index-", suffix_time, ".json");
@@ -426,6 +430,8 @@
   this->RemoveOldFiles("content");
   this->RemoveOldFiles("trace");
 
+  this->indexLock.Release();
+
   return 0;
 }
 
@@ -465,11 +471,17 @@
     info.RunOSCheck();
     this->ranOSCheck = true;
   }
+  if (!this->ranSystemChecks) {
+    info.RunCPUCheck();
+    info.RunMemoryCheck();
+    this->ranSystemChecks = true;
+  }
   Json::Value infoRoot;
   infoRoot["familyId"] = info.GetFamilyID();
   infoRoot["hostname"] = info.GetHostname();
   infoRoot["is64Bits"] = info.Is64Bits();
   infoRoot["modelId"] = info.GetModelID();
+  infoRoot["modelName"] = info.GetModelName();
   infoRoot["numberOfLogicalCPU"] = info.GetNumberOfLogicalCPU();
   infoRoot["numberOfPhysicalCPU"] = info.GetNumberOfPhysicalCPU();
   infoRoot["OSName"] = info.GetOSName();
@@ -487,6 +499,14 @@
     static_cast<Json::Value::UInt64>(info.GetTotalVirtualMemory());
   infoRoot["vendorID"] = info.GetVendorID();
   infoRoot["vendorString"] = info.GetVendorString();
+
+  // Record fields unable to be determined as null JSON objects.
+  for (std::string const& field : infoRoot.getMemberNames()) {
+    if ((infoRoot[field].isNumeric() && infoRoot[field].asInt64() <= 0) ||
+        (infoRoot[field].isString() && infoRoot[field].asString().empty())) {
+      infoRoot[field] = Json::nullValue;
+    }
+  }
   root["staticSystemInformation"] = infoRoot;
 }
 
@@ -727,15 +747,21 @@
 
   // Don't write configure snippet until generate time
   if (command_type == "configure") {
-    this->configureSnippetData = root;
-    this->configureSnippetName = file_name;
+    this->configureSnippetData[file_name] = root;
   } else {
     // Add reference to CMake content and write out configure snippet after
     // generate
     if (command_type == "generate") {
-      addCMakeContent(this->configureSnippetData);
-      this->WriteInstrumentationJson(this->configureSnippetData, "data",
-                                     this->configureSnippetName);
+      for (auto it = this->configureSnippetData.begin();
+           it != this->configureSnippetData.end(); ++it) {
+        if (std::next(it) != this->configureSnippetData.end()) {
+          it->second["cmakeContent"] = Json::nullValue;
+        } else {
+          addCMakeContent(it->second);
+        }
+        this->WriteInstrumentationJson(it->second, "data", it->first);
+      }
+      this->configureSnippetData.clear();
     }
     this->WriteInstrumentationJson(root, "data", file_name);
   }
@@ -794,6 +820,7 @@
   return type == cmStateEnums::TargetType::EXECUTABLE ||
     type == cmStateEnums::TargetType::SHARED_LIBRARY ||
     type == cmStateEnums::TargetType::STATIC_LIBRARY ||
+    type == cmStateEnums::TargetType::MODULE_LIBRARY ||
     type == cmStateEnums::TargetType::OBJECT_LIBRARY;
 }
 
@@ -814,7 +841,7 @@
   // preBuild Hook
   if (this->LockBuildDaemon()) {
     // Release lock before spawning the build daemon, to prevent blocking it.
-    this->lock.Release();
+    this->buildLock.Release();
     this->CollectTimingData(cmInstrumentationQuery::Hook::PreBuild);
   }
 
@@ -836,11 +863,26 @@
 // Prevent multiple build daemons from running simultaneously
 bool cmInstrumentation::LockBuildDaemon()
 {
-  std::string const lockFile = cmStrCat(this->timingDirv1, "/.build.lock");
-  if (!cmSystemTools::FileExists(lockFile)) {
-    cmSystemTools::Touch(lockFile, true);
+  // 0 = non-blocking, 0s timeout
+  return this->AcquireLock(".build.lock", this->buildLock, 0);
+}
+
+// Prevent multiple index processes from claiming snippets simultaneously
+bool cmInstrumentation::LockIndexing()
+{
+  return this->AcquireLock(".index.lock", this->indexLock,
+                           // -1 = no timeout
+                           static_cast<unsigned long>(-1));
+}
+
+bool cmInstrumentation::AcquireLock(std::string const& lock_file,
+                                    cmFileLock& lock, unsigned long timeout)
+{
+  std::string const lock_path = cmStrCat(this->timingDirv1, '/', lock_file);
+  if (!cmSystemTools::FileExists(lock_path)) {
+    cmSystemTools::Touch(lock_path, true);
   }
-  return this->lock.Lock(lockFile, 0).IsOk();
+  return lock.Lock(lock_path, timeout).IsOk();
 }
 
 /*
@@ -867,6 +909,7 @@
   int ret = this->InstrumentCommand(
     "build", {}, [waitForBuild]() { return waitForBuild(); }, cm::nullopt,
     cm::nullopt, LoadQueriesAfter::Yes);
+  this->buildLock.Release();
   this->CollectTimingData(cmInstrumentationQuery::Hook::PostBuild);
   return ret;
 }
diff --git a/Source/cmInstrumentation.h b/Source/cmInstrumentation.h
index aba0f37..c99a221 100644
--- a/Source/cmInstrumentation.h
+++ b/Source/cmInstrumentation.h
@@ -70,6 +70,7 @@
   int CollectTimingData(cmInstrumentationQuery::Hook hook);
   int SpawnBuildDaemon();
   bool LockBuildDaemon();
+  bool LockIndexing();
   int CollectTimingAfterBuild(int ppid);
   void AddHook(cmInstrumentationQuery::Hook hook);
   void AddOption(cmInstrumentationQuery::Option option);
@@ -87,6 +88,8 @@
 
 private:
   Json::Value ReadJsonSnippet(std::string const& file_name);
+  bool AcquireLock(std::string const& lock_file, cmFileLock& lock,
+                   unsigned long timeout);
   void WriteInstrumentationJson(Json::Value& index,
                                 std::string const& directory,
                                 std::string const& file_name);
@@ -111,6 +114,7 @@
                               Json::Value const& snippetData);
   size_t AssignTargetToTraceThread(std::vector<uint64_t>& workers,
                                    uint64_t timeStart, uint64_t duration);
+  void ResetQueries();
   std::string binaryDir;
   std::string timingDirv1;
   std::string userTimingDirv1;
@@ -126,13 +130,13 @@
   bool hasQuery = false;
   bool ranSystemChecks = false;
   bool ranOSCheck = false;
-  Json::Value customContent;
-  Json::Value configureSnippetData;
-  std::string configureSnippetName;
+  Json::Value customContent = Json::objectValue;
+  std::map<std::string, Json::Value> configureSnippetData;
 #ifndef CMAKE_BOOTSTRAP
   std::unique_ptr<cmsys::SystemInformation> systemInformation;
   cmsys::SystemInformation& GetSystemInformation();
 #endif
   int writtenJsonQueries = 0;
-  cmFileLock lock;
+  cmFileLock buildLock; // non-blocking
+  cmFileLock indexLock; // never held alongside buildLock
 };
diff --git a/Source/cmInstrumentationCommand.cxx b/Source/cmInstrumentationCommand.cxx
index 8d0813f..e48b3c4 100644
--- a/Source/cmInstrumentationCommand.cxx
+++ b/Source/cmInstrumentationCommand.cxx
@@ -3,7 +3,6 @@
 #include "cmInstrumentationCommand.h"
 
 #include <algorithm>
-#include <cctype>
 #include <cstdlib>
 #include <functional>
 #include <set>
@@ -14,28 +13,27 @@
 #include <cm3p/json/reader.h>
 #include <cm3p/json/value.h>
 
+#include "cmsys/String.h"
+
 #include "cmArgumentParser.h"
 #include "cmArgumentParserTypes.h"
 #include "cmExecutionStatus.h"
-#include "cmExperimental.h"
 #include "cmInstrumentation.h"
 #include "cmInstrumentationQuery.h"
 #include "cmList.h"
 #include "cmMakefile.h"
+#include "cmMessageType.h"
 #include "cmStringAlgorithms.h"
 #include "cmValue.h"
 #include "cmake.h"
 
 namespace {
 
-bool isCharDigit(char ch)
-{
-  return std::isdigit(static_cast<unsigned char>(ch));
-}
 bool validateVersion(std::string const& key, std::string const& versionString,
                      int& version, cmExecutionStatus& status)
 {
-  if (!std::all_of(versionString.begin(), versionString.end(), isCharDigit)) {
+  if (!std::all_of(versionString.begin(), versionString.end(),
+                   cmsysString_isdigit)) {
     status.SetError(cmStrCat("given a non-integer ", key, '.'));
     return false;
   }
@@ -68,16 +66,15 @@
 bool cmInstrumentationCommand(std::vector<std::string> const& args,
                               cmExecutionStatus& status)
 {
-  // if (status->GetMakefile().GetPropertyKeys) {
-  if (!cmExperimental::HasSupportEnabled(
-        status.GetMakefile(), cmExperimental::Feature::Instrumentation)) {
-    status.SetError(
-      "requires the experimental Instrumentation flag to be enabled");
+  if (args.empty()) {
+    status.SetError("must be called with arguments.");
     return false;
   }
 
-  if (args.empty()) {
-    status.SetError("must be called with arguments.");
+  if (status.GetMakefile().GetCMakeInstance()->GetInInitialCache()) {
+    status.GetMakefile().IssueMessage(
+      MessageType::FATAL_ERROR,
+      "Cannot invoke cmake_instrumentation() within an initial cache file.");
     return false;
   }
 
diff --git a/Source/cmInstrumentationQuery.cxx b/Source/cmInstrumentationQuery.cxx
index d453d5c..6876870 100644
--- a/Source/cmInstrumentationQuery.cxx
+++ b/Source/cmInstrumentationQuery.cxx
@@ -20,9 +20,9 @@
   "cdashVerbose", "trace"
 };
 std::vector<std::string> const cmInstrumentationQuery::HookString{
-  "postGenerate",     "preBuild",        "postBuild",
-  "preCMakeBuild",    "postCMakeBuild",  "postCTest",
-  "postCMakeInstall", "prepareForCDash", "manual"
+  "postGenerate",    "preBuild",  "postBuild",        "preCMakeBuild",
+  "postCMakeBuild",  "postCTest", "postCMakeInstall", "postCMakeWorkflow",
+  "prepareForCDash", "manual"
 };
 
 namespace ErrorMessages {
diff --git a/Source/cmInstrumentationQuery.h b/Source/cmInstrumentationQuery.h
index feeb22d..9e82bda 100644
--- a/Source/cmInstrumentationQuery.h
+++ b/Source/cmInstrumentationQuery.h
@@ -31,6 +31,7 @@
     PostCMakeBuild,
     PostCTest,
     PostCMakeInstall,
+    PostCMakeWorkflow,
     PrepareForCDash,
     Manual
   };
diff --git a/Source/cmLDConfigLDConfigTool.cxx b/Source/cmLDConfigLDConfigTool.cxx
index dcc17e3..4afdce3 100644
--- a/Source/cmLDConfigLDConfigTool.cxx
+++ b/Source/cmLDConfigLDConfigTool.cxx
@@ -51,7 +51,7 @@
 
   std::string line;
   static cmsys::RegularExpression const regex("^([^\t:]*):");
-  cmUVPipeIStream output(process.GetLoop(), process.OutputStream());
+  cmUVIStream output(process.OutputStream());
   while (std::getline(output, line)) {
     cmsys::RegularExpressionMatch match;
     if (regex.find(line.c_str(), match)) {
diff --git a/Source/cmLinkLineDeviceComputer.cxx b/Source/cmLinkLineDeviceComputer.cxx
index daacea5..6fb481b 100644
--- a/Source/cmLinkLineDeviceComputer.cxx
+++ b/Source/cmLinkLineDeviceComputer.cxx
@@ -45,7 +45,7 @@
   // * '-pthread' => drop
   // * '-a' => drop
   // * '-framework Name' (as one string) => drop
-  return (!cmHasLiteralPrefix(item, "-") || //
+  return (!cmHasPrefix(item, '-') ||        //
           cmHasLiteralPrefix(item, "-l") || //
           cmHasLiteralPrefix(item, "-L") || //
           cmHasLiteralPrefix(item, "--library"));
diff --git a/Source/cmList.cxx b/Source/cmList.cxx
index 9087457..af1d89a 100644
--- a/Source/cmList.cxx
+++ b/Source/cmList.cxx
@@ -114,9 +114,9 @@
 
   StringFilter GetCaseFilter(CaseSensitivity sensitivity)
   {
-    constexpr std::string (*filter)(std::string const&) =
-      cmSystemTools::LowerCase;
-    return (sensitivity == CaseSensitivity::INSENSITIVE) ? filter : nullptr;
+    return (sensitivity == CaseSensitivity::INSENSITIVE)
+      ? cmsys::SystemTools::LowerCase
+      : nullptr;
   }
 
   using ComparisonFunction =
diff --git a/Source/cmList.h b/Source/cmList.h
index e94914c..74a3420 100644
--- a/Source/cmList.h
+++ b/Source/cmList.h
@@ -813,6 +813,8 @@
 
   void resize(size_type count) { this->Values.resize(count); }
 
+  void reserve(size_type count) { this->Values.reserve(count); }
+
   enum class FilterMode
   {
     INCLUDE,
diff --git a/Source/cmLoadCacheCommand.cxx b/Source/cmLoadCacheCommand.cxx
index d88dbb3..5a665cb 100644
--- a/Source/cmLoadCacheCommand.cxx
+++ b/Source/cmLoadCacheCommand.cxx
@@ -8,6 +8,7 @@
 
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
+#include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmSystemTools.h"
 #include "cmake.h"
@@ -31,8 +32,9 @@
     return ReadWithPrefix(args, status);
   }
 
-  if (status.GetMakefile().GetCMakeInstance()->GetWorkingMode() ==
-      cmake::SCRIPT_MODE) {
+  cmState::Role const role =
+    status.GetMakefile().GetCMakeInstance()->GetState()->GetRole();
+  if (role != cmState::Role::Project) {
     status.SetError(
       "Only load_cache(READ_WITH_PREFIX) may be used in script mode");
     return false;
diff --git a/Source/cmLocalFastbuildGenerator.cxx b/Source/cmLocalFastbuildGenerator.cxx
index b2e4a69..599fa95 100644
--- a/Source/cmLocalFastbuildGenerator.cxx
+++ b/Source/cmLocalFastbuildGenerator.cxx
@@ -127,3 +127,9 @@
   }
   return converted;
 }
+
+std::string cmLocalFastbuildGenerator::MaybeRelativeToWorkDir(
+  std::string const& path) const
+{
+  return this->MaybeRelativeToTopBinDir(path);
+}
diff --git a/Source/cmLocalFastbuildGenerator.h b/Source/cmLocalFastbuildGenerator.h
index 2821786..4bdb59a 100644
--- a/Source/cmLocalFastbuildGenerator.h
+++ b/Source/cmLocalFastbuildGenerator.h
@@ -33,4 +33,5 @@
 private:
   std::string ConvertToIncludeReference(
     std::string const& path, cmOutputConverter::OutputFormat format) override;
+  std::string MaybeRelativeToWorkDir(std::string const& path) const override;
 };
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 473de56..2af0dc0 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -5,11 +5,11 @@
 #include <algorithm>
 #include <array>
 #include <cassert>
-#include <cctype>
 #include <cstdio>
 #include <cstdlib>
 #include <initializer_list>
 #include <iterator>
+#include <queue>
 #include <sstream>
 #include <unordered_set>
 #include <utility>
@@ -22,6 +22,7 @@
 #include <cmext/string_view>
 
 #include "cmsys/RegularExpression.hxx"
+#include "cmsys/String.h"
 
 #include "cmAlgorithms.h"
 #include "cmCMakePath.h"
@@ -50,6 +51,7 @@
 #include "cmSourceFile.h"
 #include "cmSourceFileLocation.h"
 #include "cmSourceFileLocationKind.h"
+#include "cmSourceGroup.h"
 #include "cmStandardLevelResolver.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
@@ -319,6 +321,13 @@
   }
 }
 
+#ifndef CMAKE_BOOTSTRAP
+void cmLocalGenerator::ResolveSourceGroupGenex()
+{
+  this->Makefile->ResolveSourceGroupGenex(this);
+}
+#endif
+
 void cmLocalGenerator::GenerateTestFiles()
 {
   if (!this->Makefile->IsOn("CMAKE_TESTING_ENABLED")) {
@@ -1396,24 +1405,18 @@
   std::string const& config, std::string const& linkLanguage,
   cmGeneratorTarget* target)
 {
-  std::string const configUpper = cmSystemTools::UpperCase(config);
   std::vector<BT<std::string>> flags;
   if (linkLanguage != "Swift" && !this->IsSplitSwiftBuild()) {
     std::string staticLibFlags;
-    this->AppendFlags(
-      staticLibFlags,
-      this->Makefile->GetSafeDefinition("CMAKE_STATIC_LINKER_FLAGS"));
-    if (!configUpper.empty()) {
-      std::string name = "CMAKE_STATIC_LINKER_FLAGS_" + configUpper;
-      this->AppendFlags(staticLibFlags,
-                        this->Makefile->GetSafeDefinition(name));
-    }
+    this->AddConfigVariableFlags(staticLibFlags, "CMAKE_STATIC_LINKER_FLAGS",
+                                 config);
     if (!staticLibFlags.empty()) {
       flags.emplace_back(std::move(staticLibFlags));
     }
   }
 
   std::string staticLibFlags;
+  std::string const configUpper = cmSystemTools::UpperCase(config);
   this->AppendFlags(staticLibFlags,
                     target->GetSafeProperty("STATIC_LIBRARY_FLAGS"));
   if (!configUpper.empty()) {
@@ -1495,8 +1498,6 @@
 {
   std::string const configUpper = cmSystemTools::UpperCase(config);
   cmComputeLinkInformation* pcli = target->GetLinkInformation(config);
-  char const* libraryLinkVariable =
-    "CMAKE_SHARED_LINKER_FLAGS"; // default to shared library
 
   std::string const linkLanguage =
     linkLineComputer->GetLinkerLanguage(target, config);
@@ -1514,33 +1515,25 @@
       linkFlags = this->GetStaticLibraryFlags(config, linkLanguage, target);
       break;
     case cmStateEnums::MODULE_LIBRARY:
-      libraryLinkVariable = "CMAKE_MODULE_LINKER_FLAGS";
       CM_FALLTHROUGH;
     case cmStateEnums::SHARED_LIBRARY: {
       if (this->IsSplitSwiftBuild() || linkLanguage != "Swift") {
         std::string libFlags;
-        this->AddConfigVariableFlags(libFlags, libraryLinkVariable, target,
-                                     cmBuildStep::Link, linkLanguage, config);
+        this->AddTargetTypeLinkerFlags(libFlags, target, linkLanguage, config);
         if (!libFlags.empty()) {
           linkFlags.emplace_back(std::move(libFlags));
         }
       }
 
-      std::string sharedLibFlags;
-      cmValue targetLinkFlags = target->GetProperty("LINK_FLAGS");
-      if (targetLinkFlags) {
-        sharedLibFlags += *targetLinkFlags;
-        sharedLibFlags += " ";
-      }
-      if (!configUpper.empty()) {
-        targetLinkFlags =
-          target->GetProperty(cmStrCat("LINK_FLAGS_", configUpper));
-        if (targetLinkFlags) {
-          sharedLibFlags += *targetLinkFlags;
-          sharedLibFlags += " ";
-        }
+      std::string langLinkFlags;
+      this->AddPerLanguageLinkFlags(langLinkFlags, target, linkLanguage,
+                                    config);
+      if (!langLinkFlags.empty()) {
+        linkFlags.emplace_back(std::move(langLinkFlags));
       }
 
+      std::string sharedLibFlags;
+      this->AddTargetPropertyLinkFlags(sharedLibFlags, target, config);
       if (!sharedLibFlags.empty()) {
         this->GetGlobalGenerator()->EncodeLiteral(sharedLibFlags);
         linkFlags.emplace_back(std::move(sharedLibFlags));
@@ -1559,23 +1552,21 @@
       }
     } break;
     case cmStateEnums::EXECUTABLE: {
-      if (linkLanguage.empty()) {
-        cmSystemTools::Error(
-          "CMake can not determine linker language for target: " +
-          target->GetName());
-        return;
-      }
-
       if (linkLanguage != "Swift") {
         std::string exeFlags;
-        this->AddConfigVariableFlags(exeFlags, "CMAKE_EXE_LINKER_FLAGS",
-                                     target, cmBuildStep::Link, linkLanguage,
-                                     config);
+        this->AddTargetTypeLinkerFlags(exeFlags, target, linkLanguage, config);
         if (!exeFlags.empty()) {
           linkFlags.emplace_back(std::move(exeFlags));
         }
       }
 
+      std::string langLinkFlags;
+      this->AddPerLanguageLinkFlags(langLinkFlags, target, linkLanguage,
+                                    config);
+      if (!langLinkFlags.empty()) {
+        linkFlags.emplace_back(std::move(langLinkFlags));
+      }
+
       {
         auto exeType = cmStrCat(
           "CMAKE_", linkLanguage, "_CREATE_",
@@ -1614,19 +1605,7 @@
         exeFlags += " ";
       }
 
-      cmValue targetLinkFlags = target->GetProperty("LINK_FLAGS");
-      if (targetLinkFlags) {
-        exeFlags += *targetLinkFlags;
-        exeFlags += " ";
-      }
-      if (!configUpper.empty()) {
-        targetLinkFlags =
-          target->GetProperty(cmStrCat("LINK_FLAGS_", configUpper));
-        if (targetLinkFlags) {
-          exeFlags += *targetLinkFlags;
-          exeFlags += " ";
-        }
-      }
+      this->AddTargetPropertyLinkFlags(exeFlags, target, config);
 
       if (!exeFlags.empty()) {
         this->GetGlobalGenerator()->EncodeLiteral(exeFlags);
@@ -2342,7 +2321,7 @@
   if (name.empty()) {
     return false;
   }
-  if (cmSystemTools::GetFilenameLastExtension(name) == ".exe") {
+  if (cmHasSuffix(name, ".exe"_s)) {
     name = cmSystemTools::GetFilenameWithoutLastExtension(name);
   }
 
@@ -2577,7 +2556,8 @@
 void cmLocalGenerator::AppendFlags(std::string& flags,
                                    std::string const& newFlags) const
 {
-  bool allSpaces = std::all_of(newFlags.begin(), newFlags.end(), cmIsSpace);
+  bool allSpaces =
+    std::all_of(newFlags.begin(), newFlags.end(), cmsysString_isspace);
 
   if (!newFlags.empty() && !allSpaces) {
     if (!flags.empty()) {
@@ -2603,6 +2583,25 @@
     this->EscapeForShell(rawFlag, false, false, false, this->IsNinjaMulti()));
 }
 
+void cmLocalGenerator::AppendLinkFlagsWithParsing(
+  std::string& flags, std::string const& newFlags,
+  cmGeneratorTarget const* target, std::string const& language)
+{
+  std::vector<std::string> options;
+  cmSystemTools::ParseUnixCommandLine(newFlags.c_str(), options);
+  this->SetLinkScriptShell(this->GlobalGenerator->GetUseLinkScript());
+  std::vector<BT<std::string>> optionsWithBT{ options.size() };
+  std::transform(options.cbegin(), options.cend(), optionsWithBT.begin(),
+                 [](std::string const& item) -> BT<std::string> {
+                   return BT<std::string>{ item };
+                 });
+  target->ResolveLinkerWrapper(optionsWithBT, language);
+  for (auto const& item : optionsWithBT) {
+    this->AppendFlagEscape(flags, item.Value);
+  }
+  this->SetLinkScriptShell(false);
+}
+
 void cmLocalGenerator::AppendFlags(std::string& flags,
                                    std::string const& newFlags,
                                    std::string const& name,
@@ -2631,19 +2630,7 @@
       break;
     case cmPolicies::NEW:
       if (compileOrLink == cmBuildStep::Link) {
-        std::vector<std::string> options;
-        cmSystemTools::ParseUnixCommandLine(newFlags.c_str(), options);
-        this->SetLinkScriptShell(this->GlobalGenerator->GetUseLinkScript());
-        std::vector<BT<std::string>> optionsWithBT{ options.size() };
-        std::transform(options.cbegin(), options.cend(), optionsWithBT.begin(),
-                       [](std::string const& item) -> BT<std::string> {
-                         return BT<std::string>{ item };
-                       });
-        target->ResolveLinkerWrapper(optionsWithBT, language);
-        for (auto const& item : optionsWithBT) {
-          this->AppendFlagEscape(flags, item.Value);
-        }
-        this->SetLinkScriptShell(false);
+        this->AppendLinkFlagsWithParsing(flags, newFlags, target, language);
       } else {
         this->AppendFlags(flags, newFlags);
       }
@@ -3371,6 +3358,67 @@
   }
 }
 
+void cmLocalGenerator::AddPerLanguageLinkFlags(std::string& flags,
+                                               cmGeneratorTarget const* target,
+                                               std::string const& lang,
+                                               std::string const& config)
+{
+  switch (target->GetType()) {
+    case cmStateEnums::MODULE_LIBRARY:
+    case cmStateEnums::SHARED_LIBRARY:
+    case cmStateEnums::EXECUTABLE:
+      break;
+    default:
+      return;
+  }
+
+  std::string langLinkFlags =
+    this->Makefile->GetSafeDefinition(cmStrCat("CMAKE_", lang, "_LINK_FLAGS"));
+
+  switch (target->GetPolicyStatusCMP0210()) {
+    case cmPolicies::WARN:
+      // WARN only when CMAKE_<LANG>_LINK_FLAGS is set, and when the current
+      // target is not an executable, and CMAKE_<LANG>_LINK_FLAGS is not equal
+      // to CMAKE_EXECUTABLE_CREATE_<LANG>_FLAGS. This warns users trying to
+      // use the NEW behavior on old projects (since CMake will be ignoring
+      // their wishes), while also exempting cases when the latter variable
+      // (substituted for the former spelling under the NEW behavior) is being
+      // used legitimately by CMake.
+      // Additionally, WARN at most once per language, instead of on every
+      // target.
+      if (!langLinkFlags.empty() &&
+          target->GetType() != cmStateEnums::EXECUTABLE &&
+          langLinkFlags !=
+            this->Makefile->GetSafeDefinition(
+              cmStrCat("CMAKE_EXECUTABLE_CREATE_", lang, "_FLAGS")) &&
+          this->GlobalGenerator->ShouldWarnCMP0210(lang)) {
+        this->IssueMessage(
+          MessageType::AUTHOR_WARNING,
+          cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0210), "\n",
+                   "For compatibility with older versions of CMake, ",
+                   "CMAKE_", lang, "_LINK_FLAGS will be ignored for all ",
+                   "non-EXECUTABLE targets which use these flags."));
+      }
+      CM_FALLTHROUGH;
+    case cmPolicies::OLD:
+      // OLD behavior is to do nothing here, since the use of
+      // CMAKE_<LANG>_LINK_FLAGS for EXECUTABLEs is handled elsewhere.
+      break;
+    case cmPolicies::NEW:
+      // NEW behavior is to support per-language link flags for all target
+      // types.
+      this->AppendLinkFlagsWithParsing(flags, langLinkFlags, target, lang);
+      if (!config.empty()) {
+        std::string lankLinkFlagsConfig =
+          this->Makefile->GetSafeDefinition(cmStrCat(
+            "CMAKE_", lang, "_LINK_FLAGS_", cmSystemTools::UpperCase(config)));
+        this->AppendLinkFlagsWithParsing(flags, lankLinkFlagsConfig, target,
+                                         lang);
+      }
+      break;
+  }
+}
+
 void cmLocalGenerator::AppendTargetCreationLinkFlags(
   std::string& flags, cmGeneratorTarget const* target,
   std::string const& linkLanguage)
@@ -3394,7 +3442,9 @@
       }
       break;
     case cmStateEnums::EXECUTABLE:
-      createFlagsVar = cmStrCat("CMAKE_", linkLanguage, "_LINK_FLAGS");
+      createFlagsVar = target->GetPolicyStatusCMP0210() == cmPolicies::NEW
+        ? cmStrCat("CMAKE_EXECUTABLE_CREATE_", linkLanguage, "_FLAGS")
+        : cmStrCat("CMAKE_", linkLanguage, "_LINK_FLAGS");
       createFlagsVal = this->Makefile->GetDefinition(createFlagsVar);
       break;
     default:
@@ -3444,8 +3494,7 @@
     }
   } else if (linkerType != "DEFAULT"_s) {
     auto isCMakeLinkerType = [](std::string const& type) -> bool {
-      return std::all_of(type.cbegin(), type.cend(),
-                         [](char c) { return std::isupper(c); });
+      return std::all_of(type.cbegin(), type.cend(), cmsysString_isupper);
     };
     if (isCMakeLinkerType(linkerType)) {
       this->IssueMessage(
@@ -3462,6 +3511,45 @@
   }
 }
 
+void cmLocalGenerator::AddTargetTypeLinkerFlags(
+  std::string& flags, cmGeneratorTarget const* target, std::string const& lang,
+  std::string const& config)
+{
+  std::string linkerFlagsVar;
+  switch (target->GetType()) {
+    case cmStateEnums::EXECUTABLE:
+      linkerFlagsVar = "CMAKE_EXE_LINKER_FLAGS";
+      break;
+    case cmStateEnums::SHARED_LIBRARY:
+      linkerFlagsVar = "CMAKE_SHARED_LINKER_FLAGS";
+      break;
+    case cmStateEnums::MODULE_LIBRARY:
+      linkerFlagsVar = "CMAKE_MODULE_LINKER_FLAGS";
+      break;
+    default:
+      return;
+  }
+  this->AddConfigVariableFlags(flags, linkerFlagsVar, target,
+                               cmBuildStep::Link, lang, config);
+}
+
+void cmLocalGenerator::AddTargetPropertyLinkFlags(
+  std::string& flags, cmGeneratorTarget const* target,
+  std::string const& config)
+{
+  cmValue targetLinkFlags = target->GetProperty("LINK_FLAGS");
+  if (targetLinkFlags) {
+    this->AppendFlags(flags, *targetLinkFlags);
+  }
+  if (!config.empty()) {
+    cmValue targetLinkFlagsConfig = target->GetProperty(
+      cmStrCat("LINK_FLAGS_", cmSystemTools::UpperCase(config)));
+    if (targetLinkFlagsConfig) {
+      this->AppendFlags(flags, *targetLinkFlagsConfig);
+    }
+  }
+}
+
 void cmLocalGenerator::AppendIPOLinkerFlags(std::string& flags,
                                             cmGeneratorTarget* target,
                                             std::string const& config,
@@ -4097,6 +4185,54 @@
   return ssin;
 }
 
+void cmLocalGenerator::ComputeSourceGroupSearchIndex()
+{
+#if !defined(CMAKE_BOOTSTRAP)
+  SourceGroupVector const& sourceGroups = this->Makefile->GetSourceGroups();
+
+  // Build lookup index from sources to source groups
+  std::queue<cmSourceGroup*> sgToVisit;
+  for (auto const& group : sourceGroups) {
+    cmSourceGroup* cmSourceGroup = group.get();
+    sgToVisit.emplace(cmSourceGroup);
+  }
+
+  while (!sgToVisit.empty()) {
+    cmSourceGroup* sourceGroup = sgToVisit.front();
+    sgToVisit.pop();
+    for (auto const& sgChild : sourceGroup->GetGroupChildren()) {
+      sgToVisit.emplace(sgChild.get());
+    }
+    for (std::string const& source : sourceGroup->GetGroupFiles()) {
+      this->SourceGroupSearchIndex.emplace(source, sourceGroup);
+    }
+  }
+#endif
+}
+
+cmSourceGroup* cmLocalGenerator::FindSourceGroup(std::string const& source)
+{
+#if !defined(CMAKE_BOOTSTRAP)
+  auto const indexIt = SourceGroupSearchIndex.find(source);
+  if (indexIt != SourceGroupSearchIndex.cend()) {
+    if (cmSourceGroup* result = indexIt->second) {
+      return result;
+    }
+  }
+
+  cmSourceGroup* sourceGroup =
+    cmSourceGroup::FindSourceGroup(source, this->Makefile->GetSourceGroups());
+  if (sourceGroup) {
+    // Update index if we have a miss
+    SourceGroupSearchIndex.emplace(source, sourceGroup);
+  }
+  return sourceGroup;
+#else
+  static_cast<void>(source);
+  return nullptr;
+#endif
+}
+
 std::string& cmLocalGenerator::CreateSafeUniqueObjectFileName(
   std::string const& sin, std::string const& dir_max)
 {
@@ -4561,8 +4697,6 @@
   cmSourceFile const& source) const
 {
   std::string objectName = this->GetRelativeSourceFileName(source);
-  std::string objectFileName =
-    cmSystemTools::GetFilenameName(source.GetFullPath());
   cmCryptoHash objNameHasher(cmCryptoHash::AlgoSHA3_512);
   std::string terseObjectName =
     objNameHasher.HashString(objectName).substr(0, 8);
@@ -5068,7 +5202,7 @@
   std::vector<std::string> computedObjects;
   computedObjects.reserve(ispcSuffixes.size());
 
-  auto extension = cmSystemTools::GetFilenameLastExtension(objectName);
+  auto extension = cmSystemTools::GetFilenameLastExtensionView(objectName);
 
   // We can't use cmSystemTools::GetFilenameWithoutLastExtension as it
   // drops any directories in objectName
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index d9726ff..50e710f 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -41,6 +41,7 @@
 struct cmObjectLocations;
 class cmRulePlaceholderExpander;
 class cmSourceFile;
+class cmSourceGroup;
 class cmState;
 class cmTarget;
 class cmake;
@@ -84,6 +85,13 @@
    */
   void TraceDependencies() const;
 
+#ifndef CMAKE_BOOTSTRAP
+  /**
+   * Resolve source group genex.
+   */
+  void ResolveSourceGroupGenex();
+#endif
+
   virtual void AddHelperCommands() {}
 
   /**
@@ -162,6 +170,10 @@
    * Append flags after parsing, prefixes processing (like LINKER:) and
    * escaping
    */
+  void AppendLinkFlagsWithParsing(std::string& flags,
+                                  std::string const& newFlags,
+                                  cmGeneratorTarget const* target,
+                                  std::string const& lang);
   void AppendFlags(std::string& flags, std::string const& newFlags,
                    std::string const& name, cmGeneratorTarget const* target,
                    cmBuildStep compileOrLink, std::string const& lang);
@@ -169,12 +181,23 @@
   void AddPchDependencies(cmGeneratorTarget* target);
   void AddUnityBuild(cmGeneratorTarget* target);
   virtual void AddXCConfigSources(cmGeneratorTarget* /* target */) {}
+  void AddPerLanguageLinkFlags(std::string& flags,
+                               cmGeneratorTarget const* target,
+                               std::string const& lang,
+                               std::string const& config);
   void AppendTargetCreationLinkFlags(std::string& flags,
                                      cmGeneratorTarget const* target,
                                      std::string const& linkLanguage);
   void AppendLinkerTypeFlags(std::string& flags, cmGeneratorTarget* target,
                              std::string const& config,
                              std::string const& linkLanguage);
+  void AddTargetTypeLinkerFlags(std::string& flags,
+                                cmGeneratorTarget const* target,
+                                std::string const& lang,
+                                std::string const& config);
+  void AddTargetPropertyLinkFlags(std::string& flags,
+                                  cmGeneratorTarget const* target,
+                                  std::string const& config);
   void AppendIPOLinkerFlags(std::string& flags, cmGeneratorTarget* target,
                             std::string const& config,
                             std::string const& lang);
@@ -566,6 +589,16 @@
 
   std::string CreateSafeObjectFileName(std::string const& sin) const;
 
+  /**
+   * Build the search index from source files to source groups
+   */
+  void ComputeSourceGroupSearchIndex();
+
+  /**
+   * find what source group this source is in
+   */
+  cmSourceGroup* FindSourceGroup(std::string const& source);
+
 protected:
   // The default implementation converts to a Windows shortpath to
   // help older toolchains handle spaces and such.  A generator may
@@ -624,6 +657,12 @@
 
   bool EmitUniversalBinaryFlags;
 
+#if !defined(CMAKE_BOOTSTRAP)
+  // Map from source file path to source group for lookup acceleration
+  using SourceGroupMap = std::unordered_map<std::string, cmSourceGroup*>;
+  SourceGroupMap SourceGroupSearchIndex;
+#endif
+
 private:
   /**
    * See LinearGetSourceFileWithOutput for background information
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index 4f186a8..b6cc3a6 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -489,7 +489,7 @@
   auto it = std::find_if(args.cbegin(), args.cend(),
                          [](std::string const& arg) -> bool {
                            // FIXME: Detect more windows shell operators.
-                           return cmHasLiteralPrefix(arg, ">");
+                           return cmHasPrefix(arg, '>');
                          });
   return it != args.cend();
 }
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 39c842f..567ce3b 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -3,7 +3,6 @@
 #include "cmLocalVisualStudio7Generator.h"
 
 #include <algorithm>
-#include <cassert>
 #include <cstring>
 #include <functional>
 #include <sstream>
@@ -967,34 +966,12 @@
     static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
   std::string temp;
   std::string extraLinkOptions;
-  if (target->GetType() == cmStateEnums::EXECUTABLE) {
-    this->AddConfigVariableFlags(extraLinkOptions, "CMAKE_EXE_LINKER_FLAGS",
-                                 target, cmBuildStep::Link, linkLanguage,
+  this->AddTargetTypeLinkerFlags(extraLinkOptions, target, linkLanguage,
                                  configName);
-  }
-  if (target->GetType() == cmStateEnums::SHARED_LIBRARY) {
-    this->AddConfigVariableFlags(extraLinkOptions, "CMAKE_SHARED_LINKER_FLAGS",
-                                 target, cmBuildStep::Link, linkLanguage,
-                                 configName);
-  }
-  if (target->GetType() == cmStateEnums::MODULE_LIBRARY) {
-    this->AddConfigVariableFlags(extraLinkOptions, "CMAKE_MODULE_LINKER_FLAGS",
-                                 target, cmBuildStep::Link, linkLanguage,
-                                 configName);
-  }
+  this->AddPerLanguageLinkFlags(extraLinkOptions, target, linkLanguage,
+                                configName);
 
-  cmValue targetLinkFlags = target->GetProperty("LINK_FLAGS");
-  if (targetLinkFlags) {
-    extraLinkOptions += ' ';
-    extraLinkOptions += *targetLinkFlags;
-  }
-  std::string configTypeUpper = cmSystemTools::UpperCase(configName);
-  std::string linkFlagsConfig = cmStrCat("LINK_FLAGS_", configTypeUpper);
-  targetLinkFlags = target->GetProperty(linkFlagsConfig);
-  if (targetLinkFlags) {
-    extraLinkOptions += ' ';
-    extraLinkOptions += *targetLinkFlags;
-  }
+  this->AddTargetPropertyLinkFlags(extraLinkOptions, target, configName);
 
   std::vector<std::string> opts;
   target->GetLinkOptions(opts, configName,
@@ -1406,9 +1383,6 @@
   std::vector<std::string> configs =
     this->Makefile->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
 
-  // We may be modifying the source groups temporarily, so make a copy.
-  std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
-
   AllConfigSources sources;
   sources.Sources = target->GetAllConfigSources();
 
@@ -1450,21 +1424,21 @@
     }
     // Add the file to the list of sources.
     std::string const source = sf->GetFullPath();
-    cmSourceGroup* sourceGroup =
-      this->Makefile->FindSourceGroup(source, sourceGroups);
+    cmSourceGroup* sourceGroup = this->FindSourceGroup(source);
     sourceGroup->AssignSource(sf);
   }
 
   // open the project
-  this->WriteProjectStart(fout, libName, target, sourceGroups);
+  this->WriteProjectStart(fout, libName, target);
   // write the configuration information
   this->WriteConfigurations(fout, configs, libName, target);
 
   fout << "\t<Files>\n";
 
   // Loop through every source group.
+  SourceGroupVector const& sourceGroups = this->Makefile->GetSourceGroups();
   for (auto const& sg : sourceGroups) {
-    this->WriteGroup(&sg, target, fout, libName, configs, sources);
+    this->WriteGroup(sg.get(), target, fout, libName, configs, sources);
   }
 
   fout << "\t</Files>\n";
@@ -1511,8 +1485,8 @@
     std::string configUpper = cmSystemTools::UpperCase(config);
     cmLVS7GFileConfig fc;
 
-    std::string lang =
-      lg->GlobalGenerator->GetLanguageFromExtension(sf.GetExtension().c_str());
+    std::string lang = std::string(
+      lg->GlobalGenerator->GetLanguageFromExtension(sf.GetExtension()));
     std::string const& sourceLang = lg->GetSourceFileLanguage(sf);
     bool needForceLang = false;
     // source file does not match its extension language
@@ -1679,13 +1653,14 @@
   cmGlobalVisualStudio7Generator* gg =
     static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
   std::vector<cmSourceFile const*> const& sourceFiles = sg->GetSourceFiles();
-  std::vector<cmSourceGroup> const& children = sg->GetGroupChildren();
+  SourceGroupVector const& children = sg->GetGroupChildren();
 
   // Write the children to temporary output.
   bool hasChildrenWithSources = false;
   std::ostringstream tmpOut;
   for (auto const& child : children) {
-    if (this->WriteGroup(&child, target, tmpOut, libName, configs, sources)) {
+    if (this->WriteGroup(child.get(), target, tmpOut, libName, configs,
+                         sources)) {
       hasChildrenWithSources = true;
     }
   }
@@ -1705,17 +1680,19 @@
 
   // Loop through each source in the source group.
   for (cmSourceFile const* sf : sourceFiles) {
+    // We only need source group members that are part of this target.
+    auto si = sources.Index.find(sf);
+    if (si == sources.Index.end()) {
+      continue;
+    }
+
     std::string source = sf->GetFullPath();
 
     if (source != libName || target->GetType() == cmStateEnums::UTILITY ||
         target->GetType() == cmStateEnums::GLOBAL_TARGET ||
         target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
-      // Look up the source kind and configs.
-      auto map_it = sources.Index.find(sf);
-      // The map entry must exist because we populated it earlier.
-      assert(map_it != sources.Index.end());
       cmGeneratorTarget::AllConfigSource const& acs =
-        sources.Sources[map_it->second];
+        sources.Sources[si->second];
 
       FCInfo fcinfo(this, target, acs, configs);
 
@@ -2057,8 +2034,7 @@
 }
 
 void cmLocalVisualStudio7Generator::WriteProjectStart(
-  std::ostream& fout, std::string const& libName, cmGeneratorTarget* target,
-  std::vector<cmSourceGroup>&)
+  std::ostream& fout, std::string const& libName, cmGeneratorTarget* target)
 {
   if (this->FortranProject) {
     this->WriteProjectStartFortran(fout, libName, target);
diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h
index 837a0e1..38df53b 100644
--- a/Source/cmLocalVisualStudio7Generator.h
+++ b/Source/cmLocalVisualStudio7Generator.h
@@ -130,8 +130,7 @@
                                 std::vector<std::string> const& dirs);
   void WriteProjectSCC(std::ostream& fout, cmGeneratorTarget* target);
   void WriteProjectStart(std::ostream& fout, std::string const& libName,
-                         cmGeneratorTarget* tgt,
-                         std::vector<cmSourceGroup>& sgs);
+                         cmGeneratorTarget* target);
   void WriteProjectStartFortran(std::ostream& fout, std::string const& libName,
                                 cmGeneratorTarget* tgt);
   void WriteVCProjBeginGroup(std::ostream& fout, char const* group,
diff --git a/Source/cmLocale.h b/Source/cmLocale.h
deleted file mode 100644
index b0d1065..0000000
--- a/Source/cmLocale.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file LICENSE.rst or https://cmake.org/licensing for details.  */
-#pragma once
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include <clocale>
-#include <string>
-
-class cmLocaleRAII
-{
-public:
-  cmLocaleRAII()
-    : OldLocale(setlocale(LC_CTYPE, nullptr))
-  {
-    setlocale(LC_CTYPE, "");
-  }
-
-  ~cmLocaleRAII() { setlocale(LC_CTYPE, this->OldLocale.c_str()); }
-
-  cmLocaleRAII(cmLocaleRAII const&) = delete;
-  cmLocaleRAII& operator=(cmLocaleRAII const&) = delete;
-
-private:
-  std::string OldLocale;
-};
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index e968723..16ed8d6 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -6,7 +6,6 @@
 
 #include <algorithm>
 #include <cassert>
-#include <cctype>
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
@@ -28,6 +27,7 @@
 
 #include "cmsys/FStream.hxx"
 #include "cmsys/RegularExpression.hxx"
+#include "cmsys/String.h"
 
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
@@ -194,7 +194,8 @@
   this->AddSourceGroup("Object Files", "\\.(lo|o|obj)$");
 
   this->ObjectLibrariesSourceGroupIndex = this->SourceGroups.size();
-  this->SourceGroups.emplace_back("Object Libraries", "^MATCH_NO_SOURCES$");
+  this->SourceGroups.emplace_back(
+    cm::make_unique<cmSourceGroup>("Object Libraries", "^MATCH_NO_SOURCES$"));
 #endif
 }
 
@@ -338,14 +339,15 @@
   std::vector<std::string> const& trace_only_this_files =
     this->GetCMakeInstance()->GetTraceSources();
   std::string const& full_path = bt.Top().FilePath;
-  std::string const& only_filename = cmSystemTools::GetFilenameName(full_path);
+  cm::string_view only_filename =
+    cmSystemTools::GetFilenameNameView(full_path);
   bool trace = trace_only_this_files.empty();
   if (!trace) {
     for (std::string const& file : trace_only_this_files) {
       std::string::size_type const pos = full_path.rfind(file);
       trace = (pos != std::string::npos) &&
         ((pos + file.size()) == full_path.size()) &&
-        (only_filename == cmSystemTools::GetFilenameName(file));
+        (only_filename == cmSystemTools::GetFilenameNameView(file));
       if (trace) {
         break;
       }
@@ -585,7 +587,7 @@
         }
       }
       if (this->GetCMakeInstance()->HasScriptModeExitCode() &&
-          this->GetCMakeInstance()->GetWorkingMode() == cmake::SCRIPT_MODE) {
+          this->GetCMakeInstance()->RoleSupportsExitCode()) {
         // pass-through the exit code from inner cmake_language(EXIT) ,
         // possibly from include() or similar command...
         status.SetExitCode(this->GetCMakeInstance()->GetScriptModeExitCode());
@@ -1296,8 +1298,8 @@
   for (std::string::size_type lpos = dflags.find(flag, 0);
        lpos != std::string::npos; lpos = dflags.find(flag, lpos)) {
     std::string::size_type rpos = lpos + len;
-    if ((lpos <= 0 || cmIsSpace(dflags[lpos - 1])) &&
-        (rpos >= dflags.size() || cmIsSpace(dflags[rpos]))) {
+    if ((lpos <= 0 || cmsysString_isspace(dflags[lpos - 1])) &&
+        (rpos >= dflags.size() || cmsysString_isspace(dflags[rpos]))) {
       dflags.erase(lpos, len);
     } else {
       ++lpos;
@@ -1428,6 +1430,16 @@
   }
 }
 
+bool cmMakefile::ExplicitlyGeneratesSbom() const
+{
+  return this->ExplicitSbomGenerator;
+}
+
+void cmMakefile::SetExplicitlyGeneratesSbom(bool status)
+{
+  this->ExplicitSbomGenerator = status;
+}
+
 void cmMakefile::PushFunctionScope(std::string const& fileName,
                                    cmPolicies::PolicyMap const& pm)
 {
@@ -2081,16 +2093,24 @@
 }
 
 #if !defined(CMAKE_BOOTSTRAP)
+
+void cmMakefile::ResolveSourceGroupGenex(cmLocalGenerator* lg)
+{
+  for (auto const& sourceGroup : this->SourceGroups) {
+    sourceGroup->ResolveGenex(lg, {});
+  }
+}
+
 cmSourceGroup* cmMakefile::GetSourceGroup(
   std::vector<std::string> const& name) const
 {
   cmSourceGroup* sg = nullptr;
 
   // first look for source group starting with the same as the one we want
-  for (cmSourceGroup const& srcGroup : this->SourceGroups) {
-    std::string const& sgName = srcGroup.GetName();
+  for (auto const& srcGroup : this->SourceGroups) {
+    std::string const& sgName = srcGroup->GetName();
     if (sgName == name[0]) {
-      sg = const_cast<cmSourceGroup*>(&srcGroup);
+      sg = srcGroup.get();
       break;
     }
   }
@@ -2142,7 +2162,8 @@
   if (i == -1) {
     // group does not exist nor belong to any existing group
     // add its first component
-    this->SourceGroups.emplace_back(name[0], regex);
+    this->SourceGroups.emplace_back(
+      cm::make_unique<cmSourceGroup>(name[0], regex));
     sg = this->GetSourceGroup(currentName);
     i = 0; // last component found
   }
@@ -2152,7 +2173,8 @@
   }
   // build the whole source group path
   for (++i; i <= lastElement; ++i) {
-    sg->AddChild(cmSourceGroup(name[i], nullptr, sg->GetFullName().c_str()));
+    sg->AddChild(cm::make_unique<cmSourceGroup>(name[i], nullptr,
+                                                sg->GetFullName().c_str()));
     sg = sg->LookupChild(name[i]);
   }
 
@@ -2176,36 +2198,6 @@
   return this->GetOrCreateSourceGroup(
     cmTokenize(name, p ? cm::string_view(*p) : R"(\/)"_s));
 }
-
-/**
- * Find a source group whose regular expression matches the filename
- * part of the given source name.  Search backward through the list of
- * source groups, and take the first matching group found.  This way
- * non-inherited SOURCE_GROUP commands will have precedence over
- * inherited ones.
- */
-cmSourceGroup* cmMakefile::FindSourceGroup(
-  std::string const& source, std::vector<cmSourceGroup>& groups) const
-{
-  // First search for a group that lists the file explicitly.
-  for (auto sg = groups.rbegin(); sg != groups.rend(); ++sg) {
-    cmSourceGroup* result = sg->MatchChildrenFiles(source);
-    if (result) {
-      return result;
-    }
-  }
-
-  // Now search for a group whose regex matches the file.
-  for (auto sg = groups.rbegin(); sg != groups.rend(); ++sg) {
-    cmSourceGroup* result = sg->MatchChildrenRegex(source);
-    if (result) {
-      return result;
-    }
-  }
-
-  // Shouldn't get here, but just in case, return the default group.
-  return groups.data();
-}
 #endif
 
 bool cmMakefile::IsOn(std::string const& name) const
@@ -2712,7 +2704,7 @@
             last = next + 1;
           } else if (nextc == ';' && openstack.empty()) {
             // Handled in ExpandListArgument; pass the backslash literally.
-          } else if (isalnum(nextc) || nextc == '\0') {
+          } else if (cmsysString_isalnum(nextc) || nextc == '\0') {
             errorstr += "Invalid character escape '\\";
             if (nextc) {
               errorstr += nextc;
@@ -2780,8 +2772,8 @@
         CM_FALLTHROUGH;
       default: {
         if (!openstack.empty() &&
-            !(isalnum(inc) || inc == '_' || inc == '/' || inc == '.' ||
-              inc == '+' || inc == '-')) {
+            !(cmsysString_isalnum(inc) || inc == '_' || inc == '/' ||
+              inc == '.' || inc == '+' || inc == '-')) {
           errorstr += cmStrCat("Invalid character ('", inc);
           result.append(last, in - last);
           errorstr += cmStrCat("') in a variable name: '",
@@ -3155,7 +3147,7 @@
   // file that compiles to it. Needs a policy as it likely affects link
   // language selection if done unconditionally.
 #if !defined(CMAKE_BOOTSTRAP)
-  this->SourceGroups[this->ObjectLibrariesSourceGroupIndex].AddGroupFile(
+  this->SourceGroups[this->ObjectLibrariesSourceGroupIndex]->AddGroupFile(
     sf->ResolveFullPath());
 #endif
 }
@@ -3251,8 +3243,7 @@
   // make sure the same generator is used
   // use this program as the cmake to be run, it should not
   // be run that way but the cmake object requires a valid path
-  cmake cm(cmake::RoleProject, cmState::Project,
-           cmState::ProjectKind::TryCompile);
+  cmake cm(cmState::Role::Project, cmState::TryCompile::Yes);
   auto gg = cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName());
   if (!gg) {
     this->IssueMessage(MessageType::INTERNAL_ERROR,
@@ -3349,7 +3340,7 @@
 
   // finally call the generator to actually build the resulting project
   int ret = this->GetGlobalGenerator()->TryCompile(
-    jobs, srcdir, bindir, projectName, targetName, fast, output, this);
+    jobs, bindir, projectName, targetName, fast, output, this);
 
   this->IsSourceFileTryCompile = false;
   return ret;
@@ -3378,8 +3369,7 @@
 #ifndef CMAKE_BOOTSTRAP
 cmVariableWatch* cmMakefile::GetVariableWatch() const
 {
-  if (this->GetCMakeInstance() &&
-      this->GetCMakeInstance()->GetVariableWatch()) {
+  if (this->GetCMakeInstance()) {
     return this->GetCMakeInstance()->GetVariableWatch();
   }
   return nullptr;
@@ -3394,8 +3384,8 @@
 void cmMakefile::DisplayStatus(std::string const& message, float s) const
 {
   cmake* cm = this->GetCMakeInstance();
-  if (cm->GetWorkingMode() == cmake::FIND_PACKAGE_MODE) {
-    // don't output any STATUS message in FIND_PACKAGE_MODE, since they will
+  if (cm->GetState()->GetRole() == cmState::Role::FindPackage) {
+    // don't output any STATUS message in --find-package mode, since they will
     // directly be fed to the compiler, which will be confused.
     return;
   }
@@ -4104,7 +4094,7 @@
   }
 
   // Deprecate old policies.
-  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0143 &&
+  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0151 &&
       !(this->GetCMakeInstance()->GetIsInTryCompile() &&
         (
           // Policies set by cmCoreTryCompile::TryCompileCode.
@@ -4121,7 +4111,9 @@
   this->StateSnapshot.SetPolicy(id, status);
 
   // Handle CMAKE_PARENT_LIST_FILE for CMP0198 policy changes
-  if (id == cmPolicies::CMP0198) {
+  if (id == cmPolicies::CMP0198 &&
+      this->GetCMakeInstance()->GetState()->GetRole() ==
+        cmState::Role::Project) {
     this->UpdateParentListFileVariable();
   }
 
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 73ab212..f2f06d1 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -40,6 +40,10 @@
 // will not compile without the complete type.
 #include "cmTarget.h" // IWYU pragma: keep
 
+#if !defined(CMAKE_BOOTSTRAP)
+#  include "cmSourceGroup.h"
+#endif
+
 enum class cmCustomCommandType;
 enum class cmObjectLibraryCommands;
 
@@ -60,10 +64,6 @@
 class cmVariableWatch;
 class cmake;
 
-#if !defined(CMAKE_BOOTSTRAP)
-class cmSourceGroup;
-#endif
-
 /** A type-safe wrapper for a string representing a directory id.  */
 class cmDirectoryId
 {
@@ -612,10 +612,16 @@
   bool CanIWriteThisFile(std::string const& fileName) const;
 
 #if !defined(CMAKE_BOOTSTRAP)
+
+  /**
+   * Resolve source group genex.
+   */
+  void ResolveSourceGroupGenex(cmLocalGenerator* lg);
+
   /**
    * Get the vector source groups.
    */
-  std::vector<cmSourceGroup> const& GetSourceGroups() const
+  SourceGroupVector const& GetSourceGroups() const
   {
     return this->SourceGroups;
   }
@@ -648,12 +654,6 @@
    * The name will be tokenized.
    */
   cmSourceGroup* GetOrCreateSourceGroup(std::string const& name);
-
-  /**
-   * find what source group this source is in
-   */
-  cmSourceGroup* FindSourceGroup(std::string const& source,
-                                 std::vector<cmSourceGroup>& groups) const;
 #endif
 
   /**
@@ -854,6 +854,9 @@
   //! Initialize a makefile from its parent
   void InitializeFromParent(cmMakefile* parent);
 
+  bool ExplicitlyGeneratesSbom() const;
+  void SetExplicitlyGeneratesSbom(bool status = true);
+
   void AddInstallGenerator(std::unique_ptr<cmInstallGenerator> g);
 
   std::vector<std::unique_ptr<cmInstallGenerator>>& GetInstallGenerators()
@@ -1145,7 +1148,7 @@
   std::string DefineFlags;
 
 #if !defined(CMAKE_BOOTSTRAP)
-  std::vector<cmSourceGroup> SourceGroups;
+  SourceGroupVector SourceGroups;
   size_t ObjectLibrariesSourceGroupIndex;
 #endif
 
@@ -1253,6 +1256,7 @@
   cmFindPackageStack FindPackageStack;
   unsigned int FindPackageStackNextIndex = 0;
 
+  bool ExplicitSbomGenerator = false;
   bool DebugFindPkg = false;
 
   bool CheckSystemVars;
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index e966f64..453fbe2 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -379,9 +379,10 @@
   // Add flags to create an executable.
   this->LocalGenerator->AppendTargetCreationLinkFlags(
     linkFlags, this->GeneratorTarget, linkLanguage);
-  this->LocalGenerator->AddConfigVariableFlags(
-    linkFlags, "CMAKE_EXE_LINKER_FLAGS", this->GeneratorTarget,
-    cmBuildStep::Link, linkLanguage, this->GetConfigName());
+  this->LocalGenerator->AddTargetTypeLinkerFlags(
+    linkFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
+  this->LocalGenerator->AddPerLanguageLinkFlags(
+    linkFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
 
   {
     auto exeType =
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index 54074f9..09026ca 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -178,9 +178,10 @@
   std::string extraFlags;
   this->LocalGenerator->AppendTargetCreationLinkFlags(
     extraFlags, this->GeneratorTarget, linkLanguage);
-  this->LocalGenerator->AddConfigVariableFlags(
-    extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->GeneratorTarget,
-    cmBuildStep::Link, linkLanguage, this->GetConfigName());
+  this->LocalGenerator->AddTargetTypeLinkerFlags(
+    extraFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
+  this->LocalGenerator->AddPerLanguageLinkFlags(
+    extraFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
 
   std::unique_ptr<cmLinkLineComputer> linkLineComputer =
     this->CreateLinkLineComputer(
@@ -217,9 +218,10 @@
   std::string extraFlags;
   this->LocalGenerator->AppendTargetCreationLinkFlags(
     extraFlags, this->GeneratorTarget, linkLanguage);
-  this->LocalGenerator->AddConfigVariableFlags(
-    extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->GeneratorTarget,
-    cmBuildStep::Link, linkLanguage, this->GetConfigName());
+  this->LocalGenerator->AddTargetTypeLinkerFlags(
+    extraFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
+  this->LocalGenerator->AddPerLanguageLinkFlags(
+    extraFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
 
   std::unique_ptr<cmLinkLineComputer> linkLineComputer =
     this->CreateLinkLineComputer(
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 4e3cee9..86c1138 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -138,13 +138,8 @@
 void cmMakefileTargetGenerator::GetTargetLinkFlags(
   std::string& flags, std::string const& linkLanguage)
 {
-  this->LocalGenerator->AppendFlags(
-    flags, this->GeneratorTarget->GetSafeProperty("LINK_FLAGS"));
-
-  std::string const linkFlagsConfig =
-    cmStrCat("LINK_FLAGS_", cmSystemTools::UpperCase(this->GetConfigName()));
-  this->LocalGenerator->AppendFlags(
-    flags, this->GeneratorTarget->GetSafeProperty(linkFlagsConfig));
+  this->LocalGenerator->AddTargetPropertyLinkFlags(
+    flags, this->GeneratorTarget, this->GetConfigName());
 
   std::vector<std::string> opts;
   this->GeneratorTarget->GetLinkOptions(opts, this->GetConfigName(),
@@ -919,7 +914,7 @@
       cmOutputConverter::SHELL);
 
     if (this->LocalGenerator->IsMinGWMake() &&
-        cmHasLiteralSuffix(targetOutPathCompilePDB, "\\")) {
+        cmHasSuffix(targetOutPathCompilePDB, '\\')) {
       // mingw32-make incorrectly interprets 'a\ b c' as 'a b' and 'c'
       // (but 'a\ b "c"' as 'a\', 'b', and 'c'!).  Workaround this by
       // avoiding a trailing backslash in the argument.
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index 3b5681a..e5cb1c0 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -478,6 +478,11 @@
       vars.Includes = "$INCLUDES";
     }
 
+    if (this->TargetLinkLanguage(config) == "Rust") {
+      vars.RustSources = "$RUST_SOURCES";
+      vars.RustObjectDeps = "$RUST_OBJECT_DEPS";
+    }
+
     std::string responseFlag;
 
     std::string cmakeVarLang =
@@ -1276,6 +1281,40 @@
         gt->IsExecutableWithExports()) {
       linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]);
     }
+  } else if (this->TargetLinkLanguage(config) == "Rust") {
+    // Use one-step build/link for Rust.
+    // Compute specific libraries to link with.
+    std::vector<cmSourceFile const*> sources;
+    gt->GetObjectSources(sources, config);
+    cmLocalGenerator const* lg = this->GetLocalGenerator();
+    std::string entry_obj;
+
+    for (auto const& source : sources) {
+      if (source->GetLanguage() == "Rust") {
+        if (vars.count("RUST_SOURCES") == 0) {
+          std::string const sourcePath =
+            this->GetCompiledSourceNinjaPath(source);
+          vars["RUST_SOURCES"] =
+            lg->ConvertToOutputFormat(sourcePath, cmOutputConverter::SHELL);
+          entry_obj = this->GetObjectFilePath(source, config);
+        } else {
+          assert(false && "Rust crate can only have 1 entry");
+        }
+      }
+    }
+
+    linkBuild.ExplicitDeps = this->GetObjects(config);
+    std::stringstream obj_deps;
+
+    // Do not try linking to object file created from the crate entry.
+    for (auto const& obj : linkBuild.ExplicitDeps) {
+      if (obj != entry_obj) {
+        obj_deps << " "
+                 << lg->ConvertToOutputFormat(obj, cmOutputConverter::SHELL);
+      }
+    }
+
+    vars["RUST_OBJECT_DEPS"] = obj_deps.str();
   } else {
     linkBuild.ExplicitDeps = this->GetObjects(config);
   }
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index ef8dabe..b2308b5 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -265,15 +265,19 @@
     }
 
     if (!this->GeneratorTarget->Target->IsNormal()) {
-      auto flag = this->GetMakefile()->GetSafeDefinition(
-        "CMAKE_CXX_MODULE_BMI_ONLY_FLAG");
-      cmRulePlaceholderExpander::RuleVariables compileObjectVars;
-      compileObjectVars.Object = objectFileName.c_str();
-      auto rulePlaceholderExpander =
-        this->GetLocalGenerator()->CreateRulePlaceholderExpander();
-      rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
-                                                   flag, compileObjectVars);
-      this->LocalGenerator->AppendCompileOptions(flags, flag);
+      if (this->GetMakefile()
+            ->GetDefinition("CMAKE_CXX_COMPILE_BMI")
+            .IsEmpty()) {
+        auto flag = this->GetMakefile()->GetSafeDefinition(
+          "CMAKE_CXX_MODULE_BMI_ONLY_FLAG");
+        cmRulePlaceholderExpander::RuleVariables compileObjectVars;
+        compileObjectVars.Object = objectFileName.c_str();
+        auto rulePlaceholderExpander =
+          this->GetLocalGenerator()->CreateRulePlaceholderExpander();
+        rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
+                                                     flag, compileObjectVars);
+        this->LocalGenerator->AppendCompileOptions(flags, flag);
+      }
     }
   }
 
@@ -456,7 +460,7 @@
 {
   // Choose an extension to compile already-preprocessed source.
   std::string ppExt = source->GetExtension();
-  if (cmHasLiteralPrefix(ppExt, "F")) {
+  if (cmHasPrefix(ppExt, 'F')) {
     // Some Fortran compilers automatically enable preprocessing for
     // upper-case extensions.  Since the source is already preprocessed,
     // use a lower-case extension.
@@ -517,6 +521,13 @@
   return this->GeneratorTarget->GetName();
 }
 
+std::string cmNinjaTargetGenerator::ConvertToOutputFormatForShell(
+  cm::string_view path) const
+{
+  return this->LocalGenerator->ConvertToOutputFormat(path,
+                                                     cmOutputConverter::SHELL);
+}
+
 bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(
   cmNinjaVars& vars, std::string const& config) const
 {
@@ -534,11 +545,10 @@
                          this->GeneratorTarget->GetPDBName(config));
     }
 
-    vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat(
-      this->ConvertToNinjaPath(pdbPath), cmOutputConverter::SHELL);
-    vars["TARGET_COMPILE_PDB"] =
-      this->GetLocalGenerator()->ConvertToOutputFormat(
-        this->ConvertToNinjaPath(compilePdbPath), cmOutputConverter::SHELL);
+    vars["TARGET_PDB"] =
+      this->ConvertToOutputFormatForShell(this->ConvertToNinjaPath(pdbPath));
+    vars["TARGET_COMPILE_PDB"] = this->ConvertToOutputFormatForShell(
+      this->ConvertToNinjaPath(compilePdbPath));
 
     this->EnsureParentDirectoryExists(pdbPath);
     this->EnsureParentDirectoryExists(compilePdbPath);
@@ -646,6 +656,19 @@
   this->WriteCompileRule(lang, config, WithScanning::No);
 }
 
+std::string cmNinjaTargetGenerator::GetCompileTemplateVar(
+  std::string const& lang) const
+{
+  std::string cmdVar = cmStrCat("CMAKE_", lang, "_COMPILE_OBJECT");
+  if (!this->GetGeneratorTarget()->IsNormal()) {
+    std::string bmiCmdVar = cmStrCat("CMAKE_", lang, "_COMPILE_BMI");
+    if (!this->GetMakefile()->GetDefinition(bmiCmdVar).IsEmpty()) {
+      cmdVar = std::move(bmiCmdVar);
+    }
+  }
+  return cmdVar;
+}
+
 void cmNinjaTargetGenerator::WriteCompileRule(std::string const& lang,
                                               std::string const& config,
                                               WithScanning withScanning)
@@ -693,9 +716,8 @@
   auto rulePlaceholderExpander =
     this->GetLocalGenerator()->CreateRulePlaceholderExpander();
 
-  std::string const tdi = this->GetLocalGenerator()->ConvertToOutputFormat(
-    this->ConvertToNinjaPath(this->GetTargetDependInfoPath(lang, config)),
-    cmLocalGenerator::SHELL);
+  std::string const tdi = this->ConvertToOutputFormatForShell(
+    this->ConvertToNinjaPath(this->GetTargetDependInfoPath(lang, config)));
 
   std::string launcher;
   std::string val = this->GetLocalGenerator()->GetRuleLauncher(
@@ -705,8 +727,7 @@
   }
 
   std::string const cmakeCmd =
-    this->GetLocalGenerator()->ConvertToOutputFormat(
-      cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
+    this->ConvertToOutputFormatForShell(cmSystemTools::GetCMakeCommand());
 
   if (withScanning == WithScanning::Yes) {
     auto const& scanDepType = this->GetMakefile()->GetSafeDefinition(
@@ -924,7 +945,7 @@
   }
 
   // Rule for compiling object file.
-  std::string const cmdVar = cmStrCat("CMAKE_", lang, "_COMPILE_OBJECT");
+  std::string const cmdVar = this->GetCompileTemplateVar(lang);
   std::string const& compileCmd = mf->GetRequiredDefinition(cmdVar);
   cmList compileCmds(compileCmd);
 
@@ -1281,8 +1302,7 @@
   this->LocalGenerator->AppendFlags(flags, "-output-file-map");
   this->LocalGenerator->AppendFlags(
     flags,
-    this->GetLocalGenerator()->ConvertToOutputFormat(
-      ConvertToNinjaPath(mapFilePath), cmOutputConverter::SHELL));
+    this->ConvertToOutputFormatForShell(ConvertToNinjaPath(mapFilePath)));
 }
 
 namespace {
@@ -1331,11 +1351,13 @@
 
   // Tell dependency scanner the object file that will result from
   // compiling the source.
-  scanBuild.Variables["OBJ_FILE"] = objectFileName;
+  scanBuild.Variables["OBJ_FILE"] =
+    tg->ConvertToOutputFormatForShell(objectFileName);
 
   // Tell dependency scanner where to store dyndep intermediate results.
   std::string ddiFileName = cmStrCat(objectFileName, ".ddi");
-  scanBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFileName;
+  scanBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] =
+    tg->ConvertToOutputFormatForShell(ddiFileName);
   scanBuild.RspFile = cmStrCat(ddiFileName, ".rsp");
 
   // Outputs of the scan/preprocessor build statement.
@@ -1344,7 +1366,8 @@
     scanBuild.ImplicitOuts.push_back(ddiFileName);
   } else {
     scanBuild.Outputs.push_back(ddiFileName);
-    scanBuild.Variables["PREPROCESSED_OUTPUT_FILE"] = ppFileName;
+    scanBuild.Variables["PREPROCESSED_OUTPUT_FILE"] =
+      tg->ConvertToOutputFormatForShell(ppFileName);
     if (!compilationPreprocesses) {
       // Compilation does not preprocess and we are not compiling an
       // already-preprocessed source.  Make compilation depend on the scan
@@ -1425,8 +1448,8 @@
     : this->GetGeneratorTarget()->GetPropertyAsBool("SKIP_LINTING");
 
   if (!skipCodeCheck) {
-    auto const cmakeCmd = this->GetLocalGenerator()->ConvertToOutputFormat(
-      cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
+    auto const cmakeCmd =
+      this->ConvertToOutputFormatForShell(cmSystemTools::GetCMakeCommand());
     vars["CODE_CHECK"] =
       this->GenerateCodeCheckRules(*source, compilerLauncher, cmakeCmd, config,
                                    [this](std::string const& path) {
@@ -1630,7 +1653,8 @@
       // `cmNinjaTargetGenerator::ExportObjectCompileCommand` to expect the
       // corresponding file path.
       std::string ddModmapFile = cmStrCat(objectFileName, ".modmap");
-      vars["DYNDEP_MODULE_MAP_FILE"] = ddModmapFile;
+      vars["DYNDEP_MODULE_MAP_FILE"] =
+        this->ConvertToOutputFormatForShell(ddModmapFile);
       objBuild.ImplicitDeps.push_back(ddModmapFile);
       scanningFiles.ModuleMapFile = std::move(ddModmapFile);
     }
@@ -1642,13 +1666,10 @@
 
   this->EnsureParentDirectoryExists(objectFileName);
 
-  vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
-    objectDir, cmOutputConverter::SHELL);
+  vars["OBJECT_DIR"] = this->ConvertToOutputFormatForShell(objectDir);
   vars["TARGET_SUPPORT_DIR"] =
-    this->GetLocalGenerator()->ConvertToOutputFormat(targetSupportDir,
-                                                     cmOutputConverter::SHELL);
-  vars["OBJECT_FILE_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
-    objectFileDir, cmOutputConverter::SHELL);
+    this->ConvertToOutputFormatForShell(targetSupportDir);
+  vars["OBJECT_FILE_DIR"] = this->ConvertToOutputFormatForShell(objectFileDir);
 
   this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
                              source, vars);
@@ -1707,9 +1728,7 @@
       }
     }
 
-    vars["ISPC_HEADER_FILE"] =
-      this->GetLocalGenerator()->ConvertToOutputFormat(
-        ispcHeader, cmOutputConverter::SHELL);
+    vars["ISPC_HEADER_FILE"] = this->ConvertToOutputFormatForShell(ispcHeader);
   } else {
     auto headers = this->GeneratorTarget->GetGeneratedISPCHeaders(config);
     if (!headers.empty()) {
@@ -1862,7 +1881,8 @@
 
     if (!modmapFormat.empty()) {
       std::string ddModmapFile = cmStrCat(bmiFileName, ".modmap");
-      vars["DYNDEP_MODULE_MAP_FILE"] = ddModmapFile;
+      vars["DYNDEP_MODULE_MAP_FILE"] =
+        this->ConvertToOutputFormatForShell(ddModmapFile);
       scanningFiles.ModuleMapFile = std::move(ddModmapFile);
     }
 
@@ -1873,13 +1893,10 @@
 
   this->EnsureParentDirectoryExists(bmiFileName);
 
-  vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
-    bmiDir, cmOutputConverter::SHELL);
+  vars["OBJECT_DIR"] = this->ConvertToOutputFormatForShell(bmiDir);
   vars["TARGET_SUPPORT_DIR"] =
-    this->GetLocalGenerator()->ConvertToOutputFormat(targetSupportDir,
-                                                     cmOutputConverter::SHELL);
-  vars["OBJECT_FILE_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
-    bmiFileDir, cmOutputConverter::SHELL);
+    this->ConvertToOutputFormatForShell(targetSupportDir);
+  vars["OBJECT_FILE_DIR"] = this->ConvertToOutputFormatForShell(bmiFileDir);
 
   this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
                              source, vars);
@@ -2313,7 +2330,7 @@
     compileObjectVars.CudaCompileMode = cudaCompileMode.c_str();
   }
 
-  std::string const cmdVar = cmStrCat("CMAKE_", language, "_COMPILE_OBJECT");
+  std::string const cmdVar = this->GetCompileTemplateVar(language);
   std::string const& compileCmd =
     this->Makefile->GetRequiredDefinition(cmdVar);
   cmList compileCmds(compileCmd);
@@ -2497,9 +2514,7 @@
 void cmNinjaTargetGenerator::AddDepfileBinding(cmNinjaVars& vars,
                                                std::string depfile) const
 {
-  std::string depfileForShell =
-    this->GetLocalGenerator()->ConvertToOutputFormat(depfile,
-                                                     cmOutputConverter::SHELL);
+  std::string depfileForShell = this->ConvertToOutputFormatForShell(depfile);
   if (depfile != depfileForShell) {
     vars["depfile"] = std::move(depfile);
   }
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
index c4dc51f..39d3026 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -11,6 +11,8 @@
 #include <utility>
 #include <vector>
 
+#include <cm/string_view>
+
 #include <cm3p/json/value.h>
 
 #include "cmCommonTargetGenerator.h"
@@ -42,6 +44,8 @@
 
   std::string GetTargetName() const;
 
+  std::string ConvertToOutputFormatForShell(cm::string_view path) const;
+
   void AddDepfileBinding(cmNinjaVars& vars, std::string depfile) const;
   void RemoveDepfileBinding(cmNinjaVars& vars) const;
 
@@ -164,6 +168,7 @@
 
   void WriteLanguageRules(std::string const& language,
                           std::string const& config);
+  std::string GetCompileTemplateVar(std::string const& lang) const;
   void WriteCompileRule(std::string const& language,
                         std::string const& config);
   void WriteCompileRule(std::string const& language, std::string const& config,
diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx
index ddae68c..c72dbe4 100644
--- a/Source/cmOutputConverter.cxx
+++ b/Source/cmOutputConverter.cxx
@@ -4,7 +4,6 @@
 
 #include <algorithm>
 #include <cassert>
-#include <cctype>
 #include <set>
 #include <vector>
 
@@ -13,6 +12,8 @@
 #  include <utility>
 #endif
 
+#include "cmsys/String.h"
+
 #include "cmList.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
@@ -425,7 +426,7 @@
 
 static bool Shell_CharIsMakeVariableName(char c)
 {
-  return c && (c == '_' || isalpha((static_cast<int>(c))));
+  return c && (c == '_' || cmsysString_isalpha((static_cast<int>(c))));
 }
 
 bool cmOutputConverter::Shell_CharNeedsQuotes(char c, int flags)
diff --git a/Source/cmPackageInfoArguments.cxx b/Source/cmPackageInfoArguments.cxx
index a9731ba..8408152 100644
--- a/Source/cmPackageInfoArguments.cxx
+++ b/Source/cmPackageInfoArguments.cxx
@@ -2,35 +2,20 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "cmPackageInfoArguments.h"
 
-#include <utility>
-
 #include <cm/string_view>
 
 #include "cmExecutionStatus.h"
-#include "cmGeneratorExpression.h"
-#include "cmMakefile.h"
-#include "cmStateSnapshot.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
-#include "cmValue.h"
 
 template void cmPackageInfoArguments::Bind<void>(cmArgumentParser<void>&,
                                                  cmPackageInfoArguments*);
 
-namespace {
-
-bool ArgWasSpecified(std::string const& value)
+cm::string_view cmPackageInfoArguments::CommandName() const
 {
-  return !value.empty();
+  return "PACKAGE_INFO"_s;
 }
 
-bool ArgWasSpecified(std::vector<std::string> const& value)
-{
-  return !value.empty();
-}
-
-} // anonymous namespace
-
 #define ENFORCE_REQUIRES(req, value, arg)                                     \
   do {                                                                        \
     if (ArgWasSpecified(value)) {                                             \
@@ -60,9 +45,6 @@
                       "DEFAULT_CONFIGURATIONS");
     ENFORCE_EXCLUSIVE("APPENDIX", this->ProjectName, "PROJECT");
   }
-  if (this->NoProjectDefaults) {
-    ENFORCE_EXCLUSIVE("PROJECT", this->ProjectName, "NO_PROJECT_METADATA");
-  }
 
   // Check for options that require other options.
   if (this->Version.empty()) {
@@ -70,67 +52,12 @@
     ENFORCE_REQUIRES("VERSION", this->VersionSchema, "VERSION_SCHEMA");
   }
 
-  // Validate the package name.
-  if (!this->PackageName.empty()) {
-    if (!cmGeneratorExpression::IsValidTargetName(this->PackageName) ||
-        this->PackageName.find(':') != std::string::npos) {
-      status.SetError(
-        cmStrCat(R"(PACKAGE_INFO given invalid package name ")"_s,
-                 this->PackageName, R"(".)"_s));
-      return false;
-    }
-  }
-
-  return true;
+  return cmProjectInfoArguments::Check(status);
 }
 
 #undef ENFORCE_REQUIRES
 #undef ENFORCE_EXCLUSIVE
 
-bool cmPackageInfoArguments::SetMetadataFromProject(cmExecutionStatus& status)
-{
-  // Determine what project to use for inherited metadata.
-  if (!this->SetEffectiveProject(status)) {
-    return false;
-  }
-
-  if (this->ProjectName.empty()) {
-    // We are not inheriting from a project.
-    return true;
-  }
-
-  cmMakefile& mf = status.GetMakefile();
-  auto mapProjectValue = [&](std::string& arg, cm::string_view suffix) {
-    cmValue const& projectValue =
-      mf.GetDefinition(cmStrCat(this->ProjectName, '_', suffix));
-    if (projectValue) {
-      arg = *projectValue;
-      return true;
-    }
-    return false;
-  };
-
-  if (this->Version.empty()) {
-    if (mapProjectValue(this->Version, "VERSION"_s)) {
-      mapProjectValue(this->VersionCompat, "COMPAT_VERSION"_s);
-    }
-  }
-
-  if (this->License.empty()) {
-    mapProjectValue(this->License, "SPDX_LICENSE"_s);
-  }
-
-  if (this->Description.empty()) {
-    mapProjectValue(this->Description, "DESCRIPTION"_s);
-  }
-
-  if (this->Website.empty()) {
-    mapProjectValue(this->Website, "HOMEPAGE_URL"_s);
-  }
-
-  return true;
-}
-
 bool cmPackageInfoArguments::SetEffectiveProject(cmExecutionStatus& status)
 {
   if (!this->Appendix.empty()) {
@@ -138,28 +65,7 @@
     return true;
   }
 
-  if (this->NoProjectDefaults) {
-    // User requested that metadata not be inherited.
-    return true;
-  }
-
-  cmMakefile& mf = status.GetMakefile();
-  if (!this->ProjectName.empty()) {
-    // User specified a project; make sure it exists.
-    if (!mf.GetStateSnapshot().CheckProjectName(this->ProjectName)) {
-      status.SetError(cmStrCat(R"(PROJECT given unknown project name ")"_s,
-                               this->ProjectName, R"(".)"_s));
-      return false;
-    }
-  } else {
-    // No project was specified; check if the package name is also a project.
-    std::string project = mf.GetStateSnapshot().GetProjectName();
-    if (this->PackageName == project) {
-      this->ProjectName = std::move(project);
-    }
-  }
-
-  return true;
+  return cmProjectInfoArguments::SetEffectiveProject(status);
 }
 
 std::string cmPackageInfoArguments::GetNamespace() const
diff --git a/Source/cmPackageInfoArguments.h b/Source/cmPackageInfoArguments.h
index a76dd46..f8f1753 100644
--- a/Source/cmPackageInfoArguments.h
+++ b/Source/cmPackageInfoArguments.h
@@ -7,13 +7,13 @@
 #include <string>
 #include <vector>
 
+#include <cm/string_view>
 #include <cm/type_traits>
 #include <cmext/string_view>
 
 #include "cmArgumentParser.h" // IWYU pragma: keep
 #include "cmArgumentParserTypes.h"
-
-class cmExecutionStatus;
+#include "cmProjectInfoArguments.h"
 
 /** \class cmPackageInfoArguments
  * \brief Convey information about a package.
@@ -23,7 +23,7 @@
  * container, and also provides utilities to obtain this metadata from commands
  * which produce packages (i.e. export and install).
  */
-class cmPackageInfoArguments
+class cmPackageInfoArguments : public cmProjectInfoArguments
 {
 public:
   template <typename T,
@@ -31,7 +31,8 @@
               std::is_base_of<cmPackageInfoArguments, T>::value>>
   static void Bind(cmArgumentParser<T>& parser)
   {
-    cmPackageInfoArguments::Bind(parser, nullptr);
+    cmPackageInfoArguments* const self = nullptr;
+    cmPackageInfoArguments::Bind(parser, self);
   }
 
   void Bind(cmArgumentParser<void>& parser)
@@ -43,76 +44,50 @@
   std::string GetPackageDirName() const;
   std::string GetPackageFileName() const;
 
-  /// Ensure that no conflicting options were specified.
-  bool Check(cmExecutionStatus& status) const;
+  bool Check(cmExecutionStatus& status) const override;
 
-  /// Set metadata (not already specified) from either the specified project,
-  /// or from the project which matches the package name.
-  bool SetMetadataFromProject(cmExecutionStatus& status);
-
-  ArgumentParser::NonEmpty<std::string> PackageName;
   ArgumentParser::NonEmpty<std::string> Appendix;
-  ArgumentParser::NonEmpty<std::string> Version;
-  ArgumentParser::NonEmpty<std::string> VersionCompat;
-  ArgumentParser::NonEmpty<std::string> VersionSchema;
-  ArgumentParser::NonEmpty<std::string> License;
   ArgumentParser::NonEmpty<std::string> DefaultLicense;
-  ArgumentParser::NonEmpty<std::string> Description;
-  ArgumentParser::NonEmpty<std::string> Website;
   ArgumentParser::NonEmpty<std::vector<std::string>> DefaultTargets;
   ArgumentParser::NonEmpty<std::vector<std::string>> DefaultConfigs;
   bool LowerCase = false;
 
-  ArgumentParser::NonEmpty<std::string> ProjectName;
-  bool NoProjectDefaults = false;
+protected:
+  cm::string_view CommandName() const override;
 
-private:
-  bool SetEffectiveProject(cmExecutionStatus& status);
+  bool SetEffectiveProject(cmExecutionStatus& status) override;
 
   template <typename T>
   static void Bind(cmArgumentParser<T>& parser, cmPackageInfoArguments* self)
   {
-    Bind(self, parser, "PACKAGE_INFO"_s, &cmPackageInfoArguments::PackageName);
+    cmProjectInfoArguments* const base = self;
+
+    Bind(base, parser, "PACKAGE_INFO"_s, &cmProjectInfoArguments::PackageName);
     Bind(self, parser, "LOWER_CASE_FILE"_s,
          &cmPackageInfoArguments::LowerCase);
     Bind(self, parser, "APPENDIX"_s, &cmPackageInfoArguments::Appendix);
-    Bind(self, parser, "VERSION"_s, &cmPackageInfoArguments::Version);
-    Bind(self, parser, "COMPAT_VERSION"_s,
-         &cmPackageInfoArguments::VersionCompat);
-    Bind(self, parser, "VERSION_SCHEMA"_s,
-         &cmPackageInfoArguments::VersionSchema);
+
+    Bind(base, parser, "COMPAT_VERSION"_s,
+         &cmProjectInfoArguments::VersionCompat);
+    Bind(base, parser, "VERSION_SCHEMA"_s,
+         &cmProjectInfoArguments::VersionSchema);
     Bind(self, parser, "DEFAULT_TARGETS"_s,
          &cmPackageInfoArguments::DefaultTargets);
     Bind(self, parser, "DEFAULT_CONFIGURATIONS"_s,
          &cmPackageInfoArguments::DefaultConfigs);
-    Bind(self, parser, "LICENSE"_s, &cmPackageInfoArguments::License);
     Bind(self, parser, "DEFAULT_LICENSE"_s,
          &cmPackageInfoArguments::DefaultLicense);
-    Bind(self, parser, "DESCRIPTION"_s, &cmPackageInfoArguments::Description);
-    Bind(self, parser, "HOMEPAGE_URL"_s, &cmPackageInfoArguments::Website);
 
-    Bind(self, parser, "PROJECT"_s, &cmPackageInfoArguments::ProjectName);
-    Bind(self, parser, "NO_PROJECT_METADATA"_s,
-         &cmPackageInfoArguments::NoProjectDefaults);
+    cmProjectInfoArguments::Bind(parser, self);
   }
 
-  template <typename T, typename U,
-            typename = cm::enable_if_t<
-              std::is_base_of<cmPackageInfoArguments, T>::value>>
-  static void Bind(cmPackageInfoArguments*, cmArgumentParser<T>& parser,
-                   cm::static_string_view name,
-                   U cmPackageInfoArguments::*member)
+  using cmProjectInfoArguments::Bind;
+
+  static bool ArgWasSpecified(std::vector<std::string> const& value)
   {
-    parser.Bind(name, member);
+    return !value.empty();
   }
-
-  template <typename U>
-  static void Bind(cmPackageInfoArguments* self,
-                   cmArgumentParser<void>& parser, cm::static_string_view name,
-                   U cmPackageInfoArguments::*member)
-  {
-    parser.Bind(name, (self)->*member);
-  }
+  using cmProjectInfoArguments::ArgWasSpecified;
 };
 
 extern template void cmPackageInfoArguments::Bind<void>(
diff --git a/Source/cmPackageInfoReader.cxx b/Source/cmPackageInfoReader.cxx
index 6ee574c..f871332 100644
--- a/Source/cmPackageInfoReader.cxx
+++ b/Source/cmPackageInfoReader.cxx
@@ -18,6 +18,7 @@
 #include "cmsys/FStream.hxx"
 #include "cmsys/RegularExpression.hxx"
 
+#include "cmCxxModuleMetadata.h"
 #include "cmExecutionStatus.h"
 #include "cmList.h"
 #include "cmListFileCache.h"
@@ -129,7 +130,7 @@
   // Check that we understand this version.
   return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL,
                                        version, "0.13") &&
-    cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, version, "1");
+    cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, version, "0.15");
 
   // TODO Eventually this probably needs to return the version tuple, and
   // should share code with cmPackageInfoReader::ParseVersion.
@@ -229,7 +230,7 @@
 std::string NormalizeTargetName(std::string const& name,
                                 std::string const& context)
 {
-  if (cmHasLiteralPrefix(name, ":")) {
+  if (cmHasPrefix(name, ':')) {
     return cmStrCat(context, ':', name);
   }
 
@@ -255,6 +256,21 @@
   }
 }
 
+void AppendImportProperty(cmMakefile* makefile, cmTarget* target,
+                          cm::string_view property,
+                          cm::string_view configuration,
+                          std::string const& value)
+{
+  if (!configuration.empty()) {
+    std::string const fullprop = cmStrCat(
+      "IMPORTED_", property, '_', cmSystemTools::UpperCase(configuration));
+    target->AppendProperty(fullprop, value, makefile->GetBacktrace());
+  } else {
+    std::string const fullprop = cmStrCat("IMPORTED_", property);
+    target->AppendProperty(fullprop, value, makefile->GetBacktrace());
+  }
+}
+
 template <typename Transform>
 void AppendLanguageProperties(cmMakefile* makefile, cmTarget* target,
                               cm::string_view property,
@@ -774,12 +790,33 @@
                    NormalizeTargetName(dep, package));
   }
 
+  for (std::string const& dep : ReadList(data, "compile_requires")) {
+    std::string const& lib =
+      cmStrCat("$<COMPILE_ONLY:"_s, NormalizeTargetName(dep, package), '>');
+    AppendProperty(makefile, target, "LINK_LIBRARIES"_s, configuration, lib);
+  }
+
   for (std::string const& dep : ReadList(data, "link_requires")) {
     std::string const& lib =
       cmStrCat("$<LINK_ONLY:"_s, NormalizeTargetName(dep, package), '>');
     AppendProperty(makefile, target, "LINK_LIBRARIES"_s, configuration, lib);
   }
 
+  for (std::string const& dep : ReadList(data, "dyld_requires")) {
+    AppendImportProperty(makefile, target, "LINK_DEPENDENT_LIBRARIES"_s,
+                         configuration, NormalizeTargetName(dep, package));
+  }
+
+  for (std::string const& lib : ReadList(data, "link_libraries")) {
+    AppendProperty(makefile, target, "LINK_LIBRARIES"_s, configuration, lib);
+  }
+
+  // TODO: Handle non-configuration modules
+  // once IMPORTED_CXX_MODULES supports it
+  if (!configuration.empty()) {
+    this->ReadCxxModulesMetadata(makefile, target, configuration, data);
+  }
+
   // Add other information.
   if (configuration.empty()) {
     this->SetMetaProperty(makefile, target, "SPDX_LICENSE", data, "license",
@@ -787,12 +824,37 @@
   }
 }
 
+void cmPackageInfoReader::ReadCxxModulesMetadata(
+  cmMakefile* makefile, cmTarget* target, cm::string_view configuration,
+  Json::Value const& object) const
+{
+#ifndef CMAKE_BOOTSTRAP
+  Json::Value const& path = object["cpp_module_metadata"];
+
+  if (!path.isString()) {
+    return;
+  }
+
+  cmCxxModuleMetadata::ParseResult result =
+    cmCxxModuleMetadata::LoadFromFile(this->ResolvePath(path.asString()));
+
+  if (!result) {
+    makefile->IssueMessage(
+      MessageType::WARNING,
+      cmStrCat("Error parsing module manifest:\n"_s, result.Error));
+    return;
+  }
+
+  cmCxxModuleMetadata::PopulateTarget(*target, *result.Meta, configuration);
+#endif
+}
+
 cmTarget* cmPackageInfoReader::AddLibraryComponent(
   cmMakefile* makefile, cmStateEnums::TargetType type, std::string const& name,
-  Json::Value const& data, std::string const& package) const
+  Json::Value const& data, std::string const& package, bool global) const
 {
   // Create the imported target.
-  cmTarget* const target = makefile->AddImportedTarget(name, type, false);
+  cmTarget* const target = makefile->AddImportedTarget(name, type, global);
   target->SetOrigin(cmTarget::Origin::Cps);
 
   // Set target properties.
@@ -806,7 +868,7 @@
 }
 
 bool cmPackageInfoReader::ImportTargets(cmMakefile* makefile,
-                                        cmExecutionStatus& status)
+                                        cmExecutionStatus& status, bool global)
 {
   std::string const& package = this->GetName();
 
@@ -828,23 +890,23 @@
       }
     }
 
+    auto createTarget = [&](cmStateEnums::TargetType typeEnum) {
+      return this->AddLibraryComponent(makefile, typeEnum, fullName, *ci,
+                                       package, global);
+    };
+
     cmTarget* target = nullptr;
     if (type == "symbolic"_s) {
-      target = this->AddLibraryComponent(
-        makefile, cmStateEnums::INTERFACE_LIBRARY, fullName, *ci, package);
+      target = createTarget(cmStateEnums::INTERFACE_LIBRARY);
       target->SetSymbolic(true);
     } else if (type == "dylib"_s) {
-      target = this->AddLibraryComponent(
-        makefile, cmStateEnums::SHARED_LIBRARY, fullName, *ci, package);
+      target = createTarget(cmStateEnums::SHARED_LIBRARY);
     } else if (type == "module"_s) {
-      target = this->AddLibraryComponent(
-        makefile, cmStateEnums::MODULE_LIBRARY, fullName, *ci, package);
+      target = createTarget(cmStateEnums::MODULE_LIBRARY);
     } else if (type == "archive"_s) {
-      target = this->AddLibraryComponent(
-        makefile, cmStateEnums::STATIC_LIBRARY, fullName, *ci, package);
+      target = createTarget(cmStateEnums::STATIC_LIBRARY);
     } else if (type == "interface"_s) {
-      target = this->AddLibraryComponent(
-        makefile, cmStateEnums::INTERFACE_LIBRARY, fullName, *ci, package);
+      target = createTarget(cmStateEnums::INTERFACE_LIBRARY);
     } else {
       makefile->IssueMessage(MessageType::WARNING,
                              cmStrCat(R"(component ")"_s, fullName,
@@ -868,7 +930,7 @@
     }
 
     cmTarget* const target = makefile->AddImportedTarget(
-      package, cmStateEnums::INTERFACE_LIBRARY, false);
+      package, cmStateEnums::INTERFACE_LIBRARY, global);
     for (std::string const& name : defaultComponents) {
       std::string const& fullName = cmStrCat(package, "::"_s, name);
       AppendProperty(makefile, target, "LINK_LIBRARIES"_s, {}, fullName);
diff --git a/Source/cmPackageInfoReader.h b/Source/cmPackageInfoReader.h
index 6f4211a..0050955 100644
--- a/Source/cmPackageInfoReader.h
+++ b/Source/cmPackageInfoReader.h
@@ -77,7 +77,8 @@
   std::vector<std::string> GetComponentNames() const;
 
   /// Create targets for components specified in the CPS file.
-  bool ImportTargets(cmMakefile* makefile, cmExecutionStatus& status);
+  bool ImportTargets(cmMakefile* makefile, cmExecutionStatus& status,
+                     bool global);
 
   /// Add configuration-specific properties for targets.
   bool ImportTargetConfigurations(cmMakefile* makefile,
@@ -90,7 +91,7 @@
                                 cmStateEnums::TargetType type,
                                 std::string const& name,
                                 Json::Value const& data,
-                                std::string const& package) const;
+                                std::string const& package, bool global) const;
 
   void AddTargetConfiguration(cmTarget* target,
                               cm::string_view configuration) const;
@@ -107,6 +108,9 @@
                        std::string const& property, Json::Value const& object,
                        std::string const& attribute,
                        std::string const& defaultValue = {}) const;
+  void ReadCxxModulesMetadata(cmMakefile* makefile, cmTarget* target,
+                              cm::string_view configuration,
+                              Json::Value const& object) const;
 
   std::string ResolvePath(std::string path) const;
 
diff --git a/Source/cmPathResolver.cxx b/Source/cmPathResolver.cxx
index 32f3ef7..f384dbf 100644
--- a/Source/cmPathResolver.cxx
+++ b/Source/cmPathResolver.cxx
@@ -13,9 +13,9 @@
 #include <cmext/string_view>
 
 #ifdef _WIN32
-#  include <cctype>
-
 #  include <windows.h>
+
+#  include <cmsys/String.h>
 #endif
 
 #define MAX_SYMBOLIC_LINKS 32
@@ -95,7 +95,7 @@
 Root ClassifyRoot(cm::string_view p)
 {
 #ifdef _WIN32
-  if (p.size() >= 2 && std::isalpha(p[0]) && p[1] == ':') {
+  if (p.size() >= 2 && cmsysString_isalpha(p[0]) && p[1] == ':') {
     return Root::Drive;
   }
   if (p.size() >= 3 && p[0] == '/' && p[1] == '/' && p[2] != '/') {
@@ -170,7 +170,8 @@
   // Use the drive's working directory, if any.
   std::string d = this->OS.GetWorkingDirectoryOnDrive(letter);
   std::replace(d.begin(), d.end(), '\\', '/');
-  if (d.size() >= 3 && std::toupper(d[0]) == std::toupper(letter) &&
+  if (d.size() >= 3 &&
+      cmsysString_toupper(d[0]) == cmsysString_toupper(letter) &&
       d[1] == ':' && d[2] == '/') {
     d[0] = letter;
     d.push_back('/');
@@ -179,7 +180,8 @@
 
   // Use the current working directory if the drive matches.
   d = this->OS.GetWorkingDirectory();
-  if (d.size() >= 3 && std::toupper(d[0]) == std::toupper(letter) &&
+  if (d.size() >= 3 &&
+      cmsysString_toupper(d[0]) == cmsysString_toupper(letter) &&
       d[1] == ':' && d[2] == '/') {
     d[0] = letter;
     d.push_back('/');
@@ -280,7 +282,7 @@
 
     if (Policy::ActualCase == Options::ActualCase::Yes) {
       // Normalize the drive letter to upper-case.
-      P[0] = static_cast<char>(std::toupper(P[0]));
+      P[0] = static_cast<char>(cmsysString_toupper(P[0]));
     }
 
     // The root is a drive letter.  The root '/' immediately follows.
diff --git a/Source/cmPkgConfigResolver.cxx b/Source/cmPkgConfigResolver.cxx
index 8be5f34..54598c8 100644
--- a/Source/cmPkgConfigResolver.cxx
+++ b/Source/cmPkgConfigResolver.cxx
@@ -4,7 +4,6 @@
 #include "cmPkgConfigResolver.h"
 
 #include <algorithm>
-#include <cctype>
 #include <cstring>
 #include <iterator>
 #include <string>
@@ -15,6 +14,8 @@
 #include <cm/optional>
 #include <cm/string_view>
 
+#include "cmsys/String.h"
+
 #include "cmPkgConfigParser.h"
 #include "cmStringAlgorithms.h"
 
@@ -24,7 +25,7 @@
 {
   if (!str.empty()) {
     auto it = str.end() - 1;
-    for (; std::isspace(*it); --it) {
+    for (; cmsysString_isspace(*it); --it) {
       if (it == str.begin()) {
         str.clear();
         return;
@@ -45,11 +46,11 @@
   auto begin = str.begin() + size;
   auto cur = str.end() - 1;
 
-  while (cur != begin && std::isspace(*cur)) {
+  while (cur != begin && cmsysString_isspace(*cur)) {
     --cur;
   }
 
-  if (std::isspace(*cur)) {
+  if (cmsysString_isspace(*cur)) {
     return {};
   }
 
@@ -59,7 +60,8 @@
 cm::string_view TrimFlag(cm::string_view flag)
 {
   std::size_t trim_size = 2;
-  for (auto c = flag.rbegin(); c != flag.rend() && std::isspace(*c); ++c) {
+  for (auto c = flag.rbegin(); c != flag.rend() && cmsysString_isspace(*c);
+       ++c) {
     ++trim_size;
   }
   return { flag.data() + 2, flag.size() - trim_size };
@@ -406,7 +408,7 @@
   std::vector<cm::string_view> result;
 
   auto it = flagline.begin();
-  while (it != flagline.end() && std::isspace(*it)) {
+  while (it != flagline.end() && cmsysString_isspace(*it)) {
     ++it;
   }
 
@@ -414,11 +416,11 @@
     char const* start = &(*it);
     std::size_t len = 0;
 
-    for (; it != flagline.end() && !std::isspace(*it); ++it) {
+    for (; it != flagline.end() && !cmsysString_isspace(*it); ++it) {
       ++len;
     }
 
-    for (; it != flagline.end() && std::isspace(*it); ++it) {
+    for (; it != flagline.end() && cmsysString_isspace(*it); ++it) {
       ++len;
     }
 
@@ -665,12 +667,12 @@
       return result;
     }
 
-    if (!std::isspace(*cur)) {
+    if (!cmsysString_isspace(*cur)) {
       break;
     }
   }
 
-  for (; cur != end && !std::isspace(*cur) && *cur != ','; ++cur) {
+  for (; cur != end && !cmsysString_isspace(*cur) && *cur != ','; ++cur) {
     result.Version += *cur;
   }
 
@@ -687,7 +689,7 @@
   auto end = deps.end();
 
   while (cur != end) {
-    while ((std::isspace(*cur) || *cur == ',')) {
+    while ((cmsysString_isspace(*cur) || *cur == ',')) {
       if (++cur == end) {
         return result;
       }
@@ -696,7 +698,7 @@
     result.emplace_back();
     auto& dep = result.back();
 
-    while (!std::isspace(*cur) && *cur != ',') {
+    while (!cmsysString_isspace(*cur) && *cur != ',') {
       dep.Name += *cur;
       if (++cur == end) {
         return result;
@@ -713,7 +715,7 @@
           return true;
         }
 
-        if (!std::isspace(*cur)) {
+        if (!cmsysString_isspace(*cur)) {
           return false;
         }
       }
@@ -769,11 +771,11 @@
   auto b_end = provided.end();
 
   while (a_cur != a_end && b_cur != b_end) {
-    while (a_cur != a_end && !std::isalnum(*a_cur) && *a_cur != '~') {
+    while (a_cur != a_end && !cmsysString_isalnum(*a_cur) && *a_cur != '~') {
       ++a_cur;
     }
 
-    while (b_cur != b_end && !std::isalnum(*b_cur) && *b_cur != '~') {
+    while (b_cur != b_end && !cmsysString_isalnum(*b_cur) && *b_cur != '~') {
       ++b_cur;
     }
 
@@ -799,23 +801,23 @@
     auto b_seg = b_cur;
     bool is_num;
 
-    if (std::isdigit(*a_cur)) {
+    if (cmsysString_isdigit(*a_cur)) {
       is_num = true;
-      while (a_cur != a_end && std::isdigit(*a_cur)) {
+      while (a_cur != a_end && cmsysString_isdigit(*a_cur)) {
         ++a_cur;
       }
 
-      while (b_cur != b_end && std::isdigit(*b_cur)) {
+      while (b_cur != b_end && cmsysString_isdigit(*b_cur)) {
         ++b_cur;
       }
 
     } else {
       is_num = false;
-      while (a_cur != a_end && std::isalpha(*a_cur)) {
+      while (a_cur != a_end && cmsysString_isalpha(*a_cur)) {
         ++a_cur;
       }
 
-      while (b_cur != b_end && std::isalpha(*b_cur)) {
+      while (b_cur != b_end && cmsysString_isalpha(*b_cur)) {
         ++b_cur;
       }
     }
diff --git a/Source/cmPlaceholderExpander.cxx b/Source/cmPlaceholderExpander.cxx
index f5dc544..aea427b 100644
--- a/Source/cmPlaceholderExpander.cxx
+++ b/Source/cmPlaceholderExpander.cxx
@@ -2,7 +2,7 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "cmPlaceholderExpander.h"
 
-#include <cctype>
+#include "cmsys/String.h"
 
 std::string& cmPlaceholderExpander::ExpandVariables(std::string& s)
 {
@@ -23,7 +23,7 @@
     char c = s[start + 1];
     // if the next char after the < is not A-Za-z then
     // skip it and try to find the next < in the string
-    if (!isalpha(c)) {
+    if (!cmsysString_isalpha(c)) {
       start = s.find('<', start + 1);
     } else {
       // extract the var
diff --git a/Source/cmPlistParser.cxx b/Source/cmPlistParser.cxx
index d0fedec..eaf0fd0 100644
--- a/Source/cmPlistParser.cxx
+++ b/Source/cmPlistParser.cxx
@@ -27,7 +27,7 @@
 
   Json::Reader reader;
   Json::Value value;
-  cmUVPipeIStream outputStream(chain.GetLoop(), chain.OutputStream());
+  cmUVIStream outputStream(chain.OutputStream());
   if (!reader.parse(outputStream, value)) {
     return cm::nullopt;
   }
diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx
index 4583863..337f220 100644
--- a/Source/cmPolicies.cxx
+++ b/Source/cmPolicies.cxx
@@ -3,12 +3,13 @@
 #include "cmPolicies.h"
 
 #include <cassert>
-#include <cctype>
 #include <cstdio>
 #include <cstring>
 #include <sstream>
 #include <vector>
 
+#include "cmsys/String.h"
+
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -32,7 +33,7 @@
     return true;
   }
   for (int i = 3; i < 7; ++i) {
-    if (!isdigit(*(input + i))) {
+    if (!cmsysString_isdigit(*(input + i))) {
       return false;
     }
   }
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index a278d7f..8afb04b 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -612,7 +612,24 @@
          4, 2, 0, WARN)                                                       \
   SELECT(POLICY, CMP0204,                                                     \
          "A character set is always defined when targeting the MSVC ABI.", 4, \
-         2, 0, WARN)
+         2, 0, WARN)                                                          \
+  SELECT(POLICY, CMP0205,                                                     \
+         "file(CREATE_LINK) with COPY_ON_ERROR copies directory content.", 4, \
+         3, 0, WARN)                                                          \
+  SELECT(POLICY, CMP0206,                                                     \
+         "The CPack Archive Generator defaults to UID 0 and GID 0.", 4, 3, 0, \
+         WARN)                                                                \
+  SELECT(POLICY, CMP0207,                                                     \
+         "file(GET_RUNTIME_DEPENDENCIES) normalizes paths before matching.",  \
+         4, 3, 0, WARN)                                                       \
+  SELECT(POLICY, CMP0208, "export(EXPORT) does not allow empty arguments.",   \
+         4, 3, 0, WARN)                                                       \
+  SELECT(POLICY, CMP0209,                                                     \
+         "Verify interface header sets checks executables without exports.",  \
+         4, 3, 0, WARN)                                                       \
+  SELECT(POLICY, CMP0210,                                                     \
+         "CMAKE_<LANG>_LINK_FLAGS adds link flags to all target types.", 4,   \
+         3, 0, WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \
@@ -665,7 +682,9 @@
   F(CMP0200)                                                                  \
   F(CMP0202)                                                                  \
   F(CMP0203)                                                                  \
-  F(CMP0204)
+  F(CMP0204)                                                                  \
+  F(CMP0209)                                                                  \
+  F(CMP0210)
 
 #define CM_FOR_EACH_CUSTOM_COMMAND_POLICY(F)                                  \
   F(CMP0116)                                                                  \
diff --git a/Source/cmProcessTools.cxx b/Source/cmProcessTools.cxx
index d5d5160..f072e2e 100644
--- a/Source/cmProcessTools.cxx
+++ b/Source/cmProcessTools.cxx
@@ -9,7 +9,6 @@
 #include <cm3p/uv.h>
 
 #include "cmProcessOutput.h"
-#include "cmUVHandlePtr.h"
 #include "cmUVStream.h"
 
 std::vector<cmUVProcessChain::Status> cmProcessTools::RunProcess(
@@ -24,11 +23,8 @@
   auto chain = builder.Start();
 
   std::string strdata;
-  cm::uv_pipe_ptr outputPipe;
-  outputPipe.init(chain.GetLoop(), 0);
-  uv_pipe_open(outputPipe, chain.OutputStream());
   auto outputHandle = cmUVStreamRead(
-    outputPipe,
+    chain.OutputStream(),
     [&out, &processOutput, &strdata](std::vector<char> data) {
       if (out) {
         processOutput.DecodeText(data.data(), data.size(), strdata, 1);
@@ -38,11 +34,8 @@
       }
     },
     [&out]() { out = nullptr; });
-  cm::uv_pipe_ptr errorPipe;
-  errorPipe.init(chain.GetLoop(), 0);
-  uv_pipe_open(errorPipe, chain.ErrorStream());
   auto errorHandle = cmUVStreamRead(
-    errorPipe,
+    chain.ErrorStream(),
     [&err, &processOutput, &strdata](std::vector<char> data) {
       if (err) {
         processOutput.DecodeText(data.data(), data.size(), strdata, 2);
diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx
index dd91fe868..8551132 100644
--- a/Source/cmProjectCommand.cxx
+++ b/Source/cmProjectCommand.cxx
@@ -17,7 +17,6 @@
 #include "cmArgumentParser.h"
 #include "cmArgumentParserTypes.h"
 #include "cmExecutionStatus.h"
-#include "cmExperimental.h"
 #include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -68,24 +67,18 @@
   parser.BindKeywordMissingValue(missingValueKeywords)
     .BindParsedKeywords(parsedKeywords)
     .Bind("VERSION"_s, prArgs.Version)
+    .Bind("COMPAT_VERSION"_s, prArgs.CompatVersion)
+    .Bind("SPDX_LICENSE"_s, prArgs.License)
     .Bind("DESCRIPTION"_s, prArgs.Description)
     .Bind("HOMEPAGE_URL"_s, prArgs.HomepageURL)
     .Bind("LANGUAGES"_s, prArgs.Languages);
 
-  cmMakefile& mf = status.GetMakefile();
-  bool enablePackageInfo = cmExperimental::HasSupportEnabled(
-    mf, cmExperimental::Feature::ExportPackageInfo);
-
-  if (enablePackageInfo) {
-    parser.Bind("COMPAT_VERSION"_s, prArgs.CompatVersion);
-    parser.Bind("SPDX_LICENSE"_s, prArgs.License);
-  }
-
   if (args.empty()) {
     status.SetError("PROJECT called with incorrect number of arguments");
     return false;
   }
 
+  cmMakefile& mf = status.GetMakefile();
   std::string const& projectName = args[0];
   if (parser.HasKeyword(projectName)) {
     mf.IssueMessage(
@@ -273,7 +266,7 @@
   // Note, this intentionally doesn't touch cache variables as the legacy
   // behavior did not modify cache
   auto checkAndClearVariables = [&](cm::string_view var) {
-    std::vector<std::string> vv = { "PROJECT_", cmStrCat(projectName, "_") };
+    std::vector<std::string> vv = { "PROJECT_", cmStrCat(projectName, '_') };
     if (mf.IsRootMakefile()) {
       vv.push_back("CMAKE_PROJECT_");
     }
diff --git a/Source/cmProjectInfoArguments.cxx b/Source/cmProjectInfoArguments.cxx
new file mode 100644
index 0000000..ab186e5
--- /dev/null
+++ b/Source/cmProjectInfoArguments.cxx
@@ -0,0 +1,129 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#include "cmProjectInfoArguments.h"
+
+#include <utility>
+
+#include <cm/string_view>
+
+#include "cmExecutionStatus.h"
+#include "cmGeneratorExpression.h"
+#include "cmMakefile.h"
+#include "cmStateSnapshot.h"
+#include "cmStringAlgorithms.h"
+#include "cmValue.h"
+
+template void cmProjectInfoArguments::Bind<void>(cmArgumentParser<void>&,
+                                                 cmProjectInfoArguments*);
+
+#define ENFORCE_REQUIRES(req, value, arg)                                     \
+  do {                                                                        \
+    if (ArgWasSpecified(value)) {                                             \
+      status.SetError(arg " requires " req ".");                              \
+      return false;                                                           \
+    }                                                                         \
+  } while (false)
+
+#define ENFORCE_EXCLUSIVE(arg1, value, arg2)                                  \
+  do {                                                                        \
+    if (ArgWasSpecified(value)) {                                             \
+      status.SetError(arg1 " and " arg2 " are mutually exclusive.");          \
+      return false;                                                           \
+    }                                                                         \
+  } while (false)
+
+cmProjectInfoArguments::cmProjectInfoArguments() = default;
+
+bool cmProjectInfoArguments::Check(cmExecutionStatus& status) const
+{
+  // Check for incompatible options.
+  if (this->NoProjectDefaults) {
+    ENFORCE_EXCLUSIVE("PROJECT", this->ProjectName, "NO_PROJECT_METADATA");
+  }
+
+  // Validate the package name.
+  if (!this->PackageName.empty()) {
+    if (!cmGeneratorExpression::IsValidTargetName(this->PackageName) ||
+        this->PackageName.find(':') != std::string::npos) {
+      status.SetError(cmStrCat(this->CommandName(),
+                               " given invalid package name \""_s,
+                               this->PackageName, "\"."_s));
+      return false;
+    }
+  }
+
+  return true;
+}
+
+#undef ENFORCE_REQUIRES
+#undef ENFORCE_EXCLUSIVE
+
+bool cmProjectInfoArguments::SetMetadataFromProject(cmExecutionStatus& status)
+{
+  // Determine what project to use for inherited metadata.
+  if (!this->SetEffectiveProject(status)) {
+    return false;
+  }
+
+  if (this->ProjectName.empty()) {
+    // We are not inheriting from a project.
+    return true;
+  }
+
+  cmMakefile& mf = status.GetMakefile();
+  auto mapProjectValue = [&](std::string& arg, cm::string_view suffix) {
+    cmValue const& projectValue =
+      mf.GetDefinition(cmStrCat(this->ProjectName, '_', suffix));
+    if (projectValue) {
+      arg = *projectValue;
+      return true;
+    }
+    return false;
+  };
+
+  if (this->Version.empty()) {
+    if (mapProjectValue(this->Version, "VERSION"_s)) {
+      mapProjectValue(this->VersionCompat, "COMPAT_VERSION"_s);
+    }
+  }
+
+  if (this->License.empty()) {
+    mapProjectValue(this->License, "SPDX_LICENSE"_s);
+  }
+
+  if (this->Description.empty()) {
+    mapProjectValue(this->Description, "DESCRIPTION"_s);
+  }
+
+  if (this->Website.empty()) {
+    mapProjectValue(this->Website, "HOMEPAGE_URL"_s);
+  }
+
+  return true;
+}
+
+bool cmProjectInfoArguments::SetEffectiveProject(cmExecutionStatus& status)
+{
+  if (this->NoProjectDefaults) {
+    // User requested that metadata not be inherited.
+    return true;
+  }
+
+  cmMakefile& mf = status.GetMakefile();
+  if (!this->ProjectName.empty()) {
+    // User specified a project; make sure it exists.
+    if (!mf.GetStateSnapshot().CheckProjectName(this->ProjectName)) {
+      status.SetError(cmStrCat(R"(PROJECT given unknown project name ")"_s,
+                               this->ProjectName, R"(".)"_s));
+      return false;
+    }
+  } else {
+    // No project was specified; check if the package name is also a project.
+    std::string project = mf.GetStateSnapshot().GetProjectName();
+    if (this->PackageName == project) {
+      this->ProjectName = std::move(project);
+    }
+  }
+
+  return true;
+}
diff --git a/Source/cmProjectInfoArguments.h b/Source/cmProjectInfoArguments.h
new file mode 100644
index 0000000..6b80223
--- /dev/null
+++ b/Source/cmProjectInfoArguments.h
@@ -0,0 +1,103 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+
+#include <cm/string_view>
+#include <cm/type_traits>
+#include <cmext/string_view>
+
+#include "cmArgumentParser.h" // IWYU pragma: keep
+#include "cmArgumentParserTypes.h"
+
+class cmExecutionStatus;
+
+/** \class cmProjectInfoArguments
+ * \brief Convey information about a project.
+ *
+ * This class encapsulates several attributes of project metadata;
+ * specifically, those which can be inherited from the project. It is used as
+ * the base class for classes specific to SBOM and PACKAGE_INFO exports.
+ */
+class cmProjectInfoArguments
+{
+public:
+  cmProjectInfoArguments();
+  cmProjectInfoArguments(cmProjectInfoArguments const&) = default;
+  cmProjectInfoArguments& operator=(cmProjectInfoArguments const&) = default;
+  cmProjectInfoArguments(cmProjectInfoArguments&&) = default;
+  cmProjectInfoArguments& operator=(cmProjectInfoArguments&&) = default;
+
+  virtual ~cmProjectInfoArguments() = default;
+
+  /// Ensure that no conflicting options were specified.
+  virtual bool Check(cmExecutionStatus& status) const;
+
+  /// Set metadata (not already specified) from either the specified project,
+  /// or from the project which matches the package name.
+  bool SetMetadataFromProject(cmExecutionStatus& status);
+
+  ArgumentParser::NonEmpty<std::string> PackageName;
+  ArgumentParser::NonEmpty<std::string> Version;
+  ArgumentParser::NonEmpty<std::string> VersionCompat;
+  ArgumentParser::NonEmpty<std::string> VersionSchema;
+  ArgumentParser::NonEmpty<std::string> License;
+  ArgumentParser::NonEmpty<std::string> Description;
+  ArgumentParser::NonEmpty<std::string> Website;
+
+  ArgumentParser::NonEmpty<std::string> ProjectName;
+  bool NoProjectDefaults = false;
+
+protected:
+  virtual cm::string_view CommandName() const = 0;
+
+  virtual bool SetEffectiveProject(cmExecutionStatus& status);
+
+  template <typename T>
+  static void Bind(cmArgumentParser<T>& parser, cmProjectInfoArguments* self)
+  {
+    Bind(self, parser, "VERSION"_s, &cmProjectInfoArguments::Version);
+    Bind(self, parser, "LICENSE"_s, &cmProjectInfoArguments::License);
+    Bind(self, parser, "DESCRIPTION"_s, &cmProjectInfoArguments::Description);
+    Bind(self, parser, "HOMEPAGE_URL"_s, &cmProjectInfoArguments::Website);
+
+    Bind(self, parser, "PROJECT"_s, &cmProjectInfoArguments::ProjectName);
+    Bind(self, parser, "NO_PROJECT_METADATA"_s,
+         &cmProjectInfoArguments::NoProjectDefaults);
+  }
+
+  template <
+    typename Self, typename T, typename U,
+    typename =
+      cm::enable_if_t<std::is_base_of<cmProjectInfoArguments, Self>::value>,
+    typename =
+      cm::enable_if_t<std::is_base_of<cmProjectInfoArguments, T>::value>>
+  static void Bind(Self*, cmArgumentParser<T>& parser,
+                   cm::static_string_view name, U Self::*member)
+  {
+    parser.Bind(name, member);
+  }
+
+  template <
+    typename Self, typename T, typename U,
+    typename =
+      cm::enable_if_t<std::is_base_of<cmProjectInfoArguments, Self>::value>,
+    typename =
+      cm::enable_if_t<std::is_base_of<cmProjectInfoArguments, T>::value>>
+  static void Bind(Self* self, cmArgumentParser<void>& parser,
+                   cm::static_string_view name, U T::*member)
+  {
+    parser.Bind(name, (self)->*member);
+  }
+
+  static bool ArgWasSpecified(std::string const& value)
+  {
+    return !value.empty();
+  }
+};
+
+extern template void cmProjectInfoArguments::Bind<void>(
+  cmArgumentParser<void>&, cmProjectInfoArguments*);
diff --git a/Source/cmProperty.h b/Source/cmProperty.h
index 5aa631d..43e5fab 100644
--- a/Source/cmProperty.h
+++ b/Source/cmProperty.h
@@ -17,6 +17,7 @@
     TEST,
     VARIABLE,
     CACHED_VARIABLE,
-    INSTALL
+    INSTALL,
+    FILE_SET
   };
 };
diff --git a/Source/cmPropertyDefinition.cxx b/Source/cmPropertyDefinition.cxx
index 49281ae..4130f79 100644
--- a/Source/cmPropertyDefinition.cxx
+++ b/Source/cmPropertyDefinition.cxx
@@ -3,6 +3,7 @@
 #include "cmPropertyDefinition.h"
 
 #include <tuple>
+#include <utility>
 
 cmPropertyDefinition::cmPropertyDefinition(std::string shortDescription,
                                            std::string fullDescription,
@@ -20,22 +21,29 @@
   std::string const& ShortDescription, std::string const& FullDescription,
   bool chain, std::string const& initializeFromVariable)
 {
-  auto it = this->Map_.find(KeyType(name, scope));
+  auto it = this->Map_.find(name);
   if (it == this->Map_.end()) {
+    it = this->Map_.emplace(name, ScopeMap()).first;
+  }
+  ScopeMap& scopeMap = it->second;
+  auto scopeIter = scopeMap.find(scope);
+  if (scopeIter == scopeMap.end()) {
     // try_emplace() since C++17
-    this->Map_.emplace(std::piecewise_construct,
-                       std::forward_as_tuple(name, scope),
-                       std::forward_as_tuple(ShortDescription, FullDescription,
-                                             chain, initializeFromVariable));
+    scopeMap.emplace(std::piecewise_construct, std::forward_as_tuple(scope),
+                     std::forward_as_tuple(ShortDescription, FullDescription,
+                                           chain, initializeFromVariable));
   }
 }
 
 cmPropertyDefinition const* cmPropertyDefinitionMap::GetPropertyDefinition(
   std::string const& name, cmProperty::ScopeType scope) const
 {
-  auto it = this->Map_.find(KeyType(name, scope));
-  if (it != this->Map_.end()) {
-    return &it->second;
+  auto nameIter = this->Map_.find(name);
+  if (nameIter != this->Map_.end()) {
+    auto scopeIter = nameIter->second.find(scope);
+    if (scopeIter != nameIter->second.end()) {
+      return &scopeIter->second;
+    }
   }
 
   return nullptr;
diff --git a/Source/cmPropertyDefinition.h b/Source/cmPropertyDefinition.h
index 4147d9b..7a6a00a 100644
--- a/Source/cmPropertyDefinition.h
+++ b/Source/cmPropertyDefinition.h
@@ -6,7 +6,6 @@
 
 #include <map>
 #include <string>
-#include <utility>
 
 #include "cmProperty.h"
 
@@ -69,12 +68,9 @@
   cmPropertyDefinition const* GetPropertyDefinition(
     std::string const& name, cmProperty::ScopeType scope) const;
 
-  using KeyType = std::pair<std::string, cmProperty::ScopeType>;
-  std::map<KeyType, cmPropertyDefinition> const& GetMap() const
-  {
-    return this->Map_;
-  }
+  using ScopeMap = std::map<cmProperty::ScopeType, cmPropertyDefinition>;
+  std::map<std::string, ScopeMap> const& GetMap() const { return this->Map_; }
 
 private:
-  std::map<KeyType, cmPropertyDefinition> Map_;
+  std::map<std::string, ScopeMap> Map_;
 };
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 3955237..cdba0c9 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -1291,11 +1291,18 @@
       // Output file name
       if (this->MultiConfig && !this->GlobalGen->IsXcode() &&
           this->UseBetterGraph) {
-        qrc.OutputFile = cmStrCat(this->Dir.Build, '/', qrc.QrcPathChecksum,
-                                  "_$<CONFIG>/qrc_", qrc.QrcName, ".cpp");
+        this->ConfigFileNamesAndGenex(qrc.OutputFile, qrc.OutputFileGenex,
+                                      cmStrCat(this->Dir.Build, '/',
+                                               qrc.QrcPathChecksum, "/qrc_",
+                                               qrc.QrcName),
+                                      ".cpp"_s);
       } else {
-        qrc.OutputFile = cmStrCat(this->Dir.Build, '/', qrc.QrcPathChecksum,
-                                  "/qrc_", qrc.QrcName, ".cpp");
+        // For non-better-graph, all configs use the same file
+        std::string const outputFile =
+          cmStrCat(this->Dir.Build, '/', qrc.QrcPathChecksum, "/qrc_",
+                   qrc.QrcName, ".cpp");
+        this->ConfigFileNameCommon(qrc.OutputFile, outputFile);
+        qrc.OutputFileGenex = outputFile;
       }
       std::string const base = cmStrCat(this->Dir.Info, "/AutoRcc_",
                                         qrc.QrcName, '_', qrc.QrcPathChecksum);
@@ -1727,12 +1734,23 @@
     // Register info file as generated by CMake
     this->Makefile->AddCMakeOutputFile(qrc.InfoFile);
     // Register file at target
-    {
-      cmSourceFile* sf = this->AddGeneratedSource(qrc.OutputFile, this->Rcc);
-      sf->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "On");
+    this->AddGeneratedSource(qrc.OutputFile, this->Rcc);
+
+    // Set SKIP_UNITY_BUILD_INCLUSION property on generated source(s)
+    auto setSkipUnity = [this](std::string const& path) {
+      if (cmSourceFile* sf = this->Makefile->GetSource(path)) {
+        sf->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "On");
+      }
+    };
+    if (!this->MultiConfig || this->GlobalGen->IsXcode()) {
+      setSkipUnity(qrc.OutputFile.Default);
+    } else {
+      for (auto const& p : qrc.OutputFile.Config) {
+        setSkipUnity(p.second);
+      }
     }
 
-    std::vector<std::string> ccOutput{ qrc.OutputFile };
+    std::vector<std::string> ccOutput{ qrc.OutputFileGenex };
 
     // Add the .qrc and info file to the custom command dependencies
     std::vector<std::string> ccDepends{ qrc.QrcFile, qrc.InfoFile };
@@ -2027,9 +2045,23 @@
       this->GenTarget->Makefile->GetSafeDefinition(CompileOptionFlag);
 
     if (!CompileOptionValue.empty()) {
-      if (this->Moc.PredefsCmd.size() >= 3) {
-        this->Moc.PredefsCmd.insert(this->Moc.PredefsCmd.begin() + 1,
-                                    CompileOptionValue);
+      // Determine where to insert the compile option (e.g., -std=gnu++23).
+      // CMAKE_CXX_COMPILER_PREDEFINES_COMMAND is built as:
+      //   [CMAKE_CXX_COMPILER, CMAKE_CXX_COMPILER_ARG1, predefs_flags...]
+      // We need to insert after all compiler elements, before predefs flags.
+      size_t compilerElements = 1; // CMAKE_CXX_COMPILER
+
+      cmValue compilerArg1 =
+        this->Makefile->GetDefinition("CMAKE_CXX_COMPILER_ARG1");
+      if (compilerArg1 && !compilerArg1->empty()) {
+        std::vector<std::string> arg1List;
+        cmSystemTools::ParseUnixCommandLine(compilerArg1->c_str(), arg1List);
+        compilerElements += arg1List.size();
+      }
+
+      if (this->Moc.PredefsCmd.size() > compilerElements) {
+        this->Moc.PredefsCmd.insert(
+          this->Moc.PredefsCmd.begin() + compilerElements, CompileOptionValue);
       }
     }
     info.SetArray("MOC_PREDEFS_CMD", this->Moc.PredefsCmd);
@@ -2094,7 +2126,8 @@
     // qrc file
     info.Set("SOURCE", qrc.QrcFile);
     info.Set("OUTPUT_CHECKSUM", qrc.QrcPathChecksum);
-    info.Set("OUTPUT_NAME", cmSystemTools::GetFilenameName(qrc.OutputFile));
+    info.Set("OUTPUT_NAME",
+             cmSystemTools::GetFilenameName(qrc.OutputFileGenex));
     info.SetArray("OPTIONS", qrc.Options);
     info.SetConfigArray("INPUTS", qrc.Resources);
 
@@ -2223,6 +2256,17 @@
   }
 }
 
+void cmQtAutoGenInitializer::ConfigFileNameCommon(ConfigString& configString,
+                                                  std::string const& fileName)
+{
+  configString.Default = fileName;
+  if (this->MultiConfig) {
+    for (auto const& cfg : this->ConfigsList) {
+      configString.Config[cfg] = fileName;
+    }
+  }
+}
+
 void cmQtAutoGenInitializer::ConfigFileClean(ConfigString& configString)
 {
   this->AddCleanFile(configString.Default);
diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h
index afb3bfa..8749961 100644
--- a/Source/cmQtAutoGenInitializer.h
+++ b/Source/cmQtAutoGenInitializer.h
@@ -44,7 +44,8 @@
     std::string QrcPathChecksum;
     std::string InfoFile;
     ConfigString SettingsFile;
-    std::string OutputFile;
+    ConfigString OutputFile;
+    std::string OutputFileGenex;
     bool Generated = false;
     bool Unique = false;
     std::vector<std::string> Options;
@@ -135,6 +136,8 @@
                        cm::string_view suffix);
   void ConfigFileNamesAndGenex(ConfigString& configString, std::string& genex,
                                cm::string_view prefix, cm::string_view suffix);
+  void ConfigFileNameCommon(ConfigString& configString,
+                            std::string const& fileName);
   void ConfigFileClean(ConfigString& configString);
 
   std::string GetMocBuildPath(MUFile const& muf);
diff --git a/Source/cmQtAutoRcc.cxx b/Source/cmQtAutoRcc.cxx
index d8120f4..a1fff8f 100644
--- a/Source/cmQtAutoRcc.cxx
+++ b/Source/cmQtAutoRcc.cxx
@@ -35,11 +35,6 @@
 private:
   // -- Utility
   bool IsMultiConfig() const { return this->MultiConfig_; }
-  std::string const& GetGenerator() const { return this->Generator_; }
-  bool IsXcode() const
-  {
-    return this->GetGenerator().find("Xcode") != std::string::npos;
-  }
   std::string MultiConfigOutput() const;
 
   // -- Abstract processing interface
@@ -114,6 +109,13 @@
       !info.GetArray("OPTIONS", this->Options_, false)) {
     return false;
   }
+
+  // Expand $<CONFIG> in RccFileName if present (for better graph multi-config)
+  if (this->IsMultiConfig()) {
+    cmSystemTools::ReplaceString(this->RccFileName_, "$<CONFIG>",
+                                 this->InfoConfig());
+  }
+
   if (this->UseBetterGraph_) {
     if (!info.GetArrayConfig("INPUTS", this->Inputs_, false)) {
       return false;
@@ -142,15 +144,10 @@
   // -- Derive information
   this->QrcFileName_ = cmSystemTools::GetFilenameName(this->QrcFile_);
   this->QrcFileDir_ = cmSystemTools::GetFilenamePath(this->QrcFile_);
-  if (IsMultiConfig() && !this->IsXcode() && this->UseBetterGraph_) {
-    this->RccFilePublic_ =
-      cmStrCat(this->AutogenBuildDir_, '/', this->RccPathChecksum_, '_',
-               this->InfoConfig(), '/', this->RccFileName_);
-  } else {
-    this->RccFilePublic_ =
-      cmStrCat(this->AutogenBuildDir_, '/', this->RccPathChecksum_, '/',
-               this->RccFileName_);
-  }
+  // For better graph multi-config, OUTPUT_NAME already includes config suffix
+  this->RccFilePublic_ =
+    cmStrCat(this->AutogenBuildDir_, '/', this->RccPathChecksum_, '/',
+             this->RccFileName_);
 
   // rcc output file name
   if (this->IsMultiConfig()) {
diff --git a/Source/cmRST.cxx b/Source/cmRST.cxx
index 51245d6..e490370 100644
--- a/Source/cmRST.cxx
+++ b/Source/cmRST.cxx
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "cmsys/FStream.hxx"
+#include "cmsys/String.h"
 
 #include "cmAlgorithms.h"
 #include "cmRange.h"
@@ -158,7 +159,7 @@
   // A line starting in .. is an explicit markup start.
   if (line == ".." ||
       (line.size() >= 3 && line[0] == '.' && line[1] == '.' &&
-       cmIsSpace(line[2]))) {
+       cmsysString_isspace(line[2]))) {
     this->Reset();
     this->MarkupType =
       (line.find_first_not_of(" \t", 2) == std::string::npos ? Markup::Empty
@@ -218,7 +219,7 @@
   }
   // Indented lines following an explicit markup start are explicit markup.
   else if (this->MarkupType != Markup::None &&
-           (line.empty() || cmIsSpace(line[0]))) {
+           (line.empty() || cmsysString_isspace(line[0]))) {
     this->MarkupType = Markup::Normal;
     // Record markup lines if the start line was recorded.
     if (!this->MarkupLines.empty()) {
diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx
index 9261007..83eef77 100644
--- a/Source/cmRulePlaceholderExpander.cxx
+++ b/Source/cmRulePlaceholderExpander.cxx
@@ -143,6 +143,16 @@
       return this->ReplaceValues->SwiftSources;
     }
   }
+  if (this->ReplaceValues->RustSources) {
+    if (variable == "RUST_SOURCES") {
+      return this->ReplaceValues->RustSources;
+    }
+  }
+  if (this->ReplaceValues->RustObjectDeps) {
+    if (variable == "RUST_OBJECT_DEPS") {
+      return this->ReplaceValues->RustObjectDeps;
+    }
+  }
   if (this->ReplaceValues->TargetPDB) {
     if (variable == "TARGET_PDB") {
       return this->ReplaceValues->TargetPDB;
diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h
index bb6250f..4b44c64 100644
--- a/Source/cmRulePlaceholderExpander.h
+++ b/Source/cmRulePlaceholderExpander.h
@@ -69,6 +69,8 @@
     char const* SwiftModuleName = nullptr;
     char const* SwiftOutputFileMapOption = nullptr;
     char const* SwiftSources = nullptr;
+    char const* RustSources = nullptr;
+    char const* RustObjectDeps = nullptr;
     char const* ISPCHeader = nullptr;
     char const* CudaCompileMode = nullptr;
     char const* Fatbinary = nullptr;
diff --git a/Source/cmRuntimeDependencyArchive.cxx b/Source/cmRuntimeDependencyArchive.cxx
index 1a0aeef..a837b72 100644
--- a/Source/cmRuntimeDependencyArchive.cxx
+++ b/Source/cmRuntimeDependencyArchive.cxx
@@ -368,7 +368,7 @@
       break;
     }
   }
-  it->second.insert(path);
+  it->second.emplace(path);
   this->RPaths[path] = std::move(rpaths);
 }
 
diff --git a/Source/cmSPDXSerializer.cxx b/Source/cmSPDXSerializer.cxx
deleted file mode 100644
index 7d22103..0000000
--- a/Source/cmSPDXSerializer.cxx
+++ /dev/null
@@ -1,1375 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file LICENSE.rst or https://cmake.org/licensing for details.  */
-#include "cmSPDXSerializer.h"
-
-#include <new>
-#include <string>
-
-#include <cm/optional>
-
-#include <cm3p/json/value.h>
-
-// Serialization Utilities
-
-template <typename T>
-void addVectorSPDXValue(Json::Value& obj, std::string const& key,
-                        std::vector<T> const& vec)
-{
-  auto& list = obj[key];
-  list = Json::Value(Json::arrayValue);
-  for (auto const& val : vec) {
-    list.append(val.toJsonLD());
-  }
-}
-
-template <>
-void addVectorSPDXValue(Json::Value& obj, std::string const& key,
-                        std::vector<std::string> const& vec)
-{
-  auto& list = obj[key];
-  list = Json::Value(Json::arrayValue);
-  for (auto const& val : vec) {
-    list.append(val);
-  }
-}
-
-template <typename T>
-void addOptionalSPDXValue(Json::Value& obj, std::string const& key,
-                          cm::optional<std::vector<T>> const& opt)
-{
-  if (opt) {
-    addVectorSPDXValue(obj, key, *opt);
-  }
-}
-
-template <typename T>
-void addOptionalSPDXValue(Json::Value& obj, std::string const& key,
-                          cm::optional<T> const& opt)
-{
-  if (opt) {
-    obj[key] = opt->toJsonLD();
-  }
-}
-
-template <>
-void addOptionalSPDXValue(Json::Value& obj, std::string const& key,
-                          cm::optional<std::string> const& opt)
-{
-  if (opt) {
-    obj[key] = *opt;
-  }
-}
-
-// Base Class
-
-cmSPDXSerializationBase::SPDXTypeId cmSPDXSerializationBase::getTypeId() const
-{
-  return TypeId;
-}
-
-cmSPDXSerializationBase::cmSPDXSerializationBase(SPDXTypeId id)
-  : TypeId(id)
-{
-}
-
-cmSPDXSerializationBase::cmSPDXSerializationBase(SPDXTypeId id,
-                                                 std::string nodeId)
-  : NodeId(std::move(nodeId))
-  , TypeId(id)
-{
-}
-
-// Convenience Classes
-
-cmSPDXIdentifierReference::cmSPDXIdentifierReference()
-  : cmSPDXSerializationBase(CM_IDENTIFIER_REFERENCE)
-{
-}
-cmSPDXIdentifierReference::cmSPDXIdentifierReference(
-  cmSPDXSerializationBase const& ref)
-  : cmSPDXSerializationBase(CM_IDENTIFIER_REFERENCE, ref.NodeId)
-{
-}
-cmSPDXIdentifierReference::cmSPDXIdentifierReference(std::string const& ref)
-  : cmSPDXSerializationBase(CM_IDENTIFIER_REFERENCE, ref)
-{
-}
-
-Json::Value cmSPDXIdentifierReference::toJsonLD() const
-{
-  return NodeId;
-}
-
-cmSPDXNonElementBase::cmSPDXNonElementBase(SPDXTypeId id)
-  : cmSPDXSerializationBase(id)
-{
-}
-
-Json::Value cmSPDXNonElementBase::toJsonLD() const
-{
-  Json::Value obj(Json::objectValue);
-  obj["@id"] = NodeId;
-  return obj;
-}
-
-// SPDX Core Enums
-
-cmSPDXAnnotationType::cmSPDXAnnotationType(cmSPDXAnnotationTypeId typeId)
-  : TypeId(typeId)
-{
-}
-
-Json::Value cmSPDXAnnotationType::toJsonLD() const
-{
-  switch (TypeId) {
-    case OTHER:
-      return "other";
-    case REVIEW:
-      return "review";
-    default:
-      return "INVALID_ANNOTATION_TYPE_ID";
-  }
-}
-
-cmSPDXExternalIdentifierType::cmSPDXExternalIdentifierType(
-  cmSPDXExternalIdentifierTypeId typeId)
-  : TypeId(typeId)
-{
-}
-
-Json::Value cmSPDXExternalIdentifierType::toJsonLD() const
-{
-  switch (TypeId) {
-    case CPE22:
-      return "cpe22";
-    case CPE23:
-      return "cpe23";
-    case CVE:
-      return "cve";
-    case EMAIL:
-      return "email";
-    case GITOID:
-      return "gitoid";
-    case OTHER:
-      return "other";
-    case PACKAGE_URL:
-      return "packageUrl";
-    case SECURITY_OTHER:
-      return "securityOther";
-    case SWHID:
-      return "swhid";
-    case SWID:
-      return "swid";
-    case URL_SCHEME:
-      return "urlScheme";
-    default:
-      return "INVALID_EXTERNAL_IDENTIFIER_TYPE_ID";
-  }
-}
-
-cmSPDXExternalRefType::cmSPDXExternalRefType(cmSPDXExternalRefTypeId typeId)
-  : TypeId(typeId)
-{
-}
-
-Json::Value cmSPDXExternalRefType::toJsonLD() const
-{
-  switch (TypeId) {
-    case ALT_DOWNLOAD_LOCATION:
-      return "altDownloadLocation:";
-    case ALT_WEB_PAGE:
-      return "altWebPage";
-    case BINARY_ARTIFACT:
-      return "binaryArtifact";
-    case BOWER:
-      return "bower";
-    case BUILD_META:
-      return "buildMeta";
-    case BUILD_SYSTEM:
-      return "buildSystem";
-    case CERTIFICATION_REPORT:
-      return "certificationReport";
-    case CHAT:
-      return "chat";
-    case COMPONENT_ANALYSIS_REPORT:
-      return "componentAnalysisReport";
-    case CWE:
-      return "cwe";
-    case DOCUMENTATION:
-      return "documentation";
-    case DYNAMIC_ANALYSIS_REPORT:
-      return "dynamicAnalysisReport";
-    case EOL_NOTICE:
-      return "eolNotice";
-    case EXPORT_CONTROL_ASSESSMENT:
-      return "exportControlAssessment";
-    case FUNDING:
-      return "funding";
-    case ISSUE_TRACKER:
-      return "issueTracker";
-    case LICENSE:
-      return "license";
-    case MAILING_LIST:
-      return "mailingList";
-    case MAVEN_CENTRAL:
-      return "mavenCentral";
-    case METRICS:
-      return "metrics";
-    case NPM:
-      return "npm";
-    case NUGET:
-      return "nuget";
-    case OTHER:
-      return "other";
-    case PRIVACY_ASSESSMENT:
-      return "privacyAssessment";
-    case PRODUCT_METADATA:
-      return "productMetadata";
-    case PURCHASE_ORDER:
-      return "purchaseOrder";
-    case QUALITY_ASSESSMENT_REPORT:
-      return "qualityAssessmentReport";
-    case RELEASE_HISTORY:
-      return "releaseHistory";
-    case RELEASE_NOTES:
-      return "releaseNotes";
-    case RISK_ASSESSMENT:
-      return "riskAssessment";
-    case RUNTIME_ANALYSIS_REPORT:
-      return "runtimeAnalysisReport";
-    case SECURE_SOFTWARE_ATTESTATION:
-      return "secureSoftwareAttestation";
-    case SECURITY_ADVERSARY_MODEL:
-      return "securityAdversaryModel";
-    case SECURITY_ADVISORY:
-      return "securityAdvisory";
-    case SECURITY_FIX:
-      return "securityFix";
-    case SECURITY_OTHER:
-      return "securityOther";
-    case SECURITY_PEN_TEST_REPORT:
-      return "securityPenTestReport";
-    case SECURITY_POLICY:
-      return "securityPolicy";
-    case SECURITY_THREAT_MODEL:
-      return "securityThreatModel";
-    case SOCIAL_MEDIA:
-      return "socialMedia";
-    case SOURCE_ARTIFACT:
-      return "sourceArtifact";
-    case STATIC_ANALYSIS_REPORT:
-      return "staticAnalysisReport";
-    case SUPPORT:
-      return "support";
-    case VCS:
-      return "vcs";
-    case VULNERABILITY_DISCLOSURE_REPORT:
-      return "vulnerabilityDisclosureReport";
-    case VULNERABILITY_EXPLOITABILITY_ASSESSMENT:
-      return "vulnerabilityExploitabilityAssessment";
-    default:
-      return "INVALID_EXTERNAL_REF_TYPE_ID";
-  }
-}
-
-cmSPDXHashAlgorithm::cmSPDXHashAlgorithm(cmSPDXHashAlgorithmId typeId)
-  : TypeId(typeId)
-{
-}
-
-Json::Value cmSPDXHashAlgorithm::toJsonLD() const
-{
-  switch (TypeId) {
-    case ADLER32:
-      return "adler32";
-    case BLAKE2B256:
-      return "blake2b256";
-    case BLAKE2B384:
-      return "blake2b384";
-    case BLAKE2B512:
-      return "blake2b512";
-    case BLAKE3:
-      return "blake3";
-    case CRYSTALS_DILITHIUM:
-      return "crystalsDilithium";
-    case CRYSTALS_KYBER:
-      return "crystalsLyber";
-    case FALCON:
-      return "falcon";
-    case MD2:
-      return "md2";
-    case MD4:
-      return "md4";
-    case MD5:
-      return "md5";
-    case MD6:
-      return "md6";
-    case OTHER:
-      return "other";
-    case SHA1:
-      return "sha1";
-    case SHA224:
-      return "sha224";
-    case SHA256:
-      return "sha256";
-    case SHA384:
-      return "sha384";
-    case SHA3_224:
-      return "sha3_224";
-    case SHA3_256:
-      return "sha3_256";
-    case SHA3_384:
-      return "sha3_384";
-    case SHA3_512:
-      return "sha3_512";
-    case SHA512:
-      return "sha512";
-    default:
-      return "INVALID_HASH_TYPE_ID";
-  }
-}
-
-cmSPDXLifecycleScopeType::cmSPDXLifecycleScopeType(
-  cmSPDXLifecycleScopeTypeId typeId)
-  : TypeId(typeId)
-{
-}
-
-Json::Value cmSPDXLifecycleScopeType::toJsonLD() const
-{
-  switch (TypeId) {
-    case BUILD:
-      return "build";
-    case DESIGN:
-      return "design";
-    case DEVELOPMENT:
-      return "development";
-    case OTHER:
-      return "other";
-    case RUNTIME:
-      return "runtime";
-    case TEST:
-      return "test";
-    default:
-      return "INVALID_LIFECYCLE_SCOPE_TYPE_ID";
-  }
-}
-
-cmSPDXProfileIdentifierType::cmSPDXProfileIdentifierType(
-  cmSPDXProfileIdentifierTypeId typeId)
-  : TypeId(typeId)
-{
-}
-
-Json::Value cmSPDXProfileIdentifierType::toJsonLD() const
-{
-  switch (TypeId) {
-    case AI:
-      return "ai";
-    case BUILD:
-      return "build";
-    case CORE:
-      return "code";
-    case DATASET:
-      return "dataset";
-    case EXPANDED_LICENSING:
-      return "expandedLicensing";
-    case EXTENSION:
-      return "extension";
-    case LITE:
-      return "lite";
-    case SECURITY:
-      return "security";
-    case SIMPLE_LICENSING:
-      return "simpleLicensing";
-    case SOFTWARE:
-      return "software";
-    default:
-      return "INVALID_PROFILE_IDENTIFIER_TYPE_ID";
-  }
-}
-
-cmSPDXRelationshipCompletenessType::cmSPDXRelationshipCompletenessType(
-  cmSPDXRelationshipCompletenessTypeId typeId)
-  : TypeId(typeId)
-{
-}
-
-Json::Value cmSPDXRelationshipCompletenessType::toJsonLD() const
-{
-  switch (TypeId) {
-    case COMPLETE:
-      return "complete";
-    case INCOMPLETE:
-      return "incomplete";
-    case NO_ASSERTION:
-      return "noAssertion";
-    default:
-      return "INVALID_RELATIONSHIP_COMPLETENESS_TYPE_ID";
-  }
-}
-
-cmSPDXRelationshipType::cmSPDXRelationshipType(cmSPDXRelationshipTypeId typeId)
-  : TypeId(typeId)
-{
-}
-
-Json::Value cmSPDXRelationshipType::toJsonLD() const
-{
-  switch (TypeId) {
-    case AFFECTS:
-      return "affects";
-    case AMENDED_BY:
-      return "amendedBy";
-    case ANCESTOR_OF:
-      return "ancestorOf";
-    case AVAILABLE_FROM:
-      return "availableFrom";
-    case CONFIGURES:
-      return "configures";
-    case CONTAINS:
-      return "contains";
-    case COORDINATED_BY:
-      return "coordinatedBy";
-    case COPIED_TO:
-      return "copiedTo";
-    case DELEGATED_TO:
-      return "delegatedTo";
-    case DEPENDS_ON:
-      return "dependsOn";
-    case DESCENDANT_OF:
-      return "descendantOf";
-    case DESCRIBES:
-      return "describes";
-    case DOES_NOT_AFFECT:
-      return "doesNotAffect";
-    case EXPANDS_TO:
-      return "expandsTo";
-    case EXPLOIT_CREATED_BY:
-      return "exploitCreatedBy";
-    case FIXED_BY:
-      return "fixedBy";
-    case FIXED_IN:
-      return "fixedIn";
-    case FOUND_BY:
-      return "foundBy";
-    case GENERATES:
-      return "generates";
-    case HAS_ADDED_FILE:
-      return "hasAddedFile";
-    case HAS_ASSESSMENT_FOR:
-      return "hasAssessmentFor";
-    case HAS_ASSOCIATED_VULNERABILITY:
-      return "hasAssociatedVulnerability";
-    case HAS_CONCLUDED_LICENSE:
-      return "hasConcludedLicense";
-    case HAS_DATA_FILE:
-      return "hasDataFile";
-    case HAS_DECLARED_LICENSE:
-      return "hasDeclaredLicense";
-    case HAS_DELETED_FILE:
-      return "hasDeletedFile";
-    case HAS_DEPENDENCY_MANIFEST:
-      return "hasDependencyManifest";
-    case HAS_DISTRIBUTION_ARTIFACT:
-      return "hasDistributionArtifact";
-    case HAS_DOCUMENTATION:
-      return "hasDocumentation";
-    case HAS_DYNAMIC_LINK:
-      return "hasDynamicLink";
-    case HAS_EVIDENCE:
-      return "hasEvidence";
-    case HAS_EXAMPLE:
-      return "hasExample";
-    case HAS_HOST:
-      return "hasHost";
-    case HAS_INPUT:
-      return "hasInput";
-    case HAS_METADATA:
-      return "hasMetadata";
-    case HAS_OPTIONAL_COMPONENT:
-      return "hasOptionalComponent";
-    case HAS_OPTIONAL_DEPENDENCY:
-      return "hasOptionalDependency";
-    case HAS_OUTPUT:
-      return "hasOutput";
-    case HAS_PREREQUISITE:
-      return "hasPrerequisite";
-    case HAS_PROVIDED_DEPENDENCY:
-      return "hasProvidedDependency";
-    case HAS_REQUIREMENT:
-      return "hasRequirement";
-    case HAS_SPECIFICATION:
-      return "hasSpecification";
-    case HAS_STATIC_LINK:
-      return "hasStaticLink";
-    case HAS_TEST:
-      return "hasTest";
-    case HAS_TEST_CASE:
-      return "hasTestCase";
-    case HAS_VARIANT:
-      return "hasVariant";
-    case INVOKED_BY:
-      return "invokedBy";
-    case MODIFIED_BY:
-      return "modifiedBy";
-    case OTHER:
-      return "other";
-    case PACKAGED_BY:
-      return "packagedBy";
-    case PATCHED_BY:
-      return "patchedBy";
-    case PUBLISHED_BY:
-      return "publishedBy";
-    case REPORTED_BY:
-      return "reportedBy";
-    case REPUBLISHED_BY:
-      return "republishedBy";
-    case SERIALIZED_IN_ARTIFACT:
-      return "serializedInArtifact";
-    case TESTED_ON:
-      return "testedOn";
-    case TRAINED_ON:
-      return "trainedOn";
-    case UNDER_INVESTIGATION_FOR:
-      return "underInvestigationFor";
-    case USES_TOOL:
-      return "usesTool";
-    default:
-      return "INVALID_RELATIONSHIP_TYPE_ID";
-  }
-}
-
-cmSPDXSupportType::cmSPDXSupportType(cmSPDXSupportTypeId typeId)
-  : TypeId(typeId)
-{
-}
-
-Json::Value cmSPDXSupportType::toJsonLD() const
-{
-  switch (TypeId) {
-    case DEPLOYED:
-      return "deployed";
-    case DEVELOPMENT:
-      return "development";
-    case END_OF_SUPPORT:
-      return "endOfSupport";
-    case LIMITED_SUPPORT:
-      return "limitedSupport";
-    case NO_ASSERTION:
-      return "noAssertion";
-    case NO_SUPPORT:
-      return "noSupport";
-    case SUPPORT:
-      return "support";
-    default:
-      return "INVALID_SUPPORT_TYPE_ID";
-  }
-}
-
-// SPDX Core NonElement Classes, Abstract
-
-cmSPDXIntegrityMethod::cmSPDXIntegrityMethod(SPDXTypeId id)
-  : cmSPDXNonElementBase(id)
-{
-}
-
-Json::Value cmSPDXIntegrityMethod::toJsonLD() const
-{
-  auto obj = cmSPDXNonElementBase::toJsonLD();
-  addOptionalSPDXValue(obj, "comment", Comment);
-  return obj;
-}
-
-// SPDX Core NonElement Classes, Concrete
-
-cmSPDXCreationInfo::cmSPDXCreationInfo()
-  : cmSPDXNonElementBase(CORE_CREATION_INFO)
-{
-}
-
-Json::Value cmSPDXCreationInfo::toJsonLD() const
-{
-  auto obj = cmSPDXNonElementBase::toJsonLD();
-  obj["type"] = "CreationInfo";
-  addOptionalSPDXValue(obj, "Comment", Comment);
-  obj["created"] = Created;
-  addVectorSPDXValue(obj, "createdBy", CreatedBy);
-  addOptionalSPDXValue(obj, "createdUsing", CreatedUsing);
-  return obj;
-}
-
-cmSPDXDictionaryEntry::cmSPDXDictionaryEntry()
-  : cmSPDXNonElementBase(CORE_DICTIONARY_ENTRY)
-{
-}
-cmSPDXDictionaryEntry::cmSPDXDictionaryEntry(std::string key)
-  : cmSPDXNonElementBase(CORE_DICTIONARY_ENTRY)
-  , Key(std::move(key))
-{
-}
-cmSPDXDictionaryEntry::cmSPDXDictionaryEntry(std::string key, std::string val)
-  : cmSPDXNonElementBase(CORE_DICTIONARY_ENTRY)
-  , Key(std::move(key))
-  , Value(std::move(val))
-{
-}
-
-Json::Value cmSPDXDictionaryEntry::toJsonLD() const
-{
-  auto obj = cmSPDXNonElementBase::toJsonLD();
-  obj["type"] = "DictionaryEntry";
-  obj["key"] = Key;
-  addOptionalSPDXValue(obj, "value", Value);
-  return obj;
-}
-
-cmSPDXExternalIdentifier::cmSPDXExternalIdentifier()
-  : cmSPDXNonElementBase(CORE_EXTERNAL_IDENTIFIER)
-{
-}
-
-Json::Value cmSPDXExternalIdentifier::toJsonLD() const
-{
-  auto obj = cmSPDXNonElementBase::toJsonLD();
-  obj["type"] = "ExternalIdentifier";
-  addOptionalSPDXValue(obj, "comment", Comment);
-  obj["externalIdentifierType"] = ExternalIdentifierType.toJsonLD();
-  obj["identifier"] = Identifier;
-  addOptionalSPDXValue(obj, "identifierLocator", IdentifierLocator);
-  addOptionalSPDXValue(obj, "issuingAuthority", IssuingAuthority);
-  return obj;
-}
-
-cmSPDXExternalMap::cmSPDXExternalMap()
-  : cmSPDXNonElementBase(CORE_EXTERNAL_MAP)
-{
-}
-
-Json::Value cmSPDXExternalMap::toJsonLD() const
-{
-  auto obj = cmSPDXNonElementBase::toJsonLD();
-  obj["type"] = "ExternalMap";
-  addOptionalSPDXValue(obj, "definingArtifact", DefiningArtifact);
-  obj["externalSpdxId"] = ExternalSpdxId;
-  addOptionalSPDXValue(obj, "locationHint", LocationHint);
-  addOptionalSPDXValue(obj, "integrityMethod", IntegrityMethod);
-  return obj;
-}
-
-cmSPDXExternalRef::cmSPDXExternalRef()
-  : cmSPDXNonElementBase(CORE_EXTERNAL_REF)
-{
-}
-
-Json::Value cmSPDXExternalRef::toJsonLD() const
-{
-  auto obj = cmSPDXNonElementBase::toJsonLD();
-  obj["type"] = "ExternalRef";
-  addOptionalSPDXValue(obj, "comment", Comment);
-  addOptionalSPDXValue(obj, "contentType", ContentType);
-  addOptionalSPDXValue(obj, "externalRefType", ExternalRefType);
-  addOptionalSPDXValue(obj, "locator", Locator);
-  return obj;
-}
-
-cmSPDXHash::cmSPDXHash()
-  : cmSPDXIntegrityMethod(CORE_HASH)
-{
-}
-
-Json::Value cmSPDXHash::toJsonLD() const
-{
-  auto obj = cmSPDXIntegrityMethod::toJsonLD();
-  obj["type"] = "Hash";
-  obj["algorithm"] = Algorithm.toJsonLD();
-  obj["hashValue"] = HashValue;
-  return obj;
-}
-
-cmSPDXNamespaceMap::cmSPDXNamespaceMap()
-  : cmSPDXNonElementBase(CORE_NAMESPACE_MAP)
-{
-}
-
-Json::Value cmSPDXNamespaceMap::toJsonLD() const
-{
-  auto obj = cmSPDXNonElementBase::toJsonLD();
-  obj["type"] = "NamespaceMap";
-  obj["namespace"] = Namespace;
-  obj["prefix"] = Namespace;
-  return obj;
-}
-
-cmSPDXPackageVerificationCode::cmSPDXPackageVerificationCode()
-  : cmSPDXIntegrityMethod(CORE_PACKAGE_VERIFICATION_CODE)
-{
-}
-
-Json::Value cmSPDXPackageVerificationCode::toJsonLD() const
-{
-  auto obj = cmSPDXIntegrityMethod::toJsonLD();
-  obj["type"] = "PackageVerificationCode";
-  obj["algorithm"] = Algorithm.toJsonLD();
-  obj["hashValue"] = HashValue;
-  return obj;
-}
-
-cmSPDXPositiveIntegerRange::cmSPDXPositiveIntegerRange(
-  unsigned int beingIntegerRange, unsigned int endIntegerRange)
-  : cmSPDXNonElementBase(CORE_POSITIVE_INTEGER_RANGE)
-  , BeginIntegerRange(beingIntegerRange)
-  , EndIntegerRange(endIntegerRange)
-{
-}
-
-Json::Value cmSPDXPositiveIntegerRange::toJsonLD() const
-{
-  auto obj = cmSPDXNonElementBase::toJsonLD();
-  obj["type"] = "PositiveIntegerRange";
-  obj["beginIntegerRange"] = BeginIntegerRange;
-  obj["endIntegerRange"] = EndIntegerRange;
-  return obj;
-}
-
-// SPDX Core Element Classes, Abstract
-
-cmSPDXElement::cmSPDXElement(SPDXTypeId id,
-                             cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXSerializationBase(id)
-  , CreationInfo(creationInfo)
-{
-}
-
-Json::Value cmSPDXElement::toJsonLD() const
-{
-  Json::Value obj(Json::objectValue);
-  addOptionalSPDXValue(obj, "comment", Comment);
-  obj["creationInfo"] = CreationInfo.toJsonLD();
-  addOptionalSPDXValue(obj, "description", Description);
-  addOptionalSPDXValue(obj, "extension", Extension);
-  addOptionalSPDXValue(obj, "externalIdentifier", ExternalIdentifier);
-  addOptionalSPDXValue(obj, "externalRef", ExternalRef);
-  addOptionalSPDXValue(obj, "name", Name);
-  obj["spdxId"] = NodeId;
-  addOptionalSPDXValue(obj, "summary", Summary);
-  addOptionalSPDXValue(obj, "verifiedUsing", VerifiedUsing);
-  return obj;
-}
-
-cmSPDXArtifact::cmSPDXArtifact(SPDXTypeId id,
-                               cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXElement(id, creationInfo)
-{
-}
-
-Json::Value cmSPDXArtifact::toJsonLD() const
-{
-  auto obj = cmSPDXElement::toJsonLD();
-  addOptionalSPDXValue(obj, "builtTime", BuiltTime);
-  addOptionalSPDXValue(obj, "originateBy", OriginatedBy);
-  addOptionalSPDXValue(obj, "releaseTime", ReleaseTime);
-  addOptionalSPDXValue(obj, "standardName", StandardName);
-  addOptionalSPDXValue(obj, "suppliedBy", SuppliedBy);
-  addOptionalSPDXValue(obj, "supportType", SupportType);
-  addOptionalSPDXValue(obj, "validUntilTime", ValidUntilTime);
-  return obj;
-}
-
-cmSPDXElementCollection::cmSPDXElementCollection(
-  SPDXTypeId id, cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXElement(id, creationInfo)
-{
-}
-
-Json::Value cmSPDXElementCollection::toJsonLD() const
-{
-  auto obj = cmSPDXElement::toJsonLD();
-  addOptionalSPDXValue(obj, "element", Element);
-  addOptionalSPDXValue(obj, "profileConformance", ProfileConformance);
-  addOptionalSPDXValue(obj, "rootElement", RootElement);
-  return obj;
-}
-
-// SPDX Implicit Core Element Classes, Abstract
-
-// Nominally an inheritable class, but adds nothing to Element
-using cmSPDXAgentAbstract = cmSPDXElement;
-
-cmSPDXBundleAbstract::cmSPDXBundleAbstract(
-  SPDXTypeId id, cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXElementCollection(id, creationInfo)
-{
-}
-
-Json::Value cmSPDXBundleAbstract::toJsonLD() const
-{
-  auto obj = cmSPDXElementCollection::toJsonLD();
-  obj["context"] = Context;
-  return obj;
-}
-
-// Nominally an inheritable class, but adds nothing to Bundle
-using cmSPDXBomAbstract = cmSPDXBundleAbstract;
-
-cmSPDXRelationshipAbstract::cmSPDXRelationshipAbstract(
-  SPDXTypeId id, cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXElement(id, creationInfo)
-{
-}
-
-Json::Value cmSPDXRelationshipAbstract::toJsonLD() const
-{
-  auto obj = cmSPDXElement::toJsonLD();
-  addOptionalSPDXValue(obj, "completeness", Completeness);
-  addOptionalSPDXValue(obj, "endTime", EndTime);
-  obj["from"] = From.toJsonLD();
-  obj["relationshipType"] = RelationshipType.toJsonLD();
-  addOptionalSPDXValue(obj, "startTime", StartTime);
-  addVectorSPDXValue(obj, "to", To);
-  return obj;
-}
-
-// SPDX Core Element Classes, Concrete
-
-cmSPDXAgent::cmSPDXAgent(cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXAgentAbstract(CORE_AGENT, creationInfo)
-{
-}
-
-Json::Value cmSPDXAgent::toJsonLD() const
-{
-  auto obj = cmSPDXAgentAbstract::toJsonLD();
-  obj["type"] = "Agent";
-  return obj;
-}
-
-cmSPDXAnnotation::cmSPDXAnnotation(cmSPDXCreationInfo const& creationInfo,
-                                   cmSPDXIdentifierReference subject)
-  : cmSPDXElement(CORE_ANNOTATION, creationInfo)
-  , Subject(std::move(subject))
-{
-}
-
-Json::Value cmSPDXAnnotation::toJsonLD() const
-{
-  auto obj = cmSPDXElement::toJsonLD();
-  obj["type"] = "Annotation";
-  obj["annotationType"] = AnnotationType.toJsonLD();
-  addOptionalSPDXValue(obj, "contentType", ContentType);
-  addOptionalSPDXValue(obj, "statement", Statement);
-  obj["subject"] = Subject.toJsonLD();
-  return obj;
-}
-
-cmSPDXBom::cmSPDXBom(cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXBomAbstract(CORE_BOM, creationInfo)
-{
-}
-
-Json::Value cmSPDXBom::toJsonLD() const
-{
-  auto obj = cmSPDXBomAbstract::toJsonLD();
-  obj["type"] = "Bom";
-  return obj;
-}
-
-cmSPDXBundle::cmSPDXBundle(cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXBundleAbstract(CORE_BUNDLE, creationInfo)
-{
-}
-
-Json::Value cmSPDXBundle::toJsonLD() const
-{
-  auto obj = cmSPDXBundleAbstract::toJsonLD();
-  obj["type"] = "Bundle";
-  return obj;
-}
-
-cmSPDXIndividualElement::cmSPDXIndividualElement(
-  cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXElement(CORE_INDIVIDUAL_ELEMENT, creationInfo)
-{
-}
-
-Json::Value cmSPDXIndividualElement::toJsonLD() const
-{
-  auto obj = cmSPDXElement::toJsonLD();
-  obj["type"] = "IndividualElement";
-  return obj;
-}
-
-cmSPDXLifecycleScopedRelationship::cmSPDXLifecycleScopedRelationship(
-  cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXRelationshipAbstract(CORE_LIFECYCLE_SCOPED_RELATIONSHIP,
-                               creationInfo)
-{
-}
-
-Json::Value cmSPDXLifecycleScopedRelationship::toJsonLD() const
-{
-  auto obj = cmSPDXRelationshipAbstract::toJsonLD();
-  obj["type"] = "LifecycleScopedRelationship";
-  addOptionalSPDXValue(obj, "scope", Scope);
-  return obj;
-}
-
-cmSPDXOrganization::cmSPDXOrganization(cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXAgentAbstract(CORE_ORGANIZATION, creationInfo)
-{
-}
-
-Json::Value cmSPDXOrganization::toJsonLD() const
-{
-  auto obj = cmSPDXAgentAbstract::toJsonLD();
-  obj["type"] = "Organization";
-  return obj;
-}
-
-cmSPDXPerson::cmSPDXPerson(cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXAgentAbstract(CORE_PERSON, creationInfo)
-{
-}
-
-Json::Value cmSPDXPerson::toJsonLD() const
-{
-  auto obj = cmSPDXAgentAbstract::toJsonLD();
-  obj["type"] = "Person";
-  return obj;
-}
-
-cmSPDXRelationship::cmSPDXRelationship(cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXRelationshipAbstract(CORE_RELATIONSHIP, creationInfo)
-{
-}
-
-Json::Value cmSPDXRelationship::toJsonLD() const
-{
-  auto obj = cmSPDXRelationshipAbstract::toJsonLD();
-  obj["type"] = "Relationship";
-  return obj;
-}
-
-cmSPDXSoftwareAgent::cmSPDXSoftwareAgent(
-  cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXAgentAbstract(CORE_SOFTWARE_AGENT, creationInfo)
-{
-}
-
-Json::Value cmSPDXSoftwareAgent::toJsonLD() const
-{
-  auto obj = cmSPDXAgentAbstract::toJsonLD();
-  obj["type"] = "SoftwareAgent";
-  return obj;
-}
-
-cmSPDXSpdxDocument::cmSPDXSpdxDocument(cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXElementCollection(CORE_SPDX_DOCUMENT, creationInfo)
-{
-}
-
-Json::Value cmSPDXSpdxDocument::toJsonLD() const
-{
-  auto obj = cmSPDXElementCollection::toJsonLD();
-  obj["type"] = "SpdxDocument";
-  addOptionalSPDXValue(obj, "dataLicense", DataLicense);
-  addOptionalSPDXValue(obj, "externalMap", ExternalMap);
-  addOptionalSPDXValue(obj, "namespaceMap", NamespaceMap);
-  return obj;
-}
-
-cmSPDXTool::cmSPDXTool(cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXElement(CORE_TOOL, creationInfo)
-{
-}
-
-Json::Value cmSPDXTool::toJsonLD() const
-{
-  auto obj = cmSPDXElement::toJsonLD();
-  obj["type"] = "Tool";
-  return obj;
-}
-
-// SPDX Software Enums
-
-cmSPDXContentIdentifierType::cmSPDXContentIdentifierType(
-  cmSPDXContentIdentifierTypeId typeId)
-  : TypeId(typeId)
-{
-}
-
-Json::Value cmSPDXContentIdentifierType::toJsonLD() const
-{
-  switch (TypeId) {
-    case GITOID:
-      return "gitoid";
-    case SWHID:
-      return "swhid";
-    default:
-      return "INVALID_CONTENT_IDENTIFIER_TYPE_ID";
-  }
-}
-
-cmSPDXFileKindType::cmSPDXFileKindType(cmSPDXFileKindTypeId typeId)
-  : TypeId(typeId)
-{
-}
-
-Json::Value cmSPDXFileKindType::toJsonLD() const
-{
-  switch (TypeId) {
-    case DIRECTORY:
-      return "directory";
-    case FILE:
-      return "file";
-    default:
-      return "INVALID_FILE_KIND_TYPE_ID";
-  }
-}
-
-cmSPDXSbomType::cmSPDXSbomType(cmSPDXSbomTypeId typeId)
-  : TypeId(typeId)
-{
-}
-
-Json::Value cmSPDXSbomType::toJsonLD() const
-{
-  switch (TypeId) {
-    case ANALYZED:
-      return "analyzed";
-    case BUILD:
-      return "build";
-    case DEPLOYED:
-      return "deployed";
-    case DESIGN:
-      return "design";
-    case RUNTIME:
-      return "runtime";
-    case SOURCE:
-      return "source";
-    default:
-      return "INVALID_SBOM_TYPE_ID";
-  }
-}
-
-cmSPDXSoftwarePurpose::cmSPDXSoftwarePurpose(cmSPDXSoftwarePurposeId typeId)
-  : TypeId(typeId)
-{
-}
-
-Json::Value cmSPDXSoftwarePurpose::toJsonLD() const
-{
-  switch (TypeId) {
-    case APPLICATION:
-      return "application";
-    case ARCHIVE:
-      return "archive";
-    case BOM:
-      return "bom";
-    case CONFIGURATION:
-      return "configuration";
-    case CONTAINER:
-      return "container";
-    case DATA:
-      return "data";
-    case DEVICE:
-      return "device";
-    case DEVICE_DRIVER:
-      return "deviceDriver";
-    case DISK_IMAGE:
-      return "diskImage";
-    case DOCUMENTATION:
-      return "documentation";
-    case EVIDENCE:
-      return "evidence";
-    case EXECUTABLE:
-      return "executable";
-    case FILE:
-      return "file";
-    case FILESYSTEM_IMAGE:
-      return "filesystemImage";
-    case FIRMWARE:
-      return "firmware";
-    case FRAMEWORK:
-      return "framework";
-    case INSTALL:
-      return "install";
-    case LIBRARY:
-      return "library";
-    case MANIFEST:
-      return "manifest";
-    case MODEL:
-      return "model";
-    case MODULE:
-      return "module";
-    case OPERATING_SYSTEM:
-      return "operatingSystem";
-    case OTHER:
-      return "other";
-    case PATCH:
-      return "patch";
-    case PLATFORM:
-      return "platform";
-    case REQUIREMENT:
-      return "requirement";
-    case SOURCE:
-      return "source";
-    case SPECIFICATION:
-      return "specification";
-    case TEST:
-      return "test";
-    default:
-      return "INVALID_SOFTWARE_PURPOSE_ID";
-  }
-}
-
-// SPDX Software NonElement Classes, Concrete
-
-cmSPDXContentIdentifier::cmSPDXContentIdentifier()
-  : cmSPDXIntegrityMethod(SOFTWARE_CONTENT_IDENTIFIER)
-{
-}
-
-Json::Value cmSPDXContentIdentifier::toJsonLD() const
-{
-  auto obj = cmSPDXIntegrityMethod::toJsonLD();
-  obj["type"] = "ContentIdentifier";
-  obj["contentIdentifierType"] = ContentIdentifierType.toJsonLD();
-  obj["contentIdentifierValue"] = ContentIdentifierValue;
-  return obj;
-}
-
-// SPDX Software Element Classes, Abstract
-
-cmSPDXSoftwareArtifact::cmSPDXSoftwareArtifact(
-  SPDXTypeId id, cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXArtifact(id, creationInfo)
-{
-}
-
-Json::Value cmSPDXSoftwareArtifact::toJsonLD() const
-{
-  auto obj = cmSPDXArtifact::toJsonLD();
-  addOptionalSPDXValue(obj, "additionalPurpose", AdditionalPurpose);
-  addOptionalSPDXValue(obj, "attributionText", AttributionText);
-  addOptionalSPDXValue(obj, "contentIdentifier", ContentIdentifier);
-  addOptionalSPDXValue(obj, "copyrightText", CopyrightText);
-  addOptionalSPDXValue(obj, "primaryPurpose", PrimaryPurpose);
-  return obj;
-}
-
-// SPDX Software Element Classes, Concrete
-
-cmSPDXFile::cmSPDXFile(cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXSoftwareArtifact(SOFTWARE_FILE, creationInfo)
-{
-}
-
-Json::Value cmSPDXFile::toJsonLD() const
-{
-  auto obj = cmSPDXSoftwareArtifact::toJsonLD();
-  obj["type"] = "File";
-  addOptionalSPDXValue(obj, "contentType", ContentType);
-  addOptionalSPDXValue(obj, "fileKind", FileKind);
-  return obj;
-}
-
-cmSPDXPackage::cmSPDXPackage(cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXSoftwareArtifact(SOFTWARE_PACKAGE, creationInfo)
-{
-}
-
-Json::Value cmSPDXPackage::toJsonLD() const
-{
-  auto obj = cmSPDXSoftwareArtifact::toJsonLD();
-  obj["type"] = "Package";
-  addOptionalSPDXValue(obj, "downloadLocation", DownloadLocation);
-  addOptionalSPDXValue(obj, "homePage", HomePage);
-  addOptionalSPDXValue(obj, "packageUrl", PackageUrl);
-  addOptionalSPDXValue(obj, "packageVersion", PackageVersion);
-  addOptionalSPDXValue(obj, "sourceInfo", SourceInfo);
-  return obj;
-}
-
-cmSPDXSbom::cmSPDXSbom(cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXBomAbstract(SOFTWARE_SBOM, creationInfo)
-{
-}
-
-Json::Value cmSPDXSbom::toJsonLD() const
-{
-  auto obj = cmSPDXBomAbstract::toJsonLD();
-  obj["type"] = "Sbom";
-  addOptionalSPDXValue(obj, "sbomType", SbomType);
-  return obj;
-}
-
-cmSPDXSnippet::cmSPDXSnippet(cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXSoftwareArtifact(SOFTWARE_SNIPPET, creationInfo)
-{
-}
-
-Json::Value cmSPDXSnippet::toJsonLD() const
-{
-  auto obj = cmSPDXSoftwareArtifact::toJsonLD();
-  obj["type"] = "Snippet";
-  addOptionalSPDXValue(obj, "byteRange", ByteRange);
-  addOptionalSPDXValue(obj, "lineRange", LineRange);
-  obj["snippetFromFile"] = SnippetFromFile.toJsonLD();
-  return obj;
-}
-
-// SPDX SimpleLicensing Element Classes, Concrete
-
-cmSPDXLicenseExpression::cmSPDXLicenseExpression(
-  cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXAnyLicenseInfo(SIMPLE_LICENSING_LICENSE_EXPRESSION, creationInfo)
-{
-}
-
-Json::Value cmSPDXLicenseExpression::toJsonLD() const
-{
-  auto obj = cmSPDXAnyLicenseInfo::toJsonLD();
-  obj["type"] = "LicenseExpression";
-  addOptionalSPDXValue(obj, "customIdToUri", CustomIdToUri);
-  obj["licenseExpression"] = LicenseExpression;
-  addOptionalSPDXValue(obj, "licenseListVersion", LicenseListVersion);
-  return obj;
-}
-
-cmSPDXSimpleLicensingText::cmSPDXSimpleLicensingText(
-  cmSPDXCreationInfo const& creationInfo)
-  : cmSPDXElement(SIMPLE_LICENSING_SIMPLE_LICENSING_TEXT, creationInfo)
-{
-}
-
-Json::Value cmSPDXSimpleLicensingText::toJsonLD() const
-{
-  auto obj = cmSPDXElement::toJsonLD();
-  obj["type"] = "SimpleLicensingText";
-  obj["licenseText"] = LicenseText;
-  return obj;
-}
-
-// Graph Manipulation
-
-#define X_SPDX(classtype, enumid, member, camel)                              \
-  template <>                                                                 \
-  cmSPDXSerializationBase::SPDXTypeId cmSPDXGetTypeId<classtype>()            \
-  {                                                                           \
-    return cmSPDXSerializationBase::enumid;                                   \
-  }                                                                           \
-                                                                              \
-  template <>                                                                 \
-  std::string cmSPDXGetTypeName<classtype>()                                  \
-  {                                                                           \
-    return #camel;                                                            \
-  }                                                                           \
-                                                                              \
-  cmSPDXObject::cmSPDXObject(classtype val)                                   \
-    : member(std::move(val)) {};                                              \
-                                                                              \
-  void cmSPDXObject::get(classtype** ptr)                                     \
-  {                                                                           \
-    *ptr = SerializationBase.getTypeId() == cmSPDXSerializationBase::enumid   \
-      ? &member                                                               \
-      : nullptr;                                                              \
-  }
-#include "cmSPDXTypes.def"
-
-cmSPDXObject::cmSPDXObject()
-  : IdentifierReference("UNINITIALIZED_SPDX_OBJECT")
-{
-}
-
-cmSPDXObject::cmSPDXObject(cmSPDXObject const& other)
-{
-  switch (other.SerializationBase.getTypeId()) {
-#define X_SPDX(classtype, enumid, member, camel)                              \
-  case cmSPDXSerializationBase::enumid:                                       \
-    new (&member) classtype(other.member);                                    \
-    break;
-#include "cmSPDXTypes.def"
-    default:
-      new (&IdentifierReference)
-        cmSPDXIdentifierReference("UNINITIALIZED_SPDX_OBJECT");
-  }
-}
-
-cmSPDXObject::cmSPDXObject(cmSPDXObject&& other) noexcept
-{
-  switch (other.SerializationBase.getTypeId()) {
-#define X_SPDX(classtype, enumid, member, camel)                              \
-  case cmSPDXSerializationBase::enumid:                                       \
-    new (&member) classtype(std::move(other.member));                         \
-    break;
-#include "cmSPDXTypes.def"
-    default:
-      new (&IdentifierReference)
-        cmSPDXIdentifierReference("UNINITIALIZED_SPDX_OBJECT");
-  }
-}
-
-cmSPDXObject& cmSPDXObject::operator=(cmSPDXObject const& other)
-{
-  this->~cmSPDXObject();
-  new (this) cmSPDXObject(other);
-  return *this;
-}
-
-cmSPDXObject& cmSPDXObject::operator=(cmSPDXObject&& other) noexcept
-{
-  this->~cmSPDXObject();
-  new (this) cmSPDXObject(std::move(other));
-  return *this;
-}
-
-cmSPDXObject::~cmSPDXObject()
-{
-  switch (SerializationBase.getTypeId()) {
-#define X_SPDX(classtype, enumid, member, camel)                              \
-  case cmSPDXSerializationBase::enumid:                                       \
-    member.~classtype();                                                      \
-    break;
-#include "cmSPDXTypes.def"
-    default:
-      break;
-  }
-}
-
-Json::Value cmSPDXObject::toJsonLD() const
-{
-  switch (SerializationBase.getTypeId()) {
-#define X_SPDX(classtype, enumid, member, camel)                              \
-  case cmSPDXSerializationBase::enumid:                                       \
-    return member.toJsonLD();
-#include "cmSPDXTypes.def"
-    default:
-      return "INVALID_SPDX_OBJECT_TYPE_ID";
-  }
-}
-
-cmSPDXSimpleGraph::cmSPDXSimpleGraph(std::string iriBase,
-                                     cmSPDXCreationInfo creationInfo)
-  : IRIBase(std::move(iriBase))
-  , CreationInfo(&insert<cmSPDXCreationInfo>(std::move(creationInfo)))
-{
-}
-
-cmSPDXCreationInfo& cmSPDXSimpleGraph::getCreationInfo()
-{
-  return *CreationInfo;
-}
-
-Json::Value cmSPDXSimpleGraph::toJsonLD()
-{
-  Json::Value obj(Json::objectValue);
-  obj["@context"] = "https://spdx.org/rdf/3.0.1/spdx-context.jsonld";
-
-  auto& graph = obj["@graph"];
-  for (auto const& it : Graph) {
-    graph.append(it.second.toJsonLD());
-  }
-
-  return obj;
-}
diff --git a/Source/cmSPDXSerializer.h b/Source/cmSPDXSerializer.h
deleted file mode 100644
index 65bf214..0000000
--- a/Source/cmSPDXSerializer.h
+++ /dev/null
@@ -1,1008 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file LICENSE.rst or https://cmake.org/licensing for details.  */
-#pragma once
-
-#include <array>
-#include <cstddef>
-#include <map>
-#include <new>
-#include <string>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-#include <cm/optional>
-#include <cm/type_traits>
-
-#include <cm3p/json/value.h>
-
-#include "cmStringAlgorithms.h"
-
-// Base Class
-
-struct cmSPDXSerializationBase
-{
-  enum SPDXTypeId
-  {
-    INVALID = -1,
-    NULL_ID = 0,
-
-#define X_SPDX(classtype, enumid, title, camel) enumid,
-#include "cmSPDXTypes.def"
-
-    SPDX_TYPE_ID_MAX,
-  };
-
-  SPDXTypeId getTypeId() const;
-
-  std::string NodeId;
-
-protected:
-  cmSPDXSerializationBase(SPDXTypeId id);
-  cmSPDXSerializationBase(SPDXTypeId id, std::string nodeId);
-
-private:
-  SPDXTypeId TypeId;
-};
-
-// Convenience Classes
-
-struct cmSPDXIdentifierReference : cmSPDXSerializationBase
-{
-  cmSPDXIdentifierReference();
-  cmSPDXIdentifierReference(cmSPDXSerializationBase const& ref);
-  cmSPDXIdentifierReference(std::string const& ref);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXNonElementBase : cmSPDXSerializationBase
-{
-protected:
-  cmSPDXNonElementBase(SPDXTypeId id);
-
-  Json::Value toJsonLD() const;
-};
-
-// SPDX Core Data Types
-
-// Nominally these are supposed to be validated strings
-using cmSPDXDateTime = std::string;
-using cmSPDXMediaType = std::string;
-using cmSPDXSemVer = std::string;
-
-// SPDX Core Enums
-
-struct cmSPDXAnnotationType
-{
-  enum cmSPDXAnnotationTypeId
-  {
-    INVALID = -1,
-    NULL_ID = 0,
-    OTHER,
-    REVIEW,
-  };
-
-  cmSPDXAnnotationTypeId TypeId;
-
-  cmSPDXAnnotationType(cmSPDXAnnotationTypeId typeId = NULL_ID);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXExternalIdentifierType
-{
-  enum cmSPDXExternalIdentifierTypeId
-  {
-    INVALID = -1,
-    NULL_ID = 0,
-    CPE22,
-    CPE23,
-    CVE,
-    EMAIL,
-    GITOID,
-    OTHER,
-    PACKAGE_URL,
-    SECURITY_OTHER,
-    SWHID,
-    SWID,
-    URL_SCHEME,
-  };
-
-  cmSPDXExternalIdentifierTypeId TypeId;
-
-  cmSPDXExternalIdentifierType(
-    cmSPDXExternalIdentifierTypeId typeId = NULL_ID);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXExternalRefType
-{
-  enum cmSPDXExternalRefTypeId
-  {
-    INVALID = -1,
-    NULL_ID = 0,
-    ALT_DOWNLOAD_LOCATION,
-    ALT_WEB_PAGE,
-    BINARY_ARTIFACT,
-    BOWER,
-    BUILD_META,
-    BUILD_SYSTEM,
-    CERTIFICATION_REPORT,
-    CHAT,
-    COMPONENT_ANALYSIS_REPORT,
-    CWE,
-    DOCUMENTATION,
-    DYNAMIC_ANALYSIS_REPORT,
-    EOL_NOTICE,
-    EXPORT_CONTROL_ASSESSMENT,
-    FUNDING,
-    ISSUE_TRACKER,
-    LICENSE,
-    MAILING_LIST,
-    MAVEN_CENTRAL,
-    METRICS,
-    NPM,
-    NUGET,
-    OTHER,
-    PRIVACY_ASSESSMENT,
-    PRODUCT_METADATA,
-    PURCHASE_ORDER,
-    QUALITY_ASSESSMENT_REPORT,
-    RELEASE_HISTORY,
-    RELEASE_NOTES,
-    RISK_ASSESSMENT,
-    RUNTIME_ANALYSIS_REPORT,
-    SECURE_SOFTWARE_ATTESTATION,
-    SECURITY_ADVERSARY_MODEL,
-    SECURITY_ADVISORY,
-    SECURITY_FIX,
-    SECURITY_OTHER,
-    SECURITY_PEN_TEST_REPORT,
-    SECURITY_POLICY,
-    SECURITY_THREAT_MODEL,
-    SOCIAL_MEDIA,
-    SOURCE_ARTIFACT,
-    STATIC_ANALYSIS_REPORT,
-    SUPPORT,
-    VCS,
-    VULNERABILITY_DISCLOSURE_REPORT,
-    VULNERABILITY_EXPLOITABILITY_ASSESSMENT,
-  };
-
-  cmSPDXExternalRefTypeId TypeId;
-
-  cmSPDXExternalRefType(cmSPDXExternalRefTypeId typeId = NULL_ID);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXHashAlgorithm
-{
-  enum cmSPDXHashAlgorithmId
-  {
-    INVALID = -1,
-    NULL_ID = 0,
-    ADLER32,
-    BLAKE2B256,
-    BLAKE2B384,
-    BLAKE2B512,
-    BLAKE3,
-    CRYSTALS_DILITHIUM,
-    CRYSTALS_KYBER,
-    FALCON,
-    MD2,
-    MD4,
-    MD5,
-    MD6,
-    OTHER,
-    SHA1,
-    SHA224,
-    SHA256,
-    SHA384,
-    SHA3_224,
-    SHA3_256,
-    SHA3_384,
-    SHA3_512,
-    SHA512,
-  };
-
-  cmSPDXHashAlgorithmId TypeId;
-
-  cmSPDXHashAlgorithm(cmSPDXHashAlgorithmId typeId = NULL_ID);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXLifecycleScopeType
-{
-  enum cmSPDXLifecycleScopeTypeId
-  {
-    INVALID = -1,
-    NULL_ID = 0,
-    BUILD,
-    DESIGN,
-    DEVELOPMENT,
-    OTHER,
-    RUNTIME,
-    TEST,
-  };
-
-  cmSPDXLifecycleScopeTypeId TypeId;
-
-  cmSPDXLifecycleScopeType(cmSPDXLifecycleScopeTypeId typeId = NULL_ID);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXProfileIdentifierType
-{
-  enum cmSPDXProfileIdentifierTypeId
-  {
-    INVALID = -1,
-    NULL_ID = 0,
-    AI,
-    BUILD,
-    CORE,
-    DATASET,
-    EXPANDED_LICENSING,
-    EXTENSION,
-    LITE,
-    SECURITY,
-    SIMPLE_LICENSING,
-    SOFTWARE,
-  };
-
-  cmSPDXProfileIdentifierTypeId TypeId;
-
-  cmSPDXProfileIdentifierType(cmSPDXProfileIdentifierTypeId typeId = NULL_ID);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXRelationshipCompletenessType
-{
-  enum cmSPDXRelationshipCompletenessTypeId
-  {
-    INVALID = -1,
-    NULL_ID = 0,
-    COMPLETE,
-    INCOMPLETE,
-    NO_ASSERTION,
-  };
-
-  cmSPDXRelationshipCompletenessTypeId TypeId;
-
-  cmSPDXRelationshipCompletenessType(
-    cmSPDXRelationshipCompletenessTypeId typeId = NULL_ID);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXRelationshipType
-{
-  enum cmSPDXRelationshipTypeId
-  {
-    INVALID = -1,
-    NULL_ID = 0,
-    AFFECTS,
-    AMENDED_BY,
-    ANCESTOR_OF,
-    AVAILABLE_FROM,
-    CONFIGURES,
-    CONTAINS,
-    COORDINATED_BY,
-    COPIED_TO,
-    DELEGATED_TO,
-    DEPENDS_ON,
-    DESCENDANT_OF,
-    DESCRIBES,
-    DOES_NOT_AFFECT,
-    EXPANDS_TO,
-    EXPLOIT_CREATED_BY,
-    FIXED_BY,
-    FIXED_IN,
-    FOUND_BY,
-    GENERATES,
-    HAS_ADDED_FILE,
-    HAS_ASSESSMENT_FOR,
-    HAS_ASSOCIATED_VULNERABILITY,
-    HAS_CONCLUDED_LICENSE,
-    HAS_DATA_FILE,
-    HAS_DECLARED_LICENSE,
-    HAS_DELETED_FILE,
-    HAS_DEPENDENCY_MANIFEST,
-    HAS_DISTRIBUTION_ARTIFACT,
-    HAS_DOCUMENTATION,
-    HAS_DYNAMIC_LINK,
-    HAS_EVIDENCE,
-    HAS_EXAMPLE,
-    HAS_HOST,
-    HAS_INPUT,
-    HAS_METADATA,
-    HAS_OPTIONAL_COMPONENT,
-    HAS_OPTIONAL_DEPENDENCY,
-    HAS_OUTPUT,
-    HAS_PREREQUISITE,
-    HAS_PROVIDED_DEPENDENCY,
-    HAS_REQUIREMENT,
-    HAS_SPECIFICATION,
-    HAS_STATIC_LINK,
-    HAS_TEST,
-    HAS_TEST_CASE,
-    HAS_VARIANT,
-    INVOKED_BY,
-    MODIFIED_BY,
-    OTHER,
-    PACKAGED_BY,
-    PATCHED_BY,
-    PUBLISHED_BY,
-    REPORTED_BY,
-    REPUBLISHED_BY,
-    SERIALIZED_IN_ARTIFACT,
-    TESTED_ON,
-    TRAINED_ON,
-    UNDER_INVESTIGATION_FOR,
-    USES_TOOL,
-  };
-
-  cmSPDXRelationshipTypeId TypeId;
-
-  cmSPDXRelationshipType(cmSPDXRelationshipTypeId typeId = NULL_ID);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXSupportType
-{
-  enum cmSPDXSupportTypeId
-  {
-    INVALID = -1,
-    NULL_ID = 0,
-    DEPLOYED,
-    DEVELOPMENT,
-    END_OF_SUPPORT,
-    LIMITED_SUPPORT,
-    NO_ASSERTION,
-    NO_SUPPORT,
-    SUPPORT,
-  };
-
-  cmSPDXSupportTypeId TypeId;
-
-  cmSPDXSupportType(cmSPDXSupportTypeId typeId = NULL_ID);
-
-  Json::Value toJsonLD() const;
-};
-
-// SPDX Core NonElement Classes, Abstract
-
-struct cmSPDXIntegrityMethod : cmSPDXNonElementBase
-{
-
-  cm::optional<std::string> Comment;
-
-protected:
-  cmSPDXIntegrityMethod(SPDXTypeId id);
-
-  Json::Value toJsonLD() const;
-};
-
-// SPDX Core NonElement Classes, Concrete
-
-struct cmSPDXCreationInfo : cmSPDXNonElementBase
-{
-  cm::optional<std::string> Comment;
-  cmSPDXDateTime Created;
-  std::vector<cmSPDXIdentifierReference> CreatedBy;
-  cm::optional<std::vector<cmSPDXIdentifierReference>> CreatedUsing;
-
-  cmSPDXCreationInfo();
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXDictionaryEntry : cmSPDXNonElementBase
-{
-  std::string Key;
-  cm::optional<std::string> Value;
-
-  cmSPDXDictionaryEntry();
-  cmSPDXDictionaryEntry(std::string key);
-  cmSPDXDictionaryEntry(std::string key, std::string val);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXExternalIdentifier : cmSPDXNonElementBase
-{
-  cm::optional<std::string> Comment;
-  cmSPDXExternalIdentifierType ExternalIdentifierType;
-  std::string Identifier;
-  cm::optional<std::vector<std::string>> IdentifierLocator;
-  cm::optional<std::string> IssuingAuthority;
-
-  cmSPDXExternalIdentifier();
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXExternalMap : cmSPDXNonElementBase
-{
-  cm::optional<cmSPDXIdentifierReference> DefiningArtifact;
-  std::string ExternalSpdxId;
-  cm::optional<std::string> LocationHint;
-  cm::optional<std::vector<cmSPDXIdentifierReference>> IntegrityMethod;
-
-  cmSPDXExternalMap();
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXExternalRef : cmSPDXNonElementBase
-{
-  cm::optional<std::string> Comment;
-  cm::optional<cmSPDXMediaType> ContentType;
-  cm::optional<cmSPDXExternalRefType> ExternalRefType;
-  cm::optional<std::vector<std::string>> Locator;
-
-  cmSPDXExternalRef();
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXHash : cmSPDXIntegrityMethod
-{
-  cmSPDXHashAlgorithm Algorithm;
-  std::string HashValue;
-
-  cmSPDXHash();
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXNamespaceMap : cmSPDXNonElementBase
-{
-  std::string Namespace;
-  std::string Prefix;
-
-  cmSPDXNamespaceMap();
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXPackageVerificationCode : cmSPDXIntegrityMethod
-{
-  cmSPDXHashAlgorithm Algorithm;
-  std::string HashValue;
-  cm::optional<std::vector<std::string>> PackageVerificationCodeExcludedFile;
-
-  cmSPDXPackageVerificationCode();
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXPositiveIntegerRange : cmSPDXNonElementBase
-{
-  unsigned int BeginIntegerRange;
-  unsigned int EndIntegerRange;
-
-  cmSPDXPositiveIntegerRange(unsigned int beingIntegerRange = 0,
-                             unsigned int endIntegerRange = 0);
-
-  Json::Value toJsonLD() const;
-};
-
-// SPDX Core Element Classes, Abstract
-
-struct cmSPDXElement : cmSPDXSerializationBase
-{
-  cm::optional<std::string> Comment;
-  cmSPDXIdentifierReference CreationInfo;
-  cm::optional<std::string> Description;
-  cm::optional<std::vector<cmSPDXIdentifierReference>> Extension;
-  cm::optional<std::vector<cmSPDXIdentifierReference>> ExternalIdentifier;
-  cm::optional<std::vector<cmSPDXIdentifierReference>> ExternalRef;
-  cm::optional<std::string> Name;
-  // SpdxId is the NodeId
-  cm::optional<std::string> Summary;
-  cm::optional<std::vector<cmSPDXIdentifierReference>> VerifiedUsing;
-
-protected:
-  cmSPDXElement(SPDXTypeId id, cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXArtifact : cmSPDXElement
-{
-  cm::optional<cmSPDXDateTime> BuiltTime;
-  cm::optional<std::vector<cmSPDXIdentifierReference>> OriginatedBy;
-  cm::optional<cmSPDXDateTime> ReleaseTime;
-  cm::optional<std::vector<std::string>> StandardName;
-  cm::optional<cmSPDXIdentifierReference> SuppliedBy;
-  cm::optional<std::vector<cmSPDXSupportType>> SupportType;
-  cm::optional<cmSPDXDateTime> ValidUntilTime;
-
-protected:
-  cmSPDXArtifact(SPDXTypeId id, cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXElementCollection : cmSPDXElement
-{
-  cm::optional<std::vector<cmSPDXIdentifierReference>> Element;
-  cm::optional<std::vector<cmSPDXProfileIdentifierType>> ProfileConformance;
-  cm::optional<std::vector<cmSPDXIdentifierReference>> RootElement;
-
-protected:
-  cmSPDXElementCollection(SPDXTypeId id,
-                          cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-// SPDX Implicit Core Element Classes, Abstract
-
-// Nominally an inheritable class, but adds nothing to Element
-using cmSPDXAgentAbstract = cmSPDXElement;
-
-struct cmSPDXBundleAbstract : cmSPDXElementCollection
-{
-  std::string Context;
-
-protected:
-  cmSPDXBundleAbstract(SPDXTypeId id, cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-// Nominally an inheritable class, but adds nothing to Bundle
-using cmSPDXBomAbstract = cmSPDXBundleAbstract;
-
-struct cmSPDXRelationshipAbstract : cmSPDXElement
-{
-  cm::optional<cmSPDXRelationshipCompletenessType> Completeness;
-  cm::optional<cmSPDXDateTime> EndTime;
-  cmSPDXIdentifierReference From;
-  cmSPDXRelationshipType RelationshipType;
-  cm::optional<cmSPDXDateTime> StartTime;
-  std::vector<cmSPDXIdentifierReference> To;
-
-protected:
-  cmSPDXRelationshipAbstract(SPDXTypeId id,
-                             cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-// SPDX Core Element Classes, Concrete
-
-struct cmSPDXAgent : cmSPDXAgentAbstract
-{
-  cmSPDXAgent(cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXAnnotation : cmSPDXElement
-{
-  cmSPDXAnnotationType AnnotationType;
-  cm::optional<cmSPDXMediaType> ContentType;
-  cm::optional<std::string> Statement;
-  cmSPDXIdentifierReference Subject;
-
-  cmSPDXAnnotation(cmSPDXCreationInfo const& creationInfo,
-                   cmSPDXIdentifierReference subject = {});
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXBom : cmSPDXBomAbstract
-{
-  cmSPDXBom(cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXBundle : cmSPDXBundleAbstract
-{
-  cmSPDXBundle(cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXIndividualElement : cmSPDXElement
-{
-  cmSPDXIndividualElement(cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXLifecycleScopedRelationship : cmSPDXRelationshipAbstract
-{
-  cm::optional<cmSPDXLifecycleScopeType> Scope;
-
-  cmSPDXLifecycleScopedRelationship(cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXOrganization : cmSPDXAgentAbstract
-{
-  cmSPDXOrganization(cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXPerson : cmSPDXAgentAbstract
-{
-  cmSPDXPerson(cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXRelationship : cmSPDXRelationshipAbstract
-{
-  cmSPDXRelationship(cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXSoftwareAgent : cmSPDXAgentAbstract
-{
-  cmSPDXSoftwareAgent(cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXSpdxDocument : cmSPDXElementCollection
-{
-  cm::optional<cmSPDXIdentifierReference> DataLicense;
-  cm::optional<cmSPDXIdentifierReference> ExternalMap;
-  cm::optional<cmSPDXIdentifierReference> NamespaceMap;
-
-  cmSPDXSpdxDocument(cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXTool : cmSPDXElement
-{
-  cmSPDXTool(cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-// SPDX Software Enums
-
-struct cmSPDXContentIdentifierType
-{
-  enum cmSPDXContentIdentifierTypeId
-  {
-    INVALID = -1,
-    NULL_ID = 0,
-    GITOID,
-    SWHID,
-  };
-
-  cmSPDXContentIdentifierTypeId TypeId;
-
-  cmSPDXContentIdentifierType(cmSPDXContentIdentifierTypeId typeId = NULL_ID);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXFileKindType
-{
-  enum cmSPDXFileKindTypeId
-  {
-    INVALID = -1,
-    NULL_ID = 0,
-    DIRECTORY,
-    FILE,
-  };
-
-  cmSPDXFileKindTypeId TypeId;
-
-  cmSPDXFileKindType(cmSPDXFileKindTypeId typeId = NULL_ID);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXSbomType
-{
-  enum cmSPDXSbomTypeId
-  {
-    INVALID = -1,
-    NULL_ID = 0,
-    ANALYZED,
-    BUILD,
-    DEPLOYED,
-    DESIGN,
-    RUNTIME,
-    SOURCE,
-  };
-
-  cmSPDXSbomTypeId TypeId;
-
-  cmSPDXSbomType(cmSPDXSbomTypeId typeId = NULL_ID);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXSoftwarePurpose
-{
-  enum cmSPDXSoftwarePurposeId
-  {
-    INVALID = -1,
-    NULL_ID = 0,
-    APPLICATION,
-    ARCHIVE,
-    BOM,
-    CONFIGURATION,
-    CONTAINER,
-    DATA,
-    DEVICE,
-    DEVICE_DRIVER,
-    DISK_IMAGE,
-    DOCUMENTATION,
-    EVIDENCE,
-    EXECUTABLE,
-    FILE,
-    FILESYSTEM_IMAGE,
-    FIRMWARE,
-    FRAMEWORK,
-    INSTALL,
-    LIBRARY,
-    MANIFEST,
-    MODEL,
-    MODULE,
-    OPERATING_SYSTEM,
-    OTHER,
-    PATCH,
-    PLATFORM,
-    REQUIREMENT,
-    SOURCE,
-    SPECIFICATION,
-    TEST,
-  };
-
-  cmSPDXSoftwarePurposeId TypeId;
-
-  cmSPDXSoftwarePurpose(cmSPDXSoftwarePurposeId typeId = NULL_ID);
-
-  Json::Value toJsonLD() const;
-};
-
-// SPDX Software NonElement Classes, Concrete
-
-struct cmSPDXContentIdentifier : cmSPDXIntegrityMethod
-{
-  cmSPDXContentIdentifierType ContentIdentifierType;
-  std::string ContentIdentifierValue;
-
-  cmSPDXContentIdentifier();
-
-  Json::Value toJsonLD() const;
-};
-
-// SPDX Software Element Classes, Abstract
-
-struct cmSPDXSoftwareArtifact : cmSPDXArtifact
-{
-  cm::optional<std::vector<cmSPDXSoftwarePurpose>> AdditionalPurpose;
-  cm::optional<std::string> AttributionText;
-  cm::optional<cmSPDXIdentifierReference> ContentIdentifier;
-  cm::optional<std::string> CopyrightText;
-  cm::optional<cmSPDXSoftwarePurpose> PrimaryPurpose;
-
-protected:
-  cmSPDXSoftwareArtifact(SPDXTypeId id,
-                         cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-// SPDX Software Element Classes, Concrete
-
-struct cmSPDXFile : cmSPDXSoftwareArtifact
-{
-  cm::optional<cmSPDXMediaType> ContentType;
-  cm::optional<cmSPDXFileKindType> FileKind;
-
-  cmSPDXFile(cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXPackage : cmSPDXSoftwareArtifact
-{
-  cm::optional<std::string> DownloadLocation;
-  cm::optional<std::string> HomePage;
-  cm::optional<std::string> PackageUrl;
-  cm::optional<std::string> PackageVersion;
-  cm::optional<std::string> SourceInfo;
-
-  cmSPDXPackage(cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXSbom : cmSPDXBomAbstract
-{
-  cm::optional<std::vector<cmSPDXSbomType>> SbomType;
-
-  cmSPDXSbom(cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXSnippet : cmSPDXSoftwareArtifact
-{
-  cm::optional<cmSPDXIdentifierReference> ByteRange;
-  cm::optional<cmSPDXIdentifierReference> LineRange;
-  cmSPDXIdentifierReference SnippetFromFile;
-
-  cmSPDXSnippet(cmSPDXCreationInfo const& creationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-// SPDX SimpleLicensing Element Classes, Abstract
-
-// Nominally an inheritable class, but adds nothing to Element
-using cmSPDXAnyLicenseInfo = cmSPDXElement;
-
-// SPDX SimpleLicensing Element Classes, Concrete
-
-struct cmSPDXLicenseExpression : cmSPDXAnyLicenseInfo
-{
-  cm::optional<std::vector<cmSPDXIdentifierReference>> CustomIdToUri;
-  std::string LicenseExpression;
-  cm::optional<cmSPDXSemVer> LicenseListVersion;
-
-  cmSPDXLicenseExpression(cmSPDXCreationInfo const& CreationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-struct cmSPDXSimpleLicensingText : cmSPDXElement
-{
-  std::string LicenseText;
-
-  cmSPDXSimpleLicensingText(cmSPDXCreationInfo const& CreationInfo);
-
-  Json::Value toJsonLD() const;
-};
-
-// Graph Manipulation
-
-template <typename T>
-cmSPDXSerializationBase::SPDXTypeId cmSPDXGetTypeId();
-
-template <typename T>
-std::string cmSPDXGetTypeName();
-
-#define X_SPDX(classtype, enumid, member, camel)                              \
-  template <>                                                                 \
-  cmSPDXSerializationBase::SPDXTypeId cmSPDXGetTypeId<classtype>();           \
-                                                                              \
-  template <>                                                                 \
-  std::string cmSPDXGetTypeName<classtype>();
-#include "cmSPDXTypes.def"
-
-template <class T>
-struct cmSPDXTag
-{
-  using type = T;
-};
-
-union cmSPDXObject
-{
-
-  cmSPDXSerializationBase SerializationBase;
-
-  cmSPDXObject();
-  cmSPDXObject(cmSPDXObject const& other);
-  cmSPDXObject(cmSPDXObject&& other) noexcept;
-
-#define X_SPDX(classtype, enumid, member, camel)                              \
-  classtype member;                                                           \
-  cmSPDXObject(classtype val);                                                \
-                                                                              \
-  template <typename... Args>                                                 \
-  cmSPDXObject(cmSPDXTag<classtype>, Args&&... args)                          \
-  {                                                                           \
-    new (&member) classtype(std::forward<Args>(args)...);                     \
-  }
-#include "cmSPDXTypes.def"
-
-  cmSPDXObject& operator=(cmSPDXObject const& other);
-  cmSPDXObject& operator=(cmSPDXObject&& other) noexcept;
-
-  ~cmSPDXObject();
-
-  template <typename T>
-  T* get()
-  {
-    T* ptr;
-    get(&ptr);
-    return ptr;
-  }
-
-  Json::Value toJsonLD() const;
-
-private:
-#define X_SPDX(classtype, enumid, member, camel) void get(classtype** ptr);
-#include "cmSPDXTypes.def"
-};
-
-struct cmSPDXSimpleGraph
-{
-  cmSPDXSimpleGraph(std::string iriBase, cmSPDXCreationInfo creationInfo = {});
-
-  template <typename T, typename... Args>
-  cm::enable_if_t<std::is_base_of<cmSPDXElement, T>::value, T>& insert(
-    Args&&... args)
-  {
-    std::string nodeId = cmStrCat(IRIBase, IRICount++);
-    auto const& it =
-      Graph.emplace(std::piecewise_construct, std::forward_as_tuple(nodeId),
-                    std::forward_as_tuple(cmSPDXTag<T>{}, *CreationInfo,
-                                          std::forward<Args>(args)...));
-    auto& node = *it.first->second.template get<T>();
-    node.NodeId = std::move(nodeId);
-    return node;
-  }
-
-  cmSPDXCreationInfo& getCreationInfo();
-
-  template <typename T, typename... Args>
-  cm::enable_if_t<std::is_base_of<cmSPDXNonElementBase, T>::value, T>& insert(
-    Args&&... args)
-  {
-    std::size_t nodeCount = BlankCounts[cmSPDXGetTypeId<T>()]++;
-    std::string nodeId =
-      cmStrCat("_:", cmSPDXGetTypeName<T>(), "_", nodeCount);
-    auto const& it = Graph.emplace(
-      std::piecewise_construct, std::forward_as_tuple(nodeId),
-      std::forward_as_tuple(cmSPDXTag<T>{}, std::forward<Args>(args)...));
-    auto& node = *it.first->second.template get<T>();
-    node.NodeId = std::move(nodeId);
-    return node;
-  }
-
-  template <typename T>
-  T* get(std::string const& key)
-  {
-    auto it = Graph.find(key);
-    if (it == Graph.end()) {
-      return nullptr;
-    }
-    return it->second.get<T>();
-  }
-
-  template <typename T>
-  T* get(cmSPDXIdentifierReference const& key)
-  {
-    auto it = Graph.find(key.NodeId);
-    if (it == Graph.end()) {
-      return nullptr;
-    }
-    return it->second.get<T>();
-  }
-
-  Json::Value toJsonLD();
-
-private:
-  std::string IRIBase;
-  std::size_t IRICount{ 0 };
-  std::array<std::size_t, cmSPDXSerializationBase::SPDX_TYPE_ID_MAX>
-    BlankCounts{};
-
-  std::map<std::string, cmSPDXObject> Graph;
-  cmSPDXCreationInfo* CreationInfo;
-};
diff --git a/Source/cmSPDXTypes.def b/Source/cmSPDXTypes.def
deleted file mode 100644
index 88d8043..0000000
--- a/Source/cmSPDXTypes.def
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file LICENSE.rst or https://cmake.org/licensing for details.  */
-#ifndef X_SPDX
-#  define X_SPDX(classtype, enumid, member, camel)
-#endif
-
-// Convenience
-X_SPDX(cmSPDXIdentifierReference, CM_IDENTIFIER_REFERENCE, IdentifierReference,
-       identifierReference)
-
-// Core
-X_SPDX(cmSPDXAgent, CORE_AGENT, Agent, agent)
-X_SPDX(cmSPDXAnnotation, CORE_ANNOTATION, Annotation, annotation)
-X_SPDX(cmSPDXBom, CORE_BOM, Bom, bom)
-X_SPDX(cmSPDXBundle, CORE_BUNDLE, Bundle, bundle)
-X_SPDX(cmSPDXCreationInfo, CORE_CREATION_INFO, CreationInfo, creationInfo)
-X_SPDX(cmSPDXDictionaryEntry, CORE_DICTIONARY_ENTRY, DictionaryEntry,
-       dictionaryEntry)
-X_SPDX(cmSPDXExternalIdentifier, CORE_EXTERNAL_IDENTIFIER, ExternalIdentifier,
-       externalIdentifier)
-X_SPDX(cmSPDXExternalMap, CORE_EXTERNAL_MAP, ExternalMap, externalMap)
-X_SPDX(cmSPDXExternalRef, CORE_EXTERNAL_REF, ExternalRef, externalRef)
-X_SPDX(cmSPDXHash, CORE_HASH, Hash, hash)
-X_SPDX(cmSPDXIndividualElement, CORE_INDIVIDUAL_ELEMENT, IndividualElement,
-       individualElement)
-X_SPDX(cmSPDXLifecycleScopedRelationship, CORE_LIFECYCLE_SCOPED_RELATIONSHIP,
-       LifecycleScopedRelationship, lifecycleScopedRelationship)
-X_SPDX(cmSPDXNamespaceMap, CORE_NAMESPACE_MAP, NamespaceMap, namespaceMap)
-X_SPDX(cmSPDXOrganization, CORE_ORGANIZATION, Organization, organization)
-X_SPDX(cmSPDXPackageVerificationCode, CORE_PACKAGE_VERIFICATION_CODE,
-       PackageVerificationCode, packageVerificationCode)
-X_SPDX(cmSPDXPerson, CORE_PERSON, Person, person)
-X_SPDX(cmSPDXPositiveIntegerRange, CORE_POSITIVE_INTEGER_RANGE,
-       PositiveIntegerRange, positiveIntegerRange)
-X_SPDX(cmSPDXRelationship, CORE_RELATIONSHIP, Relationship, relationship)
-X_SPDX(cmSPDXSoftwareAgent, CORE_SOFTWARE_AGENT, SoftwareAgent, softwareAgent)
-X_SPDX(cmSPDXSpdxDocument, CORE_SPDX_DOCUMENT, SpdxDocument, spdxDocument)
-X_SPDX(cmSPDXTool, CORE_TOOL, Tool, tool)
-
-// Software
-X_SPDX(cmSPDXContentIdentifier, SOFTWARE_CONTENT_IDENTIFIER, ContentIdentifier,
-       contentIdentifier)
-X_SPDX(cmSPDXFile, SOFTWARE_FILE, File, file)
-X_SPDX(cmSPDXPackage, SOFTWARE_PACKAGE, Package, package)
-X_SPDX(cmSPDXSbom, SOFTWARE_SBOM, Sbom, sbom)
-X_SPDX(cmSPDXSnippet, SOFTWARE_SNIPPET, Snippet, snippet)
-
-// SimpleLicensing
-X_SPDX(cmSPDXLicenseExpression, SIMPLE_LICENSING_LICENSE_EXPRESSION,
-       LicenseExpression, licenseExpression)
-X_SPDX(cmSPDXSimpleLicensingText, SIMPLE_LICENSING_SIMPLE_LICENSING_TEXT,
-       SimpleLicensingText, simpleLicensingText)
-
-#undef X_SPDX
diff --git a/Source/cmSarifLog.cxx b/Source/cmSarifLog.cxx
index e5953db..7294949 100644
--- a/Source/cmSarifLog.cxx
+++ b/Source/cmSarifLog.cxx
@@ -12,6 +12,7 @@
 
 #include "cmListFileCache.h"
 #include "cmMessageType.h"
+#include "cmState.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmValue.h"
@@ -371,7 +372,7 @@
     // normal mode, the project variable `CMAKE_EXPORT_SARIF` can also enable
     // SARIF logging.
     return cm.GetSarifFilePath().has_value() ||
-      (cm.GetWorkingMode() == cmake::NORMAL_MODE &&
+      (cm.GetState()->GetRole() == cmState::Role::Project &&
        cm.GetCacheDefinition(cmSarif::PROJECT_SARIF_FILE_VARIABLE).IsOn());
   });
 
diff --git a/Source/cmSarifLog.h b/Source/cmSarifLog.h
index d267d00..f7e065a 100644
--- a/Source/cmSarifLog.h
+++ b/Source/cmSarifLog.h
@@ -197,7 +197,7 @@
 
   // Mapping of rule IDs to rule indices in the log.
   // In SARIF, rule metadata is typically only included if the rule is
-  // referenced. The indices are unique to one log output and and vary
+  // referenced. The indices are unique to one log output and vary
   // depending on when the rule was first encountered.
   mutable std::unordered_map<std::string, std::size_t> RuleToIndex;
 
diff --git a/Source/cmSbomArguments.cxx b/Source/cmSbomArguments.cxx
new file mode 100644
index 0000000..76322ab
--- /dev/null
+++ b/Source/cmSbomArguments.cxx
@@ -0,0 +1,105 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#include "cmSbomArguments.h"
+
+#include <algorithm>
+
+#include <cm/string_view>
+
+#include "cmsys/String.h"
+
+#include "cmExecutionStatus.h"
+#include "cmGeneratorExpression.h"
+#include "cmStringAlgorithms.h"
+
+struct SbomFormatPattern
+{
+  cm::string_view Name;
+  cm::string_view Alias;
+  cmSbomArguments::SbomFormat Id;
+};
+
+static SbomFormatPattern SbomPatterns[] = {
+  { "spdx-3.0+json", "spdx", cmSbomArguments::SbomFormat::SPDX_3_0_JSON },
+};
+
+cmSbomArguments::SbomFormat ParseSbomFormat(std::string const& input)
+{
+  if (input.empty()) {
+    return cmSbomArguments::SbomFormat::SPDX_3_0_JSON;
+  }
+
+  cm::string_view s(input);
+  for (auto const& p : SbomPatterns) {
+    if (s == p.Name || (!p.Alias.empty() && s == p.Alias)) {
+      return p.Id;
+    }
+  }
+  return cmSbomArguments::SbomFormat::NONE;
+}
+
+std::string GetSbomFileExtension(cmSbomArguments::SbomFormat id)
+{
+  switch (id) {
+    case cmSbomArguments::SbomFormat::SPDX_3_0_JSON:
+      return ".spdx.json";
+    default:
+      return "";
+  }
+}
+
+template void cmSbomArguments::Bind<void>(cmArgumentParser<void>&,
+                                          cmSbomArguments*);
+
+bool cmSbomArguments::Check(cmExecutionStatus& status) const
+{
+  if (!this->PackageName.empty()) {
+    if (!cmGeneratorExpression::IsValidTargetName(this->PackageName) ||
+        this->PackageName.find(':') != std::string::npos) {
+      status.SetError(cmStrCat(R"(SBOM given invalid package name ")"_s,
+                               this->PackageName, R"(".)"_s));
+      return false;
+    }
+  }
+
+  if (!this->Format.empty()) {
+    if (this->GetFormat() == SbomFormat::NONE) {
+      status.SetError(
+        cmStrCat(R"(SBOM given invalid format ")"_s, this->Format, R"(".)"_s));
+      return false;
+    }
+  }
+  return true;
+}
+
+cm::string_view cmSbomArguments::CommandName() const
+{
+  return "SBOM"_s;
+}
+
+std::string cmSbomArguments::GetNamespace() const
+{
+  return cmStrCat(this->PackageName, "::"_s);
+}
+
+std::string cmSbomArguments::GetPackageDirName() const
+{
+  return this->PackageName;
+}
+
+cmSbomArguments::SbomFormat cmSbomArguments::GetFormat() const
+{
+  if (this->Format.empty()) {
+    return SbomFormat::SPDX_3_0_JSON;
+  }
+  return ParseSbomFormat(this->Format);
+}
+
+std::string cmSbomArguments::GetPackageFileName() const
+{
+  std::string const pkgNameOnDisk = this->GetPackageDirName();
+  std::string format = GetSbomFileExtension(this->GetFormat());
+  std::transform(format.begin(), format.end(), format.begin(),
+                 cmsysString_tolower);
+  return cmStrCat(pkgNameOnDisk, format);
+}
diff --git a/Source/cmSbomArguments.h b/Source/cmSbomArguments.h
new file mode 100644
index 0000000..50f0498
--- /dev/null
+++ b/Source/cmSbomArguments.h
@@ -0,0 +1,61 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+
+#include <cm/string_view>
+#include <cm/type_traits>
+#include <cmext/string_view>
+
+#include "cmArgumentParser.h" // IWYU pragma: keep
+#include "cmArgumentParserTypes.h"
+#include "cmProjectInfoArguments.h"
+
+class cmSbomArguments : public cmProjectInfoArguments
+{
+public:
+  enum class SbomFormat
+  {
+    SPDX_3_0_JSON,
+    NONE,
+  };
+
+  template <
+    typename T,
+    typename = cm::enable_if_t<std::is_base_of<cmSbomArguments, T>::value>>
+  static void Bind(cmArgumentParser<T>& parser)
+  {
+    cmSbomArguments* const self = nullptr;
+    cmSbomArguments::Bind(parser, self);
+  }
+  void Bind(cmArgumentParser<void>& parser) { Bind(parser, this); }
+
+  bool Check(cmExecutionStatus& status) const override;
+  std::string GetNamespace() const;
+  std::string GetPackageDirName() const;
+  std::string GetPackageFileName() const;
+  SbomFormat GetFormat() const;
+
+  ArgumentParser::NonEmpty<std::string> Format;
+
+protected:
+  cm::string_view CommandName() const override;
+
+private:
+  using cmProjectInfoArguments::Bind;
+
+  template <typename T>
+  static void Bind(cmArgumentParser<T>& parser, cmSbomArguments* self)
+  {
+    cmProjectInfoArguments* const base = self;
+    Bind(base, parser, "SBOM"_s, &cmProjectInfoArguments::PackageName);
+    Bind(self, parser, "FORMAT"_s, &cmSbomArguments::Format);
+    cmProjectInfoArguments::Bind(parser, self);
+  }
+};
+
+extern template void cmSbomArguments::Bind<void>(cmArgumentParser<void>&,
+                                                 cmSbomArguments*);
diff --git a/Source/cmSbomObject.h b/Source/cmSbomObject.h
new file mode 100644
index 0000000..3f42cfb
--- /dev/null
+++ b/Source/cmSbomObject.h
@@ -0,0 +1,270 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <cm/type_traits>
+
+#include "cmSbomSerializer.h"
+
+class cmSbomObject;
+
+template <typename T>
+inline void SerializeDispatch(T const& t, cmSbomSerializer& serializer)
+{
+  serializer.BeginObject();
+  t.Serialize(serializer);
+  serializer.EndObject();
+}
+
+template <typename T>
+inline void SerializeDispatch(T* p, cmSbomSerializer& serializer)
+{
+  if (p->SpdxId) {
+    serializer.AddReference(*p->SpdxId);
+  }
+}
+
+inline void SerializeDispatch(std::nullptr_t, cmSbomSerializer&)
+{
+}
+
+struct ObjectInterface
+{
+  virtual ObjectInterface* Copy(void* storage) const = 0;
+  virtual ObjectInterface* Move(void* storage) = 0;
+  virtual void* Addr() noexcept = 0;
+  virtual void const* Addr() const noexcept = 0;
+  virtual void SerializeImpl(cmSbomSerializer& os) const = 0;
+  virtual ~ObjectInterface() = default;
+
+  ObjectInterface() = default;
+  ObjectInterface(ObjectInterface const&) = default;
+  ObjectInterface& operator=(ObjectInterface const&) = default;
+  ObjectInterface(ObjectInterface&&) noexcept = default;
+  ObjectInterface& operator=(ObjectInterface&&) noexcept = default;
+};
+
+namespace impl {
+
+#if defined(__GLIBCXX__) && __GLIBCXX__ <= 20150623
+using max_align_t = ::max_align_t;
+#else
+using max_align_t = std::max_align_t;
+#endif
+
+enum class StorageKind
+{
+  Stack,
+  Heap
+};
+
+template <typename, StorageKind>
+struct Storage
+{
+};
+
+template <typename T>
+struct Storage<T, StorageKind::Stack> : ObjectInterface
+{
+  using ValueType = cm::decay_t<T>;
+
+  explicit Storage(T x)
+    : Value(std::move(x))
+  {
+  }
+
+  Storage(Storage&&) noexcept(
+    std::is_nothrow_move_constructible<ValueType>::value) = default;
+  ~Storage() override = default;
+
+  void* Addr() noexcept override { return std::addressof(Value); }
+  void const* Addr() const noexcept override { return std::addressof(Value); }
+
+  ValueType& get() { return Value; }
+  ValueType const& get() const { return Value; }
+
+private:
+  ValueType Value;
+};
+
+template <typename T>
+struct Storage<T, StorageKind::Heap> : ObjectInterface
+{
+  using ValueType = cm::decay_t<T>;
+
+  explicit Storage(T x)
+    : Ptr(new T(std::move(x)))
+  {
+  }
+
+  Storage(Storage&&) noexcept = default;
+  ~Storage() override = default;
+
+  void* Addr() noexcept override { return Ptr.get(); }
+  void const* Addr() const noexcept override { return Ptr.get(); }
+
+  ValueType& get() { return *Ptr; }
+  ValueType const& get() const { return *Ptr; }
+
+private:
+  std::unique_ptr<ValueType> Ptr;
+};
+
+template <>
+struct Storage<std::nullptr_t, StorageKind::Stack> : ObjectInterface
+{
+  explicit Storage(std::nullptr_t) {}
+
+  Storage(Storage&&) noexcept = default;
+  ~Storage() override = default;
+
+  void* Addr() noexcept override { return nullptr; }
+  void const* Addr() const noexcept override { return nullptr; }
+
+  void SerializeImpl(cmSbomSerializer&) const override {}
+
+  std::nullptr_t get() { return nullptr; }
+  std::nullptr_t get() const { return nullptr; }
+};
+
+}
+
+struct ObjectStorage
+{
+  template <typename T>
+  using Stack = impl::Storage<T, impl::StorageKind::Stack>;
+  template <typename T>
+  using Heap = impl::Storage<T, impl::StorageKind::Heap>;
+
+  static constexpr std::size_t BufferSize = 128u;
+
+  static constexpr std::size_t Size = sizeof(Heap<std::nullptr_t>) > BufferSize
+    ? sizeof(Heap<std::nullptr_t>)
+    : BufferSize;
+  static constexpr std::size_t Align = alignof(impl::max_align_t);
+
+  struct Buffer
+  {
+    alignas(Align) unsigned char Data[Size];
+  };
+
+  template <typename Concrete>
+  using Model = cm::conditional_t<sizeof(Stack<Concrete>) <= Size &&
+                                    alignof(Stack<Concrete>) <= Align,
+                                  Stack<Concrete>, Heap<Concrete>>;
+};
+
+class cmSbomObject
+{
+public:
+  template <typename T>
+  struct Instance : ObjectStorage::Model<T>
+  {
+    using Base = ObjectStorage::Model<T>;
+    using Base::Base;
+    Instance(Instance&&) noexcept = default;
+
+    ObjectInterface* Copy(void* storage) const override
+    {
+      return ::new (storage) Instance(this->get());
+    }
+
+    ObjectInterface* Move(void* storage) override
+    {
+      return ::new (storage) Instance(std::move(*this));
+    }
+
+    void SerializeImpl(cmSbomSerializer& os) const override
+    {
+      SerializeDispatch(this->get(), os);
+    }
+  };
+
+  cmSbomObject() { ::new (Storage()) Instance<std::nullptr_t>(nullptr); }
+  cmSbomObject(std::nullptr_t)
+    : cmSbomObject()
+  {
+  }
+
+  template <
+    typename T, typename Decayed = cm::remove_cv_t<cm::remove_reference_t<T>>,
+    typename = cm::enable_if_t<!std::is_same<Decayed, cmSbomObject>::value>>
+  cmSbomObject(T&& x)
+  {
+    ::new (Storage()) Instance<Decayed>(std::forward<T>(x));
+  }
+
+  cmSbomObject(cmSbomObject const& other)
+  {
+    other.Interface().Copy(Storage());
+  }
+  cmSbomObject(cmSbomObject&& other) noexcept
+  {
+    other.Interface().Move(Storage());
+  }
+
+  ~cmSbomObject() noexcept { Interface().~ObjectInterface(); }
+
+  cmSbomObject& operator=(cmSbomObject rhs)
+  {
+    Interface().~ObjectInterface();
+    rhs.Interface().Move(Storage());
+    return *this;
+  }
+
+  bool IsNull() const noexcept { return Interface().Addr() == nullptr; }
+  explicit operator bool() const noexcept { return !IsNull(); }
+
+  void Serialize(cmSbomSerializer& os) const { Interface().SerializeImpl(os); }
+
+  template <typename T>
+  T& CastUnchecked()
+  {
+    return *static_cast<T*>(Interface().Addr());
+  }
+
+  template <typename T>
+  T const& CastUnchecked() const
+  {
+    return *static_cast<T const*>(Interface().Addr());
+  }
+
+  ObjectInterface& Interface()
+  {
+    return *static_cast<ObjectInterface*>(Storage());
+  }
+  ObjectInterface const& Interface() const
+  {
+    return *static_cast<ObjectInterface const*>(Storage());
+  }
+
+  void* Storage() { return &Data.Data; }
+  void const* Storage() const { return &Data.Data; }
+
+  template <typename U>
+  U* ptr() noexcept
+  {
+    return std::addressof(this->template CastUnchecked<U>());
+  }
+
+  template <typename U>
+  U const* ptr() const noexcept
+  {
+    return std::addressof(this->template CastUnchecked<U>());
+  }
+
+private:
+  ObjectStorage::Buffer Data{};
+};
+
+template <typename T, typename U = cm::decay_t<T>>
+U* insert_back(std::vector<cmSbomObject>& vec, T&& obj) noexcept
+{
+  vec.emplace_back(std::forward<U>(obj));
+  return std::addressof(vec.back().CastUnchecked<U>());
+}
diff --git a/Source/cmSbomSerializer.h b/Source/cmSbomSerializer.h
new file mode 100644
index 0000000..019a1c7
--- /dev/null
+++ b/Source/cmSbomSerializer.h
@@ -0,0 +1,38 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+
+class cmSbomObject;
+class cmSbomSerializer
+{
+public:
+  cmSbomSerializer() = default;
+  cmSbomSerializer(cmSbomSerializer const&) = default;
+  cmSbomSerializer(cmSbomSerializer&&) = default;
+  cmSbomSerializer& operator=(cmSbomSerializer const&) = default;
+  cmSbomSerializer& operator=(cmSbomSerializer&&) = default;
+
+  virtual void BeginObject() {}
+  virtual void EndObject() {}
+  virtual void BeginArray() {}
+  virtual void EndArray() {}
+
+  virtual void AddReference(std::string const& id) = 0;
+
+  virtual void AddString(std::string const& key, std::string const& value) = 0;
+  virtual void AddVisitable(std::string const& key,
+                            cmSbomObject const& visitable) = 0;
+
+  virtual void AddVectorIfPresent(std::string const& key,
+                                  std::vector<cmSbomObject> const& vec) = 0;
+  virtual void AddVectorIfPresent(std::string const& key,
+                                  std::vector<std::string> const& vec) = 0;
+
+  virtual bool WriteSbom(std::ostream& os, cmSbomObject const& document) = 0;
+  virtual ~cmSbomSerializer() = default;
+};
diff --git a/Source/cmScanDepFormat.cxx b/Source/cmScanDepFormat.cxx
index bd38273..0016544 100644
--- a/Source/cmScanDepFormat.cxx
+++ b/Source/cmScanDepFormat.cxx
@@ -3,7 +3,6 @@
 
 #include "cmScanDepFormat.h"
 
-#include <cctype>
 #include <cstdio>
 #include <utility>
 
@@ -16,6 +15,7 @@
 #include <cm3p/json/writer.h>
 
 #include "cmsys/FStream.hxx"
+#include "cmsys/String.h"
 
 #include "cmGeneratedFileStream.h"
 #include "cmStringAlgorithms.h"
@@ -38,7 +38,7 @@
   data.reserve(path.size());
 
   for (auto const& byte : path) {
-    if (std::iscntrl(byte)) {
+    if (cmsysString_iscntrl(byte)) {
       // Control characters.
       data.append("\\u");
       char buf[5];
diff --git a/Source/cmSetCommand.cxx b/Source/cmSetCommand.cxx
index 6a346972..be9825c 100644
--- a/Source/cmSetCommand.cxx
+++ b/Source/cmSetCommand.cxx
@@ -81,7 +81,7 @@
 
   // watch for CACHE{} signature
   if (cmHasLiteralPrefix(variable, "CACHE{") && variable.size() > 7 &&
-      cmHasLiteralSuffix(variable, "}")) {
+      cmHasSuffix(variable, '}')) {
     // what is the variable name
     auto const& varName = variable.substr(6, variable.size() - 7);
     // VALUE handling
@@ -98,8 +98,8 @@
       {
         if (!cmState::StringToCacheEntryType(std::string{ type },
                                              this->Type)) {
-          this->AddKeywordError("TYPE"_s,
-                                cmStrCat("Invalid value: ", type, '.'));
+          this->AddKeywordError(
+            "TYPE"_s, cmStrCat("  invalid value: \""_s, type, "\"\n"_s));
         }
         return ArgumentParser::Continue::No;
       }
diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx
index 0ef8081..676a796 100644
--- a/Source/cmSetPropertyCommand.cxx
+++ b/Source/cmSetPropertyCommand.cxx
@@ -10,6 +10,7 @@
 #include <cm/string_view>
 
 #include "cmExecutionStatus.h"
+#include "cmFileSet.h"
 #include "cmGlobalGenerator.h"
 #include "cmInstalledFile.h"
 #include "cmListFileCache.h"
@@ -48,6 +49,14 @@
                   std::string const& propertyName,
                   std::string const& propertyValue, bool appendAsString,
                   bool appendMode, bool remove);
+bool HandleFileSetMode(cmExecutionStatus& status,
+                       std::set<std::string> const& names,
+                       std::string const& propertyName,
+                       std::string const& propertyValue, bool appendAsString,
+                       bool appendMode, bool remove, cmTarget* target);
+bool HandleFileSet(cmFileSet* fileSet, std::string const& propertyName,
+                   std::string const& propertyValue, bool appendAsString,
+                   bool appendMode, bool remove);
 bool HandleSourceMode(cmExecutionStatus& status,
                       std::set<std::string> const& names,
                       std::string const& propertyName,
@@ -87,6 +96,54 @@
 }
 
 namespace SetPropertyCommand {
+bool HandleFileSetTargetScopes(cmExecutionStatus& status,
+                               std::string& file_set_target_name,
+                               cmTarget*& file_set_target)
+{
+  file_set_target = status.GetMakefile().FindTargetToUse(file_set_target_name);
+  if (!file_set_target) {
+    status.SetError(
+      cmStrCat("given non-existent TARGET ", file_set_target_name));
+    return false;
+  }
+  return true;
+}
+
+bool HandleFileSetTargetScopeValidation(cmExecutionStatus& status,
+                                        bool file_set_target_option_enabled,
+                                        std::string& file_set_target_name)
+{
+  if (!file_set_target_option_enabled) {
+    status.SetError("required TARGET option is missing");
+    return false;
+  }
+
+  // Validate file set target scopes.
+  if (file_set_target_name.empty()) {
+    status.SetError("called with incorrect number of arguments "
+                    "no value provided to the TARGET option");
+    return false;
+  }
+  return true;
+}
+
+bool HandleAndValidateFileSetTargetScopes(cmExecutionStatus& status,
+                                          bool file_set_target_option_enabled,
+                                          std::string& file_set_target_name,
+                                          cmTarget*& file_set_target)
+{
+  bool scope_options_valid =
+    SetPropertyCommand::HandleFileSetTargetScopeValidation(
+      status, file_set_target_option_enabled, file_set_target_name);
+  if (!scope_options_valid) {
+    return false;
+  }
+
+  scope_options_valid = SetPropertyCommand::HandleFileSetTargetScopes(
+    status, file_set_target_name, file_set_target);
+  return scope_options_valid;
+}
+
 bool HandleSourceFileDirectoryScopes(
   cmExecutionStatus& status, std::vector<std::string>& source_file_directories,
   std::vector<std::string>& source_file_target_directories,
@@ -402,6 +459,8 @@
     scope = cmProperty::DIRECTORY;
   } else if (scopeName == "TARGET") {
     scope = cmProperty::TARGET;
+  } else if (scopeName == "FILE_SET") {
+    scope = cmProperty::FILE_SET;
   } else if (scopeName == "SOURCE") {
     scope = cmProperty::SOURCE_FILE;
   } else if (scopeName == "TEST") {
@@ -412,9 +471,8 @@
     scope = cmProperty::INSTALL;
   } else {
     status.SetError(cmStrCat("given invalid scope ", scopeName,
-                             ".  "
-                             "Valid scopes are GLOBAL, DIRECTORY, "
-                             "TARGET, SOURCE, TEST, CACHE, INSTALL."));
+                             ".  Valid scopes are GLOBAL, DIRECTORY, TARGET, "
+                             "FILE_SET, SOURCE, TEST, CACHE, INSTALL."));
     return false;
   }
 
@@ -425,6 +483,9 @@
   std::string propertyName;
   std::string propertyValue;
 
+  std::string file_set_target_name;
+  bool file_set_target_option_enabled = false;
+
   std::vector<std::string> source_file_directories;
   std::vector<std::string> source_file_target_directories;
   bool source_file_directory_option_enabled = false;
@@ -440,6 +501,7 @@
     DoingNames,
     DoingProperty,
     DoingValues,
+    DoingFileSetTarget,
     DoingSourceDirectory,
     DoingSourceTargetDirectory,
     DoingTestDirectory,
@@ -460,6 +522,10 @@
       remove = false;
       appendAsString = true;
     } else if (doing != DoingProperty && doing != DoingValues &&
+               scope == cmProperty::FILE_SET && arg == "TARGET") {
+      doing = DoingFileSetTarget;
+      file_set_target_option_enabled = true;
+    } else if (doing != DoingProperty && doing != DoingValues &&
                scope == cmProperty::SOURCE_FILE && arg == "DIRECTORY") {
       doing = DoingSourceDirectory;
       source_file_directory_option_enabled = true;
@@ -473,6 +539,10 @@
       test_directory_option_enabled = true;
     } else if (doing == DoingNames) {
       names.insert(arg);
+    } else if (doing == DoingFileSetTarget) {
+      file_set_target_name = arg;
+      file_set_target_option_enabled = true;
+      doing = DoingNone;
     } else if (doing == DoingSourceDirectory) {
       source_file_directories.push_back(arg);
     } else if (doing == DoingSourceTargetDirectory) {
@@ -500,23 +570,6 @@
     return false;
   }
 
-  std::vector<cmMakefile*> source_file_directory_makefiles;
-  bool source_file_scopes_handled =
-    SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes(
-      status, source_file_directory_option_enabled,
-      source_file_target_option_enabled, source_file_directories,
-      source_file_target_directories, source_file_directory_makefiles);
-  cmMakefile* test_directory_makefile;
-  bool test_scopes_handled =
-    SetPropertyCommand::HandleAndValidateTestDirectoryScopes(
-      status, test_directory_option_enabled, test_directory,
-      test_directory_makefile);
-  if (!(source_file_scopes_handled && test_scopes_handled)) {
-    return false;
-  }
-  bool source_file_paths_should_be_absolute =
-    source_file_directory_option_enabled || source_file_target_option_enabled;
-
   // Dispatch property setting.
   switch (scope) {
     case cmProperty::GLOBAL:
@@ -528,15 +581,44 @@
     case cmProperty::TARGET:
       return HandleTargetMode(status, names, propertyName, propertyValue,
                               appendAsString, appendMode, remove);
-    case cmProperty::SOURCE_FILE:
+    case cmProperty::FILE_SET: {
+      cmTarget* file_set_target;
+      if (!SetPropertyCommand::HandleAndValidateFileSetTargetScopes(
+            status, file_set_target_option_enabled, file_set_target_name,
+            file_set_target)) {
+        return false;
+      }
+      return HandleFileSetMode(status, names, propertyName, propertyValue,
+                               appendAsString, appendMode, remove,
+                               file_set_target);
+    }
+    case cmProperty::SOURCE_FILE: {
+      std::vector<cmMakefile*> source_file_directory_makefiles;
+      if (!SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes(
+            status, source_file_directory_option_enabled,
+            source_file_target_option_enabled, source_file_directories,
+            source_file_target_directories, source_file_directory_makefiles)) {
+        return false;
+      }
+      bool source_file_paths_should_be_absolute =
+        source_file_directory_option_enabled ||
+        source_file_target_option_enabled;
       return HandleSourceMode(status, names, propertyName, propertyValue,
                               appendAsString, appendMode, remove,
                               source_file_directory_makefiles,
                               source_file_paths_should_be_absolute);
-    case cmProperty::TEST:
+    }
+    case cmProperty::TEST: {
+      cmMakefile* test_directory_makefile;
+      if (!SetPropertyCommand::HandleAndValidateTestDirectoryScopes(
+            status, test_directory_option_enabled, test_directory,
+            test_directory_makefile)) {
+        return false;
+      }
       return HandleTestMode(status, names, propertyName, propertyValue,
                             appendAsString, appendMode, remove,
                             test_directory_makefile);
+    }
     case cmProperty::CACHE:
       return HandleCacheMode(status, names, propertyName, propertyValue,
                              appendAsString, appendMode, remove);
@@ -679,6 +761,46 @@
   return true;
 }
 
+bool HandleFileSetMode(cmExecutionStatus& status,
+                       std::set<std::string> const& names,
+                       std::string const& propertyName,
+                       std::string const& propertyValue, bool appendAsString,
+                       bool appendMode, bool remove, cmTarget* target)
+{
+  for (std::string const& name : names) {
+    if (cmFileSet* fileSet = target->GetFileSet(name)) {
+      // Handle the current file set.
+      if (!HandleFileSet(fileSet, propertyName, propertyValue, appendAsString,
+                         appendMode, remove)) {
+        return false;
+      }
+    } else {
+      status.SetError(cmStrCat("could not find FILE_SET ", name,
+                               " for TARGET ", target->GetName(),
+                               ".  Perhaps it has not yet been created."));
+      return false;
+    }
+  }
+  return true;
+}
+
+bool HandleFileSet(cmFileSet* fileSet, std::string const& propertyName,
+                   std::string const& propertyValue, bool appendAsString,
+                   bool appendMode, bool remove)
+{
+  // Set or append the property.
+  if (appendMode) {
+    fileSet->AppendProperty(propertyName, propertyValue, appendAsString);
+  } else {
+    if (remove) {
+      fileSet->SetProperty(propertyName, nullptr);
+    } else {
+      fileSet->SetProperty(propertyName, propertyValue);
+    }
+  }
+  return true;
+}
+
 bool HandleSourceMode(cmExecutionStatus& status,
                       std::set<std::string> const& names,
                       std::string const& propertyName,
diff --git a/Source/cmSetPropertyCommand.h b/Source/cmSetPropertyCommand.h
index 8291257..57ba41a 100644
--- a/Source/cmSetPropertyCommand.h
+++ b/Source/cmSetPropertyCommand.h
@@ -10,11 +10,25 @@
 class cmMakefile;
 class cmExecutionStatus;
 class cmSourceFile;
+class cmTarget;
 
 bool cmSetPropertyCommand(std::vector<std::string> const& args,
                           cmExecutionStatus& status);
 
 namespace SetPropertyCommand {
+bool HandleFileSetTargetScopes(cmExecutionStatus& status,
+                               std::string& file_set_target_name,
+                               cmTarget*& file_set_target);
+
+bool HandleFileSetTargetScopeValidation(cmExecutionStatus& status,
+                                        bool file_set_target_option_enabled,
+                                        std::string& file_set_target_name);
+
+bool HandleAndValidateFileSetTargetScopes(cmExecutionStatus& status,
+                                          bool file_set_target_option_enabled,
+                                          std::string& file_set_target_name,
+                                          cmTarget*& file_set_target);
+
 bool HandleSourceFileDirectoryScopes(
   cmExecutionStatus& status, std::vector<std::string>& source_file_directories,
   std::vector<std::string>& source_file_target_directories,
diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx
index 430f9c5..5f2cf3b 100644
--- a/Source/cmSourceFile.cxx
+++ b/Source/cmSourceFile.cxx
@@ -91,8 +91,8 @@
       this->ResolveFullPath();
     } else {
       // Use the known extension to get the language if possible.
-      std::string ext =
-        cmSystemTools::GetFilenameLastExtension(this->Location.GetName());
+      cm::string_view ext =
+        cmSystemTools::GetFilenameLastExtensionView(this->Location.GetName());
       this->CheckLanguage(ext);
     }
   }
@@ -263,11 +263,11 @@
 void cmSourceFile::CheckExtension()
 {
   // Compute the extension.
-  std::string realExt =
-    cmSystemTools::GetFilenameLastExtension(this->FullPath);
+  cm::string_view realExt =
+    cmSystemTools::GetFilenameLastExtensionView(this->FullPath);
   if (!realExt.empty()) {
     // Store the extension without the leading '.'.
-    this->Extension = realExt.substr(1);
+    this->Extension = std::string(realExt.substr(1));
   }
 
   // Look for object files.
@@ -282,14 +282,14 @@
   }
 }
 
-void cmSourceFile::CheckLanguage(std::string const& ext)
+void cmSourceFile::CheckLanguage(cm::string_view ext)
 {
   // Try to identify the source file language from the extension.
   cmMakefile const* mf = this->Location.GetMakefile();
   cmGlobalGenerator* gg = mf->GetGlobalGenerator();
-  std::string l = gg->GetLanguageFromExtension(ext.c_str());
+  cm::string_view l = gg->GetLanguageFromExtension(ext);
   if (!l.empty()) {
-    this->Language = l;
+    this->Language = std::string(l);
   }
 }
 
diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h
index fcd5fd6..d951793 100644
--- a/Source/cmSourceFile.h
+++ b/Source/cmSourceFile.h
@@ -8,6 +8,8 @@
 #include <string>
 #include <vector>
 
+#include <cm/string_view>
+
 #include "cmCustomCommand.h"
 #include "cmListFileCache.h"
 #include "cmPropertyMap.h"
@@ -200,7 +202,7 @@
 
   bool FindFullPath(std::string* error, std::string* cmp0115Warning);
   void CheckExtension();
-  void CheckLanguage(std::string const& ext);
+  void CheckLanguage(cm::string_view ext);
 
   static std::string const propLANGUAGE;
   static std::string const propLOCATION;
diff --git a/Source/cmSourceFileLocation.cxx b/Source/cmSourceFileLocation.cxx
index fd2fd37..f1d2106 100644
--- a/Source/cmSourceFileLocation.cxx
+++ b/Source/cmSourceFileLocation.cxx
@@ -103,7 +103,7 @@
 {
   assert(this->Makefile);
   // Check the extension.
-  std::string ext = cmSystemTools::GetFilenameLastExtension(name);
+  cm::string_view ext = cmSystemTools::GetFilenameLastExtensionView(name);
   if (!ext.empty()) {
     ext = ext.substr(1);
   }
@@ -112,7 +112,7 @@
   cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
   cmMakefile const* mf = this->Makefile;
   auto* cm = mf->GetCMakeInstance();
-  if (!gg->GetLanguageFromExtension(ext.c_str()).empty() ||
+  if (!gg->GetLanguageFromExtension(ext).empty() ||
       cm->IsAKnownExtension(ext)) {
     // This is a known extension.  Use the given filename with extension.
     this->Name = cmSystemTools::GetFilenameName(name);
diff --git a/Source/cmSourceGroup.cxx b/Source/cmSourceGroup.cxx
index 4a7f8e2..7251810 100644
--- a/Source/cmSourceGroup.cxx
+++ b/Source/cmSourceGroup.cxx
@@ -6,12 +6,14 @@
 
 #include <cm/memory>
 
+#include "cmGeneratorExpression.h"
+#include "cmSourceFile.h"
 #include "cmStringAlgorithms.h"
 
 class cmSourceGroupInternals
 {
 public:
-  std::vector<cmSourceGroup> GroupChildren;
+  SourceGroupVector GroupChildren;
 };
 
 cmSourceGroup::cmSourceGroup(std::string name, char const* regex,
@@ -28,28 +30,6 @@
 
 cmSourceGroup::~cmSourceGroup() = default;
 
-cmSourceGroup::cmSourceGroup(cmSourceGroup const& r)
-{
-  this->Name = r.Name;
-  this->FullName = r.FullName;
-  this->GroupRegex = r.GroupRegex;
-  this->GroupFiles = r.GroupFiles;
-  this->SourceFiles = r.SourceFiles;
-  this->Internal = cm::make_unique<cmSourceGroupInternals>(*r.Internal);
-}
-
-cmSourceGroup& cmSourceGroup::operator=(cmSourceGroup const& r)
-{
-  if (this != &r) {
-    this->Name = r.Name;
-    this->GroupRegex = r.GroupRegex;
-    this->GroupFiles = r.GroupFiles;
-    this->SourceFiles = r.SourceFiles;
-    *(this->Internal) = *(r.Internal);
-  }
-  return *this;
-}
-
 void cmSourceGroup::SetGroupRegex(char const* regex)
 {
   if (regex) {
@@ -59,6 +39,26 @@
   }
 }
 
+void cmSourceGroup::ResolveGenex(cmLocalGenerator* lg,
+                                 std::string const& config)
+{
+  std::set<std::string> files;
+
+  for (std::string const& file : this->GroupFiles) {
+    files.emplace(cmGeneratorExpression::Evaluate(file, lg, config));
+  }
+
+  this->GroupFiles = std::move(files);
+
+  if (!this->Internal) {
+    return;
+  }
+
+  for (auto const& group : this->Internal->GroupChildren) {
+    group->ResolveGenex(lg, config);
+  }
+}
+
 void cmSourceGroup::AddGroupFile(std::string const& name)
 {
   this->GroupFiles.insert(name);
@@ -74,9 +74,10 @@
   return this->FullName;
 }
 
-bool cmSourceGroup::MatchesRegex(std::string const& name)
+bool cmSourceGroup::MatchesRegex(std::string const& name) const
 {
-  return this->GroupRegex.find(name);
+  cmsys::RegularExpressionMatch match;
+  return this->GroupRegex.find(name.c_str(), match);
 }
 
 bool cmSourceGroup::MatchesFiles(std::string const& name) const
@@ -89,22 +90,27 @@
   this->SourceFiles.push_back(sf);
 }
 
+std::set<std::string> const& cmSourceGroup::GetGroupFiles() const
+{
+  return this->GroupFiles;
+}
+
 std::vector<cmSourceFile const*> const& cmSourceGroup::GetSourceFiles() const
 {
   return this->SourceFiles;
 }
 
-void cmSourceGroup::AddChild(cmSourceGroup const& child)
+void cmSourceGroup::AddChild(std::unique_ptr<cmSourceGroup> child)
 {
-  this->Internal->GroupChildren.push_back(child);
+  this->Internal->GroupChildren.push_back(std::move(child));
 }
 
-cmSourceGroup* cmSourceGroup::LookupChild(std::string const& name)
+cmSourceGroup* cmSourceGroup::LookupChild(std::string const& name) const
 {
-  for (cmSourceGroup& group : this->Internal->GroupChildren) {
-    // look if descenened is the one were looking for
-    if (group.GetName() == name) {
-      return (&group); // if it so return it
+  for (auto& group : this->Internal->GroupChildren) {
+    // look if descendant is the one we're looking for
+    if (group->GetName() == name) {
+      return group.get(); // if so return it
     }
   }
 
@@ -117,8 +123,8 @@
   if (this->MatchesFiles(name)) {
     return this;
   }
-  for (cmSourceGroup& group : this->Internal->GroupChildren) {
-    cmSourceGroup* result = group.MatchChildrenFiles(name);
+  for (auto& group : this->Internal->GroupChildren) {
+    cmSourceGroup* result = group->MatchChildrenFiles(name);
     if (result) {
       return result;
     }
@@ -132,8 +138,8 @@
   if (this->MatchesFiles(name)) {
     return this;
   }
-  for (cmSourceGroup const& group : this->Internal->GroupChildren) {
-    cmSourceGroup const* result = group.MatchChildrenFiles(name);
+  for (auto const& group : this->Internal->GroupChildren) {
+    cmSourceGroup const* result = group->MatchChildrenFiles(name);
     if (result) {
       return result;
     }
@@ -141,22 +147,52 @@
   return nullptr;
 }
 
-cmSourceGroup* cmSourceGroup::MatchChildrenRegex(std::string const& name)
+cmSourceGroup* cmSourceGroup::MatchChildrenRegex(std::string const& name) const
 {
-  for (cmSourceGroup& group : this->Internal->GroupChildren) {
-    cmSourceGroup* result = group.MatchChildrenRegex(name);
+  for (auto& group : this->Internal->GroupChildren) {
+    cmSourceGroup* result = group->MatchChildrenRegex(name);
     if (result) {
       return result;
     }
   }
   if (this->MatchesRegex(name)) {
-    return this;
+    return const_cast<cmSourceGroup*>(this);
   }
 
   return nullptr;
 }
 
-std::vector<cmSourceGroup> const& cmSourceGroup::GetGroupChildren() const
+SourceGroupVector const& cmSourceGroup::GetGroupChildren() const
 {
   return this->Internal->GroupChildren;
 }
+
+/**
+ * Find a source group whose regular expression matches the filename
+ * part of the given source name.  Search backward through the list of
+ * source groups, and take the first matching group found.  This way
+ * non-inherited SOURCE_GROUP commands will have precedence over
+ * inherited ones.
+ */
+cmSourceGroup* cmSourceGroup::FindSourceGroup(std::string const& source,
+                                              SourceGroupVector const& groups)
+{
+  // First search for a group that lists the file explicitly.
+  for (auto sg = groups.rbegin(); sg != groups.rend(); ++sg) {
+    cmSourceGroup* result = (*sg)->MatchChildrenFiles(source);
+    if (result) {
+      return result;
+    }
+  }
+
+  // Now search for a group whose regex matches the file.
+  for (auto sg = groups.rbegin(); sg != groups.rend(); ++sg) {
+    cmSourceGroup* result = (*sg)->MatchChildrenRegex(source);
+    if (result) {
+      return result;
+    }
+  }
+
+  // Shouldn't get here, but just in case, return the default group.
+  return groups.data()->get();
+}
diff --git a/Source/cmSourceGroup.h b/Source/cmSourceGroup.h
index 20f052d..4ce79ed 100644
--- a/Source/cmSourceGroup.h
+++ b/Source/cmSourceGroup.h
@@ -11,9 +11,13 @@
 
 #include "cmsys/RegularExpression.hxx"
 
+class cmLocalGenerator;
 class cmSourceFile;
+class cmSourceGroup;
 class cmSourceGroupInternals;
 
+using SourceGroupVector = std::vector<std::unique_ptr<cmSourceGroup>>;
+
 /** \class cmSourceGroup
  * \brief Hold a group of sources as specified by a SOURCE_GROUP command.
  *
@@ -29,9 +33,9 @@
 public:
   cmSourceGroup(std::string name, char const* regex,
                 char const* parentName = nullptr);
-  cmSourceGroup(cmSourceGroup const& r);
+  cmSourceGroup(cmSourceGroup const& r) = delete;
   ~cmSourceGroup();
-  cmSourceGroup& operator=(cmSourceGroup const&);
+  cmSourceGroup& operator=(cmSourceGroup const&) = delete;
 
   /**
    * Set the regular expression for this group.
@@ -39,6 +43,11 @@
   void SetGroupRegex(char const* regex);
 
   /**
+   * Resolve genex.
+   */
+  void ResolveGenex(cmLocalGenerator* lg, std::string const& config);
+
+  /**
    * Add a file name to the explicit list of files for this group.
    */
   void AddGroupFile(std::string const& name);
@@ -46,12 +55,12 @@
   /**
    * Add child to this sourcegroup
    */
-  void AddChild(cmSourceGroup const& child);
+  void AddChild(std::unique_ptr<cmSourceGroup> child);
 
   /**
    * Looks up child and returns it
    */
-  cmSourceGroup* LookupChild(std::string const& name);
+  cmSourceGroup* LookupChild(std::string const& name) const;
 
   /**
    * Get the name of this group.
@@ -66,7 +75,7 @@
   /**
    * Check if the given name matches this group's regex.
    */
-  bool MatchesRegex(std::string const& name);
+  bool MatchesRegex(std::string const& name) const;
 
   /**
    * Check if the given name matches this group's explicit file list.
@@ -88,7 +97,7 @@
   /**
    * Check if the given name matches this group's regex in children.
    */
-  cmSourceGroup* MatchChildrenRegex(std::string const& name);
+  cmSourceGroup* MatchChildrenRegex(std::string const& name) const;
 
   /**
    * Assign the given source file to this group.  Used only by
@@ -97,12 +106,23 @@
   void AssignSource(cmSourceFile const* sf);
 
   /**
+   * Get the set of file names explicitly added to this source group.
+   */
+  std::set<std::string> const& GetGroupFiles() const;
+
+  /**
    * Get the list of the source files that have been assigned to this
    * source group.
    */
   std::vector<cmSourceFile const*> const& GetSourceFiles() const;
 
-  std::vector<cmSourceGroup> const& GetGroupChildren() const;
+  SourceGroupVector const& GetGroupChildren() const;
+
+  /**
+   * Given a source group collection, find the source group for a given source.
+   */
+  static cmSourceGroup* FindSourceGroup(std::string const& source,
+                                        SourceGroupVector const& groups);
 
 private:
   /**
diff --git a/Source/cmSpdx.cxx b/Source/cmSpdx.cxx
new file mode 100644
index 0000000..870eec4
--- /dev/null
+++ b/Source/cmSpdx.cxx
@@ -0,0 +1,522 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#include "cmSpdx.h"
+
+#include <stdexcept>
+#include <string>
+
+#include "cmSbomSerializer.h"
+
+inline void SerializeIfPresent(cmSbomSerializer& s, std::string const& key,
+                               cm::optional<std::string> const& v)
+{
+  if (v) {
+    s.AddString(key, *v);
+  }
+}
+
+std::string to_string(cmSpdxIntegrityMethod::HashAlgorithmId id)
+{
+  switch (id) {
+    case cmSpdxIntegrityMethod::HashAlgorithmId::ADLER32:
+      return "ADLER32";
+    case cmSpdxIntegrityMethod::HashAlgorithmId::BLAKE2B256:
+      return "BLAKE2B256";
+    case cmSpdxIntegrityMethod::HashAlgorithmId::BLAKE2B384:
+      return "BLAKE2B384";
+    case cmSpdxIntegrityMethod::HashAlgorithmId::BLAKE2B512:
+      return "BLAKE2B512";
+    case cmSpdxIntegrityMethod::HashAlgorithmId::BLAKE3:
+      return "BLAKE3";
+    case cmSpdxIntegrityMethod::HashAlgorithmId::MD2:
+      return "MD2";
+    case cmSpdxIntegrityMethod::HashAlgorithmId::MD4:
+      return "MD4";
+    case cmSpdxIntegrityMethod::HashAlgorithmId::MD5:
+      return "MD5";
+    case cmSpdxIntegrityMethod::HashAlgorithmId::MD6:
+      return "MD6";
+    case cmSpdxIntegrityMethod::HashAlgorithmId::SHA1:
+      return "SHA1";
+    case cmSpdxIntegrityMethod::HashAlgorithmId::SHA224:
+      return "SHA224";
+    case cmSpdxIntegrityMethod::HashAlgorithmId::SHA256:
+      return "SHA256";
+    case cmSpdxIntegrityMethod::HashAlgorithmId::SHA384:
+      return "SHA384";
+    case cmSpdxIntegrityMethod::HashAlgorithmId::SHA512:
+      return "SHA512";
+    case cmSpdxIntegrityMethod::HashAlgorithmId::SHA3_256:
+      return "SHA3_256";
+    case cmSpdxIntegrityMethod::HashAlgorithmId::SHA3_384:
+      return "SHA3_384";
+    case cmSpdxIntegrityMethod::HashAlgorithmId::SHA3_512:
+      return "SHA3_512";
+  }
+  throw std::invalid_argument("Unknown HashAlgorithmId");
+}
+
+std::string to_string(cmSpdxSoftwareArtifact::PurposeId id)
+{
+  switch (id) {
+    case cmSpdxSoftwareArtifact::PurposeId::APPLICATION:
+      return "application";
+    case cmSpdxSoftwareArtifact::PurposeId::ARCHIVE:
+      return "archive";
+    case cmSpdxSoftwareArtifact::PurposeId::CONTAINER:
+      return "container";
+    case cmSpdxSoftwareArtifact::PurposeId::DATA:
+      return "data";
+    case cmSpdxSoftwareArtifact::PurposeId::DEVICE:
+      return "device";
+    case cmSpdxSoftwareArtifact::PurposeId::FIRMWARE:
+      return "firmware";
+    case cmSpdxSoftwareArtifact::PurposeId::FILE:
+      return "file";
+    case cmSpdxSoftwareArtifact::PurposeId::INSTALL:
+      return "install";
+    case cmSpdxSoftwareArtifact::PurposeId::LIBRARY:
+      return "library";
+    case cmSpdxSoftwareArtifact::PurposeId::MODULE:
+      return "module";
+    case cmSpdxSoftwareArtifact::PurposeId::OPERATING_SYSTEM:
+      return "operatingSystem";
+    case cmSpdxSoftwareArtifact::PurposeId::SOURCE:
+      return "source";
+  }
+  throw std::invalid_argument("Unknown PurposeId");
+}
+
+std::string to_string(cmSpdxSbom::TypeId id)
+{
+  switch (id) {
+    case cmSpdxSbom::TypeId::ANALYZED:
+      return "analyzed";
+    case cmSpdxSbom::TypeId::BUILD:
+      return "build";
+    case cmSpdxSbom::TypeId::DEPLOYED:
+      return "deployed";
+    case cmSpdxSbom::TypeId::DESIGN:
+      return "design";
+    case cmSpdxSbom::TypeId::RUNTIME:
+      return "runtime";
+    case cmSpdxSbom::TypeId::SOURCE:
+      return "source";
+    case cmSpdxSbom::TypeId::TEST:
+      return "test";
+  }
+  throw std::invalid_argument("Unknown Sbom::TypeId");
+}
+
+std::string to_string(cmSpdxFile::FileKindId id)
+{
+  switch (id) {
+    case cmSpdxFile::FileKindId::DIRECTORY:
+      return "directory";
+    case cmSpdxFile::FileKindId::FILE:
+      return "file";
+  }
+  throw std::invalid_argument("Unknown File::FileKindId");
+}
+
+std::string to_string(cmSpdxRelationship::RelationshipTypeId id)
+{
+  switch (id) {
+    case cmSpdxRelationship::RelationshipTypeId::DESCRIBES:
+      return "describes";
+    case cmSpdxRelationship::RelationshipTypeId::CONTAINS:
+      return "contains";
+    case cmSpdxRelationship::RelationshipTypeId::DEPENDS_ON:
+      return "dependsOn";
+    case cmSpdxRelationship::RelationshipTypeId::OTHER:
+      return "other";
+  }
+  throw std::invalid_argument("Unknown RelationshipTypeId");
+}
+
+std::string to_string(cmSpdxLifecycleScopedRelationship::ScopeId id)
+{
+  switch (id) {
+    case cmSpdxLifecycleScopedRelationship::ScopeId::BUILD:
+      return "build";
+    case cmSpdxLifecycleScopedRelationship::ScopeId::DESIGN:
+      return "design";
+    case cmSpdxLifecycleScopedRelationship::ScopeId::RUNTIME:
+      return "runtime";
+    case cmSpdxLifecycleScopedRelationship::ScopeId::TEST:
+      return "test";
+  }
+  throw std::invalid_argument("Unknown Lifecycle ScopeId");
+}
+
+std::string to_string(cmSpdxAnnotation::AnnotationTypeId id)
+{
+  switch (id) {
+    case cmSpdxAnnotation::AnnotationTypeId::REVIEW:
+      return "review";
+    case cmSpdxAnnotation::AnnotationTypeId::OTHER:
+      return "other";
+  }
+  throw std::invalid_argument("Unknown AnnotationTypeId");
+}
+
+std::string to_string(cmSpdxArtifact::SupportTypeId id)
+{
+  switch (id) {
+    case cmSpdxArtifact::SupportTypeId::COMMUNITY:
+      return "community";
+    case cmSpdxArtifact::SupportTypeId::COMMERCIAL:
+      return "commercial";
+    case cmSpdxArtifact::SupportTypeId::NONE:
+      return "none";
+  }
+  throw std::invalid_argument("Unknown SupportTypeId");
+}
+
+void cmSpdxExternalIdentifier::Serialize(cmSbomSerializer& serializer) const
+{
+  serializer.AddString("type", "ExternalIdentifier");
+  SerializeIfPresent(serializer, "externalIdentifierType",
+                     ExternalIdentifierType);
+  SerializeIfPresent(serializer, "identifier", Identifier);
+  SerializeIfPresent(serializer, "comment", Comment);
+  SerializeIfPresent(serializer, "identifierLocation", IdentifierLocation);
+  SerializeIfPresent(serializer, "issuingAuthority", IssuingAuthority);
+}
+
+void cmSpdxExternalRef::Serialize(cmSbomSerializer& serializer) const
+{
+  serializer.AddString("type", "ExternalRef");
+  SerializeIfPresent(serializer, "externalRefType", ExternalRefType);
+  SerializeIfPresent(serializer, "locator", Locator);
+  SerializeIfPresent(serializer, "contentType", ContentType);
+  SerializeIfPresent(serializer, "comment", Comment);
+}
+
+void cmSpdxChecksum::Serialize(cmSbomSerializer& serializer) const
+{
+  serializer.AddString("type", "Checksum");
+  serializer.AddString("algorithm", to_string(Algorithm));
+  serializer.AddString("checksumValue", ChecksumValue);
+}
+
+void cmSpdxCreationInfo::Serialize(cmSbomSerializer& serializer) const
+{
+  serializer.AddString("type", "CreationInfo");
+  SerializeIfPresent(serializer, "@id", SpdxId);
+  if (SpecVersion) {
+    serializer.AddString("specVersion", *SpecVersion);
+  }
+  SerializeIfPresent(serializer, "comment", Comment);
+  SerializeIfPresent(serializer, "created", Created);
+  if (!CreatedBy.empty()) {
+    serializer.AddVectorIfPresent("createdBy", CreatedBy);
+  }
+  if (!CreatedUsing.empty()) {
+    serializer.AddVectorIfPresent("createdUsing", CreatedUsing);
+  }
+}
+
+void cmSpdxIntegrityMethod::Serialize(cmSbomSerializer& serializer) const
+{
+  serializer.AddString("type", "IntegrityMethod");
+  SerializeIfPresent(serializer, "comment", Comment);
+}
+
+void cmSpdxElement::Serialize(cmSbomSerializer& serializer) const
+{
+  serializer.AddString("type", "Element");
+  SerializeIfPresent(serializer, "spdxId", SpdxId);
+  SerializeIfPresent(serializer, "name", Name);
+  SerializeIfPresent(serializer, "summary", Summary);
+  SerializeIfPresent(serializer, "description", Description);
+  SerializeIfPresent(serializer, "comment", Comment);
+  if (CreationInfo) {
+    serializer.AddVisitable("creationInfo", *CreationInfo);
+  }
+  if (VerifiedUsing) {
+    serializer.AddVisitable("verifiedUsing", *VerifiedUsing);
+  }
+  if (!ExternalRef.empty()) {
+    serializer.AddVectorIfPresent("externalRef", ExternalRef);
+  }
+  if (!ExternalIdentifier.empty()) {
+    serializer.AddVectorIfPresent("externalIdentifier", ExternalIdentifier);
+  }
+  if (Extension) {
+    serializer.AddVisitable("extension", *Extension);
+  }
+}
+
+void cmSpdxTool::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxElement::Serialize(serializer);
+  serializer.AddString("type", "Tool");
+}
+
+void cmSpdxAgent::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxElement::Serialize(serializer);
+  serializer.AddString("type", "Agent");
+}
+
+void cmSpdxOrganization::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxAgent::Serialize(serializer);
+  serializer.AddString("type", "Organization");
+}
+
+void cmSpdxPerson::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxAgent::Serialize(serializer);
+  serializer.AddString("type", "Person");
+}
+
+void cmSpdxSoftwareAgent::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxAgent::Serialize(serializer);
+  serializer.AddString("type", "SoftwareAgent");
+}
+
+void cmSpdxPositiveIntegerRange::Serialize(cmSbomSerializer& serializer) const
+{
+  serializer.AddString("type", "PositiveIntegerRange");
+  SerializeIfPresent(serializer, "beginIntegerRange", BeginIntegerRange);
+  SerializeIfPresent(serializer, "endIntegerRange", EndIntegerRange);
+}
+
+void cmSpdxRelationship::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxElement::Serialize(serializer);
+  serializer.AddString("type", "Relationship");
+  if (From) {
+    serializer.AddVisitable("from", *From);
+  }
+  if (!To.empty()) {
+    serializer.AddVectorIfPresent("to", To);
+  }
+  if (RelationshipType) {
+    serializer.AddString("relationshipType", to_string(*RelationshipType));
+  }
+  SerializeIfPresent(serializer, "startTime", StartTime);
+  SerializeIfPresent(serializer, "endTime", EndTime);
+}
+
+void cmSpdxLifecycleScopedRelationship::Serialize(
+  cmSbomSerializer& serializer) const
+{
+  cmSpdxRelationship::Serialize(serializer);
+  serializer.AddString("type", "LifecycleScopedRelationship");
+  if (Scope) {
+    serializer.AddString("scope", to_string(*Scope));
+  }
+}
+
+void cmSpdxArtifact::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxElement::Serialize(serializer);
+  serializer.AddString("type", "Artifact");
+  if (!OriginatedBy.empty()) {
+    serializer.AddVectorIfPresent("originatedBy", OriginatedBy);
+  }
+  if (SuppliedBy) {
+    serializer.AddVisitable("suppliedBy", *SuppliedBy);
+  }
+  SerializeIfPresent(serializer, "builtTime", BuiltTime);
+  SerializeIfPresent(serializer, "releaseTime", ReleaseTime);
+  SerializeIfPresent(serializer, "validUntilTime", ValidUntilTime);
+  SerializeIfPresent(serializer, "standardName", StandardName);
+  if (Support) {
+    serializer.AddString("support", to_string(*Support));
+  }
+}
+
+void cmSpdxIndividualElement::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxElement::Serialize(serializer);
+  serializer.AddString("type", "IndividualElement");
+}
+
+void cmSpdxAnnotation::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxElement::Serialize(serializer);
+  serializer.AddString("type", "Annotation");
+  if (AnnotationType) {
+    serializer.AddString("annotationType", to_string(*AnnotationType));
+  }
+  SerializeIfPresent(serializer, "contentType", ContentType);
+  SerializeIfPresent(serializer, "statement", Statement);
+  if (Element) {
+    serializer.AddVisitable("element", *Element);
+  }
+}
+
+void cmSpdxExternalMap::Serialize(cmSbomSerializer& serializer) const
+{
+  serializer.AddString("type", "ExternalMap");
+  SerializeIfPresent(serializer, "externalSpdxId", ExternalSpdxId);
+  if (VerifiedUsing) {
+    serializer.AddVisitable("verifiedUsing", *VerifiedUsing);
+  }
+  SerializeIfPresent(serializer, "locationHistory", LocationHistory);
+  if (DefiningArtifact) {
+    serializer.AddVisitable("definingArtifact", *DefiningArtifact);
+  }
+}
+
+void cmSpdxNamespaceMap::Serialize(cmSbomSerializer& serializer) const
+{
+  serializer.AddString("type", "NamespaceMap");
+  SerializeIfPresent(serializer, "prefix", Prefix);
+  SerializeIfPresent(serializer, "namespace", Namespace);
+}
+
+void cmSpdxElementCollection::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxElement::Serialize(serializer);
+  serializer.AddString("type", "ElementCollection");
+  if (!Elements.empty()) {
+    serializer.AddVectorIfPresent("element", Elements);
+  }
+  if (!RootElements.empty()) {
+    serializer.AddVectorIfPresent("rootElement", RootElements);
+  }
+  if (!ProfileConformance.empty()) {
+    serializer.AddVectorIfPresent("profileConformance", ProfileConformance);
+  }
+}
+
+void cmSpdxPackageVerificationCode::Serialize(
+  cmSbomSerializer& serializer) const
+{
+  serializer.AddString("type", "PackageVerificationCode");
+  if (Algorithm) {
+    serializer.AddString("algorithm", to_string(*Algorithm));
+  }
+  SerializeIfPresent(serializer, "hashValue", HashValue);
+  SerializeIfPresent(serializer, "packageVerificationCodeExcludedFile",
+                     PackageVerificationCodeExcludedFile);
+}
+
+void cmSpdxHash::Serialize(cmSbomSerializer& serializer) const
+{
+  serializer.AddString("type", "Hash");
+  serializer.AddString("hashAlgorithm", to_string(HashAlgorithm));
+  serializer.AddString("hashValue", HashValue);
+}
+
+void cmSpdxBundle::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxElementCollection::Serialize(serializer);
+  serializer.AddString("type", "Bundle");
+  SerializeIfPresent(serializer, "context", Context);
+}
+
+void cmSpdxBom::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxBundle::Serialize(serializer);
+  serializer.AddString("type", "Bom");
+}
+
+void cmSpdxSbom::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxBom::Serialize(serializer);
+  serializer.AddString("type", "software_Sbom");
+  if (Types) {
+    for (auto const& t : *Types) {
+      serializer.AddString("sbomType", to_string(t));
+    }
+  }
+  if (LifecycleScope) {
+    serializer.AddString("lifecycleScope", to_string(*LifecycleScope));
+  }
+}
+
+void cmSpdxSoftwareArtifact::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxArtifact::Serialize(serializer);
+  serializer.AddString("type", "software_SoftwareArtifact");
+  if (PrimaryPurpose) {
+    serializer.AddString("software_primaryPurpose",
+                         to_string(*PrimaryPurpose));
+  }
+  if (AdditionalPurpose) {
+    for (auto const& p : *AdditionalPurpose) {
+      serializer.AddString("software_AdditionalPurpose", to_string(p));
+    }
+  }
+  SerializeIfPresent(serializer, "software_copyrightText", CopyrightText);
+  SerializeIfPresent(serializer, "software_attributionText", AttributionText);
+  if (ContentIdentifier) {
+    serializer.AddVisitable("software_contentIdentifier", *ContentIdentifier);
+  }
+  SerializeIfPresent(serializer, "software_artifactSize", ArtifactSize);
+}
+
+void cmSpdxPackage::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxSoftwareArtifact::Serialize(serializer);
+  serializer.AddString("type", "software_Package");
+  SerializeIfPresent(serializer, "software_downloadLocation",
+                     DownloadLocation);
+  SerializeIfPresent(serializer, "software_homePage", Homepage);
+  SerializeIfPresent(serializer, "software_packageVersion", PackageVersion);
+  SerializeIfPresent(serializer, "software_packageUrl", PackageUrl);
+  SerializeIfPresent(serializer, "software_sourceInfo", SourceInfo);
+}
+
+void cmSpdxFile::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxArtifact::Serialize(serializer);
+  serializer.AddString("type", "software_File");
+  if (ContentType) {
+    serializer.AddString("software_contentType", *ContentType);
+  }
+  if (FileType) {
+    serializer.AddString("software_fileType", to_string(*FileType));
+  }
+}
+
+void cmSpdxContentIdentifier::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxIntegrityMethod::Serialize(serializer);
+  serializer.AddString("type", "software_contentIdentifier");
+  SerializeIfPresent(serializer, "software_contentIdentifierType",
+                     ContentIdentifierType);
+  SerializeIfPresent(serializer, "software_contentValue", ContentValue);
+}
+
+void cmSpdxSnippet::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxSoftwareArtifact::Serialize(serializer);
+  serializer.AddString("type", "software_snippet");
+  SerializeIfPresent(serializer, "software_byteRange", ByteRange);
+  SerializeIfPresent(serializer, "software_lineRange", LineRange);
+  if (SnippetFromFile) {
+    serializer.AddVisitable("software_snippetFromFile", *SnippetFromFile);
+  }
+}
+
+void cmSpdxDocument::Serialize(cmSbomSerializer& serializer) const
+{
+  cmSpdxElementCollection::Serialize(serializer);
+
+  serializer.AddString("type", "SpdxDocument");
+  if (ExternalMap) {
+    serializer.AddVisitable("externalMap", *ExternalMap);
+  }
+  if (NamespaceMap) {
+    serializer.AddVisitable("namespaceMap", *NamespaceMap);
+  }
+  SerializeIfPresent(serializer, "dataLicense", DataLicense);
+}
+
+void cmSbomDocument::Serialize(cmSbomSerializer& serializer) const
+{
+  serializer.AddString(
+    "@context",
+    Context.value_or("https://spdx.org/rdf/3.0.1/spdx-context.jsonld"));
+  if (!Graph.empty()) {
+    serializer.AddVectorIfPresent("@graph", Graph);
+  }
+}
diff --git a/Source/cmSpdx.h b/Source/cmSpdx.h
new file mode 100644
index 0000000..adaa26a
--- /dev/null
+++ b/Source/cmSpdx.h
@@ -0,0 +1,391 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#pragma once
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+
+#include "cmSbomObject.h"
+
+class cmSbomSerializer;
+
+using Datetime = std::string;
+using MediaType = std::string;
+using SemVer = std::string;
+
+struct cmSpdxExternalIdentifier
+{
+  cm::optional<std::string> SpdxId;
+  cm::optional<std::string> ExternalIdentifierType;
+  cm::optional<std::string> Identifier;
+  cm::optional<std::string> Comment;
+  cm::optional<std::string> IdentifierLocation;
+  cm::optional<std::string> IssuingAuthority;
+
+  void Serialize(cmSbomSerializer&) const;
+};
+
+struct cmSpdxExternalRef
+{
+  cm::optional<std::string> SpdxId;
+  cm::optional<std::string> ExternalRefType;
+  cm::optional<std::string> Locator;
+  cm::optional<std::string> ContentType;
+  cm::optional<std::string> Comment;
+
+  void Serialize(cmSbomSerializer&) const;
+};
+
+struct cmSpdxCreationInfo
+{
+  cm::optional<std::string> Id;
+  cm::optional<std::string> SpdxId;
+  cm::optional<SemVer> SpecVersion;
+  cm::optional<std::string> Comment;
+  cm::optional<Datetime> Created;
+  std::vector<std::string> CreatedBy;
+  std::vector<cmSbomObject> CreatedUsing;
+
+  void Serialize(cmSbomSerializer&) const;
+};
+
+struct cmSpdxIntegrityMethod
+{
+  cm::optional<std::string> SpdxId;
+  cm::optional<std::string> Comment;
+
+  enum HashAlgorithmId
+  {
+    ADLER32,
+    BLAKE2B256,
+    BLAKE2B384,
+    BLAKE2B512,
+    BLAKE3,
+    MD2,
+    MD4,
+    MD5,
+    MD6,
+    SHA1,
+    SHA224,
+    SHA256,
+    SHA384,
+    SHA512,
+    SHA3_256,
+    SHA3_384,
+    SHA3_512,
+  };
+
+  cmSpdxIntegrityMethod() = default;
+  cmSpdxIntegrityMethod(cmSpdxIntegrityMethod const&) = default;
+  cmSpdxIntegrityMethod(cmSpdxIntegrityMethod&&) = default;
+  cmSpdxIntegrityMethod& operator=(cmSpdxIntegrityMethod const&) = default;
+  cmSpdxIntegrityMethod& operator=(cmSpdxIntegrityMethod&&) = default;
+
+  virtual void Serialize(cmSbomSerializer&) const;
+  virtual ~cmSpdxIntegrityMethod() = default;
+};
+
+struct cmSpdxChecksum
+{
+  cm::optional<std::string> SpdxId;
+  cmSpdxIntegrityMethod::HashAlgorithmId Algorithm;
+  std::string ChecksumValue;
+
+  void Serialize(cmSbomSerializer&) const;
+};
+
+struct cmSpdxElement
+{
+  cm::optional<std::string> SpdxId;
+  cm::optional<std::string> Name;
+  cm::optional<std::string> Summary;
+  cm::optional<std::string> Description;
+  cm::optional<std::string> Comment;
+  cm::optional<cmSbomObject> CreationInfo;
+  cm::optional<cmSbomObject> VerifiedUsing;
+  std::vector<cmSbomObject> ExternalRef;
+  std::vector<cmSbomObject> ExternalIdentifier;
+  cm::optional<cmSbomObject> Extension;
+
+  cmSpdxElement() = default;
+  cmSpdxElement(cmSpdxElement const&) = default;
+  cmSpdxElement(cmSpdxElement&&) = default;
+  cmSpdxElement& operator=(cmSpdxElement const&) = default;
+  cmSpdxElement& operator=(cmSpdxElement&&) = default;
+
+  virtual ~cmSpdxElement() = default;
+  virtual void Serialize(cmSbomSerializer&) const;
+};
+
+struct cmSpdxTool final : cmSpdxElement
+{
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxAgent : cmSpdxElement
+{
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxOrganization final : cmSpdxAgent
+{
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxPerson final : cmSpdxAgent
+{
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxSoftwareAgent final : cmSpdxAgent
+{
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxPositiveIntegerRange
+{
+  cm::optional<std::string> SpdxId;
+  cm::optional<std::string> BeginIntegerRange;
+  cm::optional<std::string> EndIntegerRange;
+
+  void Serialize(cmSbomSerializer&) const;
+};
+
+struct cmSpdxRelationship : cmSpdxElement
+{
+  enum RelationshipTypeId
+  {
+    DESCRIBES,
+    CONTAINS,
+    DEPENDS_ON,
+    OTHER
+  };
+
+  cm::optional<cmSbomObject> From;
+  std::vector<cmSbomObject> To;
+  cm::optional<RelationshipTypeId> RelationshipType;
+  cm::optional<Datetime> StartTime;
+  cm::optional<Datetime> EndTime;
+
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxLifecycleScopedRelationship final : cmSpdxRelationship
+{
+  enum ScopeId
+  {
+    BUILD,
+    DESIGN,
+    RUNTIME,
+    TEST
+  };
+
+  cm::optional<ScopeId> Scope;
+
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxArtifact : cmSpdxElement
+{
+  enum SupportTypeId
+  {
+    COMMUNITY,
+    COMMERCIAL,
+    NONE
+  };
+
+  std::vector<cmSbomObject> OriginatedBy;
+  cm::optional<cmSbomObject> SuppliedBy;
+  cm::optional<Datetime> BuiltTime;
+  cm::optional<Datetime> ReleaseTime;
+  cm::optional<Datetime> ValidUntilTime;
+  cm::optional<std::string> StandardName;
+  cm::optional<SupportTypeId> Support;
+
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxIndividualElement final : cmSpdxElement
+{
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxAnnotation final : cmSpdxElement
+{
+  enum AnnotationTypeId
+  {
+    REVIEW,
+    OTHER
+  };
+
+  cm::optional<AnnotationTypeId> AnnotationType;
+  cm::optional<MediaType> ContentType;
+  cm::optional<std::string> Statement;
+  cm::optional<cmSbomObject> Element;
+
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxExternalMap
+{
+  cm::optional<std::string> SpdxId;
+  cm::optional<std::string> ExternalSpdxId;
+  cm::optional<cmSbomObject> VerifiedUsing;
+  cm::optional<std::string> LocationHistory;
+  cm::optional<cmSbomObject> DefiningArtifact;
+
+  void Serialize(cmSbomSerializer&) const;
+};
+
+struct cmSpdxNamespaceMap
+{
+  cm::optional<std::string> SpdxId;
+  cm::optional<std::string> Prefix;
+  cm::optional<std::string> Namespace;
+
+  void Serialize(cmSbomSerializer&) const;
+};
+
+struct cmSpdxElementCollection : cmSpdxElement
+{
+  std::vector<cmSbomObject> Elements;
+  std::vector<cmSbomObject> RootElements;
+  std::vector<std::string> ProfileConformance;
+
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxPackageVerificationCode final : cmSpdxIntegrityMethod
+{
+  cm::optional<HashAlgorithmId> Algorithm;
+  cm::optional<std::string> HashValue;
+  cm::optional<std::string> PackageVerificationCodeExcludedFile;
+
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxHash final : cmSpdxIntegrityMethod
+{
+  HashAlgorithmId HashAlgorithm;
+  std::string HashValue;
+
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxBundle : cmSpdxElementCollection
+{
+  cm::optional<std::string> Context;
+
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxBom : cmSpdxBundle
+{
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxSbom final : cmSpdxBom
+{
+  enum TypeId
+  {
+    ANALYZED,
+    BUILD,
+    DEPLOYED,
+    DESIGN,
+    RUNTIME,
+    SOURCE,
+    TEST
+  };
+
+  cm::optional<std::vector<TypeId>> Types;
+  cm::optional<TypeId> LifecycleScope;
+
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxSoftwareArtifact : cmSpdxArtifact
+{
+  enum PurposeId
+  {
+    APPLICATION,
+    ARCHIVE,
+    CONTAINER,
+    DATA,
+    DEVICE,
+    FIRMWARE,
+    FILE,
+    INSTALL,
+    LIBRARY,
+    MODULE,
+    OPERATING_SYSTEM,
+    SOURCE
+  };
+
+  cm::optional<PurposeId> PrimaryPurpose;
+  cm::optional<std::vector<PurposeId>> AdditionalPurpose;
+  cm::optional<std::string> CopyrightText;
+  cm::optional<std::string> AttributionText;
+  cm::optional<cmSbomObject> ContentIdentifier;
+  cm::optional<std::string> ArtifactSize;
+
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxPackage final : cmSpdxSoftwareArtifact
+{
+  cm::optional<std::string> DownloadLocation;
+  cm::optional<std::string> Homepage;
+  cm::optional<std::string> PackageVersion;
+  cm::optional<std::string> PackageUrl;
+  cm::optional<std::string> SourceInfo;
+
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxDocument final : cmSpdxElementCollection
+{
+  cm::optional<cmSbomObject> ExternalMap;
+  cm::optional<cmSbomObject> NamespaceMap;
+  std::string DataLicense;
+
+  void Serialize(cmSbomSerializer& serializer) const override;
+};
+
+struct cmSpdxContentIdentifier final : cmSpdxIntegrityMethod
+{
+  cm::optional<std::string> ContentIdentifierType;
+  cm::optional<std::string> ContentValue;
+
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxFile final : cmSpdxArtifact
+{
+  enum FileKindId
+  {
+    DIRECTORY,
+    FILE
+  };
+  cm::optional<MediaType> ContentType;
+  cm::optional<FileKindId> FileType;
+
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSpdxSnippet final : cmSpdxSoftwareArtifact
+{
+  cm::optional<std::string> ByteRange;
+  cm::optional<std::string> LineRange;
+  cm::optional<cmSbomObject> SnippetFromFile;
+
+  void Serialize(cmSbomSerializer&) const override;
+};
+
+struct cmSbomDocument
+{
+  cm::optional<std::string> Context;
+  std::vector<cmSbomObject> Graph;
+
+  void Serialize(cmSbomSerializer&) const;
+};
diff --git a/Source/cmSpdxSerializer.cxx b/Source/cmSpdxSerializer.cxx
new file mode 100644
index 0000000..9ba1d15
--- /dev/null
+++ b/Source/cmSpdxSerializer.cxx
@@ -0,0 +1,120 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#include "cmSpdxSerializer.h"
+
+#include <utility>
+#include <vector>
+
+#include <cm3p/json/writer.h>
+
+#include "cmSbomObject.h"
+
+cmSpdxSerializer::cmSpdxSerializer()
+{
+  Json::StreamWriterBuilder builder = Json::StreamWriterBuilder();
+  builder["indentation"] = "  ";
+  Writer.reset(builder.newStreamWriter());
+}
+
+void cmSpdxSerializer::BeginObject()
+{
+  CurrentValue = Json::objectValue;
+}
+
+void cmSpdxSerializer::BeginArray()
+{
+  CurrentValue = Json::arrayValue;
+}
+
+void cmSpdxSerializer::EndObject()
+{
+}
+
+void cmSpdxSerializer::EndArray()
+{
+}
+
+void cmSpdxSerializer::AddReference(std::string const& id)
+{
+  CurrentValue = id;
+}
+
+void cmSpdxSerializer::AddString(std::string const& key,
+                                 std::string const& value)
+{
+  if (!value.empty()) {
+    CurrentValue[key] = value;
+  }
+}
+
+void cmSpdxSerializer::AddVisitable(std::string const& key,
+                                    cmSbomObject const& visitable)
+{
+  if (visitable.IsNull()) {
+    return;
+  }
+
+  Json::Value parentValue = std::move(CurrentValue);
+  visitable.Serialize(*this);
+  Json::Value childValue = std::move(CurrentValue);
+
+  CurrentValue = std::move(parentValue);
+  CurrentValue[key] = std::move(childValue);
+}
+
+void cmSpdxSerializer::AddVectorIfPresent(std::string const& key,
+                                          std::vector<cmSbomObject> const& vec)
+{
+  if (vec.empty()) {
+    return;
+  }
+  Json::Value parentValue = std::move(CurrentValue);
+  Json::Value childValue(Json::arrayValue);
+
+  for (auto const& item : vec) {
+    if (item.IsNull()) {
+      continue;
+    }
+
+    item.Serialize(*this);
+
+    if (!CurrentValue.isNull()) {
+      childValue.append(std::move(CurrentValue));
+    }
+  }
+
+  CurrentValue = std::move(parentValue);
+  CurrentValue[key] = std::move(childValue);
+}
+
+void cmSpdxSerializer::AddVectorIfPresent(std::string const& key,
+                                          std::vector<std::string> const& vec)
+{
+  if (vec.empty()) {
+    return;
+  }
+  Json::Value parentValue = std::move(CurrentValue);
+  Json::Value childValue(Json::arrayValue);
+
+  for (auto const& item : vec) {
+    if (item.empty()) {
+      continue;
+    }
+    childValue.append(item);
+  }
+
+  CurrentValue = std::move(parentValue);
+  CurrentValue[key] = std::move(childValue);
+}
+
+bool cmSpdxSerializer::WriteSbom(std::ostream& os,
+                                 cmSbomObject const& document)
+{
+  if (document.IsNull()) {
+    return false;
+  }
+
+  document.Serialize(*this);
+  Writer->write(CurrentValue, &os);
+  return os.good();
+}
diff --git a/Source/cmSpdxSerializer.h b/Source/cmSpdxSerializer.h
new file mode 100644
index 0000000..5bcbce1
--- /dev/null
+++ b/Source/cmSpdxSerializer.h
@@ -0,0 +1,49 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include <memory>
+#include <ostream>
+#include <string>
+
+#include <cm3p/json/value.h>
+#include <cm3p/json/writer.h>
+
+#include "cmSbomSerializer.h"
+
+struct cmSpdxSerializer final : cmSbomSerializer
+{
+  cmSpdxSerializer();
+
+  ~cmSpdxSerializer() override = default;
+
+  void BeginObject() override;
+
+  void BeginArray() override;
+
+  void EndObject() override;
+
+  void EndArray() override;
+
+  void AddReference(std::string const& id) override;
+
+  void AddString(std::string const& key, std::string const& value) override;
+
+  void AddVisitable(std::string const& key,
+                    cmSbomObject const& visitable) override;
+
+  void AddVectorIfPresent(std::string const& key,
+                          std::vector<cmSbomObject> const& vec) override;
+
+  void AddVectorIfPresent(std::string const& key,
+                          std::vector<std::string> const& vec) override;
+
+  bool WriteSbom(std::ostream& os, cmSbomObject const& document) override;
+
+  Json::Value GetJson() { return CurrentValue; }
+
+private:
+  Json::Value CurrentValue;
+  std::string CurrentKey;
+  std::unique_ptr<Json::StreamWriter> Writer;
+};
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index e694a28..3255650 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -31,9 +31,9 @@
 std::string const PropertySentinel = std::string{};
 } // namespace cmStateDetail
 
-cmState::cmState(Mode mode, ProjectKind projectKind)
-  : StateMode(mode)
-  , StateProjectKind(projectKind)
+cmState::cmState(Role role, TryCompile isTryCompile)
+  : StateRole(role)
+  , IsTryCompile(isTryCompile)
 {
   this->CacheManager = cm::make_unique<cmCacheManager>();
   this->GlobVerificationManager = cm::make_unique<cmGlobVerificationManager>();
@@ -603,9 +603,8 @@
     std::vector<std::string> commands = this->GetCommandNames();
     this->SetGlobalProperty("COMMANDS", cmList::to_string(commands));
   } else if (prop == "IN_TRY_COMPILE") {
-    this->SetGlobalProperty(
-      "IN_TRY_COMPILE",
-      this->StateProjectKind == ProjectKind::TryCompile ? "1" : "0");
+    this->SetGlobalProperty("IN_TRY_COMPILE",
+                            this->IsTryCompile == TryCompile::Yes ? "1" : "0");
   } else if (prop == "GENERATOR_IS_MULTI_CONFIG") {
     this->SetGlobalProperty("GENERATOR_IS_MULTI_CONFIG",
                             this->IsGeneratorMultiConfig ? "1" : "0");
@@ -613,8 +612,7 @@
     auto langs = cmList::to_string(this->EnabledLanguages);
     this->SetGlobalProperty("ENABLED_LANGUAGES", langs);
   } else if (prop == "CMAKE_ROLE") {
-    std::string mode = this->GetModeString();
-    this->SetGlobalProperty("CMAKE_ROLE", mode);
+    this->SetGlobalProperty("CMAKE_ROLE", this->GetRoleString());
   }
 #define STRING_LIST_ELEMENT(F) ";" #F
   if (prop == "CMAKE_C_KNOWN_FEATURES") {
@@ -814,40 +812,50 @@
   return this->CacheManager->GetCacheMinorVersion();
 }
 
-cmState::Mode cmState::GetMode() const
+void cmState::SetRoleToProjectForCMakeBuildVsReconfigure()
 {
-  return this->StateMode;
+  this->StateRole = Role::Project;
 }
 
-std::string cmState::GetModeString() const
+void cmState::SetRoleToHelpForListPresets()
 {
-  return ModeToString(this->StateMode);
+  this->StateRole = Role::Help;
 }
 
-std::string cmState::ModeToString(cmState::Mode mode)
+cmState::Role cmState::GetRole() const
+{
+  return this->StateRole;
+}
+
+std::string cmState::GetRoleString() const
+{
+  return RoleToString(this->StateRole);
+}
+
+std::string cmState::RoleToString(cmState::Role mode)
 {
   switch (mode) {
-    case Project:
+    case Role::Project:
       return "PROJECT";
-    case Script:
+    case Role::Script:
       return "SCRIPT";
-    case FindPackage:
+    case Role::FindPackage:
       return "FIND_PACKAGE";
-    case CTest:
+    case Role::CTest:
       return "CTEST";
-    case CPack:
+    case Role::CPack:
       return "CPACK";
-    case Help:
+    case Role::Help:
       return "HELP";
-    case Unknown:
-      return "UNKNOWN";
+    case Role::Internal:
+      return "INTERNAL";
   }
   return "UNKNOWN";
 }
 
-cmState::ProjectKind cmState::GetProjectKind() const
+cmState::TryCompile cmState::GetIsTryCompile() const
 {
-  return this->StateProjectKind;
+  return this->IsTryCompile;
 }
 
 std::string const& cmState::GetBinaryDirectory() const
diff --git a/Source/cmState.h b/Source/cmState.h
index 4775b74..885ade5 100644
--- a/Source/cmState.h
+++ b/Source/cmState.h
@@ -44,24 +44,24 @@
   friend class cmStateSnapshot;
 
 public:
-  enum Mode
+  enum class Role
   {
-    Unknown,
+    Internal,
     Project,
     Script,
     FindPackage,
     CTest,
     CPack,
-    Help
+    Help,
   };
 
-  enum class ProjectKind
+  enum class TryCompile
   {
-    Normal,
-    TryCompile,
+    No,
+    Yes,
   };
 
-  cmState(Mode mode, ProjectKind projectKind = ProjectKind::Normal);
+  cmState(Role role, TryCompile isTryCompile = TryCompile::No);
   ~cmState();
 
   cmState(cmState const&) = delete;
@@ -231,12 +231,14 @@
   unsigned int GetCacheMajorVersion() const;
   unsigned int GetCacheMinorVersion() const;
 
-  Mode GetMode() const;
-  std::string GetModeString() const;
+  void SetRoleToProjectForCMakeBuildVsReconfigure();
+  void SetRoleToHelpForListPresets();
+  Role GetRole() const;
+  std::string GetRoleString() const;
 
-  static std::string ModeToString(Mode mode);
+  static std::string RoleToString(Role role);
 
-  ProjectKind GetProjectKind() const;
+  TryCompile GetIsTryCompile() const;
 
   void ClearDependencyProvider() { this->DependencyProvider.reset(); }
   void SetDependencyProvider(cmDependencyProvider provider)
@@ -304,8 +306,8 @@
   bool Ninja = false;
   bool NinjaMulti = false;
   bool FastbuildMake = false;
-  Mode StateMode = Unknown;
-  ProjectKind StateProjectKind = ProjectKind::Normal;
+  Role StateRole = Role::Internal;
+  TryCompile IsTryCompile = TryCompile::No;
   cm::optional<cmDependencyProvider> DependencyProvider;
   bool ProcessingTopLevelIncludes = false;
 };
diff --git a/Source/cmStdIoInit.cxx b/Source/cmStdIoInit.cxx
index 49f3187..0d7a3d0 100644
--- a/Source/cmStdIoInit.cxx
+++ b/Source/cmStdIoInit.cxx
@@ -3,6 +3,7 @@
 #include "cmStdIoInit.h"
 
 #include <cerrno>
+#include <clocale>
 #include <cstdio>
 #include <cstdlib>
 #include <iostream>
@@ -106,14 +107,19 @@
   static Globals& Get();
 };
 
-#ifdef _WIN32
 Globals::Globals()
 {
+#ifdef _WIN32
+  // On Windows, setlocale offers a ".<code-page>" syntax to select the
+  // user's locale with a specific character set.  We always use UTF-8.
+  std::setlocale(LC_CTYPE, ".UTF-8");
+
   SetConsoleCtrlHandler(CtrlHandler, TRUE);
-}
 #else
-Globals::Globals() = default;
+  // On non-Windows platforms, we select the user's locale.
+  std::setlocale(LC_CTYPE, "");
 #endif
+}
 
 Globals& Globals::Get()
 {
diff --git a/Source/cmStdIoStream.cxx b/Source/cmStdIoStream.cxx
index baea8df..5aa9a06 100644
--- a/Source/cmStdIoStream.cxx
+++ b/Source/cmStdIoStream.cxx
@@ -43,7 +43,7 @@
 #else
 // List of known `TERM` names that support VT100 escape sequences.
 // Order by `LC_COLLATE=C sort` to search using `std::lower_bound`.
-std::array<cm::string_view, 56> const kVT100Names{ {
+std::array<cm::string_view, 57> const kVT100Names{ {
   "Eterm"_s,
   "alacritty"_s,
   "alacritty-direct"_s,
@@ -98,6 +98,7 @@
   "xterm-88color"_s,
   "xterm-color"_s,
   "xterm-debian"_s,
+  "xterm-ghostty"_s,
   "xterm-kitty"_s,
   "xterm-termite"_s,
 } };
diff --git a/Source/cmString.hxx b/Source/cmString.hxx
index c346230..f7dcb2b 100644
--- a/Source/cmString.hxx
+++ b/Source/cmString.hxx
@@ -425,6 +425,16 @@
     r.append(v.data(), v.size());
     return *this = std::move(r);
   }
+  template <typename T>
+  typename std::enable_if<AsStringView<T>::value, String&>::type append(T&& s)
+  {
+    string_view v = AsStringView<T>::view(std::forward<T>(s));
+    std::string r;
+    r.reserve(this->size() + v.size());
+    r.assign(this->data(), this->size());
+    r.append(v.data(), v.size());
+    return *this = std::move(r);
+  }
 
   /** Assign to an empty string.  */
   void clear() { *this = ""_s; }
@@ -432,6 +442,20 @@
   /** Insert 'count' copies of 'ch' at position 'index'.  */
   String& insert(size_type index, size_type count, char ch);
 
+  /** Insert into the string using any type that implements the
+      AsStringView trait.  */
+  template <typename T>
+  typename std::enable_if<AsStringView<T>::value, String&>::type insert(
+    size_type index, T&& s)
+  {
+    string_view v = AsStringView<T>::view(std::forward<T>(s));
+    std::string r;
+    r.reserve(this->size() + v.size());
+    r.assign(this->data(), this->size());
+    r.insert(index, v.data(), v.size());
+    return *this = std::move(r);
+  }
+
   /** Erase 'count' characters starting at position 'index'.  */
   String& erase(size_type index = 0, size_type count = npos);
 
diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx
index df3b7d9..e13c226 100644
--- a/Source/cmStringAlgorithms.cxx
+++ b/Source/cmStringAlgorithms.cxx
@@ -8,14 +8,17 @@
 #include <cstdio>
 #include <cstdlib>
 
+#include "cmsys/String.h"
+
 bool cmStrCaseEq(cm::string_view s1, cm::string_view s2)
 {
   if (s1.size() != s2.size()) {
     return false;
   }
 
-  return std::equal(s1.begin(), s1.end(), s2.begin(),
-                    [](char a, char b) { return tolower(a) == tolower(b); });
+  return std::equal(s1.begin(), s1.end(), s2.begin(), [](char a, char b) {
+    return cmsysString_tolower(a) == cmsysString_tolower(b);
+  });
 }
 
 std::string cmTrimWhitespace(cm::string_view str)
@@ -24,7 +27,7 @@
   // because the qualification of `auto` is platform-dependent.
   // NOLINTNEXTLINE(readability-qualified-auto)
   auto start = str.begin();
-  while (start != str.end() && cmIsSpace(*start)) {
+  while (start != str.end() && cmsysString_isspace(*start)) {
     ++start;
   }
   if (start == str.end()) {
@@ -32,12 +35,30 @@
   }
   // NOLINTNEXTLINE(readability-qualified-auto)
   auto stop = str.end() - 1;
-  while (cmIsSpace(*stop)) {
+  while (cmsysString_isspace(*stop)) {
     --stop;
   }
   return std::string(start, stop + 1);
 }
 
+cm::string_view cmStripWhitespace(cm::string_view str)
+{
+  std::string::size_type const l = str.size();
+
+  std::string::size_type s = 0;
+  while (s < l && cmsysString_isspace(str[s])) {
+    ++s;
+  }
+  if (s == l) {
+    return cm::string_view{};
+  }
+  std::string::size_type e = l - 1;
+  while (cmsysString_isspace(str[e])) {
+    --e;
+  }
+  return str.substr(s, e + 1 - s);
+}
+
 std::string cmRemoveQuotes(cm::string_view str)
 {
   // We process only strings that have two quotes at least.
@@ -177,7 +198,7 @@
 {
   errno = 0;
   char* endp;
-  while (cmIsSpace(*str)) {
+  while (cmsysString_isspace(*str)) {
     ++str;
   }
   if (*str == '-') {
@@ -209,7 +230,7 @@
 {
   errno = 0;
   char* endp;
-  while (cmIsSpace(*str)) {
+  while (cmsysString_isspace(*str)) {
     ++str;
   }
   if (*str == '-') {
diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h
index b0d01c0..966091a 100644
--- a/Source/cmStringAlgorithms.h
+++ b/Source/cmStringAlgorithms.h
@@ -4,7 +4,6 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
-#include <cctype>
 #include <cstring>
 #include <initializer_list>
 #include <iterator>
@@ -50,18 +49,15 @@
  */
 bool cmStrCaseEq(cm::string_view a, cm::string_view b);
 
-/** Returns true if the character @a ch is a whitespace character.  **/
-inline bool cmIsSpace(char ch)
-{
-  // isspace takes 'int' but documents that the value must be representable
-  // by 'unsigned char', or be EOF.  Cast to 'unsigned char' to avoid sign
-  // extension while converting to 'int'.
-  return std::isspace(static_cast<unsigned char>(ch));
-}
-
 /** Returns a string that has whitespace removed from the start and the end. */
 std::string cmTrimWhitespace(cm::string_view str);
 
+/**
+ * Returns a string view that has whitespace removed from the start and the
+ * end.
+ */
+cm::string_view cmStripWhitespace(cm::string_view str);
+
 /** Returns a string that has quotes removed from the start and the end. */
 std::string cmRemoveQuotes(cm::string_view str);
 
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index 0503033..1a888c1 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -5,9 +5,9 @@
 
 #include "cmStringCommand.h"
 
-#include <algorithm>
 #include <cstdio>
 #include <cstdlib>
+#include <exception>
 #include <limits>
 #include <memory>
 #include <stdexcept>
@@ -22,22 +22,14 @@
 #include <cm3p/json/value.h>
 #include <cm3p/json/writer.h>
 
-#include "cmsys/RegularExpression.hxx"
-
-#include "cmCryptoHash.h"
+#include "cmCMakeString.hxx"
 #include "cmExecutionStatus.h"
-#include "cmGeneratorExpression.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
-#include "cmPolicies.h"
 #include "cmRange.h"
 #include "cmStringAlgorithms.h"
-#include "cmStringReplaceHelper.h"
 #include "cmSubcommandTable.h"
-#include "cmSystemTools.h"
-#include "cmTimestamp.h"
-#include "cmUuid.h"
-#include "cmValue.h"
 
 namespace {
 
@@ -62,13 +54,16 @@
     return false;
   }
 
-  std::unique_ptr<cmCryptoHash> hash(cmCryptoHash::New(args[0]));
-  if (hash) {
-    std::string out = hash->HashString(args[2]);
-    status.GetMakefile().AddDefinition(args[1], out);
+  cm::CMakeString data{ args[2] };
+
+  try {
+    data.Hash(args[0]);
+    status.GetMakefile().AddDefinition(args[1], data);
     return true;
+  } catch (std::exception const& e) {
+    status.SetError(e.what());
+    return false;
   }
-  return false;
 }
 
 bool HandleToUpperLowerCommand(std::vector<std::string> const& args,
@@ -80,16 +75,16 @@
   }
 
   std::string const& outvar = args[2];
-  std::string output;
+  cm::CMakeString data{ args[1] };
 
   if (toUpper) {
-    output = cmSystemTools::UpperCase(args[1]);
+    data.ToUpper();
   } else {
-    output = cmSystemTools::LowerCase(args[1]);
+    data.ToLower();
   }
 
   // Store the output in the provided variable.
-  status.GetMakefile().AddDefinition(outvar, output);
+  status.GetMakefile().AddDefinition(outvar, data);
   return true;
 }
 
@@ -112,23 +107,17 @@
     status.SetError("No output variable specified");
     return false;
   }
-  std::string::size_type cc;
-  std::string const& outvar = args.back();
-  std::string output;
-  for (cc = 1; cc < args.size() - 1; cc++) {
-    int ch = atoi(args[cc].c_str());
-    if (ch > 0 && ch < 256) {
-      output += static_cast<char>(ch);
-    } else {
-      std::string error =
-        cmStrCat("Character with code ", args[cc], " does not exist.");
-      status.SetError(error);
-      return false;
-    }
+
+  try {
+    std::string const& outvar = args.back();
+    cm::CMakeString data;
+    data.FromASCII(cmMakeRange(args).advance(1).retreat(1));
+    status.GetMakefile().AddDefinition(outvar, data);
+    return true;
+  } catch (std::exception const& e) {
+    status.SetError(e.what());
+    return false;
   }
-  // Store the output in the provided variable.
-  status.GetMakefile().AddDefinition(outvar, output);
-  return true;
 }
 
 bool HandleHexCommand(std::vector<std::string> const& args,
@@ -138,17 +127,13 @@
     status.SetError("Incorrect number of arguments");
     return false;
   }
-  auto const& instr = args[1];
+
   auto const& outvar = args[2];
-  std::string output(instr.size() * 2, ' ');
+  cm::CMakeString data{ args[1] };
 
-  std::string::size_type hexIndex = 0;
-  for (auto const& c : instr) {
-    snprintf(&output[hexIndex], 3, "%.2x", c & 0xFFu);
-    hexIndex += 2;
-  }
+  data.ToHexadecimal();
 
-  status.GetMakefile().AddDefinition(outvar, output);
+  status.GetMakefile().AddDefinition(outvar, data);
   return true;
 }
 
@@ -239,33 +224,21 @@
 {
   //"STRING(REGEX MATCH <regular_expression> <output variable>
   // <input> [<input>...])\n";
-  std::string const& regex = args[2];
-  std::string const& outvar = args[3];
+  try {
+    std::string const& regex = args[2];
+    std::string const& outvar = args[3];
+    cm::CMakeString data{ cmMakeRange(args).advance(4) };
 
-  status.GetMakefile().ClearMatches();
-  // Compile the regular expression.
-  cmsys::RegularExpression re;
-  if (!re.compile(regex)) {
-    std::string e =
-      "sub-command REGEX, mode MATCH failed to compile regex \"" + regex +
-      "\".";
-    status.SetError(e);
+    auto result = data.Match(regex, cm::CMakeString::MatchItems::Once,
+                             &status.GetMakefile());
+    // Store the result in the provided variable.
+    status.GetMakefile().AddDefinition(outvar, result.to_string());
+    return true;
+  } catch (std::exception const& e) {
+    status.SetError(
+      cmStrCat("sub-command REGEX, mode MATCH: ", e.what(), '.'));
     return false;
   }
-
-  // Concatenate all the last arguments together.
-  std::string input = cmJoin(cmMakeRange(args).advance(4), std::string());
-
-  // Scan through the input for all matches.
-  std::string output;
-  if (re.find(input)) {
-    status.GetMakefile().StoreMatches(re);
-    output = re.match();
-  }
-
-  // Store the output in the provided variable.
-  status.GetMakefile().AddDefinition(outvar, output);
-  return true;
 }
 
 bool RegexMatchAll(std::vector<std::string> const& args,
@@ -273,55 +246,21 @@
 {
   //"STRING(REGEX MATCHALL <regular_expression> <output variable> <input>
   // [<input>...])\n";
-  std::string const& regex = args[2];
-  std::string const& outvar = args[3];
+  try {
+    std::string const& regex = args[2];
+    std::string const& outvar = args[3];
+    cm::CMakeString data{ cmMakeRange(args).advance(4) };
 
-  status.GetMakefile().ClearMatches();
-  // Compile the regular expression.
-  cmsys::RegularExpression re;
-  if (!re.compile(regex)) {
-    std::string e =
-      "sub-command REGEX, mode MATCHALL failed to compile regex \"" + regex +
-      "\".";
-    status.SetError(e);
+    auto result = data.Match(regex, cm::CMakeString::MatchItems::All,
+                             &status.GetMakefile());
+    // Store the result in the provided variable.
+    status.GetMakefile().AddDefinition(outvar, result.to_string());
+    return true;
+  } catch (std::exception const& e) {
+    status.SetError(
+      cmStrCat("sub-command REGEX, mode MATCHALL: ", e.what(), '.'));
     return false;
   }
-
-  // Concatenate all the last arguments together.
-  std::string input = cmJoin(cmMakeRange(args).advance(4), std::string());
-
-  unsigned optAnchor = 0;
-  if (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0186) !=
-      cmPolicies::NEW) {
-    optAnchor = cmsys::RegularExpression::BOL_AT_OFFSET;
-  }
-
-  // Scan through the input for all matches.
-  std::string output;
-  std::string::size_type base = 0;
-  unsigned optNonEmpty = 0;
-  while (re.find(input, base, optAnchor | optNonEmpty)) {
-    status.GetMakefile().ClearMatches();
-    status.GetMakefile().StoreMatches(re);
-    if (!output.empty() || optNonEmpty) {
-      output += ";";
-    }
-    output += re.match();
-    base = re.end();
-
-    if (re.start() == input.length()) {
-      break;
-    }
-    if (re.start() == re.end()) {
-      optNonEmpty = cmsys::RegularExpression::NONEMPTY_AT_OFFSET;
-    } else {
-      optNonEmpty = 0;
-    }
-  }
-
-  // Store the output in the provided variable.
-  status.GetMakefile().AddDefinition(outvar, output);
-  return true;
 }
 
 bool RegexReplace(std::vector<std::string> const& args,
@@ -332,38 +271,20 @@
   std::string const& regex = args[2];
   std::string const& replace = args[3];
   std::string const& outvar = args[4];
-  cmStringReplaceHelper replaceHelper(regex, replace, &status.GetMakefile());
 
-  if (!replaceHelper.IsReplaceExpressionValid()) {
+  try {
+    cm::CMakeString data{ cmMakeRange(args).advance(5) };
+
+    data.Replace(regex, replace, cm::CMakeString::Regex::Yes,
+                 &status.GetMakefile());
+    // Store the result in the provided variable.
+    status.GetMakefile().AddDefinition(outvar, data);
+    return true;
+  } catch (std::exception const& e) {
     status.SetError(
-      "sub-command REGEX, mode REPLACE: " + replaceHelper.GetError() + ".");
+      cmStrCat("sub-command REGEX, mode REPLACE: ", e.what(), '.'));
     return false;
   }
-
-  status.GetMakefile().ClearMatches();
-
-  if (!replaceHelper.IsRegularExpressionValid()) {
-    std::string e =
-      "sub-command REGEX, mode REPLACE failed to compile regex \"" + regex +
-      "\".";
-    status.SetError(e);
-    return false;
-  }
-
-  // Concatenate all the last arguments together.
-  std::string const input =
-    cmJoin(cmMakeRange(args).advance(5), std::string());
-  std::string output;
-
-  if (!replaceHelper.Replace(input, output)) {
-    status.SetError(
-      "sub-command REGEX, mode REPLACE: " + replaceHelper.GetError() + ".");
-    return false;
-  }
-
-  // Store the output in the provided variable.
-  status.GetMakefile().AddDefinition(outvar, output);
-  return true;
 }
 
 bool RegexQuote(std::vector<std::string> const& args,
@@ -371,21 +292,19 @@
 {
   //"STRING(REGEX QUOTE <output variable> <input> [<input>...]\n"
   std::string const& outvar = args[2];
-  std::string const input =
-    cmJoin(cmMakeRange(args).advance(3), std::string());
-  std::string output;
+  cm::CMakeString data{ cmMakeRange(args).advance(3) };
 
-  // Escape all regex special characters
-  cmStringReplaceHelper replaceHelper("([][()+*^.$?|\\\\])", R"(\\\1)");
-  if (!replaceHelper.Replace(input, output)) {
+  try {
+    // Escape all regex special characters
+    data.Quote();
+    // Store the output in the provided variable.
+    status.GetMakefile().AddDefinition(outvar, data);
+    return true;
+  } catch (std::exception const& e) {
     status.SetError(
-      "sub-command REGEX, mode QUOTE: " + replaceHelper.GetError() + ".");
+      cmStrCat("sub-command REGEX, mode QUOTE: ", e.what(), '.'));
     return false;
   }
-
-  // Store the output in the provided variable.
-  status.GetMakefile().AddDefinition(outvar, output);
-  return true;
 }
 
 bool HandleFindCommand(std::vector<std::string> const& args,
@@ -423,19 +342,14 @@
   }
 
   // try to find the character and return its position
-  size_t pos;
-  if (!reverseMode) {
-    pos = sstring.find(schar);
-  } else {
-    pos = sstring.rfind(schar);
-  }
-  if (std::string::npos != pos) {
-    status.GetMakefile().AddDefinition(outvar, std::to_string(pos));
-    return true;
-  }
+  auto pos = cm::CMakeString{ sstring }.Find(
+    schar,
+    reverseMode ? cm::CMakeString::FindFrom::End
+                : cm::CMakeString::FindFrom::Begin);
 
-  // the character was not found, but this is not really an error
-  status.GetMakefile().AddDefinition(outvar, "-1");
+  status.GetMakefile().AddDefinition(
+    outvar, pos != cm::CMakeString::npos ? std::to_string(pos) : "-1");
+
   return true;
 }
 
@@ -462,25 +376,22 @@
     std::string const& right = args[3];
     std::string const& outvar = args[4];
     bool result;
+    cm::CMakeString::CompOperator op = cm::CMakeString::CompOperator::EQUAL;
     if (mode == "LESS") {
-      result = (left < right);
+      op = cm::CMakeString::CompOperator::LESS;
     } else if (mode == "LESS_EQUAL") {
-      result = (left <= right);
+      op = cm::CMakeString::CompOperator::LESS_EQUAL;
     } else if (mode == "GREATER") {
-      result = (left > right);
+      op = cm::CMakeString::CompOperator::GREATER;
     } else if (mode == "GREATER_EQUAL") {
-      result = (left >= right);
-    } else if (mode == "EQUAL") {
-      result = (left == right);
-    } else // if(mode == "NOTEQUAL")
-    {
-      result = !(left == right);
+      op = cm::CMakeString::CompOperator::GREATER_EQUAL;
     }
-    if (result) {
-      status.GetMakefile().AddDefinition(outvar, "1");
-    } else {
-      status.GetMakefile().AddDefinition(outvar, "0");
+    result = cm::CMakeString{ left }.Compare(op, right);
+    if (mode == "NOTEQUAL") {
+      result = !result;
     }
+
+    status.GetMakefile().AddDefinition(outvar, result ? "1" : "0");
     return true;
   }
   std::string e = "sub-command COMPARE does not recognize mode " + mode;
@@ -496,17 +407,19 @@
     return false;
   }
 
-  std::string const& matchExpression = args[1];
-  std::string const& replaceExpression = args[2];
-  std::string const& variableName = args[3];
+  try {
+    std::string const& matchExpression = args[1];
+    std::string const& replaceExpression = args[2];
+    std::string const& variableName = args[3];
+    cm::CMakeString data{ cmMakeRange(args).advance(4) };
 
-  std::string input = cmJoin(cmMakeRange(args).advance(4), std::string());
-
-  cmsys::SystemTools::ReplaceString(input, matchExpression.c_str(),
-                                    replaceExpression.c_str());
-
-  status.GetMakefile().AddDefinition(variableName, input);
-  return true;
+    data.Replace(matchExpression, replaceExpression);
+    status.GetMakefile().AddDefinition(variableName, data);
+    return true;
+  } catch (std::exception const& e) {
+    status.SetError(cmStrCat("sub-command REPLACE: ", e.what(), '.'));
+    return false;
+  }
 }
 
 bool HandleSubstringCommand(std::vector<std::string> const& args,
@@ -517,25 +430,19 @@
     return false;
   }
 
-  std::string const& stringValue = args[1];
-  int begin = atoi(args[2].c_str());
-  int end = atoi(args[3].c_str());
-  std::string const& variableName = args[4];
+  try {
+    std::string const& stringValue = args[1];
+    int begin = atoi(args[2].c_str());
+    int end = atoi(args[3].c_str());
+    std::string const& variableName = args[4];
 
-  size_t stringLength = stringValue.size();
-  int intStringLength = static_cast<int>(stringLength);
-  if (begin < 0 || begin > intStringLength) {
-    status.SetError(
-      cmStrCat("begin index: ", begin, " is out of range 0 - ", stringLength));
+    cm::CMakeString data{ stringValue };
+    status.GetMakefile().AddDefinition(variableName,
+                                       data.Substring(begin, end));
+  } catch (std::exception const& e) {
+    status.SetError(e.what());
     return false;
   }
-  if (end < -1) {
-    status.SetError(cmStrCat("end index: ", end, " should be -1 or greater"));
-    return false;
-  }
-
-  status.GetMakefile().AddDefinition(variableName,
-                                     stringValue.substr(begin, end));
   return true;
 }
 
@@ -550,11 +457,8 @@
   std::string const& stringValue = args[1];
   std::string const& variableName = args[2];
 
-  size_t length = stringValue.size();
-  char buffer[1024];
-  snprintf(buffer, sizeof(buffer), "%d", static_cast<int>(length));
-
-  status.GetMakefile().AddDefinition(variableName, buffer);
+  status.GetMakefile().AddDefinition(
+    variableName, std::to_string(cm::CMakeString{ stringValue }.Length()));
   return true;
 }
 
@@ -572,12 +476,10 @@
   }
 
   auto const& variableName = args[1];
+  cm::CMakeString data{ status.GetMakefile().GetDefinition(variableName) };
 
-  cm::string_view oldView{ status.GetMakefile().GetSafeDefinition(
-    variableName) };
-
-  auto const newValue = cmJoin(cmMakeRange(args).advance(2), {}, oldView);
-  status.GetMakefile().AddDefinition(variableName, newValue);
+  data.Append(cmMakeRange(args).advance(2));
+  status.GetMakefile().AddDefinition(variableName, data);
 
   return true;
 }
@@ -596,13 +498,10 @@
   }
 
   std::string const& variable = args[1];
+  cm::CMakeString data{ status.GetMakefile().GetDefinition(variable) };
 
-  std::string value = cmJoin(cmMakeRange(args).advance(2), std::string());
-  cmValue oldValue = status.GetMakefile().GetDefinition(variable);
-  if (oldValue) {
-    value += *oldValue;
-  }
-  status.GetMakefile().AddDefinition(variable, value);
+  data.Prepend(cmMakeRange(args).advance(2));
+  status.GetMakefile().AddDefinition(variable, data);
   return true;
 }
 
@@ -634,9 +533,9 @@
   std::string const& variableName = args[varIdx];
   // NOTE Items to concat/join placed right after the variable for
   // both `CONCAT` and `JOIN` sub-commands.
-  std::string value = cmJoin(cmMakeRange(args).advance(varIdx + 1), glue);
+  cm::CMakeString data{ cmMakeRange(args).advance(varIdx + 1), glue };
 
-  makefile.AddDefinition(variableName, value);
+  makefile.AddDefinition(variableName, data);
   return true;
 }
 
@@ -652,7 +551,7 @@
   std::string const& variableName = args[2];
 
   status.GetMakefile().AddDefinition(variableName,
-                                     cmSystemTools::MakeCidentifier(input));
+                                     cm::CMakeString{}.MakeCIdentifier(input));
   return true;
 }
 
@@ -664,14 +563,11 @@
     return false;
   }
 
-  std::string const& input = args[1];
-
-  std::string result = cmGeneratorExpression::Preprocess(
-    input, cmGeneratorExpression::StripAllGeneratorExpressions);
-
+  cm::CMakeString data{ args[1] };
   std::string const& variableName = args[2];
 
-  status.GetMakefile().AddDefinition(variableName, result);
+  status.GetMakefile().AddDefinition(
+    variableName, data.Strip(cm::CMakeString::StripItems::Genex));
   return true;
 }
 
@@ -683,36 +579,10 @@
     return false;
   }
 
-  std::string const& stringValue = args[1];
+  cm::CMakeString data{ args[1] };
   std::string const& variableName = args[2];
-  size_t inStringLength = stringValue.size();
-  size_t startPos = inStringLength + 1;
-  size_t endPos = 0;
-  char const* ptr = stringValue.c_str();
-  size_t cc;
-  for (cc = 0; cc < inStringLength; ++cc) {
-    if (!cmIsSpace(*ptr)) {
-      if (startPos > inStringLength) {
-        startPos = cc;
-      }
-      endPos = cc;
-    }
-    ++ptr;
-  }
 
-  size_t outLength = 0;
-
-  // if the input string didn't contain any non-space characters, return
-  // an empty string
-  if (startPos > inStringLength) {
-    outLength = 0;
-    startPos = 0;
-  } else {
-    outLength = endPos - startPos + 1;
-  }
-
-  status.GetMakefile().AddDefinition(variableName,
-                                     stringValue.substr(startPos, outLength));
+  status.GetMakefile().AddDefinition(variableName, data.Strip());
   return true;
 }
 
@@ -744,30 +614,12 @@
     return true;
   }
 
-  auto const& stringValue = args[ArgPos::VALUE];
+  cm::CMakeString data{ args[ArgPos::VALUE] };
+  data.Repeat(times);
+
   auto const& variableName = args[ArgPos::OUTPUT_VARIABLE];
-  auto const inStringLength = stringValue.size();
 
-  std::string result;
-  switch (inStringLength) {
-    case 0u:
-      // Nothing to do for zero length input strings
-      break;
-    case 1u:
-      // NOTE If the string to repeat consists of the only character,
-      // use the appropriate constructor.
-      result = std::string(times, stringValue[0]);
-      break;
-    default:
-      result = std::string(inStringLength * times, char{});
-      for (auto i = 0u; i < times; ++i) {
-        std::copy(cm::cbegin(stringValue), cm::cend(stringValue),
-                  &result[i * inStringLength]);
-      }
-      break;
-  }
-
-  makefile.AddDefinition(variableName, result);
+  makefile.AddDefinition(variableName, data);
   return true;
 }
 
@@ -779,14 +631,10 @@
     return false;
   }
 
-  static bool seeded = false;
+  int length = 5;
+  cm::string_view alphabet;
   bool force_seed = false;
   unsigned int seed = 0;
-  int length = 5;
-  char const cmStringCommandDefaultAlphabet[] = "qwertyuiopasdfghjklzxcvbnm"
-                                                "QWERTYUIOPASDFGHJKLZXCVBNM"
-                                                "0123456789";
-  std::string alphabet;
 
   if (args.size() > 3) {
     size_t i = 1;
@@ -806,37 +654,22 @@
       }
     }
   }
-  if (alphabet.empty()) {
-    alphabet = cmStringCommandDefaultAlphabet;
-  }
 
-  double sizeofAlphabet = static_cast<double>(alphabet.size());
-  if (sizeofAlphabet < 1) {
-    status.SetError("sub-command RANDOM invoked with bad alphabet.");
+  try {
+    cm::CMakeString data;
+    std::string const& variableName = args.back();
+
+    if (force_seed) {
+      data.Random(seed, length, alphabet);
+    } else {
+      data.Random(length, alphabet);
+    }
+    status.GetMakefile().AddDefinition(variableName, data);
+    return true;
+  } catch (std::exception const& e) {
+    status.SetError(cmStrCat("sub-command RANDOM: ", e.what(), '.'));
     return false;
   }
-  if (length < 1) {
-    status.SetError("sub-command RANDOM invoked with bad length.");
-    return false;
-  }
-  std::string const& variableName = args.back();
-
-  std::vector<char> result;
-
-  if (!seeded || force_seed) {
-    seeded = true;
-    srand(force_seed ? seed : cmSystemTools::RandomSeed());
-  }
-
-  char const* alphaPtr = alphabet.c_str();
-  for (int cc = 0; cc < length; cc++) {
-    int idx = static_cast<int>(sizeofAlphabet * rand() / (RAND_MAX + 1.0));
-    result.push_back(*(alphaPtr + idx));
-  }
-  result.push_back(0);
-
-  status.GetMakefile().AddDefinition(variableName, result.data());
-  return true;
 }
 
 bool HandleTimestampCommand(std::vector<std::string> const& args,
@@ -855,26 +688,28 @@
 
   std::string const& outputVariable = args[argsIndex++];
 
-  std::string formatString;
+  cm::string_view formatString;
   if (args.size() > argsIndex && args[argsIndex] != "UTC") {
     formatString = args[argsIndex++];
   }
 
-  bool utcFlag = false;
+  cm::CMakeString::UTC utcFlag = cm::CMakeString::UTC::No;
   if (args.size() > argsIndex) {
     if (args[argsIndex] == "UTC") {
-      utcFlag = true;
+      utcFlag = cm::CMakeString::UTC::Yes;
     } else {
-      std::string e = " TIMESTAMP sub-command does not recognize option " +
-        args[argsIndex] + ".";
+      std::string e =
+        cmStrCat(" TIMESTAMP sub-command does not recognize option ",
+                 args[argsIndex], '.');
       status.SetError(e);
       return false;
     }
   }
 
-  cmTimestamp timestamp;
-  std::string result = timestamp.CurrentTime(formatString, utcFlag);
-  status.GetMakefile().AddDefinition(outputVariable, result);
+  cm::CMakeString data;
+
+  status.GetMakefile().AddDefinition(outputVariable,
+                                     data.Timestamp(formatString, utcFlag));
 
   return true;
 }
@@ -892,10 +727,10 @@
 
   std::string const& outputVariable = args[argsIndex++];
 
-  std::string uuidNamespaceString;
-  std::string uuidName;
-  std::string uuidType;
-  bool uuidUpperCase = false;
+  cm::string_view uuidNamespaceString;
+  cm::string_view uuidName;
+  cm::CMakeString::UUIDType uuidType = cm::CMakeString::UUIDType::MD5;
+  cm::CMakeString::Case uuidCase = cm::CMakeString::Case::Lower;
 
   while (args.size() > argsIndex) {
     if (args[argsIndex] == "NAMESPACE") {
@@ -918,50 +753,39 @@
         status.SetError("UUID sub-command, TYPE requires a value.");
         return false;
       }
-      uuidType = args[argsIndex++];
+      if (args[argsIndex] == "MD5") {
+        uuidType = cm::CMakeString::UUIDType::MD5;
+      } else if (args[argsIndex] == "SHA1") {
+        uuidType = cm::CMakeString::UUIDType::SHA1;
+      } else {
+        status.SetError(
+          cmStrCat("UUID sub-command, unknown TYPE '", args[argsIndex], "'."));
+        return false;
+      }
+      argsIndex++;
     } else if (args[argsIndex] == "UPPER") {
       ++argsIndex;
-      uuidUpperCase = true;
+      uuidCase = cm::CMakeString::Case::Upper;
     } else {
-      std::string e =
-        "UUID sub-command does not recognize option " + args[argsIndex] + ".";
+      std::string e = cmStrCat("UUID sub-command does not recognize option ",
+                               args[argsIndex], '.');
       status.SetError(e);
       return false;
     }
   }
 
-  std::string uuid;
-  cmUuid uuidGenerator;
+  try {
+    cm::CMakeString data;
 
-  std::vector<unsigned char> uuidNamespace;
-  if (!uuidGenerator.StringToBinary(uuidNamespaceString, uuidNamespace)) {
-    status.SetError("UUID sub-command, malformed NAMESPACE UUID.");
+    data.UUID(uuidNamespaceString, uuidName, uuidType, uuidCase);
+    status.GetMakefile().AddDefinition(outputVariable, data);
+    return true;
+  } catch (std::exception const& e) {
+    status.SetError(cmStrCat("UUID sub-command, ", e.what(), '.'));
     return false;
   }
-
-  if (uuidType == "MD5") {
-    uuid = uuidGenerator.FromMd5(uuidNamespace, uuidName);
-  } else if (uuidType == "SHA1") {
-    uuid = uuidGenerator.FromSha1(uuidNamespace, uuidName);
-  } else {
-    std::string e = "UUID sub-command, unknown TYPE '" + uuidType + "'.";
-    status.SetError(e);
-    return false;
-  }
-
-  if (uuid.empty()) {
-    status.SetError("UUID sub-command, generation failed.");
-    return false;
-  }
-
-  if (uuidUpperCase) {
-    uuid = cmSystemTools::UpperCase(uuid);
-  }
-
-  status.GetMakefile().AddDefinition(outputVariable, uuid);
-  return true;
 #else
-  status.SetError(cmStrCat(args[0], " not available during bootstrap"));
+  status.SetError("UUID sub-command not available during bootstrap.");
   return false;
 #endif
 }
@@ -1128,111 +952,122 @@
     }
 
     auto const& mode = args.PopFront("missing mode argument"_s);
-    if (mode != "GET"_s && mode != "TYPE"_s && mode != "MEMBER"_s &&
-        mode != "LENGTH"_s && mode != "REMOVE"_s && mode != "SET"_s &&
-        mode != "EQUAL"_s) {
-      throw json_error(
-        cmStrCat("got an invalid mode '"_s, mode,
-                 "', expected one of GET, TYPE, MEMBER, LENGTH, REMOVE, SET, "
-                 " EQUAL"_s));
+    if (mode != "GET"_s && mode != "GET_RAW"_s && mode != "TYPE"_s &&
+        mode != "MEMBER"_s && mode != "LENGTH"_s && mode != "REMOVE"_s &&
+        mode != "SET"_s && mode != "EQUAL"_s && mode != "STRING_ENCODE"_s) {
+      throw json_error(cmStrCat(
+        "got an invalid mode '"_s, mode,
+        "', expected one of GET, GET_RAW, TYPE, MEMBER, LENGTH, REMOVE, SET, "
+        " EQUAL, STRING_ENCODE"_s));
     }
 
     auto const& jsonstr = args.PopFront("missing json string argument"_s);
-    Json::Value json = ReadJson(jsonstr);
 
-    if (mode == "GET"_s) {
-      auto const& value = ResolvePath(json, args);
-      if (value.isObject() || value.isArray()) {
-        makefile.AddDefinition(*outputVariable, WriteJson(value));
-      } else if (value.isBool()) {
-        makefile.AddDefinitionBool(*outputVariable, value.asBool());
-      } else {
-        makefile.AddDefinition(*outputVariable, value.asString());
-      }
-
-    } else if (mode == "TYPE"_s) {
-      auto const& value = ResolvePath(json, args);
-      makefile.AddDefinition(*outputVariable, JsonTypeToString(value.type()));
-
-    } else if (mode == "MEMBER"_s) {
-      auto const& indexStr = args.PopBack("missing member index"_s);
-      auto const& value = ResolvePath(json, args);
-      if (!value.isObject()) {
-        throw json_error(
-          cmStrCat("MEMBER needs to be called with an element of "
-                   "type OBJECT, got "_s,
-                   JsonTypeToString(value.type())),
-          args);
-      }
-      auto const index = ParseIndex(
-        indexStr, Args{ args.begin(), args.end() + 1 }, value.size());
-      auto const memIt = std::next(value.begin(), index);
-      makefile.AddDefinition(*outputVariable, memIt.name());
-
-    } else if (mode == "LENGTH"_s) {
-      auto const& value = ResolvePath(json, args);
-      if (!value.isArray() && !value.isObject()) {
-        throw json_error(cmStrCat("LENGTH needs to be called with an "
-                                  "element of type ARRAY or OBJECT, got "_s,
-                                  JsonTypeToString(value.type())),
-                         args);
-      }
-
-      cmAlphaNum sizeStr{ value.size() };
-      makefile.AddDefinition(*outputVariable, sizeStr.View());
-
-    } else if (mode == "REMOVE"_s) {
-      auto const& toRemove =
-        args.PopBack("missing member or index to remove"_s);
-      auto& value = ResolvePath(json, args);
-
-      if (value.isArray()) {
-        auto const index = ParseIndex(
-          toRemove, Args{ args.begin(), args.end() + 1 }, value.size());
-        Json::Value removed;
-        value.removeIndex(index, &removed);
-
-      } else if (value.isObject()) {
-        Json::Value removed;
-        value.removeMember(toRemove, &removed);
-
-      } else {
-        throw json_error(cmStrCat("REMOVE needs to be called with an "
-                                  "element of type ARRAY or OBJECT, got "_s,
-                                  JsonTypeToString(value.type())),
-                         args);
-      }
+    if (mode == "STRING_ENCODE"_s) {
+      Json::Value json(jsonstr);
       makefile.AddDefinition(*outputVariable, WriteJson(json));
+    } else {
+      Json::Value json = ReadJson(jsonstr);
 
-    } else if (mode == "SET"_s) {
-      auto const& newValueStr = args.PopBack("missing new value remove"_s);
-      auto const& toAdd = args.PopBack("missing member name to add"_s);
-      auto& value = ResolvePath(json, args);
-
-      Json::Value newValue = ReadJson(newValueStr);
-      if (value.isObject()) {
-        value[toAdd] = newValue;
-      } else if (value.isArray()) {
-        auto const index =
-          ParseIndex(toAdd, Args{ args.begin(), args.end() + 1 });
-        if (value.isValidIndex(index)) {
-          value[static_cast<int>(index)] = newValue;
+      if (mode == "GET"_s) {
+        auto const& value = ResolvePath(json, args);
+        if (value.isObject() || value.isArray()) {
+          makefile.AddDefinition(*outputVariable, WriteJson(value));
+        } else if (value.isBool()) {
+          makefile.AddDefinitionBool(*outputVariable, value.asBool());
         } else {
-          value.append(newValue);
+          makefile.AddDefinition(*outputVariable, value.asString());
         }
-      } else {
-        throw json_error(cmStrCat("SET needs to be called with an "
-                                  "element of type OBJECT or ARRAY, got "_s,
-                                  JsonTypeToString(value.type())));
+
+      } else if (mode == "GET_RAW"_s) {
+        auto const& value = ResolvePath(json, args);
+        makefile.AddDefinition(*outputVariable, WriteJson(value));
+
+      } else if (mode == "TYPE"_s) {
+        auto const& value = ResolvePath(json, args);
+        makefile.AddDefinition(*outputVariable,
+                               JsonTypeToString(value.type()));
+
+      } else if (mode == "MEMBER"_s) {
+        auto const& indexStr = args.PopBack("missing member index"_s);
+        auto const& value = ResolvePath(json, args);
+        if (!value.isObject()) {
+          throw json_error(
+            cmStrCat("MEMBER needs to be called with an element of "
+                     "type OBJECT, got "_s,
+                     JsonTypeToString(value.type())),
+            args);
+        }
+        auto const index = ParseIndex(
+          indexStr, Args{ args.begin(), args.end() + 1 }, value.size());
+        auto const memIt = std::next(value.begin(), index);
+        makefile.AddDefinition(*outputVariable, memIt.name());
+
+      } else if (mode == "LENGTH"_s) {
+        auto const& value = ResolvePath(json, args);
+        if (!value.isArray() && !value.isObject()) {
+          throw json_error(cmStrCat("LENGTH needs to be called with an "
+                                    "element of type ARRAY or OBJECT, got "_s,
+                                    JsonTypeToString(value.type())),
+                           args);
+        }
+
+        cmAlphaNum sizeStr{ value.size() };
+        makefile.AddDefinition(*outputVariable, sizeStr.View());
+
+      } else if (mode == "REMOVE"_s) {
+        auto const& toRemove =
+          args.PopBack("missing member or index to remove"_s);
+        auto& value = ResolvePath(json, args);
+
+        if (value.isArray()) {
+          auto const index = ParseIndex(
+            toRemove, Args{ args.begin(), args.end() + 1 }, value.size());
+          Json::Value removed;
+          value.removeIndex(index, &removed);
+
+        } else if (value.isObject()) {
+          Json::Value removed;
+          value.removeMember(toRemove, &removed);
+
+        } else {
+          throw json_error(cmStrCat("REMOVE needs to be called with an "
+                                    "element of type ARRAY or OBJECT, got "_s,
+                                    JsonTypeToString(value.type())),
+                           args);
+        }
+        makefile.AddDefinition(*outputVariable, WriteJson(json));
+
+      } else if (mode == "SET"_s) {
+        auto const& newValueStr = args.PopBack("missing new value remove"_s);
+        auto const& toAdd = args.PopBack("missing member name to add"_s);
+        auto& value = ResolvePath(json, args);
+
+        Json::Value newValue = ReadJson(newValueStr);
+        if (value.isObject()) {
+          value[toAdd] = newValue;
+        } else if (value.isArray()) {
+          auto const index =
+            ParseIndex(toAdd, Args{ args.begin(), args.end() + 1 });
+          if (value.isValidIndex(index)) {
+            value[static_cast<int>(index)] = newValue;
+          } else {
+            value.append(newValue);
+          }
+        } else {
+          throw json_error(cmStrCat("SET needs to be called with an "
+                                    "element of type OBJECT or ARRAY, got "_s,
+                                    JsonTypeToString(value.type())));
+        }
+
+        makefile.AddDefinition(*outputVariable, WriteJson(json));
+
+      } else if (mode == "EQUAL"_s) {
+        auto const& jsonstr2 =
+          args.PopFront("missing second json string argument"_s);
+        Json::Value json2 = ReadJson(jsonstr2);
+        makefile.AddDefinitionBool(*outputVariable, json == json2);
       }
-
-      makefile.AddDefinition(*outputVariable, WriteJson(json));
-
-    } else if (mode == "EQUAL"_s) {
-      auto const& jsonstr2 =
-        args.PopFront("missing second json string argument"_s);
-      Json::Value json2 = ReadJson(jsonstr2);
-      makefile.AddDefinitionBool(*outputVariable, json == json2);
     }
 
   } catch (json_error const& e) {
diff --git a/Source/cmStringReplaceHelper.cxx b/Source/cmStringReplaceHelper.cxx
index 6dad0b0..0e18457 100644
--- a/Source/cmStringReplaceHelper.cxx
+++ b/Source/cmStringReplaceHelper.cxx
@@ -20,8 +20,7 @@
   this->ParseReplaceExpression();
 }
 
-bool cmStringReplaceHelper::Replace(std::string const& input,
-                                    std::string& output)
+bool cmStringReplaceHelper::Replace(cm::string_view input, std::string& output)
 {
   output.clear();
 
@@ -36,7 +35,7 @@
   auto& re = this->RegularExpression;
   std::string::size_type base = 0;
   unsigned optNonEmpty = 0;
-  while (re.find(input, base, optAnchor | optNonEmpty)) {
+  while (re.find(input.data(), base, optAnchor | optNonEmpty)) {
     if (this->Makefile) {
       this->Makefile->ClearMatches();
       this->Makefile->StoreMatches(re);
diff --git a/Source/cmStringReplaceHelper.h b/Source/cmStringReplaceHelper.h
index ffe9983..ef1c259 100644
--- a/Source/cmStringReplaceHelper.h
+++ b/Source/cmStringReplaceHelper.h
@@ -6,6 +6,8 @@
 #include <utility>
 #include <vector>
 
+#include <cm/string_view>
+
 #include "cmsys/RegularExpression.hxx"
 
 class cmMakefile;
@@ -25,7 +27,7 @@
     return this->ValidReplaceExpression;
   }
 
-  bool Replace(std::string const& input, std::string& output);
+  bool Replace(cm::string_view input, std::string& output);
 
   std::string const& GetError() { return this->ErrorString; }
 
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index ae050da..c0049ba 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -58,7 +58,6 @@
 #  include <cm3p/archive_entry.h>
 
 #  include "cmArchiveWrite.h"
-#  include "cmLocale.h"
 #  ifndef __LA_INT64_T
 #    define __LA_INT64_T la_int64_t
 #  endif
@@ -77,7 +76,6 @@
 
 #include <algorithm>
 #include <cassert>
-#include <cctype>
 #include <cerrno>
 #include <cstdint>
 #include <cstdio>
@@ -99,9 +97,12 @@
 #include <fcntl.h>
 
 #include "cmsys/Directory.hxx"
-#include "cmsys/Encoding.hxx"
+#ifdef _WIN32
+#  include "cmsys/Encoding.hxx"
+#endif
 #include "cmsys/FStream.hxx"
 #include "cmsys/RegularExpression.hxx"
+#include "cmsys/String.h"
 #include "cmsys/System.h"
 
 #if defined(_WIN32)
@@ -376,16 +377,28 @@
 #endif
 
 #if !defined(CMAKE_BOOTSTRAP)
-static std::string cm_archive_entry_pathname(struct archive_entry* entry)
+// Get path that was read from the archive.
+static char const* cm_archive_entry_pathname(struct archive_entry* entry)
 {
-  return cmsys::Encoding::ToNarrow(archive_entry_pathname_w(entry));
+#  ifdef _WIN32
+  // libarchive converts the archive's encoding to our UTF-8 encoding.
+  return archive_entry_pathname_utf8(entry);
+#  else
+  // libarchive converts the archive's encoding to our locale's encoding.
+  return archive_entry_pathname(entry);
+#  endif
 }
 
-static int cm_archive_read_open_file(struct archive* a, char const* file,
-                                     int block_size)
+// Open archive file for reading.
+static int cm_archive_read_open_filename(struct archive* a, char const* file,
+                                         int block_size)
 {
+#  ifdef _WIN32
   std::wstring wfile = cmsys::Encoding::ToWide(file);
   return archive_read_open_filename_w(a, wfile.c_str(), block_size);
+#  else
+  return archive_read_open_filename(a, file, block_size);
+#  endif
 }
 #endif
 
@@ -443,28 +456,6 @@
 }
 #endif
 
-// Return a lower case string
-std::string cmSystemTools::LowerCase(cm::string_view s)
-{
-  std::string n;
-  n.resize(s.size());
-  for (size_t i = 0; i < s.size(); i++) {
-    n[i] = static_cast<std::string::value_type>(tolower(s[i]));
-  }
-  return n;
-}
-
-// Return an upper case string
-std::string cmSystemTools::UpperCase(cm::string_view s)
-{
-  std::string n;
-  n.resize(s.size());
-  for (size_t i = 0; i < s.size(); i++) {
-    n[i] = static_cast<std::string::value_type>(toupper(s[i]));
-  }
-  return n;
-}
-
 std::string cmSystemTools::HelpFileName(cm::string_view str)
 {
   std::string name(str);
@@ -582,7 +573,7 @@
     } else {
       arg.append(backslashes, '\\');
       backslashes = 0;
-      if (cmIsSpace(*c)) {
+      if (cmsysString_isspace(*c)) {
         if (in_quotes) {
           arg.append(1, *c);
         } else if (in_argument) {
@@ -642,7 +633,7 @@
 {
   std::vector<std::string> arg_full;
   for (std::string const& arg : cmMakeRange(argBeg, argEnd)) {
-    if (cmHasLiteralPrefix(arg, "@")) {
+    if (cmHasPrefix(arg, '@')) {
       cmsys::ifstream responseFile(arg.substr(1).c_str(), std::ios::in);
       if (!responseFile) {
         std::string error = cmStrCat("failed to open for reading (",
@@ -741,7 +732,7 @@
   char const* c = command.c_str();
 
   // Skip leading whitespace.
-  while (cmIsSpace(*c)) {
+  while (cmsysString_isspace(*c)) {
     ++c;
   }
 
@@ -771,7 +762,7 @@
       in_double = true;
     } else if (*c == '\'') {
       in_single = true;
-    } else if (cmIsSpace(*c)) {
+    } else if (cmsysString_isspace(*c)) {
       break;
     } else {
       program += *c;
@@ -896,9 +887,7 @@
 
   std::vector<char> tempStdOut;
   std::vector<char> tempStdErr;
-  cm::uv_pipe_ptr outStream;
   bool outFinished = true;
-  cm::uv_pipe_ptr errStream;
   bool errFinished = true;
   cmProcessOutput processOutput(encoding);
   std::unique_ptr<cmUVStreamReadHandle> outputHandle;
@@ -906,21 +895,14 @@
   if (outputflag != OUTPUT_PASSTHROUGH &&
       (captureStdOut || captureStdErr || outputflag != OUTPUT_NONE)) {
     auto startRead =
-      [&outputflag, &processOutput,
-       &chain](cm::uv_pipe_ptr& pipe, int stream, std::string* captureStd,
-               std::vector<char>& tempStd, int id,
-               void (*outputFunc)(std::string const&),
-               bool& finished) -> std::unique_ptr<cmUVStreamReadHandle> {
-      if (stream < 0) {
-        return nullptr;
-      }
-
-      pipe.init(chain.GetLoop(), 0);
-      uv_pipe_open(pipe, stream);
-
+      [&outputflag, &processOutput](
+        uv_stream_t* stream, std::string* captureStd,
+        std::vector<char>& tempStd, int id,
+        void (*outputFunc)(std::string const&),
+        bool& finished) -> std::unique_ptr<cmUVStreamReadHandle> {
       finished = false;
       return cmUVStreamRead(
-        pipe,
+        stream,
         [outputflag, &processOutput, captureStd, &tempStd, id,
          outputFunc](std::vector<char> data) {
           // Translate NULL characters in the output into valid text.
@@ -951,13 +933,11 @@
         });
     };
 
-    outputHandle =
-      startRead(outStream, chain.OutputStream(), captureStdOut, tempStdOut, 1,
-                cmSystemTools::Stdout, outFinished);
-    if (chain.OutputStream() != chain.ErrorStream()) {
-      errorHandle =
-        startRead(errStream, chain.ErrorStream(), captureStdErr, tempStdErr, 2,
-                  cmSystemTools::Stderr, errFinished);
+    outputHandle = startRead(chain.OutputStream(), captureStdOut, tempStdOut,
+                             1, cmSystemTools::Stdout, outFinished);
+    if (chain.ErrorStream()) {
+      errorHandle = startRead(chain.ErrorStream(), captureStdErr, tempStdErr,
+                              2, cmSystemTools::Stderr, errFinished);
     }
   }
 
@@ -1359,7 +1339,7 @@
   }
   // Normalize to upper-case drive letter as cm::PathResolver does.
   if (resolved_path.size() > 1 && resolved_path[1] == ':') {
-    resolved_path[0] = toupper(resolved_path[0]);
+    resolved_path[0] = cmsysString_toupper(resolved_path[0]);
   }
   return resolved_path;
 #else
@@ -1381,10 +1361,10 @@
   // limitation to otherwise preserve susbt drives.
   if (resolved_path.size() >= 2 && resolved_path[1] == ':' &&
       path.size() >= 2 && path[1] == ':' &&
-      toupper(resolved_path[0]) != toupper(path[0])) {
+      cmsysString_toupper(resolved_path[0]) != cmsysString_toupper(path[0])) {
     // FIXME: Add thread_local or mutex if we use threads.
     static std::map<char, std::string> substMap;
-    char const drive = static_cast<char>(toupper(path[0]));
+    char const drive = static_cast<char>(cmsysString_toupper(path[0]));
     std::string maybe_subst = cmStrCat(drive, ":/");
     auto smi = substMap.find(drive);
     if (smi == substMap.end()) {
@@ -1646,20 +1626,6 @@
   return CopyResult::Success;
 }
 
-bool cmSystemTools::CopyFileIfNewer(std::string const& source,
-                                    std::string const& destination)
-{
-  return cmsys::SystemTools::CopyFileIfNewer(source, destination).IsSuccess();
-}
-
-bool cmSystemTools::CopyADirectory(std::string const& source,
-                                   std::string const& destination,
-                                   CopyWhen when)
-{
-  return cmsys::SystemTools::CopyADirectory(source, destination, when)
-    .IsSuccess();
-}
-
 bool cmSystemTools::RenameFile(std::string const& oldname,
                                std::string const& newname)
 {
@@ -1752,7 +1718,13 @@
   // On UNIX we have OS-provided calls to create 'newname' atomically.
   if (replace == Replace::No) {
     if (link(oldname.c_str(), newname.c_str()) == 0) {
-      return RenameResult::Success;
+      if (unlink(oldname.c_str()) == 0) {
+        return RenameResult::Success;
+      }
+      if (err) {
+        *err = cmsys::Status::POSIX_errno().GetString();
+      }
+      return RenameResult::Failure;
     }
     if (errno == EEXIST) {
       return RenameResult::NoReplace;
@@ -2036,7 +2008,7 @@
   if (in == top) {
     out = ".";
   } else if (cmSystemTools::IsSubDirectory(in, top)) {
-    out = in.substr(top.size() + 1);
+    out = in.substr(top.size() + (top.back() == '/' ? 0 : 1));
   } else {
     out = in;
   }
@@ -2387,12 +2359,13 @@
           cmHasLiteralSuffix(path, ".dylib"));
 }
 
-bool cmSystemTools::CreateTar(std::string const& outFileName,
+bool cmSystemTools::CreateTar(std::string const& arFileName,
                               std::vector<std::string> const& files,
                               std::string const& workingDirectory,
                               cmTarCompression compressType, bool verbose,
                               std::string const& mtime,
-                              std::string const& format, int compressionLevel)
+                              std::string const& format, int compressionLevel,
+                              int numThreads)
 {
 #if !defined(CMAKE_BOOTSTRAP)
   cmWorkingDirectory workdir(cmSystemTools::GetLogicalWorkingDirectory());
@@ -2401,9 +2374,9 @@
   }
 
   std::string const cwd = cmSystemTools::GetLogicalWorkingDirectory();
-  cmsys::ofstream fout(outFileName.c_str(), std::ios::out | std::ios::binary);
+  cmsys::ofstream fout(arFileName.c_str(), std::ios::out | std::ios::binary);
   if (!fout) {
-    std::string e = cmStrCat("Cannot open output file \"", outFileName,
+    std::string e = cmStrCat("Cannot open output file \"", arFileName,
                              "\": ", cmSystemTools::GetLastSystemError());
     cmSystemTools::Error(e);
     return false;
@@ -2422,13 +2395,29 @@
     case TarCompressZstd:
       compress = cmArchiveWrite::CompressZstd;
       break;
+    case TarCompressLZMA:
+      compress = cmArchiveWrite::CompressLZMA;
+      break;
+    case TarCompressPPMd:
+      compress = cmArchiveWrite::CompressPPMd;
+      break;
+    case TarCompressAuto:
+      // Kept for backwards compatibility with pre-4.3 versions of CMake
+      if (format == "zip") {
+        compress = cmArchiveWrite::CompressGZip;
+      } else if (format == "7zip") {
+        compress = cmArchiveWrite::CompressLZMA;
+      } else {
+        compress = cmArchiveWrite::CompressNone;
+      }
+      break;
     case TarCompressNone:
       compress = cmArchiveWrite::CompressNone;
       break;
   }
 
   cmArchiveWrite a(fout, compress, format.empty() ? "paxr" : format,
-                   compressionLevel);
+                   compressionLevel, numThreads);
 
   if (!a.Open()) {
     cmSystemTools::Error(a.GetError());
@@ -2449,7 +2438,7 @@
   }
   return tarCreatedSuccessfully;
 #else
-  (void)outFileName;
+  (void)arFileName;
   (void)files;
   (void)verbose;
   return false;
@@ -2548,7 +2537,7 @@
   }
   strftime(tmp, sizeof(tmp), fmt, localtime(&tim));
   fprintf(out, " %s ", tmp);
-  fprintf(out, "%s", cm_archive_entry_pathname(entry).c_str());
+  fprintf(out, "%s", cm_archive_entry_pathname(entry));
 
   /* Extra information for links. */
   if (archive_entry_hardlink(entry)) /* Hard link */
@@ -2629,15 +2618,26 @@
 #  endif
 }
 
-bool extract_tar(std::string const& outFileName,
+bool extract_tar(std::string const& arFileName,
                  std::vector<std::string> const& files, bool verbose,
                  cmSystemTools::cmTarExtractTimestamps extractTimestamps,
                  bool extract)
 {
-  cmLocaleRAII localeRAII;
-  static_cast<void>(localeRAII);
   struct archive* a = archive_read_new();
   struct archive* ext = archive_write_disk_new();
+  if (extract) {
+    int flags =
+      ARCHIVE_EXTRACT_SECURE_NODOTDOT | ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS;
+    if (extractTimestamps == cmSystemTools::cmTarExtractTimestamps::Yes) {
+      flags |= ARCHIVE_EXTRACT_TIME;
+    }
+    if (archive_write_disk_set_options(ext, flags) != ARCHIVE_OK) {
+      ArchiveError("Problem with archive_write_disk_set_options(): ", ext);
+      archive_write_free(ext);
+      archive_read_free(a);
+      return false;
+    }
+  }
   archive_read_support_filter_all(a);
   archive_read_support_format_all(a);
   struct archive_entry* entry;
@@ -2656,11 +2656,13 @@
     }
   }
 
-  int r = cm_archive_read_open_file(a, outFileName.c_str(), 10240);
+  int r = cm_archive_read_open_filename(a, arFileName.c_str(), 10240);
   if (r) {
-    ArchiveError("Problem with archive_read_open_file(): ", a);
+    ArchiveError("Problem with archive_read_open_filename(): ", a);
     archive_write_free(ext);
     archive_read_close(a);
+    archive_read_free(a);
+    archive_match_free(matching);
     return false;
   }
   for (;;) {
@@ -2689,14 +2691,6 @@
       cmSystemTools::Stdout(cmStrCat(cm_archive_entry_pathname(entry), '\n'));
     }
     if (extract) {
-      if (extractTimestamps == cmSystemTools::cmTarExtractTimestamps::Yes) {
-        r = archive_write_disk_set_options(ext, ARCHIVE_EXTRACT_TIME);
-        if (r != ARCHIVE_OK) {
-          ArchiveError("Problem with archive_write_disk_set_options(): ", ext);
-          break;
-        }
-      }
-
       r = archive_write_header(ext, entry);
       if (r == ARCHIVE_OK) {
         if (!copy_data(a, ext)) {
@@ -2717,8 +2711,8 @@
 #  endif
       else {
         ArchiveError("Problem with archive_write_header(): ", ext);
-        cmSystemTools::Error("Current file: " +
-                             cm_archive_entry_pathname(entry));
+        cmSystemTools::Error(
+          cmStrCat("Current file:\n  ", cm_archive_entry_pathname(entry)));
         break;
       }
     }
@@ -2752,15 +2746,15 @@
 }
 #endif
 
-bool cmSystemTools::ExtractTar(std::string const& outFileName,
+bool cmSystemTools::ExtractTar(std::string const& arFileName,
                                std::vector<std::string> const& files,
                                cmTarExtractTimestamps extractTimestamps,
                                bool verbose)
 {
 #if !defined(CMAKE_BOOTSTRAP)
-  return extract_tar(outFileName, files, verbose, extractTimestamps, true);
+  return extract_tar(arFileName, files, verbose, extractTimestamps, true);
 #else
-  (void)outFileName;
+  (void)arFileName;
   (void)files;
   (void)extractTimestamps;
   (void)verbose;
@@ -2768,15 +2762,15 @@
 #endif
 }
 
-bool cmSystemTools::ListTar(std::string const& outFileName,
+bool cmSystemTools::ListTar(std::string const& arFileName,
                             std::vector<std::string> const& files,
                             bool verbose)
 {
 #if !defined(CMAKE_BOOTSTRAP)
-  return extract_tar(outFileName, files, verbose, cmTarExtractTimestamps::Yes,
+  return extract_tar(arFileName, files, verbose, cmTarExtractTimestamps::Yes,
                      false);
 #else
-  (void)outFileName;
+  (void)arFileName;
   (void)files;
   (void)verbose;
   return false;
@@ -2785,8 +2779,7 @@
 
 cmSystemTools::WaitForLineResult cmSystemTools::WaitForLine(
   uv_loop_t* loop, uv_stream_t* outPipe, uv_stream_t* errPipe,
-  std::string& line, cmDuration timeout, std::vector<char>& out,
-  std::vector<char>& err)
+  std::string& line, std::vector<char>& out, std::vector<char>& err)
 {
   line.clear();
   auto outiter = out.begin();
@@ -2856,22 +2849,7 @@
     ReadData errData;
     auto errHandle = startRead(errPipe, errData);
 
-    cm::uv_timer_ptr timer;
-    bool timedOut = false;
-    timer.init(*loop, &timedOut);
-    timer.start(
-      [](uv_timer_t* handle) {
-        auto* timedOutPtr = static_cast<bool*>(handle->data);
-        *timedOutPtr = true;
-      },
-      static_cast<uint64_t>(timeout.count() * 1000.0), 0,
-      cm::uv_update_time::no);
-
     uv_run(loop, UV_RUN_ONCE);
-    if (timedOut) {
-      // Timeout has been exceeded.
-      return WaitForLineResult::Timeout;
-    }
     if (outData.Read) {
       processOutput.DecodeText(outData.Buffer.data(), outData.Buffer.size(),
                                strdata, 1);
@@ -3883,7 +3861,7 @@
 static size_t cm_strverscmp_find_digits_begin(char const* s, size_t i)
 {
   /* Step back until we are not preceded by a digit.  */
-  while (i > 0 && isdigit(s[i - 1])) {
+  while (i > 0 && cmsysString_isdigit(s[i - 1])) {
     --i;
   }
   return i;
@@ -3892,7 +3870,7 @@
 static size_t cm_strverscmp_find_digits_end(char const* s, size_t i)
 {
   /* Step forward over digits.  */
-  while (isdigit(s[i])) {
+  while (cmsysString_isdigit(s[i])) {
     ++i;
   }
   return i;
@@ -3902,7 +3880,7 @@
 {
   size_t i = b;
   /* Step forward over zeros that are followed by another digit.  */
-  while (s[i] == '0' && isdigit(s[i + 1])) {
+  while (s[i] == '0' && cmsysString_isdigit(s[i + 1])) {
     ++i;
   }
   return i - b;
@@ -3914,7 +3892,8 @@
   if (lhs[i] != rhs[i]) {
     /* The strings differ starting at 'i'.  Check for a digit sequence.  */
     size_t const b = cm_strverscmp_find_digits_begin(lhs, i);
-    if (b != i || (isdigit(lhs[i]) && isdigit(rhs[i]))) {
+    if (b != i ||
+        (cmsysString_isdigit(lhs[i]) && cmsysString_isdigit(rhs[i]))) {
       /* A digit sequence starts at 'b', preceding or at 'i'.  */
 
       /* Look for leading zeros, implying a leading decimal point.  */
@@ -4197,21 +4176,21 @@
   return newRPath.empty();
 }
 
-bool cmSystemTools::RepeatedRemoveDirectory(std::string const& dir)
+cmsys::Status cmSystemTools::RepeatedRemoveDirectory(std::string const& dir)
 {
 #ifdef _WIN32
   // Windows sometimes locks files temporarily so try a few times.
   WindowsFileRetry retry = cmSystemTools::GetWindowsFileRetry();
 
-  for (unsigned int i = 0; i < retry.Count; ++i) {
-    if (cmSystemTools::RemoveADirectory(dir)) {
-      return true;
-    }
+  cmsys::Status status;
+  unsigned int tries = 0;
+  while (!(status = cmSystemTools::RemoveADirectory(dir)) &&
+         ++tries < retry.Count) {
     cmSystemTools::Delay(retry.Delay);
   }
-  return false;
+  return status;
 #else
-  return static_cast<bool>(cmSystemTools::RemoveADirectory(dir));
+  return cmSystemTools::RemoveADirectory(dir);
 #endif
 }
 
@@ -4389,3 +4368,29 @@
   return ':';
 #endif
 }
+
+cm::string_view cmSystemTools::GetFilenameNameView(cm::string_view filename)
+{
+// implementation mostly taken from cmsys::SystemTools
+#if defined(_WIN32) || defined(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES)
+  cm::static_string_view separators = "/\\"_s;
+#else
+  char separators = '/';
+#endif
+  std::string::size_type slash_pos = filename.find_last_of(separators);
+  if (slash_pos == std::string::npos) {
+    return filename;
+  }
+  return filename.substr(slash_pos + 1);
+}
+
+cm::string_view cmSystemTools::GetFilenameLastExtensionView(
+  cm::string_view filename)
+{
+  cm::string_view name = cmSystemTools::GetFilenameNameView(filename);
+  cm::string_view::size_type dot_pos = name.rfind('.');
+  if (dot_pos == std::string::npos) {
+    return cm::string_view();
+  }
+  return name.substr(dot_pos);
+}
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 53b2592..c28a0b2 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -40,20 +40,22 @@
   using Superclass = cmsys::SystemTools;
   using Encoding = cmProcessOutput::Encoding;
 
-  /**
-   * Return a lower case string
-   */
-  static std::string LowerCase(cm::string_view);
+  /** Return a lower-case string.  */
+  static std::string LowerCase(cm::string_view s)
+  {
+    return cmsys::SystemTools::LowerCase(std::string(s));
+  }
   static std::string LowerCase(char const* s)
   {
     return LowerCase(cm::string_view{ s });
   }
   using cmsys::SystemTools::LowerCase;
 
-  /**
-   * Return an upper case string
-   */
-  static std::string UpperCase(cm::string_view);
+  /** Return an upper-case string.  */
+  static std::string UpperCase(cm::string_view s)
+  {
+    return cmsys::SystemTools::UpperCase(std::string(s));
+  }
   static std::string UpperCase(char const* s)
   {
     return UpperCase(cm::string_view{ s });
@@ -205,15 +207,6 @@
                                    CopyInputRecent inputRecent,
                                    std::string* err = nullptr);
 
-  /** Copy a file if it is newer than the destination. */
-  static bool CopyFileIfNewer(std::string const& source,
-                              std::string const& destination);
-
-  /** Copy directory contents with specified copy behavior. */
-  static bool CopyADirectory(std::string const& source,
-                             std::string const& destination,
-                             CopyWhen when = CopyWhen::Always);
-
   enum class Replace
   {
     Yes,
@@ -383,13 +376,11 @@
     None,
     STDOUT,
     STDERR,
-    Timeout,
   };
 
   /** a general output handler for libuv  */
   static WaitForLineResult WaitForLine(uv_loop_t* loop, uv_stream_t* outPipe,
                                        uv_stream_t* errPipe, std::string& line,
-                                       cmDuration timeout,
                                        std::vector<char>& out,
                                        std::vector<char>& err);
 
@@ -556,8 +547,11 @@
   {
     TarCompressGZip,
     TarCompressBZip2,
+    TarCompressLZMA,
     TarCompressXZ,
     TarCompressZstd,
+    TarCompressPPMd,
+    TarCompressAuto,
     TarCompressNone
   };
 
@@ -567,16 +561,16 @@
     No
   };
 
-  static bool ListTar(std::string const& outFileName,
+  static bool ListTar(std::string const& arFileName,
                       std::vector<std::string> const& files, bool verbose);
-  static bool CreateTar(std::string const& outFileName,
+  static bool CreateTar(std::string const& arFileName,
                         std::vector<std::string> const& files,
                         std::string const& workingDirectory,
                         cmTarCompression compressType, bool verbose,
                         std::string const& mtime = std::string(),
                         std::string const& format = std::string(),
-                        int compressionLevel = 0);
-  static bool ExtractTar(std::string const& inFileName,
+                        int compressionLevel = 0, int numThreads = 1);
+  static bool ExtractTar(std::string const& arFileName,
                          std::vector<std::string> const& files,
                          cmTarExtractTimestamps extractTimestamps,
                          bool verbose);
@@ -644,7 +638,7 @@
   static bool CheckRPath(std::string const& file, std::string const& newRPath);
 
   /** Remove a directory; repeat a few times in case of locked files.  */
-  static bool RepeatedRemoveDirectory(std::string const& dir);
+  static cmsys::Status RepeatedRemoveDirectory(std::string const& dir);
 
   /** Encode a string as a URL.  */
   static std::string EncodeURL(std::string const& in,
@@ -713,6 +707,16 @@
   /** Get the system path separator character */
   static char GetSystemPathlistSeparator();
 
+  /** Return subview of the full filename (i.e. file name without path) */
+  static cm::string_view GetFilenameNameView(cm::string_view filename);
+
+  /**
+   * Return subview of file extension of a full filename (dot included).
+   * Warning: this is the shortest extension (for example: .gz of .tar.gz)
+   */
+  static cm::string_view GetFilenameLastExtensionView(
+    cm::string_view filename);
+
 private:
   static bool s_ForceUnixPaths;
   static bool s_RunCommandHideConsole;
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 8539948..296adf5 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -473,6 +473,7 @@
   { "C_CPPCHECK"_s, IC::CanCompileSources },
   { "C_ICSTAT"_s, IC::CanCompileSources },
   { "C_INCLUDE_WHAT_YOU_USE"_s, IC::CanCompileSources },
+  { "C_PVS_STUDIO"_s, IC::CanCompileSources },
   // -- C++
   { "CXX_CLANG_TIDY"_s, IC::CanCompileSources },
   { "CXX_CLANG_TIDY_EXPORT_FIXES_DIR"_s, IC::CanCompileSources },
@@ -480,6 +481,7 @@
   { "CXX_CPPCHECK"_s, IC::CanCompileSources },
   { "CXX_ICSTAT"_s, IC::CanCompileSources },
   { "CXX_INCLUDE_WHAT_YOU_USE"_s, IC::CanCompileSources },
+  { "CXX_PVS_STUDIO"_s, IC::CanCompileSources },
   // -- Objective C
   { "OBJC_CLANG_TIDY"_s, IC::CanCompileSources },
   { "OBJC_CLANG_TIDY_EXPORT_FIXES_DIR"_s, IC::CanCompileSources },
@@ -498,6 +500,7 @@
   { "UNITY_BUILD_RELOCATABLE"_s, IC::CanCompileSources },
   { "OPTIMIZE_DEPENDENCIES"_s, IC::CanCompileSources },
   { "VERIFY_INTERFACE_HEADER_SETS"_s },
+  { "VERIFY_PRIVATE_HEADER_SETS"_s },
   // -- Android
   { "ANDROID_ANT_ADDITIONAL_OPTIONS"_s, IC::CanCompileSources },
   { "ANDROID_PROCESS_MAX"_s, IC::CanCompileSources },
@@ -1099,11 +1102,13 @@
   }
 
   for (auto const& prop : mf->GetState()->GetPropertyDefinitions().GetMap()) {
-    if (prop.first.second == cmProperty::TARGET &&
-        !prop.second.GetInitializeFromVariable().empty()) {
-      if (auto value =
-            mf->GetDefinition(prop.second.GetInitializeFromVariable())) {
-        this->SetProperty(prop.first.first, value);
+    auto iter = prop.second.find(cmProperty::TARGET);
+    if (iter != prop.second.end()) {
+      if (!iter->second.GetInitializeFromVariable().empty()) {
+        if (auto value =
+              mf->GetDefinition(iter->second.GetInitializeFromVariable())) {
+          this->SetProperty(prop.first, value);
+        }
       }
     }
   }
@@ -1809,6 +1814,7 @@
     "CXX_CPPCHECK",
     "CXX_ICSTAT",
     "CXX_INCLUDE_WHAT_YOU_USE",
+    "CXX_PVS_STUDIO",
     "SKIP_LINTING",
 
     // Build graph properties
@@ -3145,8 +3151,7 @@
   std::string const& name, std::string const& type, cmFileSetVisibility vis)
 {
   auto result = this->impl->FileSets.emplace(
-    name,
-    cmFileSet(*this->GetMakefile()->GetCMakeInstance(), name, type, vis));
+    name, cmFileSet(this->GetMakefile(), name, type, vis));
   if (result.second) {
     auto bt = this->impl->Makefile->GetBacktrace();
     if (type == this->impl->HeadersFileSets.TypeName) {
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
index 0d6cb7c..2c68392 100644
--- a/Source/cmTargetLinkLibrariesCommand.cxx
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -283,7 +283,7 @@
           if (cmHasLiteralPrefix(cur, "$<")) {
             ++genexNesting;
             ++pos;
-          } else if (genexNesting > 0 && cmHasLiteralPrefix(cur, ">")) {
+          } else if (genexNesting > 0 && cmHasPrefix(cur, '>')) {
             --genexNesting;
           }
         }
diff --git a/Source/cmTargetPrecompileHeadersCommand.cxx b/Source/cmTargetPrecompileHeadersCommand.cxx
index 5a57c06..7313089 100644
--- a/Source/cmTargetPrecompileHeadersCommand.cxx
+++ b/Source/cmTargetPrecompileHeadersCommand.cxx
@@ -28,7 +28,7 @@
     // Use '<foo.h>' and '"foo.h"' includes and absolute paths as-is.
     // Interpret relative paths with respect to the source directory.
     // If the path starts in a generator expression, assume it is absolute.
-    if (cmHasLiteralPrefix(src, "<") || cmHasLiteralPrefix(src, "\"") ||
+    if (cmHasPrefix(src, '<') || cmHasPrefix(src, '"') ||
         cmSystemTools::FileIsFullPath(src) ||
         cmGeneratorExpression::Find(src) == 0) {
       absoluteSrc = src;
diff --git a/Source/cmTargetTraceDependencies.cxx b/Source/cmTargetTraceDependencies.cxx
index b8f5ac6..5817978 100644
--- a/Source/cmTargetTraceDependencies.cxx
+++ b/Source/cmTargetTraceDependencies.cxx
@@ -6,6 +6,7 @@
 #include <utility>
 
 #include <cmext/algorithm>
+#include <cmext/string_view>
 
 #include "cmCustomCommand.h"
 #include "cmCustomCommandGenerator.h"
@@ -167,9 +168,11 @@
   // no output-name property which old code would not have set).  In
   // that case the target name will be the file basename of the
   // dependency.
-  std::string util = cmSystemTools::GetFilenameName(dep);
-  if (cmSystemTools::GetFilenameLastExtension(util) == ".exe") {
-    util = cmSystemTools::GetFilenameWithoutLastExtension(util);
+  std::string util;
+  if (cmHasSuffix(dep, ".exe"_s)) {
+    util = cmSystemTools::GetFilenameWithoutLastExtension(dep);
+  } else {
+    util = cmSystemTools::GetFilenameName(dep);
   }
 
   // Check for a target with this name.
diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx
index b76dd66..9c029f5 100644
--- a/Source/cmTimestamp.cxx
+++ b/Source/cmTimestamp.cxx
@@ -36,7 +36,7 @@
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
-std::string cmTimestamp::CurrentTime(std::string const& formatString,
+std::string cmTimestamp::CurrentTime(cm::string_view formatString,
                                      bool utcFlag) const
 {
   // get current time with microsecond resolution
@@ -63,11 +63,12 @@
   }
 
   return this->CreateTimestampFromTimeT(currentTimeT, microseconds,
-                                        formatString, utcFlag);
+                                        static_cast<std::string>(formatString),
+                                        utcFlag);
 }
 
 std::string cmTimestamp::FileModificationTime(char const* path,
-                                              std::string const& formatString,
+                                              cm::string_view formatString,
                                               bool utcFlag) const
 {
   std::string real_path =
@@ -89,8 +90,8 @@
   }
   uv_fs_req_cleanup(&req);
 
-  return this->CreateTimestampFromTimeT(mtime, microseconds, formatString,
-                                        utcFlag);
+  return this->CreateTimestampFromTimeT(
+    mtime, microseconds, static_cast<std::string>(formatString), utcFlag);
 }
 
 std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT,
diff --git a/Source/cmTimestamp.h b/Source/cmTimestamp.h
index 1057cc9..f6bff01 100644
--- a/Source/cmTimestamp.h
+++ b/Source/cmTimestamp.h
@@ -8,6 +8,8 @@
 #include <ctime>
 #include <string>
 
+#include <cm/string_view>
+
 /** \class cmTimestamp
  * \brief Utility class to generate string representation of a timestamp
  *
@@ -15,10 +17,10 @@
 class cmTimestamp
 {
 public:
-  std::string CurrentTime(std::string const& formatString, bool utcFlag) const;
+  std::string CurrentTime(cm::string_view formatString, bool utcFlag) const;
 
   std::string FileModificationTime(char const* path,
-                                   std::string const& formatString,
+                                   cm::string_view formatString,
                                    bool utcFlag) const;
 
   std::string CreateTimestampFromTimeT(time_t timeT, std::string formatString,
diff --git a/Source/cmTryCompileCommand.cxx b/Source/cmTryCompileCommand.cxx
index 40d3d8a..b830792 100644
--- a/Source/cmTryCompileCommand.cxx
+++ b/Source/cmTryCompileCommand.cxx
@@ -45,7 +45,8 @@
     return false;
   }
 
-  if (mf.GetCMakeInstance()->GetWorkingMode() == cmake::FIND_PACKAGE_MODE) {
+  if (mf.GetCMakeInstance()->GetState()->GetRole() ==
+      cmState::Role::FindPackage) {
     mf.IssueMessage(
       MessageType::FATAL_ERROR,
       "The try_compile() command is not supported in --find-package mode.");
diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx
index 0889ff0..5c46d7d 100644
--- a/Source/cmTryRunCommand.cxx
+++ b/Source/cmTryRunCommand.cxx
@@ -548,7 +548,8 @@
     return false;
   }
 
-  if (mf.GetCMakeInstance()->GetWorkingMode() == cmake::FIND_PACKAGE_MODE) {
+  if (mf.GetCMakeInstance()->GetState()->GetRole() ==
+      cmState::Role::FindPackage) {
     mf.IssueMessage(
       MessageType::FATAL_ERROR,
       "The try_run() command is not supported in --find-package mode.");
diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx
index 2462dab..05d9361 100644
--- a/Source/cmUVProcessChain.cxx
+++ b/Source/cmUVProcessChain.cxx
@@ -23,7 +23,7 @@
 {
   struct StreamData
   {
-    int BuiltinStream = -1;
+    cm::uv_pipe_ptr BuiltinStream;
     uv_stdio_container_t Stdio;
   };
 
@@ -219,6 +219,44 @@
       break;
   }
 
+  auto const& output =
+    this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT];
+  auto& outputData = this->OutputStreamData;
+  switch (output.Type) {
+    case cmUVProcessChainBuilder::None:
+      outputData.Stdio.flags = UV_IGNORE;
+      break;
+
+    case cmUVProcessChainBuilder::Builtin: {
+      int pipeFd[2];
+      if (cmGetPipes(pipeFd) < 0) {
+        return false;
+      }
+
+      if (outputData.BuiltinStream.init(*this->Loop, 0) < 0) {
+        return false;
+      }
+      if (uv_pipe_open(outputData.BuiltinStream, pipeFd[0]) < 0) {
+        return false;
+      }
+
+      if (this->TempOutputPipe.init(*this->Loop, 0) < 0) {
+        return false;
+      }
+      if (uv_pipe_open(this->TempOutputPipe, pipeFd[1]) < 0) {
+        return false;
+      }
+
+      outputData.Stdio.flags = UV_INHERIT_FD;
+      outputData.Stdio.data.fd = pipeFd[1];
+    } break;
+
+    case cmUVProcessChainBuilder::External:
+      outputData.Stdio.flags = UV_INHERIT_FD;
+      outputData.Stdio.data.fd = output.FileDescriptor;
+      break;
+  }
+
   auto const& error =
     this->Builder->Stdio[cmUVProcessChainBuilder::Stream_ERROR];
   auto& errorData = this->ErrorStreamData;
@@ -228,66 +266,37 @@
       break;
 
     case cmUVProcessChainBuilder::Builtin: {
-      int pipeFd[2];
-      if (cmGetPipes(pipeFd) < 0) {
-        return false;
-      }
-
-      errorData.BuiltinStream = pipeFd[0];
-      errorData.Stdio.flags = UV_INHERIT_FD;
-      errorData.Stdio.data.fd = pipeFd[1];
-
-      if (this->TempErrorPipe.init(*this->Loop, 0) < 0) {
-        return false;
-      }
-      if (uv_pipe_open(this->TempErrorPipe, errorData.Stdio.data.fd) < 0) {
-        return false;
-      }
-
-      break;
-    }
-
-    case cmUVProcessChainBuilder::External:
-      errorData.Stdio.flags = UV_INHERIT_FD;
-      errorData.Stdio.data.fd = error.FileDescriptor;
-      break;
-  }
-
-  auto const& output =
-    this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT];
-  auto& outputData = this->OutputStreamData;
-  switch (output.Type) {
-    case cmUVProcessChainBuilder::None:
-      outputData.Stdio.flags = UV_IGNORE;
-      break;
-
-    case cmUVProcessChainBuilder::Builtin:
       if (this->Builder->MergedBuiltinStreams) {
-        outputData.BuiltinStream = errorData.BuiltinStream;
-        outputData.Stdio.flags = UV_INHERIT_FD;
-        outputData.Stdio.data.fd = errorData.Stdio.data.fd;
+        errorData.Stdio.flags = UV_INHERIT_FD;
+        errorData.Stdio.data.fd = outputData.Stdio.data.fd;
       } else {
         int pipeFd[2];
         if (cmGetPipes(pipeFd) < 0) {
           return false;
         }
 
-        outputData.BuiltinStream = pipeFd[0];
-        outputData.Stdio.flags = UV_INHERIT_FD;
-        outputData.Stdio.data.fd = pipeFd[1];
+        if (errorData.BuiltinStream.init(*this->Loop, 0) < 0) {
+          return false;
+        }
+        if (uv_pipe_open(errorData.BuiltinStream, pipeFd[0]) < 0) {
+          return false;
+        }
 
-        if (this->TempOutputPipe.init(*this->Loop, 0) < 0) {
+        if (this->TempErrorPipe.init(*this->Loop, 0) < 0) {
           return false;
         }
-        if (uv_pipe_open(this->TempOutputPipe, outputData.Stdio.data.fd) < 0) {
+        if (uv_pipe_open(this->TempErrorPipe, pipeFd[1]) < 0) {
           return false;
         }
+
+        errorData.Stdio.flags = UV_INHERIT_FD;
+        errorData.Stdio.data.fd = pipeFd[1];
       }
-      break;
+    } break;
 
     case cmUVProcessChainBuilder::External:
-      outputData.Stdio.flags = UV_INHERIT_FD;
-      outputData.Stdio.data.fd = output.FileDescriptor;
+      errorData.Stdio.flags = UV_INHERIT_FD;
+      errorData.Stdio.data.fd = error.FileDescriptor;
       break;
   }
 
@@ -439,12 +448,12 @@
   return *this->Data->Loop;
 }
 
-int cmUVProcessChain::OutputStream()
+uv_stream_t* cmUVProcessChain::OutputStream()
 {
   return this->Data->OutputStreamData.BuiltinStream;
 }
 
-int cmUVProcessChain::ErrorStream()
+uv_stream_t* cmUVProcessChain::ErrorStream()
 {
   return this->Data->ErrorStreamData.BuiltinStream;
 }
diff --git a/Source/cmUVProcessChain.h b/Source/cmUVProcessChain.h
index 132c3a0..2116eb2 100644
--- a/Source/cmUVProcessChain.h
+++ b/Source/cmUVProcessChain.h
@@ -108,8 +108,8 @@
   uv_loop_t& GetLoop();
 
   // FIXME: Add stdin support
-  int OutputStream();
-  int ErrorStream();
+  uv_stream_t* OutputStream();
+  uv_stream_t* ErrorStream();
 
   bool Valid() const;
   bool Wait(uint64_t milliseconds = 0);
diff --git a/Source/cmUVStream.h b/Source/cmUVStream.h
index 5c581ca..55b0ea3 100644
--- a/Source/cmUVStream.h
+++ b/Source/cmUVStream.h
@@ -38,7 +38,7 @@
 
 template <typename CharT, typename Traits>
 cmBasicUVIStream<CharT, Traits>::cmBasicUVIStream(uv_stream_t* stream)
-  : cmBasicUVIStream()
+  : std::basic_istream<CharT, Traits>(&this->Buffer)
 {
   this->open(stream);
 }
@@ -63,50 +63,6 @@
 
 using cmUVIStream = cmBasicUVIStream<char>;
 
-template <typename CharT, typename Traits = std::char_traits<CharT>>
-class cmBasicUVPipeIStream : public cmBasicUVIStream<CharT, Traits>
-{
-public:
-  cmBasicUVPipeIStream();
-  cmBasicUVPipeIStream(uv_loop_t& loop, int fd);
-
-  using cmBasicUVIStream<CharT, Traits>::is_open;
-
-  void open(uv_loop_t& loop, int fd);
-
-  void close();
-
-private:
-  cm::uv_pipe_ptr Pipe;
-};
-
-template <typename CharT, typename Traits>
-cmBasicUVPipeIStream<CharT, Traits>::cmBasicUVPipeIStream() = default;
-
-template <typename CharT, typename Traits>
-cmBasicUVPipeIStream<CharT, Traits>::cmBasicUVPipeIStream(uv_loop_t& loop,
-                                                          int fd)
-{
-  this->open(loop, fd);
-}
-
-template <typename CharT, typename Traits>
-void cmBasicUVPipeIStream<CharT, Traits>::open(uv_loop_t& loop, int fd)
-{
-  this->Pipe.init(loop, 0);
-  uv_pipe_open(this->Pipe, fd);
-  this->cmBasicUVIStream<CharT, Traits>::open(this->Pipe);
-}
-
-template <typename CharT, typename Traits>
-void cmBasicUVPipeIStream<CharT, Traits>::close()
-{
-  this->cmBasicUVIStream<CharT, Traits>::close();
-  this->Pipe.reset();
-}
-
-using cmUVPipeIStream = cmBasicUVPipeIStream<char>;
-
 class cmUVStreamReadHandle
 {
 private:
diff --git a/Source/cmUnsetCommand.cxx b/Source/cmUnsetCommand.cxx
index 117118c..fdb1b06 100644
--- a/Source/cmUnsetCommand.cxx
+++ b/Source/cmUnsetCommand.cxx
@@ -30,7 +30,7 @@
   }
   // unset(CACHE{VAR})
   if (cmHasLiteralPrefix(variable, "CACHE{") && variable.size() > 7 &&
-      cmHasLiteralSuffix(variable, "}")) {
+      cmHasSuffix(variable, '}')) {
     // get the variable name
     auto const& varName = variable.substr(6, variable.size() - 7);
     status.GetMakefile().RemoveCacheDefinition(varName);
diff --git a/Source/cmUuid.cxx b/Source/cmUuid.cxx
index bc2ff59..4f1f9a3 100644
--- a/Source/cmUuid.cxx
+++ b/Source/cmUuid.cxx
@@ -10,7 +10,7 @@
 static std::array<int, 5> const kUuidGroups = { { 4, 2, 2, 2, 6 } };
 
 std::string cmUuid::FromMd5(std::vector<unsigned char> const& uuidNamespace,
-                            std::string const& name) const
+                            cm::string_view name) const
 {
   std::vector<unsigned char> hashInput;
   this->CreateHashInput(uuidNamespace, name, hashInput);
@@ -24,7 +24,7 @@
 }
 
 std::string cmUuid::FromSha1(std::vector<unsigned char> const& uuidNamespace,
-                             std::string const& name) const
+                             cm::string_view name) const
 {
   std::vector<unsigned char> hashInput;
   this->CreateHashInput(uuidNamespace, name, hashInput);
@@ -38,7 +38,7 @@
 }
 
 void cmUuid::CreateHashInput(std::vector<unsigned char> const& uuidNamespace,
-                             std::string const& name,
+                             cm::string_view name,
                              std::vector<unsigned char>& output) const
 {
   output = uuidNamespace;
@@ -46,7 +46,7 @@
   if (!name.empty()) {
     output.resize(output.size() + name.size());
 
-    memcpy(output.data() + uuidNamespace.size(), name.c_str(), name.size());
+    memcpy(output.data() + uuidNamespace.size(), name.data(), name.size());
   }
 }
 
@@ -67,7 +67,7 @@
   return this->BinaryToString(uuid);
 }
 
-bool cmUuid::StringToBinary(std::string const& input,
+bool cmUuid::StringToBinary(cm::string_view input,
                             std::vector<unsigned char>& output) const
 {
   output.clear();
@@ -126,7 +126,7 @@
   return result;
 }
 
-bool cmUuid::StringToBinaryImpl(std::string const& input,
+bool cmUuid::StringToBinaryImpl(cm::string_view input,
                                 std::vector<unsigned char>& output) const
 {
   if (input.size() % 2) {
diff --git a/Source/cmUuid.h b/Source/cmUuid.h
index cf51ece..f6d7067 100644
--- a/Source/cmUuid.h
+++ b/Source/cmUuid.h
@@ -7,6 +7,8 @@
 #include <string>
 #include <vector>
 
+#include <cm/string_view>
+
 /** \class cmUuid
  * \brief Utility class to generate UUIDs as defined by RFC4122
  *
@@ -15,25 +17,25 @@
 {
 public:
   std::string FromMd5(std::vector<unsigned char> const& uuidNamespace,
-                      std::string const& name) const;
+                      cm::string_view name) const;
 
   std::string FromSha1(std::vector<unsigned char> const& uuidNamespace,
-                       std::string const& name) const;
+                       cm::string_view name) const;
 
-  bool StringToBinary(std::string const& input,
+  bool StringToBinary(cm::string_view input,
                       std::vector<unsigned char>& output) const;
 
 private:
   std::string ByteToHex(unsigned char byte) const;
 
   void CreateHashInput(std::vector<unsigned char> const& uuidNamespace,
-                       std::string const& name,
+                       cm::string_view name,
                        std::vector<unsigned char>& output) const;
 
   std::string FromDigest(unsigned char const* digest,
                          unsigned char version) const;
 
-  bool StringToBinaryImpl(std::string const& input,
+  bool StringToBinaryImpl(cm::string_view input,
                           std::vector<unsigned char>& output) const;
 
   std::string BinaryToString(unsigned char const* input) const;
diff --git a/Source/cmVersion.h b/Source/cmVersion.h
index 47d56ac..8b562ad 100644
--- a/Source/cmVersion.h
+++ b/Source/cmVersion.h
@@ -2,6 +2,9 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #pragma once
 
+#include <string>
+#include <vector>
+
 /** \class cmVersion
  * \brief Helper class for providing CMake and CTest version information.
  *
@@ -10,6 +13,37 @@
 class cmVersion
 {
 public:
+  enum class DependencyType
+  {
+    System,
+    Bundled,
+  };
+
+  struct DependencyInfo
+  {
+    /**
+     * The name of the dependency.
+     * e.g. "curl", "libarchive", "zlib", etc.
+     */
+    std::string name;
+    /**
+     * The version of the dependency if available.
+     * e.g. "7.66.0", "3.8.0", "1.2.12", etc.
+     */
+    std::string version;
+
+    /**
+     * The type of the dependency.
+     */
+    DependencyType type;
+    /**
+     * The source of the dependency.
+     * e.g. "curl", "libarchive", etc.
+     * Empty if the dependency is directly passed from CMake.
+     */
+    std::string cameFrom;
+  };
+
   /**
    * Return major and minor version numbers for cmake.
    */
@@ -18,4 +52,6 @@
   static unsigned int GetPatchVersion();
   static unsigned int GetTweakVersion();
   static char const* GetCMakeVersion();
+
+  static std::vector<DependencyInfo> const& CollectDependencyInfo();
 };
diff --git a/Source/cmVersion_Dependencies.cxx b/Source/cmVersion_Dependencies.cxx
new file mode 100644
index 0000000..877bcdb
--- /dev/null
+++ b/Source/cmVersion_Dependencies.cxx
@@ -0,0 +1,363 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#include "cmVersion.h"
+
+#if !defined(CMAKE_BOOTSTRAP)
+#  include <cstddef>
+#  include <string>
+#  include <utility>
+#  include <vector>
+
+#  include <cm3p/archive.h>
+#  include <cm3p/curl/curl.h>
+#  include <cm3p/expat.h>
+#  include <cm3p/json/version.h>
+#  include <cm3p/kwiml/version.h>
+
+#  include "cmThirdParty.h" // IWYU pragma: keep
+
+#  ifdef CMAKE_USE_SYSTEM_LIBRHASH
+#    include <cstdint>
+
+#    include <cm3p/rhash.h>
+#  endif
+#  include <cm3p/uv.h>
+#  include <cm3p/zlib.h>
+
+#  include "cmStringAlgorithms.h"
+
+std::vector<cmVersion::DependencyInfo> const&
+cmVersion::CollectDependencyInfo()
+{
+  static std::vector<DependencyInfo> deps;
+  if (!deps.empty()) {
+    return deps;
+  }
+
+  // BZIP2 is not directly used in CMake, so it is not included here
+
+  // BZIP2 (libarchive)
+  {
+    char const* bzip2Version = archive_bzlib_version();
+    if (bzip2Version) {
+      DependencyInfo info;
+      info.name = "bzip2";
+      info.version = bzip2Version;
+      info.cameFrom = "libarchive";
+      size_t pos = info.version.find(',');
+      if (pos != std::string::npos) {
+        // Convert `1.0.8, 30-Mar-2009` to `1.0.8`
+        info.version.erase(pos);
+      }
+#  if defined(CMAKE_USE_SYSTEM_BZIP2) || defined(CMAKE_USE_SYSTEM_LIBARCHIVE)
+      // System BZIP2 can be used by system or bundled libarchive
+      // System libarchive always uses system BZIP2
+      info.type = DependencyType::System;
+#  else
+      info.type = DependencyType::Bundled;
+#  endif
+      deps.emplace_back(std::move(info));
+    }
+  }
+
+  // CPPDAP
+  {
+    DependencyInfo info;
+    info.name = "cppdap";
+#  ifdef CMAKE_USE_SYSTEM_CPPDAP
+    info.type = DependencyType::System;
+    // Cannot get runtime version from cppdap library
+#  else
+    info.type = DependencyType::Bundled;
+    // Hardcoded in protocol.h header file comments
+    info.version = "1.65.0";
+#  endif
+    deps.emplace_back(std::move(info));
+  }
+
+  // CURL
+  {
+    curl_version_info_data* curlVersion = curl_version_info(CURLVERSION_NOW);
+    if (curlVersion) {
+      // CURL itself
+      {
+        DependencyInfo info;
+        info.name = "curl";
+        if (curlVersion->version) {
+          info.version = curlVersion->version;
+        }
+#  ifdef CMAKE_USE_SYSTEM_CURL
+        info.type = DependencyType::System;
+#  else
+        info.type = DependencyType::Bundled;
+#  endif
+        deps.emplace_back(std::move(info));
+      }
+
+// Cannot use CURL_AT_LEAST_VERSION and CURL_VERSION_BITS macros,
+// because they needs at least curl 7.43.0,
+// but we support curl 7.29.0 from CentOS 7
+#  if LIBCURL_VERSION_NUM >= 0x074200
+      // NGHTTP2 (curl)
+      // Added in curl 7.66.0 (0x074200), CURLVERSION_SIXTH
+      if (curlVersion->age >= CURLVERSION_SIXTH &&
+          curlVersion->nghttp2_version) {
+        DependencyInfo info;
+        info.name = "nghttp2";
+        info.cameFrom = "curl";
+
+        info.version = curlVersion->nghttp2_version;
+
+#    if defined(CMAKE_USE_SYSTEM_NGHTTP2) || defined(CMAKE_USE_SYSTEM_CURL)
+        // System CURL always uses system NGHTTP2
+        // System NGHTTP2 can be used by system or bundled CURL
+        info.type = DependencyType::System;
+#    else
+        info.type = DependencyType::Bundled;
+#    endif
+        deps.emplace_back(std::move(info));
+      }
+#  endif
+
+      // OPENSSL (curl)
+      if (curlVersion->ssl_version) {
+        DependencyInfo info;
+        info.name = "ssl";
+        info.cameFrom = "curl";
+        info.version = curlVersion->ssl_version;
+
+        // With Multi-SSL, the version string is `OpenSSL/3.3.5,
+        // BoringSSL/3.3.5`, etc.
+        if (cmHasLiteralPrefix(info.version, "OpenSSL/") &&
+            info.version.find('/', 8) == std::string::npos) {
+          info.name = "openssl";
+          info.version.erase(0, 8);
+        }
+        // Bundled version of OpenSSL is not presented
+        // Multi-SSL can be used by system CURL only,
+        // so the SSL library is always system
+        info.type = DependencyType::System;
+        deps.emplace_back(std::move(info));
+      }
+
+      // ZLIB (curl)
+      if (curlVersion->libz_version) {
+        DependencyInfo info;
+        info.name = "zlib";
+        info.cameFrom = "curl";
+        info.version = curlVersion->libz_version;
+#  if defined(CMAKE_USE_SYSTEM_ZLIB) || defined(CMAKE_USE_SYSTEM_CURL)
+        // System CURL always uses system ZLIB
+        // System ZLIB can be used by system or bundled CURL
+        info.type = DependencyType::System;
+#  else
+        info.type = DependencyType::Bundled;
+#  endif
+        deps.emplace_back(std::move(info));
+      }
+    }
+  }
+
+  // EXPAT
+  {
+    DependencyInfo info;
+    info.name = "expat";
+
+    XML_Expat_Version version = XML_ExpatVersionInfo();
+    info.version =
+      cmStrCat(version.major, '.', version.minor, '.', version.micro);
+#  ifdef CMAKE_USE_SYSTEM_EXPAT
+    info.type = DependencyType::System;
+#  else
+    info.type = DependencyType::Bundled;
+#  endif
+    deps.emplace_back(std::move(info));
+  }
+
+  // FORM
+  {
+    DependencyInfo info;
+    info.name = "form";
+    // Cannot get any version from form library
+#  ifdef CMAKE_USE_SYSTEM_FORM
+    info.type = DependencyType::System;
+#  else
+    info.type = DependencyType::Bundled;
+#  endif
+    deps.emplace_back(std::move(info));
+  }
+
+  // JSONCPP
+  {
+    DependencyInfo info;
+    info.name = "jsoncpp";
+    info.version = JSONCPP_VERSION_STRING;
+#  ifdef CMAKE_USE_SYSTEM_JSONCPP
+    info.type = DependencyType::System;
+#  else
+    info.type = DependencyType::Bundled;
+#  endif
+    deps.emplace_back(std::move(info));
+  }
+
+  // KWIML
+  {
+    DependencyInfo info;
+    info.name = "kwiml";
+
+    // Library is header-only, so we can safely use the defined version
+    info.version = KWIML_VERSION_STRING;
+
+#  ifdef CMAKE_USE_SYSTEM_KWIML
+    info.type = DependencyType::System;
+#  else
+    info.type = DependencyType::Bundled;
+#  endif
+    deps.emplace_back(std::move(info));
+  }
+
+  // LIBARCHIVE
+  {
+    DependencyInfo info;
+    info.name = "libarchive";
+    info.version = archive_version_string();
+    if (cmHasLiteralPrefix(info.version, "libarchive ")) {
+      info.version.erase(0, 11);
+    }
+#  ifdef CMAKE_USE_SYSTEM_LIBARCHIVE
+    info.type = DependencyType::System;
+#  else
+    info.type = DependencyType::Bundled;
+#  endif
+    deps.emplace_back(std::move(info));
+  }
+
+  // LIBLZMA is not directly used in CMake, so it is not included here
+
+  // LIBLZMA (libarchive)
+  {
+    char const* liblzmaVersion = archive_liblzma_version();
+    if (liblzmaVersion) {
+      DependencyInfo info;
+      info.name = "liblzma";
+      info.cameFrom = "libarchive";
+      info.version = liblzmaVersion;
+#  if defined(CMAKE_USE_SYSTEM_LIBLZMA) || defined(CMAKE_USE_SYSTEM_LIBARCHIVE)
+      // System LIBLZMA can be used by system or bundled libarchive
+      // System libarchive always uses system LIBLZMA
+      info.type = DependencyType::System;
+#  else
+      info.type = DependencyType::Bundled;
+#  endif
+      deps.emplace_back(std::move(info));
+    }
+  }
+
+  // LIBRHASH
+  {
+    DependencyInfo info;
+    info.name = "librhash";
+#  ifdef CMAKE_USE_SYSTEM_LIBRHASH
+    info.type = DependencyType::System;
+    std::uint64_t version = rhash_get_version();
+    std::uint8_t major = (version >> 24) & 0xFFu;
+    std::uint8_t minor = (version >> 16) & 0xFFu;
+    std::uint8_t patch = (version >> 8) & 0xFFu;
+    info.version = cmStrCat(major, '.', minor, '.', patch);
+#  else
+    info.type = DependencyType::Bundled;
+    // Hardcoded in `update-librhash.bash` script
+    info.version = "1.4.4";
+#  endif
+    deps.emplace_back(std::move(info));
+  }
+
+  // LIBUV
+  {
+    DependencyInfo info;
+    info.name = "libuv";
+    info.version = uv_version_string();
+#  ifdef CMAKE_USE_SYSTEM_LIBUV
+    info.type = DependencyType::System;
+#  else
+    info.type = DependencyType::Bundled;
+#  endif
+    deps.emplace_back(std::move(info));
+  }
+
+  // OPENSSL is not directly used in CMake, so it is not included here
+
+#  if ARCHIVE_VERSION_NUMBER >= 3008000
+  // OPENSSL (libarchive)
+  // This function is available in libarchive 3.8.0 (3008000) and newer
+  {
+    char const* opensslVersion = archive_openssl_version();
+    if (opensslVersion) {
+      DependencyInfo info;
+      info.name = "openssl";
+      info.cameFrom = "libarchive";
+      info.version = opensslVersion;
+      // Bundled version of OpenSSL is not presented
+      info.type = DependencyType::System;
+      deps.emplace_back(std::move(info));
+    }
+  }
+#  endif
+
+  // ZLIB
+  {
+    DependencyInfo info;
+    info.name = "zlib";
+    info.version = zlibVersion();
+#  ifdef CMAKE_USE_SYSTEM_ZLIB
+    info.type = DependencyType::System;
+#  else
+    info.type = DependencyType::Bundled;
+#  endif
+    deps.emplace_back(std::move(info));
+  }
+
+  // ZLIB (libarchive)
+  {
+    char const* zlibVersion = archive_zlib_version();
+    if (zlibVersion) {
+      DependencyInfo info;
+      info.name = "zlib";
+      info.cameFrom = "libarchive";
+      info.version = zlibVersion;
+#  if defined(CMAKE_USE_SYSTEM_ZLIB) || defined(CMAKE_USE_SYSTEM_LIBARCHIVE)
+      // System ZLIB can be used by system or bundled libarchive
+      // System libarchive always uses system ZLIB
+      info.type = DependencyType::System;
+#  else
+      info.type = DependencyType::Bundled;
+#  endif
+      deps.emplace_back(std::move(info));
+    }
+  }
+
+  // ZSTD is not directly used in CMake, so it is not included here
+
+  // ZSTD (libarchive)
+  {
+    char const* zstdVersion = archive_libzstd_version();
+    if (zstdVersion) {
+      DependencyInfo info;
+      info.name = "zstd";
+      info.cameFrom = "libarchive";
+      info.version = zstdVersion;
+#  if defined(CMAKE_USE_SYSTEM_ZSTD) || defined(CMAKE_USE_SYSTEM_LIBARCHIVE)
+      // System ZSTD can be used by system or bundled libarchive
+      // System libarchive always uses system ZSTD
+      info.type = DependencyType::System;
+#  else
+      info.type = DependencyType::Bundled;
+#  endif
+      deps.emplace_back(std::move(info));
+    }
+  }
+
+  return deps;
+}
+
+#endif
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index ddbdd6c..364fd56 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -1998,29 +1998,24 @@
     return;
   }
 
-  // collect up group information
-  std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
-
   std::vector<cmGeneratorTarget::AllConfigSource> const& sources =
     this->GeneratorTarget->GetAllConfigSources();
 
   std::set<cmSourceGroup const*> groupsUsed;
   for (cmGeneratorTarget::AllConfigSource const& si : sources) {
     std::string const& source = si.Source->GetFullPath();
-    cmSourceGroup* sourceGroup =
-      this->Makefile->FindSourceGroup(source, sourceGroups);
+    cmSourceGroup* sourceGroup = this->LocalGenerator->FindSourceGroup(source);
     groupsUsed.insert(sourceGroup);
   }
 
   if (cmSourceFile const* srcCMakeLists =
         this->LocalGenerator->CreateVCProjBuildRule()) {
     std::string const& source = srcCMakeLists->GetFullPath();
-    cmSourceGroup* sourceGroup =
-      this->Makefile->FindSourceGroup(source, sourceGroups);
+    cmSourceGroup* sourceGroup = this->LocalGenerator->FindSourceGroup(source);
     groupsUsed.insert(sourceGroup);
   }
 
-  this->AddMissingSourceGroups(groupsUsed, sourceGroups);
+  this->AddMissingSourceGroups(groupsUsed, this->Makefile->GetSourceGroups());
 
   // Write out group file
   std::string path = cmStrCat(
@@ -2040,7 +2035,7 @@
                  "http://schemas.microsoft.com/developer/msbuild/2003");
 
     for (auto const& ti : this->Tools) {
-      this->WriteGroupSources(e0, ti.first, ti.second, sourceGroups);
+      this->WriteGroupSources(e0, ti.first, ti.second);
     }
 
     // Added files are images and the manifest.
@@ -2135,17 +2130,17 @@
 // Add to groupsUsed empty source groups that have non-empty children.
 void cmVisualStudio10TargetGenerator::AddMissingSourceGroups(
   std::set<cmSourceGroup const*>& groupsUsed,
-  std::vector<cmSourceGroup> const& allGroups)
+  SourceGroupVector const& allGroups)
 {
-  for (cmSourceGroup const& current : allGroups) {
-    std::vector<cmSourceGroup> const& children = current.GetGroupChildren();
+  for (auto const& current : allGroups) {
+    SourceGroupVector const& children = current->GetGroupChildren();
     if (children.empty()) {
       continue; // the group is really empty
     }
 
     this->AddMissingSourceGroups(groupsUsed, children);
 
-    if (groupsUsed.count(&current) > 0) {
+    if (groupsUsed.count(current.get()) > 0) {
       continue; // group has already been added to set
     }
 
@@ -2153,31 +2148,29 @@
     // (at least one child must already have been added)
     auto child_it = children.begin();
     while (child_it != children.end()) {
-      if (groupsUsed.count(&(*child_it)) > 0) {
+      if (groupsUsed.count(child_it->get()) > 0) {
         break; // found a child that was already added => add current group too
       }
-      child_it++;
+      ++child_it;
     }
 
     if (child_it == children.end()) {
       continue; // no descendants have source files => ignore this group
     }
 
-    groupsUsed.insert(&current);
+    groupsUsed.insert(current.get());
   }
 }
 
 void cmVisualStudio10TargetGenerator::WriteGroupSources(
-  Elem& e0, std::string const& name, ToolSources const& sources,
-  std::vector<cmSourceGroup>& sourceGroups)
+  Elem& e0, std::string const& name, ToolSources const& sources)
 {
   Elem e1(e0, "ItemGroup");
   e1.SetHasElements();
   for (ToolSource const& s : sources) {
     cmSourceFile const* sf = s.SourceFile;
     std::string const& source = sf->GetFullPath();
-    cmSourceGroup* sourceGroup =
-      this->Makefile->FindSourceGroup(source, sourceGroups);
+    cmSourceGroup* sourceGroup = this->LocalGenerator->FindSourceGroup(source);
     std::string const& filter = sourceGroup->GetFullName();
     std::string path = this->ConvertPath(source, s.RelativePath);
     ConvertToWindowsSlash(path);
@@ -2842,9 +2835,9 @@
   // Force language if the file extension does not match.
   // Note that MSVC treats the upper-case '.C' extension as C and not C++.
   std::string const ext = sf.GetExtension();
-  std::string const extLang = ext == "C"_s
-    ? "C"
-    : this->GlobalGenerator->GetLanguageFromExtension(ext.c_str());
+  cm::string_view const extLang = ext == "C"_s
+    ? "C"_s
+    : this->GlobalGenerator->GetLanguageFromExtension(ext);
   std::string lang = this->LocalGenerator->GetSourceFileLanguage(sf);
   char const* compileAs = nullptr;
   if (lang != extLang) {
@@ -3884,7 +3877,8 @@
   auto cudaVersion = this->GlobalGenerator->GetPlatformToolsetCudaString();
 
   // Get compile flags for CUDA in this directory.
-  std::string flags;
+  std::string flags =
+    this->Makefile->GetSafeDefinition("_CMAKE_CUDA_EXTRA_FLAGS");
   this->LocalGenerator->AddLanguageFlags(
     flags, this->GeneratorTarget, cmBuildStep::Compile, "CUDA", configName);
   this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, "CUDA",
@@ -4547,29 +4541,15 @@
     return false;
   }
 
-  std::string CONFIG = cmSystemTools::UpperCase(config);
-
-  char const* linkType = "SHARED";
-  if (this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) {
-    linkType = "MODULE";
-  }
-  if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
-    linkType = "EXE";
-  }
   std::string flags;
-  this->LocalGenerator->AddConfigVariableFlags(
-    flags, cmStrCat("CMAKE_", linkType, "_LINKER_FLAGS"),
-    this->GeneratorTarget, cmBuildStep::Link, linkLanguage, config);
-  cmValue targetLinkFlags = this->GeneratorTarget->GetProperty("LINK_FLAGS");
-  if (targetLinkFlags) {
-    flags += ' ';
-    flags += *targetLinkFlags;
-  }
-  std::string flagsProp = cmStrCat("LINK_FLAGS_", CONFIG);
-  if (cmValue flagsConfig = this->GeneratorTarget->GetProperty(flagsProp)) {
-    flags += ' ';
-    flags += *flagsConfig;
-  }
+  this->LocalGenerator->AddTargetTypeLinkerFlags(flags, this->GeneratorTarget,
+                                                 linkLanguage, config);
+
+  this->LocalGenerator->AddPerLanguageLinkFlags(flags, this->GeneratorTarget,
+                                                linkLanguage, config);
+
+  this->LocalGenerator->AddTargetPropertyLinkFlags(
+    flags, this->GeneratorTarget, config);
 
   std::vector<std::string> opts;
   this->GeneratorTarget->GetLinkOptions(opts, config, linkLanguage);
@@ -6051,11 +6031,8 @@
   std::string const& fullFileName = source->GetFullPath();
   std::string const& srcDir = this->Makefile->GetCurrentSourceDirectory();
   std::string const& binDir = this->Makefile->GetCurrentBinaryDirectory();
-  // unfortunately we have to copy the source groups, because
-  // FindSourceGroup uses a regex which is modifying the group
-  std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
   cmSourceGroup* sourceGroup =
-    this->Makefile->FindSourceGroup(fullFileName, sourceGroups);
+    this->LocalGenerator->FindSourceGroup(fullFileName);
   if (sourceGroup && !sourceGroup->GetFullName().empty()) {
     sourceGroupedFile =
       cmStrCat(sourceGroup->GetFullName(), '/',
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 1bfc929..1cb35c7 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -14,6 +14,7 @@
 #include <vector>
 
 #include "cmGeneratorTarget.h"
+#include "cmSourceGroup.h"
 #include "cmVsProjectType.h"
 
 class cmComputeLinkInformation;
@@ -202,10 +203,9 @@
                           std::vector<cmCustomCommand> const& commands,
                           std::string const& configName);
   void WriteGroupSources(Elem& e0, std::string const& name,
-                         ToolSources const& sources,
-                         std::vector<cmSourceGroup>&);
+                         ToolSources const& sources);
   void AddMissingSourceGroups(std::set<cmSourceGroup const*>& groupsUsed,
-                              std::vector<cmSourceGroup> const& allGroups);
+                              SourceGroupVector const& allGroups);
   bool IsResxHeader(std::string const& headerFile);
   bool IsXamlHeader(std::string const& headerFile);
   bool IsXamlSource(std::string const& headerFile);
diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx
index 5f10e02..2cae6b4 100644
--- a/Source/cmVisualStudioGeneratorOptions.cxx
+++ b/Source/cmVisualStudioGeneratorOptions.cxx
@@ -151,7 +151,7 @@
 
 void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration()
 {
-  // Create an empty CodeGeneration field, and pass the the actual
+  // Create an empty CodeGeneration field, and pass the actual
   // compile flags via additional options so that we have consistent
   // behavior and avoid issues with MSBuild extensions injecting
   // virtual code when we request real only.
diff --git a/Source/cmWindowsRegistry.cxx b/Source/cmWindowsRegistry.cxx
index 154e6d9..ecce2f5 100644
--- a/Source/cmWindowsRegistry.cxx
+++ b/Source/cmWindowsRegistry.cxx
@@ -4,7 +4,6 @@
 
 #include "cmWindowsRegistry.h"
 
-#include <cctype>
 #include <cstddef>
 #include <type_traits>
 #include <unordered_map>
@@ -13,6 +12,7 @@
 #include <cmext/string_view>
 
 #include "cmsys/RegularExpression.hxx"
+#include "cmsys/String.h"
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
 #  include <algorithm>
@@ -47,8 +47,8 @@
   cm::string_view::size_type ri = 0;
 
   do {
-    lc = std::tolower(l[li++]);
-    rc = std::tolower(r[ri++]);
+    lc = cmsysString_tolower(l[li++]);
+    rc = cmsysString_tolower(r[ri++]);
   } while (lc == rc && li < l.size() && ri < r.size());
 
   return lc == rc ? static_cast<int>(l.size() - r.size()) : lc - rc;
diff --git a/Source/cmXMLWriter.h b/Source/cmXMLWriter.h
index e15542d..16b9b60 100644
--- a/Source/cmXMLWriter.h
+++ b/Source/cmXMLWriter.h
@@ -12,6 +12,7 @@
 #include <string>
 #include <vector>
 
+#include "cmDuration.h"
 #include "cmXMLSafe.h"
 
 class cmXMLWriter
@@ -113,6 +114,9 @@
     return std::chrono::system_clock::to_time_t(value);
   }
 
+  /* Some code paths use time_since_epoch despite the unspecified epoch.  */
+  static double SafeContent(cmDuration value) { return value.count(); }
+
   template <typename T>
   static T SafeContent(T value)
   {
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 1cc9f5d..3b311e0 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -4,7 +4,9 @@
 
 #include <algorithm>
 #include <array>
+#include <cassert>
 #include <chrono>
+#include <climits>
 #include <cstdio>
 #include <cstdlib>
 #include <initializer_list>
@@ -297,13 +299,13 @@
     "not errors." }
 };
 
-cmake::cmake(Role role, cmState::Mode mode, cmState::ProjectKind projectKind)
+cmake::cmake(cmState::Role role, cmState::TryCompile isTryCompile)
   : CMakeWorkingDirectory(cmSystemTools::GetLogicalWorkingDirectory())
   , FileTimeCache(cm::make_unique<cmFileTimeCache>())
 #ifndef CMAKE_BOOTSTRAP
   , VariableWatch(cm::make_unique<cmVariableWatch>())
 #endif
-  , State(cm::make_unique<cmState>(mode, projectKind))
+  , State(cm::make_unique<cmState>(role, isTryCompile))
   , Messenger(cm::make_unique<cmMessenger>())
 {
   this->TraceFile.close();
@@ -321,14 +323,16 @@
 
   this->AddDefaultGenerators();
   this->AddDefaultExtraGenerators();
-  if (role == RoleScript || role == RoleProject) {
+  if (role == cmState::Role::Project || role == cmState::Role::FindPackage ||
+      role == cmState::Role::Script || role == cmState::Role::CTest ||
+      role == cmState::Role::CPack) {
     this->AddScriptingCommands();
   }
-  if (role == RoleProject) {
+  if (role == cmState::Role::Project || role == cmState::Role::FindPackage) {
     this->AddProjectCommands();
   }
 
-  if (mode == cmState::Project || mode == cmState::Help) {
+  if (role == cmState::Role::Project || role == cmState::Role::Help) {
     this->LoadEnvironmentPresets();
   }
 
@@ -448,6 +452,23 @@
   return result;
 }
 
+bool cmake::RoleSupportsExitCode() const
+{
+  cmState::Role const role = this->State->GetRole();
+  return role == cmState::Role::Script || role == cmState::Role::CTest;
+}
+
+cmake::CommandFailureAction cmake::GetCommandFailureAction() const
+{
+  switch (this->State->GetRole()) {
+    case cmState::Role::Project:
+    case cmState::Role::CTest:
+      return CommandFailureAction::EXIT_CODE;
+    default:
+      return CommandFailureAction::FATAL_ERROR;
+  }
+}
+
 void cmake::CleanupCommandsAndMacros()
 {
   this->CurrentSnapshot = this->State->Reset();
@@ -652,6 +673,7 @@
   };
 
   auto ScriptLambda = [&](std::string const& path, cmake* state) -> bool {
+    assert(this->State->GetRole() == cmState::Role::Script);
 #ifdef CMake_ENABLE_DEBUGGER
     // Script mode doesn't hit the usual code path in cmake::Run() that starts
     // the debugger, so start it manually here instead.
@@ -663,8 +685,6 @@
     GetProjectCommandsInScriptMode(state->GetState());
     // Documented behavior of CMAKE{,_CURRENT}_{SOURCE,BINARY}_DIR is to be
     // set to $PWD for -P mode.
-    state->SetWorkingMode(SCRIPT_MODE,
-                          cmake::CommandFailureAction::FATAL_ERROR);
     state->SetHomeDirectory(cmSystemTools::GetLogicalWorkingDirectory());
     state->SetHomeOutputDirectory(cmSystemTools::GetLogicalWorkingDirectory());
     state->ReadListFile(args, cmSystemTools::ToNormalizedPathOnDisk(path));
@@ -714,13 +734,15 @@
           cmSystemTools::Error("No file name specified for -C");
           return false;
         }
-        cmSystemTools::Stdout("loading initial cache file " + value + "\n");
+        state->SetInInitialCache(true);
+        cmSystemTools::Stdout(
+          cmStrCat("loading initial cache file ", value, '\n'));
         // Resolve script path specified on command line
         // relative to $PWD.
         auto path = cmSystemTools::ToNormalizedPathOnDisk(value);
         state->InitializeFileAPI();
-        state->InitializeInstrumentation();
         state->ReadListFile(args, path);
+        state->SetInInitialCache(false);
         return true;
       } },
 
@@ -738,7 +760,7 @@
   for (decltype(args.size()) i = 1; i < args.size(); ++i) {
     std::string const& arg = args[i];
 
-    if (arg == "--" && this->GetWorkingMode() == SCRIPT_MODE) {
+    if (arg == "--" && this->State->GetRole() == cmState::Role::Script) {
       // Stop processing CMake args and avoid possible errors
       // when arbitrary args are given to CMake script.
       break;
@@ -753,7 +775,7 @@
     }
   }
 
-  if (this->GetWorkingMode() == FIND_PACKAGE_MODE) {
+  if (this->State->GetRole() == cmState::Role::FindPackage) {
     return this->FindPackage(args);
   }
 
@@ -807,7 +829,7 @@
     snapshot.GetDirectory().SetCurrentSource(this->GetHomeDirectory());
     snapshot.SetDefaultDefinitions();
     cmMakefile mf(gg, snapshot);
-    if (this->GetWorkingMode() != NORMAL_MODE) {
+    if (this->State->GetRole() == cmState::Role::Script) {
       mf.SetScriptModeFile(path);
       mf.SetArgcArgv(args);
     }
@@ -1429,7 +1451,7 @@
     // iterate each argument
     std::string const& arg = args[i];
 
-    if (this->GetWorkingMode() == SCRIPT_MODE && arg == "--") {
+    if (this->State->GetRole() == cmState::Role::Script && arg == "--") {
       // Stop processing CMake args and avoid possible errors
       // when arbitrary args are given to CMake script.
       break;
@@ -1465,7 +1487,7 @@
     if (!parsedCorrectly) {
       cmSystemTools::Error("Run 'cmake --help' for all supported options.");
       exit(1);
-    } else if (!matched && cmHasLiteralPrefix(arg, "-")) {
+    } else if (!matched && cmHasPrefix(arg, '-')) {
       possibleUnknownArg = arg;
     } else if (!matched) {
       bool parsedDirectory = this->SetDirectoriesFromFile(arg);
@@ -1475,12 +1497,14 @@
     }
   }
 
-  if (!extraProvidedPath.empty() && this->GetWorkingMode() == NORMAL_MODE) {
+  if (!extraProvidedPath.empty() &&
+      this->State->GetRole() == cmState::Role::Project) {
     this->IssueMessage(MessageType::WARNING,
                        cmStrCat("Ignoring extra path from command line:\n \"",
                                 extraProvidedPath, '"'));
   }
-  if (!possibleUnknownArg.empty() && this->GetWorkingMode() != SCRIPT_MODE) {
+  if (!possibleUnknownArg.empty() &&
+      this->State->GetRole() != cmState::Role::Script) {
     cmSystemTools::Error(cmStrCat("Unknown argument ", possibleUnknownArg));
     cmSystemTools::Error("Run 'cmake --help' for all supported options.");
     exit(1);
@@ -1529,7 +1553,7 @@
     !presetName.empty();
 #endif
 
-  if (this->CurrentWorkingMode == cmake::NORMAL_MODE && !haveSourceDir &&
+  if (this->State->GetRole() == cmState::Role::Project && !haveSourceDir &&
       !haveBinaryDir && !havePreset) {
     this->IssueMessage(
       MessageType::WARNING,
@@ -1572,8 +1596,7 @@
         presetsGraph.PrintAllPresets();
       }
 
-      this->SetWorkingMode(WorkingMode::HELP_MODE,
-                           cmake::CommandFailureAction::FATAL_ERROR);
+      this->State->SetRoleToHelpForListPresets();
       return;
     }
 
@@ -1892,7 +1915,7 @@
     if (this->LoadCache(cachePath)) {
       cmValue existingValue =
         this->State->GetCacheEntryValue("CMAKE_HOME_DIRECTORY");
-      if (existingValue) {
+      if (existingValue && !existingValue.IsEmpty()) {
         this->SetHomeOutputDirectory(cachePath);
         this->SetHomeDirectory(*existingValue);
         return true;
@@ -1967,10 +1990,10 @@
         (cmSystemTools::GetCMakeRoot() + "/Modules/CMake.cmake"))) {
     // couldn't find modules
     cmSystemTools::Error(
-      "Could not find CMAKE_ROOT !!!\n"
-      "CMake has most likely not been installed correctly.\n"
-      "Modules directory not found in\n" +
-      cmSystemTools::GetCMakeRoot());
+      cmStrCat("Could not find CMAKE_ROOT !!!\n"
+               "CMake has most likely not been installed correctly.\n"
+               "Modules directory not found in\n",
+               cmSystemTools::GetCMakeRoot()));
     return 0;
   }
   this->AddCacheEntry("CMAKE_ROOT", cmSystemTools::GetCMakeRoot(),
@@ -2140,7 +2163,7 @@
 
   auto prev_path = this->GetHomeDirectory();
   if (prev_path != path && !prev_path.empty() &&
-      this->GetWorkingMode() == NORMAL_MODE) {
+      this->State->GetRole() == cmState::Role::Project) {
     this->IssueMessage(
       MessageType::WARNING,
       cmStrCat("Ignoring extra path from command line:\n \"", prev_path, '"'));
@@ -2150,12 +2173,13 @@
 
 void cmake::SetHomeDirectory(std::string const& dir)
 {
+  assert(!dir.empty());
   this->State->SetSourceDirectory(dir);
   if (this->CurrentSnapshot.IsValid()) {
     this->CurrentSnapshot.SetDefinition("CMAKE_SOURCE_DIR", dir);
   }
 
-  if (this->State->GetProjectKind() == cmState::ProjectKind::Normal) {
+  if (this->State->GetIsTryCompile() == cmState::TryCompile::No) {
     this->Messenger->SetTopSource(this->GetHomeDirectory());
   } else {
     this->Messenger->SetTopSource(cm::nullopt);
@@ -2169,6 +2193,7 @@
 
 void cmake::SetHomeOutputDirectory(std::string const& dir)
 {
+  assert(!dir.empty());
   this->State->SetBinaryDirectory(dir);
   if (this->CurrentSnapshot.IsValid()) {
     this->CurrentSnapshot.SetDefinition("CMAKE_BINARY_DIR", dir);
@@ -2676,6 +2701,7 @@
     this->ConfigureLog = cm::make_unique<cmConfigureLog>(
       cmStrCat(this->GetHomeOutputDirectory(), "/CMakeFiles"_s),
       this->FileAPI->GetConfigureLogVersions());
+    this->Instrumentation->ClearGeneratedQueries();
     this->Instrumentation->CheckCDashVariable();
   }
 #endif
@@ -2704,7 +2730,7 @@
   auto endTime = std::chrono::steady_clock::now();
 
   // configure result
-  if (this->GetWorkingMode() == cmake::NORMAL_MODE) {
+  if (this->State->GetRole() == cmState::Role::Project) {
     std::ostringstream msg;
     if (cmSystemTools::GetErrorOccurredFlag()) {
       msg << "Configuring incomplete, errors occurred!";
@@ -2943,7 +2969,6 @@
     this->Instrumentation = cm::make_unique<cmInstrumentation>(
       this->State->GetBinaryDirectory(),
       cmInstrumentation::LoadQueriesAfter::No);
-    this->Instrumentation->ClearGeneratedQueries();
   }
 #endif
 }
@@ -2956,7 +2981,7 @@
   if (cmSystemTools::GetErrorOccurredFlag()) {
     return -1;
   }
-  if (this->GetWorkingMode() == HELP_MODE) {
+  if (this->State->GetRole() == cmState::Role::Help) {
     return 0;
   }
 
@@ -2986,7 +3011,7 @@
     return 0;
   }
 
-  if (this->GetWorkingMode() == NORMAL_MODE) {
+  if (this->State->GetRole() == cmState::Role::Project) {
     if (this->FreshCache) {
       this->DeleteCache(this->GetHomeOutputDirectory());
     }
@@ -3032,7 +3057,7 @@
 #endif
 
   // In script mode we terminate after running the script.
-  if (this->GetWorkingMode() != NORMAL_MODE) {
+  if (this->State->GetRole() != cmState::Role::Project) {
     if (cmSystemTools::GetErrorOccurredFlag()) {
       return -1;
     }
@@ -3402,7 +3427,7 @@
 
 bool cmake::GetIsInTryCompile() const
 {
-  return this->State->GetProjectKind() == cmState::ProjectKind::TryCompile;
+  return this->State->GetIsTryCompile() == cmState::TryCompile::Yes;
 }
 
 void cmake::AppendGlobalGeneratorsDocumentation(
@@ -3492,9 +3517,7 @@
   // Read the rerun check file and use it to decide whether to do the
   // global generate.
   // Actually, all we need is the `set` command.
-  cmake cm(RoleScript, cmState::Unknown);
-  cm.SetHomeDirectory("");
-  cm.SetHomeOutputDirectory("");
+  cmake cm(cmState::Role::Script);
   cm.GetCurrentSnapshot().SetDefaultDefinitions();
   cmGlobalGenerator gg(&cm);
   cmMakefile mf(&gg, cm.GetCurrentSnapshot());
@@ -3829,14 +3852,12 @@
   return std::move(configs.data());
 }
 
-int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets,
-                 std::string config, std::vector<std::string> nativeOptions,
-                 cmBuildOptions& buildOptions, bool verbose,
-                 std::string const& presetName, bool listPresets,
-                 std::vector<std::string> const& args)
+int cmake::Build(cmBuildArgs buildArgs, std::vector<std::string> targets,
+                 std::vector<std::string> nativeOptions,
+                 cmBuildOptions& buildOptions, std::string const& presetName,
+                 bool listPresets, std::vector<std::string> const& args)
 {
-  this->SetHomeDirectory("");
-  this->SetHomeOutputDirectory("");
+  buildArgs.timeout = cmDuration::zero();
 
 #if !defined(CMAKE_BOOTSTRAP)
   if (!presetName.empty() || listPresets) {
@@ -3917,17 +3938,23 @@
       return 1;
     }
 
-    if (!expandedConfigurePreset->BinaryDir.empty()) {
-      dir = expandedConfigurePreset->BinaryDir;
+    if (buildArgs.binaryDir.empty() &&
+        !expandedConfigurePreset->BinaryDir.empty()) {
+      buildArgs.binaryDir = expandedConfigurePreset->BinaryDir;
     }
 
     this->UnprocessedPresetEnvironment = expandedPreset->Environment;
     this->ProcessPresetEnvironment();
 
-    if ((jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL ||
-         jobs == cmake::NO_BUILD_PARALLEL_LEVEL) &&
+    if ((buildArgs.jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL ||
+         buildArgs.jobs == cmake::NO_BUILD_PARALLEL_LEVEL) &&
         expandedPreset->Jobs) {
-      jobs = *expandedPreset->Jobs;
+      if (*expandedPreset->Jobs > static_cast<unsigned int>(INT_MAX)) {
+        cmSystemTools::Error(
+          "The build preset \"jobs\" value is too large.\n");
+        return 1;
+      }
+      buildArgs.jobs = *expandedPreset->Jobs;
     }
 
     if (targets.empty()) {
@@ -3935,8 +3962,8 @@
                      expandedPreset->Targets.end());
     }
 
-    if (config.empty()) {
-      config = expandedPreset->Configuration;
+    if (buildArgs.config.empty()) {
+      buildArgs.config = expandedPreset->Configuration;
     }
 
     if (!buildOptions.Clean && expandedPreset->CleanFirst) {
@@ -3948,8 +3975,8 @@
       buildOptions.ResolveMode = *expandedPreset->ResolvePackageReferences;
     }
 
-    if (!verbose && expandedPreset->Verbose) {
-      verbose = *expandedPreset->Verbose;
+    if (!buildArgs.verbose && expandedPreset->Verbose) {
+      buildArgs.verbose = *expandedPreset->Verbose;
     }
 
     if (nativeOptions.empty()) {
@@ -3960,12 +3987,12 @@
   }
 #endif
 
-  if (!cmSystemTools::FileIsDirectory(dir)) {
-    std::cerr << "Error: " << dir << " is not a directory\n";
+  if (!cmSystemTools::FileIsDirectory(buildArgs.binaryDir)) {
+    std::cerr << "Error: " << buildArgs.binaryDir << " is not a directory\n";
     return 1;
   }
 
-  std::string cachePath = FindCacheFile(dir);
+  std::string cachePath = FindCacheFile(buildArgs.binaryDir);
   if (!this->LoadCache(cachePath)) {
     std::cerr
       << "Error: not a CMake build directory (missing CMakeCache.txt)\n";
@@ -4010,17 +4037,16 @@
       return 1;
     }
   }
-  std::string projName;
   cmValue cachedProjectName =
     this->State->GetCacheEntryValue("CMAKE_PROJECT_NAME");
   if (!cachedProjectName) {
     std::cerr << "Error: could not find CMAKE_PROJECT_NAME in Cache\n";
     return 1;
   }
-  projName = *cachedProjectName;
+  buildArgs.projectName = *cachedProjectName;
 
   if (this->State->GetCacheEntryValue("CMAKE_VERBOSE_MAKEFILE").IsOn()) {
-    verbose = true;
+    buildArgs.verbose = true;
   }
 
 #ifdef CMAKE_HAVE_VS_GENERATORS
@@ -4028,43 +4054,37 @@
   // actually starting the build. If not done separately from the build
   // itself, there is the risk of building an out-of-date solution file due
   // to limitations of the underlying build system.
-  std::string const stampList = cachePath + "/" + "CMakeFiles/" +
-    cmGlobalVisualStudio14Generator::GetGenerateStampList();
+  std::string const stampList =
+    cmStrCat(cachePath, "/CMakeFiles/",
+             cmGlobalVisualStudio14Generator::GetGenerateStampList());
 
   // Note that the stampList file only exists for VS generators.
-  if (cmSystemTools::FileExists(stampList)) {
-
+  if (cmSystemTools::FileExists(stampList) &&
+      !cmakeCheckStampList(stampList)) {
+    // Upgrade cmake role from --build to reconfigure the project.
+    this->State->SetRoleToProjectForCMakeBuildVsReconfigure();
     this->AddScriptingCommands();
+    this->AddProjectCommands();
 
-    if (!cmakeCheckStampList(stampList)) {
-      // Correctly initialize the home (=source) and home output (=binary)
-      // directories, which is required for running the generation step.
-      std::string homeOrig = this->GetHomeDirectory();
-      std::string homeOutputOrig = this->GetHomeOutputDirectory();
-      this->SetDirectoriesFromFile(cachePath);
+    // Correctly initialize the home (=source) and home output (=binary)
+    // directories, which is required for running the generation step.
+    this->SetDirectoriesFromFile(cachePath);
 
-      this->AddProjectCommands();
-
-      int ret = this->Configure();
-      if (ret) {
-        cmSystemTools::Message("CMake Configure step failed.  "
-                               "Build files cannot be regenerated correctly.");
-        return ret;
-      }
-      ret = this->Generate();
-      if (ret) {
-        cmSystemTools::Message("CMake Generate step failed.  "
-                               "Build files cannot be regenerated correctly.");
-        return ret;
-      }
-      std::string message = cmStrCat("Build files have been written to: ",
-                                     this->GetHomeOutputDirectory());
-      this->UpdateProgress(message, -1);
-
-      // Restore the previously set directories to their original value.
-      this->SetHomeDirectory(homeOrig);
-      this->SetHomeOutputDirectory(homeOutputOrig);
+    int ret = this->Configure();
+    if (ret) {
+      cmSystemTools::Message("CMake Configure step failed.  "
+                             "Build files cannot be regenerated correctly.");
+      return ret;
     }
+    ret = this->Generate();
+    if (ret) {
+      cmSystemTools::Message("CMake Generate step failed.  "
+                             "Build files cannot be regenerated correctly.");
+      return ret;
+    }
+    std::string message = cmStrCat("Build files have been written to: ",
+                                   this->GetHomeOutputDirectory());
+    this->UpdateProgress(message, -1);
   }
 #endif
 
@@ -4073,7 +4093,7 @@
   }
 
 #if !defined(CMAKE_BOOTSTRAP)
-  cmInstrumentation instrumentation(dir);
+  cmInstrumentation instrumentation(buildArgs.binaryDir);
   if (instrumentation.HasErrors()) {
     return 1;
   }
@@ -4081,18 +4101,17 @@
     cmInstrumentationQuery::Hook::PreCMakeBuild);
 #endif
 
-  this->GlobalGenerator->PrintBuildCommandAdvice(std::cerr, jobs);
+  this->GlobalGenerator->PrintBuildCommandAdvice(std::cerr, buildArgs.jobs);
   std::stringstream ostr;
   // `cmGlobalGenerator::Build` logs metadata about what directory and commands
   // are being executed to the `output` parameter. If CMake is verbose, print
   // this out.
-  std::ostream& verbose_ostr = verbose ? std::cout : ostr;
-  auto doBuild = [this, jobs, dir, projName, targets, &verbose_ostr, config,
-                  buildOptions, verbose, nativeOptions]() -> int {
+  std::ostream& verbose_ostr = buildArgs.verbose ? std::cout : ostr;
+  auto doBuild = [this, targets, &verbose_ostr, buildOptions, buildArgs,
+                  nativeOptions]() -> int {
     return this->GlobalGenerator->Build(
-      jobs, "", dir, projName, targets, verbose_ostr, "", config, buildOptions,
-      verbose, cmDuration::zero(), cmSystemTools::OUTPUT_PASSTHROUGH,
-      nativeOptions);
+      buildArgs, targets, verbose_ostr, "", buildArgs.config, buildOptions,
+      buildArgs.timeout, cmSystemTools::OUTPUT_PASSTHROUGH, nativeOptions);
   };
 
 #if !defined(CMAKE_BOOTSTRAP)
@@ -4112,8 +4131,6 @@
 
 bool cmake::Open(std::string const& dir, DryRun dryRun)
 {
-  this->SetHomeDirectory("");
-  this->SetHomeOutputDirectory("");
   if (!cmSystemTools::FileIsDirectory(dir)) {
     if (dryRun == DryRun::No) {
       std::cerr << "Error: " << dir << " is not a directory\n";
@@ -4217,6 +4234,7 @@
 int cmake::Workflow(std::string const& presetName,
                     WorkflowListPresets listPresets, WorkflowFresh fresh)
 {
+  int exitStatus = 0;
 #ifndef CMAKE_BOOTSTRAP
   this->SetHomeDirectory(cmSystemTools::GetLogicalWorkingDirectory());
   this->SetHomeOutputDirectory(cmSystemTools::GetLogicalWorkingDirectory());
@@ -4289,11 +4307,12 @@
   std::vector<CalculatedStep> steps;
   steps.reserve(expandedPreset->Steps.size());
   int stepNumber = 1;
+  cmCMakePresetsGraph::ConfigurePreset const* configurePreset = {};
   for (auto const& step : expandedPreset->Steps) {
     switch (step.PresetType) {
       case cmCMakePresetsGraph::WorkflowPreset::WorkflowStep::Type::
         Configure: {
-        auto const* configurePreset = this->FindPresetForWorkflow(
+        configurePreset = this->FindPresetForWorkflow(
           "configure"_s, settingsFile.ConfigurePresets, step);
         if (!configurePreset) {
           return 1;
@@ -4354,19 +4373,27 @@
               << std::flush;
     cmUVProcessChain::Status const status = step.Action();
     if (status.ExitStatus != 0) {
-      return static_cast<int>(status.ExitStatus);
+      exitStatus = static_cast<int>(status.ExitStatus);
+      break;
     }
     auto const codeReasonPair = status.GetException();
     if (codeReasonPair.first != cmUVProcessChain::ExceptionCode::None) {
       std::cout << "Step command ended abnormally: " << codeReasonPair.second
                 << std::endl;
-      return status.SpawnResult != 0 ? status.SpawnResult : status.TermSignal;
+      exitStatus =
+        status.SpawnResult != 0 ? status.SpawnResult : status.TermSignal;
+      break;
     }
     first = false;
   }
+  if (configurePreset) {
+    cmInstrumentation instrumentation(configurePreset->BinaryDir);
+    instrumentation.CollectTimingData(
+      cmInstrumentationQuery::Hook::PostCMakeWorkflow);
+  }
 #endif
 
-  return 0;
+  return exitStatus;
 }
 
 void cmake::WatchUnusedCli(std::string const& var)
@@ -4528,10 +4555,14 @@
 
 std::string cmake::GetCMakeListFile(std::string const& dir) const
 {
-  std::string listFile = cmStrCat(dir, '/', this->CMakeListName);
-  if (this->CMakeListName.empty() ||
-      !cmSystemTools::FileExists(listFile, true)) {
-    return cmStrCat(dir, "/CMakeLists.txt");
+  assert(!dir.empty());
+  cm::string_view const slash = dir.back() != '/' ? "/"_s : ""_s;
+  std::string listFile;
+  if (!this->CMakeListName.empty()) {
+    listFile = cmStrCat(dir, slash, this->CMakeListName);
+  }
+  if (listFile.empty() || !cmSystemTools::FileExists(listFile, true)) {
+    listFile = cmStrCat(dir, slash, "CMakeLists.txt");
   }
   return listFile;
 }
diff --git a/Source/cmake.h b/Source/cmake.h
index 7b0ab96..38aef9e 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -18,9 +18,9 @@
 #include <cm/string_view>
 #include <cmext/string_view>
 
+#include "cmBuildArgs.h"
 #include "cmDocumentationEntry.h" // IWYU pragma: keep
 #include "cmGeneratedFileStream.h"
-#include "cmGlobalGeneratorFactory.h"
 #include "cmInstalledFile.h"
 #include "cmListFileCache.h"
 #include "cmMessageType.h"
@@ -54,6 +54,7 @@
 class cmMakefile;
 class cmMessenger;
 class cmVariableWatch;
+class cmGlobalGeneratorFactory;
 struct cmBuildOptions;
 struct cmGlobCacheEntry;
 
@@ -84,13 +85,6 @@
 class cmake
 {
 public:
-  enum Role
-  {
-    RoleInternal, // no commands
-    RoleScript,   // script commands
-    RoleProject   // all commands
-  };
-
   enum DiagLevel
   {
     DIAG_IGNORE,
@@ -165,12 +159,14 @@
 
   using InstalledFilesMap = std::map<std::string, cmInstalledFile>;
 
-  static int const NO_BUILD_PARALLEL_LEVEL = -1;
-  static int const DEFAULT_BUILD_PARALLEL_LEVEL = 0;
+  static int const NO_BUILD_PARALLEL_LEVEL =
+    cmBuildArgs::NO_BUILD_PARALLEL_LEVEL;
+  static int const DEFAULT_BUILD_PARALLEL_LEVEL =
+    cmBuildArgs::DEFAULT_BUILD_PARALLEL_LEVEL;
 
   /// Default constructor
-  cmake(Role role, cmState::Mode mode,
-        cmState::ProjectKind projectKind = cmState::ProjectKind::Normal);
+  cmake(cmState::Role role,
+        cmState::TryCompile isTryCompile = cmState::TryCompile::No);
   /// Destructor
   ~cmake();
 
@@ -450,18 +446,9 @@
   //! Do all the checks before running configure
   int DoPreConfigureChecks();
 
-  void SetWorkingMode(WorkingMode mode, CommandFailureAction policy)
-  {
-    this->CurrentWorkingMode = mode;
-    this->CurrentCommandFailureAction = policy;
-  }
+  bool RoleSupportsExitCode() const;
 
-  WorkingMode GetWorkingMode() const { return this->CurrentWorkingMode; }
-
-  CommandFailureAction GetCommandFailureAction() const
-  {
-    return this->CurrentCommandFailureAction;
-  }
+  CommandFailureAction GetCommandFailureAction() const;
 
   //! Debug the try compile stuff by not deleting the files
   bool GetDebugTryCompile() const { return this->DebugTryCompile; }
@@ -669,11 +656,10 @@
     cmListFileBacktrace const& backtrace = cmListFileBacktrace()) const;
 
   //! run the --build option
-  int Build(int jobs, std::string dir, std::vector<std::string> targets,
-            std::string config, std::vector<std::string> nativeOptions,
-            cmBuildOptions& buildOptions, bool verbose,
-            std::string const& presetName, bool listPresets,
-            std::vector<std::string> const& args);
+  int Build(cmBuildArgs buildArgs, std::vector<std::string> targets,
+            std::vector<std::string> nativeOptions,
+            cmBuildOptions& buildOptions, std::string const& presetName,
+            bool listPresets, std::vector<std::string> const& args);
 
   enum class DryRun
   {
@@ -711,6 +697,9 @@
   void InitializeFileAPI();
   void InitializeInstrumentation();
 
+  bool GetInInitialCache() const { return this->InInitialCache; }
+  void SetInInitialCache(bool v) { this->InInitialCache = v; }
+
   cmState* GetState() const { return this->State.get(); }
   void SetCurrentSnapshot(cmStateSnapshot const& snapshot)
   {
@@ -815,9 +804,6 @@
   std::vector<std::string> cmdArgs;
   std::string CMakeWorkingDirectory;
   ProgressCallbackType ProgressCallback;
-  WorkingMode CurrentWorkingMode = NORMAL_MODE;
-  CommandFailureAction CurrentCommandFailureAction =
-    CommandFailureAction::FATAL_ERROR;
   bool DebugOutput = false;
   bool DebugFindOutput = false;
   // Elements of `cmakeLangTraceCmdStack` are "trace requests" pushed
@@ -856,6 +842,7 @@
   bool DebugTryCompile = false;
   bool FreshCache = false;
   bool RegenerateDuringBuild = false;
+  bool InInitialCache = false;
   std::string CMakeListName;
   std::unique_ptr<cmFileTimeCache> FileTimeCache;
   std::string GraphVizFile;
diff --git a/Source/cmake.version.manifest b/Source/cmake.version.manifest
index 1eef99b..2c5a8c5 100644
--- a/Source/cmake.version.manifest
+++ b/Source/cmake.version.manifest
@@ -1,25 +1,24 @@
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
-          manifestVersion="1.0"
-          xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
-   <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
-       <application>
-           <!-- Windows Vista -->
-           <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
-           <!-- Windows 7 -->
-           <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
-           <!-- Windows 8 -->
-           <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
-           <!-- Windows 8.1 -->
-           <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
-           <!-- Windows 10 -->
-           <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
-       </application>
-   </compatibility>
-  <asmv3:application>
-    <asmv3:windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
-      <ws2:longPathAware>true</ws2:longPathAware>
-    </asmv3:windowsSettings>
-  </asmv3:application>
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <application>
+      <!-- Windows Vista -->
+      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+      <!-- Windows 7 -->
+      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+      <!-- Windows 8 -->
+      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+      <!-- Windows 8.1 -->
+      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+      <!-- Windows 10 -->
+      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+    </application>
+  </compatibility>
+  <application>
+    <windowsSettings>
+      <longPathAware  xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
+    </windowsSettings>
+  </application>
   <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
     <security>
       <requestedPrivileges>
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index d8a753f..35346af 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -5,7 +5,6 @@
 
 #include <algorithm>
 #include <cassert>
-#include <cctype>
 #include <climits>
 #include <cstring>
 #include <functional>
@@ -20,6 +19,9 @@
 
 #include <cm3p/uv.h>
 
+#include "cmsys/String.h"
+
+#include "cmBuildArgs.h"
 #include "cmBuildOptions.h"
 #include "cmCommandLineArgument.h"
 #include "cmDocumentationEntry.h"
@@ -221,9 +223,7 @@
   doc.addCMakeStandardDocSections();
   if (doc.CheckOptions(ac, av, "--")) {
     // Construct and print requested documentation.
-    cmake hcm(cmake::RoleInternal, cmState::Help);
-    hcm.SetHomeDirectory("");
-    hcm.SetHomeOutputDirectory("");
+    cmake hcm(cmState::Role::Help);
     hcm.AddCMakePaths();
 
     // the command line args are processed here so that you can do
@@ -262,7 +262,7 @@
   // (Regex) Filter on the cached variable(s) to print.
   std::string filter_var_name;
   bool view_only = false;
-  cmake::WorkingMode workingMode = cmake::NORMAL_MODE;
+  cmState::Role role = cmState::Role::Project;
   std::vector<std::string> parsedArgs;
 
   using CommandArgument =
@@ -308,20 +308,20 @@
                      CommandArgument::Values::One,
                      CommandArgument::RequiresSeparator::No,
                      [&](std::string const& value) -> bool {
-                       workingMode = cmake::SCRIPT_MODE;
+                       role = cmState::Role::Script;
                        parsedArgs.emplace_back("-P");
                        parsedArgs.push_back(value);
                        return true;
                      } },
     CommandArgument{ "--find-package", CommandArgument::Values::Zero,
                      [&](std::string const&) -> bool {
-                       workingMode = cmake::FIND_PACKAGE_MODE;
+                       role = cmState::Role::FindPackage;
                        parsedArgs.emplace_back("--find-package");
                        return true;
                      } },
     CommandArgument{ "--list-presets", CommandArgument::Values::ZeroOrOne,
                      [&](std::string const& value) -> bool {
-                       workingMode = cmake::HELP_MODE;
+                       role = cmState::Role::Help;
                        parsedArgs.emplace_back("--list-presets");
                        parsedArgs.emplace_back(value);
                        return true;
@@ -338,7 +338,7 @@
 
     // Only in script mode do we stop parsing instead
     // of preferring the last mode flag provided
-    if (arg == "--" && workingMode == cmake::SCRIPT_MODE) {
+    if (arg == "--" && role == cmState::Role::Script) {
       parsedArgs = inputArgs;
       break;
     }
@@ -361,33 +361,11 @@
   }
 
   if (sysinfo) {
-    cmake cm(cmake::RoleProject, cmState::Project);
-    cm.SetHomeDirectory("");
-    cm.SetHomeOutputDirectory("");
+    cmake cm(cmState::Role::Project);
     int ret = cm.GetSystemInformation(parsedArgs);
     return ret;
   }
-  cmake::Role const role =
-    workingMode == cmake::SCRIPT_MODE ? cmake::RoleScript : cmake::RoleProject;
-  cmState::Mode mode = cmState::Unknown;
-  switch (workingMode) {
-    case cmake::NORMAL_MODE:
-    case cmake::HELP_MODE:
-      mode = cmState::Project;
-      break;
-    case cmake::SCRIPT_MODE:
-      mode = cmState::Script;
-      break;
-    case cmake::FIND_PACKAGE_MODE:
-      mode = cmState::FindPackage;
-      break;
-  }
-  auto const failurePolicy = workingMode == cmake::NORMAL_MODE
-    ? cmake::CommandFailureAction::EXIT_CODE
-    : cmake::CommandFailureAction::FATAL_ERROR;
-  cmake cm(role, mode);
-  cm.SetHomeDirectory("");
-  cm.SetHomeOutputDirectory("");
+  cmake cm(role);
   cmSystemTools::SetMessageCallback(
     [&cm](std::string const& msg, cmMessageMetadata const& md) {
       cmakemainMessageCallback(msg, md, &cm);
@@ -395,7 +373,6 @@
   cm.SetProgressCallback([&cm](std::string const& msg, float prog) {
     cmakemainProgressCallback(msg, prog, &cm);
   });
-  cm.SetWorkingMode(workingMode, failurePolicy);
 
   int res = cm.Run(parsedArgs, view_only);
   if (list_cached || list_all_cached) {
@@ -452,7 +429,7 @@
 int extract_job_number(std::string const& command,
                        std::string const& jobString)
 {
-  int jobs = -1;
+  int jobs = cmake::NO_BUILD_PARALLEL_LEVEL;
   unsigned long numJobs = 0;
   if (jobString.empty()) {
     jobs = cmake::DEFAULT_BUILD_PARALLEL_LEVEL;
@@ -490,23 +467,22 @@
   std::cerr << "This cmake does not support --build\n";
   return -1;
 #else
-  int jobs = cmake::NO_BUILD_PARALLEL_LEVEL;
+  cmBuildArgs buildArgs;
   std::vector<std::string> targets;
-  std::string config;
-  std::string dir;
   std::vector<std::string> nativeOptions;
   bool nativeOptionsPassed = false;
   bool cleanFirst = false;
   bool foundClean = false;
   bool foundNonClean = false;
   PackageResolveMode resolveMode = PackageResolveMode::Default;
-  bool verbose = cmSystemTools::HasEnv("VERBOSE");
+  buildArgs.verbose = cmSystemTools::HasEnv("VERBOSE");
   std::string presetName;
   bool listPresets = false;
 
-  auto jLambda = extract_job_number_lambda_builder(dir, jobs, "-j");
-  auto parallelLambda =
-    extract_job_number_lambda_builder(dir, jobs, "--parallel");
+  auto jLambda = extract_job_number_lambda_builder(buildArgs.binaryDir,
+                                                   buildArgs.jobs, "-j");
+  auto parallelLambda = extract_job_number_lambda_builder(
+    buildArgs.binaryDir, buildArgs.jobs, "--parallel");
 
   auto targetLambda = [&](std::string const& value) -> bool {
     if (!value.empty()) {
@@ -525,8 +501,7 @@
   };
   auto resolvePackagesLambda = [&](std::string const& value) -> bool {
     std::string v = value;
-    std::transform(v.begin(), v.end(), v.begin(), ::tolower);
-
+    std::transform(v.begin(), v.end(), v.begin(), cmsysString_tolower);
     if (v == "on") {
       resolveMode = PackageResolveMode::Force;
     } else if (v == "only") {
@@ -540,7 +515,7 @@
     return true;
   };
   auto verboseLambda = [&](std::string const&) -> bool {
-    verbose = true;
+    buildArgs.verbose = true;
     return true;
   };
 
@@ -560,7 +535,7 @@
     CommandArgument{ "--target", CommandArgument::Values::OneOrMore,
                      targetLambda },
     CommandArgument{ "--config", CommandArgument::Values::One,
-                     CommandArgument::setToValue(config) },
+                     CommandArgument::setToValue(buildArgs.config) },
     CommandArgument{ "--clean-first", CommandArgument::Values::Zero,
                      CommandArgument::setToTrue(cleanFirst) },
     CommandArgument{ "--resolve-package-references",
@@ -595,12 +570,12 @@
         }
       }
       if (!matched && i == 0) {
-        dir = cmSystemTools::ToNormalizedPathOnDisk(arg);
+        buildArgs.binaryDir = cmSystemTools::ToNormalizedPathOnDisk(arg);
         matched = true;
         parsed = true;
       }
       if (!(matched && parsed)) {
-        dir.clear();
+        buildArgs.binaryDir.clear();
         if (!matched) {
           std::cerr << "Unknown argument " << arg << std::endl;
         }
@@ -617,38 +592,38 @@
     std::cerr << "Error: Building 'clean' and other targets together "
                  "is not supported."
               << std::endl;
-    dir.clear();
+    buildArgs.binaryDir.clear();
   }
 
-  if (jobs == cmake::NO_BUILD_PARALLEL_LEVEL) {
+  if (buildArgs.jobs == cmake::NO_BUILD_PARALLEL_LEVEL) {
     std::string parallel;
     if (cmSystemTools::GetEnv("CMAKE_BUILD_PARALLEL_LEVEL", parallel)) {
       if (parallel.empty()) {
-        jobs = cmake::DEFAULT_BUILD_PARALLEL_LEVEL;
+        buildArgs.jobs = cmake::DEFAULT_BUILD_PARALLEL_LEVEL;
       } else {
         unsigned long numJobs = 0;
         if (cmStrToULong(parallel, &numJobs)) {
           if (numJobs == 0) {
             std::cerr << "The CMAKE_BUILD_PARALLEL_LEVEL environment variable "
                          "requires a positive integer argument.\n\n";
-            dir.clear();
+            buildArgs.binaryDir.clear();
           } else if (numJobs > INT_MAX) {
             std::cerr << "The CMAKE_BUILD_PARALLEL_LEVEL environment variable "
                          "is too large.\n\n";
-            dir.clear();
+            buildArgs.binaryDir.clear();
           } else {
-            jobs = static_cast<int>(numJobs);
+            buildArgs.jobs = static_cast<int>(numJobs);
           }
         } else {
           std::cerr << "'CMAKE_BUILD_PARALLEL_LEVEL' environment variable\n"
                     << "invalid number '" << parallel << "' given.\n\n";
-          dir.clear();
+          buildArgs.binaryDir.clear();
         }
       }
     }
   }
 
-  if (dir.empty() && presetName.empty() && !listPresets) {
+  if (buildArgs.binaryDir.empty() && presetName.empty() && !listPresets) {
     /* clang-format off */
     std::cerr <<
       "Usage: cmake --build <dir>            "
@@ -685,7 +660,7 @@
     return 1;
   }
 
-  cmake cm(cmake::RoleInternal, cmState::Project);
+  cmake cm(cmState::Role::Internal);
   cmSystemTools::SetMessageCallback(
     [&cm](std::string const& msg, cmMessageMetadata const& md) {
       cmakemainMessageCallback(msg, md, &cm);
@@ -697,9 +672,8 @@
   cmBuildOptions buildOptions(cleanFirst, false, resolveMode);
   std::vector<std::string> cmd;
   cm::append(cmd, av, av + ac);
-  return cm.Build(jobs, dir, std::move(targets), std::move(config),
-                  std::move(nativeOptions), buildOptions, verbose, presetName,
-                  listPresets, cmd);
+  return cm.Build(buildArgs, std::move(targets), std::move(nativeOptions),
+                  buildOptions, presetName, listPresets, cmd);
 #endif
 }
 
@@ -967,7 +941,7 @@
     } else {
       for (auto const& script : handler.GetScripts()) {
         std::vector<std::string> cmd = script.command;
-        cmake cm(cmake::RoleScript, cmState::Script);
+        cmake cm(cmState::Role::Script);
         cmSystemTools::SetMessageCallback(
           [&cm](std::string const& msg, cmMessageMetadata const& md) {
             cmakemainMessageCallback(msg, md, &cm);
@@ -975,11 +949,7 @@
         cm.SetProgressCallback([&cm](std::string const& msg, float prog) {
           cmakemainProgressCallback(msg, prog, &cm);
         });
-        cm.SetHomeDirectory("");
-        cm.SetHomeOutputDirectory("");
         cm.SetDebugOutputOn(verbose);
-        cm.SetWorkingMode(cmake::SCRIPT_MODE,
-                          cmake::CommandFailureAction::FATAL_ERROR);
         ret_ = int(bool(cm.Run(cmd)));
       }
     }
@@ -1072,7 +1042,7 @@
     return 1;
   }
 
-  cmake cm(cmake::RoleInternal, cmState::Project);
+  cmake cm(cmState::Role::Internal);
   cmSystemTools::SetMessageCallback(
     [&cm](std::string const& msg, cmMessageMetadata const& md) {
       cmakemainMessageCallback(msg, md, &cm);
@@ -1116,7 +1086,7 @@
     return 1;
   }
 
-  cmake cm(cmake::RoleInternal, cmState::Unknown);
+  cmake cm(cmState::Role::Internal);
   cmSystemTools::SetMessageCallback(
     [&cm](std::string const& msg, cmMessageMetadata const& md) {
       cmakemainMessageCallback(msg, md, &cm);
diff --git a/Source/cmcldeps.cxx b/Source/cmcldeps.cxx
index 49e1ddd..c2f1539 100644
--- a/Source/cmcldeps.cxx
+++ b/Source/cmcldeps.cxx
@@ -265,14 +265,15 @@
     // The object will not actually be written.
     cmSystemTools::ReplaceString(clrest, "/fo ", " ");
     cmSystemTools::ReplaceString(clrest, "-fo ", " ");
-    cmSystemTools::ReplaceString(clrest, objfile, "-Fo" + objfile + ".obj");
+    cmSystemTools::ReplaceString(clrest, objfile,
+                                 cmStrCat("-Fo", objfile, ".obj"));
 
-    cl = "\"" + cl + "\" /P /DRC_INVOKED /nologo /showIncludes /TC ";
+    cl = cmStrCat('"', cl, "\" /P /DRC_INVOKED /nologo /showIncludes /TC ");
 
     // call cl in object dir so the .i is generated there
     std::string objdir;
     {
-      pos = objfile.rfind("\\");
+      pos = objfile.rfind('\\');
       if (pos != std::string::npos) {
         objdir = objfile.substr(0, pos);
       }
@@ -282,8 +283,9 @@
     int exit_code =
       process(srcfilename, dfile, objfile, prefix, cl + clrest, objdir, true);
 
-    if (exit_code != 0)
+    if (exit_code != 0) {
       return exit_code;
+    }
 
     // compile rc file with rc.exe
     std::string rc = cmStrCat('"', binpath, '"');
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 3195353..7d95c73 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -5,9 +5,11 @@
 #include <functional>
 #include <iomanip>
 #include <iterator>
+#include <limits>
 
 #include <cm/optional>
 #include <cmext/algorithm>
+#include <cmext/string_view>
 
 #include <cm3p/uv.h>
 #include <fcntl.h>
@@ -15,6 +17,7 @@
 #include "cmCommandLineArgument.h"
 #include "cmCryptoHash.h"
 #include "cmDuration.h"
+#include "cmGeneratedFileStream.h"
 #include "cmGlobalGenerator.h"
 #include "cmList.h"
 #include "cmLocalGenerator.h"
@@ -59,6 +62,7 @@
 
 #include <array>
 #include <chrono>
+#include <cstdint>
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
@@ -85,10 +89,18 @@
   std::vector<std::string>::const_iterator argBeg,
   std::vector<std::string>::const_iterator argEnd);
 
+std::ostream& operator<<(
+  std::ostream& stream,
+  std::function<std::ostream&(std::ostream&)> const& func)
+{
+  return func(stream);
+}
+
 namespace {
 // ATTENTION If you add new commands, change here,
 // and in `cmakemain.cxx` in the options table
 char const* const HELP_AVAILABLE_COMMANDS = R"(Available commands:
+  bin2c                     - Turn a binary file into a C array
   capabilities              - Report capabilities built into cmake in JSON format
   cat [--] <files>...       - concat the files and print them to the standard output
   chdir dir cmd [args...]   - run command in a given directory
@@ -180,7 +192,7 @@
     }
     if (cmHasLiteralPrefix(line, "--add-file=")) {
       files.push_back(line.substr(11));
-    } else if (cmHasLiteralPrefix(line, "-")) {
+    } else if (cmHasPrefix(line, '-')) {
       cmSystemTools::Error(cmStrCat("-E tar --files-from='", file,
                                     "' file invalid line:\n", line, '\n'));
       return false;
@@ -329,6 +341,7 @@
 #endif
 
 int HandleIWYU(std::string const& runCmd, std::string const& /* sourceFile */,
+               std::string const& /*objectFile*/,
                std::vector<std::string> const& orig_cmd)
 {
   // Construct the iwyu command line by taking what was given
@@ -361,6 +374,7 @@
 }
 
 int HandleTidy(std::string const& runCmd, std::string const& sourceFile,
+               std::string const& /*objectFile*/,
                std::vector<std::string> const& orig_cmd)
 {
   cmList tidy_cmd{ runCmd, cmList::EmptyElements::Yes };
@@ -408,7 +422,83 @@
   return ret;
 }
 
+int HandlePVSStudio(std::string const& runCmd, std::string const& sourceFile,
+                    std::string const& objectFile,
+                    std::vector<std::string> const& orig_cmd)
+{
+  cmList pvsCmd{ runCmd, cmList::EmptyElements::Yes };
+  std::string logFile = cmStrCat(objectFile, "-pvs.log");
+  std::string errFile = cmStrCat(objectFile, "-pvs.err");
+  pvsCmd.reserve(pvsCmd.size() + 5 + orig_cmd.size());
+  pvsCmd.emplace_back("--source-file");
+  pvsCmd.emplace_back(sourceFile);
+  pvsCmd.emplace_back("--output-file");
+  pvsCmd.emplace_back(logFile);
+  pvsCmd.emplace_back("--cl-params");
+  for (size_t i = 1; i < orig_cmd.size(); ++i) {
+    pvsCmd.emplace_back(orig_cmd[i]);
+  }
+  int ret;
+  std::string stdOut;
+  std::string stdErr;
+
+  // Run the PVS command line.  Capture its stdout and hide its stderr.
+  if (!cmSystemTools::RunSingleCommand(pvsCmd, &stdOut, &stdErr, &ret, nullptr,
+                                       cmSystemTools::OUTPUT_NONE)) {
+    std::cerr << "Error running '" << pvsCmd[0] << "': " << stdErr << '\n';
+    return 1;
+  }
+  if (ret != 0) {
+    if (ret == 7 && !cmSystemTools::FileExists(logFile)) {
+      return 0; // Analyzer generated no output from source
+    }
+    std::cout << stdOut;
+    std::cerr << stdErr;
+    return ret;
+  }
+
+  // Find the plog-converter tool
+#ifdef _WIN32
+  std::string plogConvertName = "HtmlGenerator.exe";
+#else
+  std::string plogConvertName = "plog-converter";
+#endif
+  std::string plogConvert = cmStrCat(
+    cmSystemTools::GetFilenamePath(pvsCmd.front()), '/', plogConvertName);
+  if (!cmSystemTools::FileIsExecutable(plogConvert)) {
+    plogConvert = cmSystemTools::FindProgram(plogConvertName);
+  }
+  if (plogConvert.empty()) {
+    std::cerr << "Could not find " << plogConvertName << std::endl;
+    return 1;
+  }
+
+  // Run the plog-converter tool
+  std::vector<std::string> plogCmd{ plogConvert, "-t",    "errorfile",
+                                    "-o",        errFile, logFile };
+  if (!cmSystemTools::RunSingleCommand(plogCmd, &stdOut, &stdErr, &ret,
+                                       nullptr, cmSystemTools::OUTPUT_NONE)) {
+    std::cerr << "Error running '" << plogCmd[0] << "': " << stdErr << '\n';
+    return 1;
+  }
+
+  // Show error messages from plog-converter output
+  if (stdOut.find("Total messages 0") == std::string::npos) {
+    cmsys::ifstream errFileStream(errFile.c_str());
+    // output always begins with a Help message
+    errFileStream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
+    std::cerr << errFileStream.rdbuf();
+  }
+  cmSystemTools::RemoveFile(logFile);
+
+  if (ret != 0) {
+    std::cerr << stdErr;
+  }
+  return ret;
+}
+
 int HandleLWYU(std::string const& runCmd, std::string const& sourceFile,
+               std::string const& /*objectFile*/,
                std::vector<std::string> const&)
 {
   // Construct the ldd -r -u (link what you use lwyu) command line
@@ -438,6 +528,7 @@
 }
 
 int HandleCppLint(std::string const& runCmd, std::string const& sourceFile,
+                  std::string const& /*objectFile*/,
                   std::vector<std::string> const&)
 {
   // Construct the cpplint command line.
@@ -465,6 +556,7 @@
 }
 
 int HandleCppCheck(std::string const& runCmd, std::string const& sourceFile,
+                   std::string const& /*objectFile*/,
                    std::vector<std::string> const& orig_cmd)
 {
   // Construct the cpplint command line.
@@ -519,6 +611,7 @@
 }
 
 int HandleIcstat(std::string const& runCmd, std::string const& sourceFile,
+                 std::string const& /*objectFile*/,
                  std::vector<std::string> const& orig_cmd)
 {
   // Construct the IAR C-STAT command line.
@@ -568,6 +661,7 @@
 }
 
 using CoCompileHandler = int (*)(std::string const&, std::string const&,
+                                 std::string const&,
                                  std::vector<std::string> const&);
 
 struct CoCompiler
@@ -577,21 +671,229 @@
   bool NoOriginalCommand;
 };
 
-std::array<CoCompiler, 6> const CoCompilers = {
-  { // Table of options and handlers.
-    { "--cppcheck=", HandleCppCheck, false },
-    { "--cpplint=", HandleCppLint, false },
-    { "--icstat=", HandleIcstat, false },
-    { "--iwyu=", HandleIWYU, false },
-    { "--lwyu=", HandleLWYU, true },
-    { "--tidy=", HandleTidy, false } }
-};
+std::array<CoCompiler, 7> const CoCompilers = { {
+  // Table of options and handlers.
+  { "--cppcheck=", HandleCppCheck, false },
+  { "--cpplint=", HandleCppLint, false },
+  { "--icstat=", HandleIcstat, false },
+  { "--iwyu=", HandleIWYU, false },
+  { "--lwyu=", HandleLWYU, true },
+  { "--pvs-studio=", HandlePVSStudio, false },
+  { "--tidy=", HandleTidy, false },
+} };
 
 struct CoCompileJob
 {
   std::string Command;
   CoCompileHandler Handler;
 };
+
+struct Bin2CTemplateFile
+{
+  std::istream* TemplateStream;
+  cm::string_view ArrayPlaceholder;
+  cm::string_view LengthPlaceholder;
+};
+
+enum class Bin2CBase
+{
+  Hex,
+  Decimal,
+};
+
+std::size_t const BIN2C_BUFFER_SIZE = 16384;
+std::size_t const BIN2C_ROW_WIDTH = 32;
+
+inline std::size_t Bin2CColumnPosHex(std::size_t column)
+{
+  return cmStrLen(" ") + column * cmStrLen(" 0x__,");
+}
+
+inline std::size_t Bin2CColumnPosDecimal(std::size_t column)
+{
+  return cmStrLen(" ") + column * cmStrLen("____,");
+}
+
+inline char Bin2CDigit(unsigned char byte, int place)
+{
+  return '0' + static_cast<char>((byte / place) % 10);
+}
+
+inline void Bin2CPrintCharToBuffer(bool printSigned, Bin2CBase base,
+                                   std::string& line, unsigned char byte,
+                                   std::uint64_t pos)
+{
+  static char const hextable[] = "0123456789ABCDEF";
+  bool neg = false;
+  if (printSigned && byte & 0x80) {
+    neg = true;
+    byte = ~byte + 1;
+  }
+  switch (base) {
+    case Bin2CBase::Hex:
+      if (printSigned) {
+        line[Bin2CColumnPosHex(pos % BIN2C_ROW_WIDTH)] = neg ? '-' : ' ';
+      }
+      line[Bin2CColumnPosHex(pos % BIN2C_ROW_WIDTH) + cmStrLen(" 0x")] =
+        hextable[byte >> 4];
+      line[Bin2CColumnPosHex(pos % BIN2C_ROW_WIDTH) + cmStrLen(" 0x_")] =
+        hextable[byte & 0xF];
+      break;
+    case Bin2CBase::Decimal:
+      std::size_t negOffset = byte >= 100 ? cmStrLen("")
+        : byte >= 10                      ? cmStrLen("_")
+                                          : cmStrLen("__");
+      for (std::size_t i = cmStrLen(""); i < negOffset; i++) {
+        line[Bin2CColumnPosDecimal(pos % BIN2C_ROW_WIDTH) + i] = ' ';
+      }
+      line[Bin2CColumnPosDecimal(pos % BIN2C_ROW_WIDTH) + negOffset] =
+        neg ? '-' : ' ';
+      if (byte >= 100) {
+        line[Bin2CColumnPosDecimal(pos % BIN2C_ROW_WIDTH) + cmStrLen("_")] =
+          Bin2CDigit(byte, 100);
+      }
+      if (byte >= 10) {
+        line[Bin2CColumnPosDecimal(pos % BIN2C_ROW_WIDTH) + cmStrLen("__")] =
+          Bin2CDigit(byte, 10);
+      }
+      line[Bin2CColumnPosDecimal(pos % BIN2C_ROW_WIDTH) + cmStrLen("___")] =
+        Bin2CDigit(byte, 1);
+      break;
+  }
+}
+
+void Bin2CPrintChar(std::ostream& sout, bool printSigned, Bin2CBase base,
+                    bool printFirstNewline, std::string& line,
+                    unsigned char byte, std::uint64_t& pos, bool& any)
+{
+  if (!any) {
+    if (printFirstNewline) {
+      sout << "\n";
+    }
+  } else if (pos % BIN2C_ROW_WIDTH == 0) {
+    sout << line;
+  }
+  Bin2CPrintCharToBuffer(printSigned, base, line, byte, pos);
+  any = true;
+  pos++;
+}
+
+std::function<std::ostream&(std::ostream& sout)> Bin2CPrintChars(
+  std::istream& sin, bool printTrailingComma, bool printSigned, Bin2CBase base,
+  bool printFirstNewline, std::uint64_t* length = nullptr)
+{
+  return [&sin, printTrailingComma, printSigned, base, printFirstNewline,
+          length](std::ostream& sout) -> std::ostream& {
+    // Construct a line buffer and modify the characters within it. This is
+    // an order of magnitude faster than `sout <<`-ing everything.
+    std::string line = " ";
+    line.reserve(
+      cmStrLen(" ") +
+      (base == Bin2CBase::Hex ? cmStrLen(" 0x__,") : cmStrLen("____,")) *
+        BIN2C_ROW_WIDTH +
+      cmStrLen("\n"));
+    for (std::size_t i = 0; i < BIN2C_ROW_WIDTH; i++) {
+      line = cmStrCat(line, base == Bin2CBase::Hex ? " 0x__," : "____,");
+    }
+    line = cmStrCat(line, '\n');
+
+    bool any = false;
+    std::uint64_t pos = 0;
+    std::size_t readSize;
+    std::vector<std::uint8_t> buffer(BIN2C_BUFFER_SIZE);
+    do {
+      sin.read(reinterpret_cast<char*>(buffer.data()), BIN2C_BUFFER_SIZE);
+      readSize = sin.gcount();
+      for (std::size_t i = 0; i < readSize; i++) {
+        Bin2CPrintChar(sout, printSigned, base, printFirstNewline, line,
+                       buffer[i], pos, any);
+      }
+    } while (readSize >= BIN2C_BUFFER_SIZE);
+    if (any) {
+      std::size_t column = pos % BIN2C_ROW_WIDTH;
+      if (column == 0) {
+        column = BIN2C_ROW_WIDTH;
+      }
+      sout << line.substr(0,
+                          (base == Bin2CBase::Hex
+                             ? Bin2CColumnPosHex(column)
+                             : Bin2CColumnPosDecimal(column)) -
+                            cmStrLen(","))
+           << (printTrailingComma ? ",\n" : "\n");
+    }
+
+    if (length) {
+      *length = pos;
+    }
+    return sout;
+  };
+}
+
+bool Bin2CFromTemplateFile(std::ostream& sout, std::istream& sin,
+                           Bin2CTemplateFile& templateFile,
+                           bool printTrailingComma, bool printSigned,
+                           Bin2CBase base)
+{
+  cm::optional<std::uint64_t> length;
+  std::string line;
+
+  bool hasNewline;
+  while (cmSystemTools::GetLineFromStream(*templateFile.TemplateStream, line,
+                                          &hasNewline)) {
+    cm::optional<std::size_t> at;
+    for (std::size_t i = 0; i < line.length(); i++) {
+      if (line[i] == '@') {
+        if (at) {
+          cm::string_view variableName{ &line[*at + 1], i - (*at + 1) };
+          at.reset();
+          if (variableName == templateFile.ArrayPlaceholder) {
+            if (length) {
+              std::cerr << "Cannot print array twice\n";
+              return false;
+            }
+            length.emplace();
+            sout << Bin2CPrintChars(sin, printTrailingComma, printSigned, base,
+                                    true, &*length);
+          } else if (variableName == templateFile.LengthPlaceholder) {
+            if (!length) {
+              std::cerr << "Cannot print length before array\n";
+              return false;
+            }
+            sout << *length;
+          } else {
+            sout << '@' << variableName;
+            at = i; // Allow for `@` outside of placeholder expansion
+          }
+        } else {
+          at = i;
+        }
+      } else if (!at) {
+        sout << line[i];
+      }
+    }
+    if (at) {
+      sout << &line[*at];
+    }
+    if (hasNewline) {
+      sout << '\n';
+    }
+  }
+
+  return true;
+}
+
+bool Bin2C(std::ostream& sout, std::istream& sin,
+           cm::optional<Bin2CTemplateFile>& templateFile,
+           bool printTrailingComma, bool printSigned, Bin2CBase base)
+{
+  if (templateFile) {
+    return Bin2CFromTemplateFile(sout, sin, *templateFile, printTrailingComma,
+                                 printSigned, base);
+  }
+
+  sout << Bin2CPrintChars(sin, printTrailingComma, printSigned, base, false);
+  return true;
+}
 }
 
 // called when args[0] == "__run_co_compile"
@@ -599,6 +901,7 @@
 {
   std::vector<CoCompileJob> jobs;
   std::string sourceFile; // store --source=
+  std::string objectFile; // store --object=
   cmList launchers;       // store --launcher=
 
   // Default is to run the original command found after -- if the option
@@ -633,6 +936,8 @@
           sourceFile = arg.substr(9);
         } else if (cmHasLiteralPrefix(arg, "--launcher=")) {
           launchers.append(arg.substr(11), cmList::EmptyElements::Yes);
+        } else if (cmHasLiteralPrefix(arg, "--object=")) {
+          objectFile = arg.substr(9);
         } else {
           // if it was not a co-compiler or --source/--launcher then error
           std::cerr << "__run_co_compile given unknown argument: " << arg
@@ -660,7 +965,7 @@
 
   for (CoCompileJob const& job : jobs) {
     // call the command handler here
-    int ret = job.Handler(job.Command, sourceFile, orig_cmd);
+    int ret = job.Handler(job.Command, sourceFile, objectFile, orig_cmd);
 
     // if the command returns non-zero then return and fail.
     // for commands that do not want to break the build, they should return
@@ -749,9 +1054,11 @@
       // If error occurs we want to continue copying next files.
       bool return_value = false;
       for (auto const& file : files) {
-        if (!cmsys::SystemTools::CopyFileAlways(file, *targetArg)) {
+        cmsys::SystemTools::CopyStatus const status =
+          cmSystemTools::CopyFileAlways(file, *targetArg);
+        if (!status) {
           std::cerr << "Error copying file \"" << file << "\" to \""
-                    << *targetArg << "\".\n";
+                    << *targetArg << "\": " << status.GetString() << '\n';
           return_value = true;
         }
       }
@@ -771,9 +1078,12 @@
       // If error occurs we want to continue copying next files.
       bool return_value = false;
       for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
-        if (!cmSystemTools::CopyFileIfDifferent(arg, args.back())) {
+        cmsys::SystemTools::CopyStatus const status =
+          cmSystemTools::CopyFileIfDifferent(arg, args.back());
+        if (!status) {
           std::cerr << "Error copying file (if different) from \"" << arg
-                    << "\" to \"" << args.back() << "\".\n";
+                    << "\" to \"" << args.back()
+                    << "\": " << status.GetString() << '\n';
           return_value = true;
         }
       }
@@ -793,9 +1103,12 @@
       // If error occurs we want to continue copying next files.
       bool return_value = false;
       for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
-        if (!cmSystemTools::CopyFileIfNewer(arg, args.back())) {
+        cmsys::SystemTools::CopyStatus const status =
+          cmSystemTools::CopyFileIfNewer(arg, args.back());
+        if (!status) {
           std::cerr << "Error copying file (if newer) from \"" << arg
-                    << "\" to \"" << args.back() << "\".\n";
+                    << "\" to \"" << args.back()
+                    << "\": " << status.GetString() << '\n';
           return_value = true;
         }
       }
@@ -818,9 +1131,11 @@
       }
 
       for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
-        if (!cmSystemTools::CopyADirectory(arg, args.back(), when)) {
+        cmsys::Status const status =
+          cmSystemTools::CopyADirectory(arg, args.back(), when);
+        if (!status) {
           std::cerr << "Error copying directory from \"" << arg << "\" to \""
-                    << args.back() << "\".\n";
+                    << args.back() << "\": " << status.GetString() << '\n';
           return_value = true;
         }
       }
@@ -1023,8 +1338,10 @@
       // If an error occurs, we want to continue making directories.
       bool return_value = false;
       for (auto const& arg : cmMakeRange(args).advance(2)) {
-        if (!cmSystemTools::MakeDirectory(arg)) {
-          std::cerr << "Error creating directory \"" << arg << "\".\n";
+        cmsys::Status const status = cmSystemTools::MakeDirectory(arg);
+        if (!status) {
+          std::cerr << "Error creating directory \"" << arg
+                    << "\": " << status.GetString() << '\n';
           return_value = true;
         }
       }
@@ -1072,7 +1389,7 @@
       bool doing_options = true;
       bool at_least_one_file = false;
       for (auto const& arg : cmMakeRange(args).advance(2)) {
-        if (doing_options && cmHasLiteralPrefix(arg, "-")) {
+        if (doing_options && cmHasPrefix(arg, '-')) {
           if (arg == "--") {
             doing_options = false;
           }
@@ -1150,7 +1467,7 @@
         std::cerr << "-E capabilities accepts no additional arguments\n";
         return 1;
       }
-      cmake cm(cmake::RoleInternal, cmState::Unknown);
+      cmake cm(cmState::Role::Internal);
       std::cout << cm.ReportCapabilities();
       return 0;
     }
@@ -1227,7 +1544,7 @@
           // Destroy console buffers to drop cout/cerr encoding transform.
           console.reset();
           cmCatFile(arg);
-        } else if (doing_options && cmHasLiteralPrefix(arg, "-")) {
+        } else if (doing_options && cmHasPrefix(arg, '-')) {
           if (arg == "--") {
             doing_options = false;
           } else {
@@ -1398,7 +1715,7 @@
 
       // Create a cmake object instance to process dependencies.
       // All we need is the `set` command.
-      cmake cm(cmake::RoleScript, cmState::Unknown);
+      cmake cm(cmState::Role::Script);
       std::string gen;
       std::string homeDir;
       std::string startDir;
@@ -1563,17 +1880,21 @@
 
     // Tar files
     if (args[1] == "tar" && args.size() > 3) {
-      char const* knownFormats[] = { "7zip", "gnutar", "pax", "paxr", "zip" };
+      char const* knownFormats[] = { "7zip", "gnutar", "pax",
+                                     "paxr", "raw",    "zip" };
 
       std::string const& flags = args[2];
       std::string const& outFile = args[3];
       std::vector<std::string> files;
       std::string mtime;
       std::string format;
+      int numThreads = 1;
+      int compressionLevel = 0;
+      bool compressionLevelFlagPassed = false;
       cmSystemTools::cmTarExtractTimestamps extractTimestamps =
         cmSystemTools::cmTarExtractTimestamps::Yes;
       cmSystemTools::cmTarCompression compress =
-        cmSystemTools::TarCompressNone;
+        cmSystemTools::TarCompressAuto;
       int nCompress = 0;
       bool doing_options = true;
       for (auto const& arg : cmMakeRange(args).advance(4)) {
@@ -1583,8 +1904,97 @@
           } else if (arg == "--zstd") {
             compress = cmSystemTools::TarCompressZstd;
             ++nCompress;
+          } else if (arg == "--lzma") {
+            compress = cmSystemTools::TarCompressLZMA;
+            ++nCompress;
           } else if (cmHasLiteralPrefix(arg, "--mtime=")) {
             mtime = arg.substr(8);
+          } else if (cmHasLiteralPrefix(arg, "--cmake-tar-threads=")) {
+            std::string const& numThreadsStr = arg.substr(20);
+            long numThreadsLong = 0;
+            if (!cmStrToLong(numThreadsStr, &numThreadsLong)) {
+              cmSystemTools::Error(
+                cmStrCat("Invalid --cmake-tar-threads value: '", numThreadsStr,
+                         "' - not a number"));
+              return 1;
+            }
+            if (numThreadsLong >
+                std::numeric_limits<decltype(numThreads)>::max()) {
+              cmSystemTools::Error(
+                cmStrCat("Invalid --cmake-tar-threads value: '", numThreadsStr,
+                         "' - too large"));
+              return 1;
+            }
+            if (numThreadsLong <
+                std::numeric_limits<decltype(numThreads)>::min()) {
+              cmSystemTools::Error(
+                cmStrCat("Invalid --cmake-tar-threads value: '", numThreadsStr,
+                         "' - too small"));
+              return 1;
+            }
+
+            numThreads = static_cast<decltype(numThreads)>(numThreadsLong);
+          } else if (cmHasLiteralPrefix(arg,
+                                        "--cmake-tar-compression-level=")) {
+            std::string const& compressionLevelStr = arg.substr(30);
+            long compressionLevelLong = 0;
+            if (!cmStrToLong(compressionLevelStr, &compressionLevelLong)) {
+              cmSystemTools::Error(
+                cmStrCat("Invalid --cmake-tar-compression-level value: '",
+                         compressionLevelStr, "' - not a number"));
+              return 1;
+            }
+            if (compressionLevelLong >
+                std::numeric_limits<decltype(compressionLevel)>::max()) {
+              cmSystemTools::Error(
+                cmStrCat("Invalid --cmake-tar-compression-level value: '",
+                         compressionLevelStr, "' - too large"));
+              return 1;
+            }
+            if (compressionLevelLong <
+                std::numeric_limits<decltype(compressionLevel)>::min()) {
+              cmSystemTools::Error(
+                cmStrCat("Invalid --cmake-tar-compression-level value: '",
+                         compressionLevelStr, "' - too small"));
+              return 1;
+            }
+
+            compressionLevel =
+              static_cast<decltype(compressionLevel)>(compressionLevelLong);
+            compressionLevelFlagPassed = true;
+          } else if (cmHasLiteralPrefix(arg,
+                                        "--cmake-tar-compression-method=")) {
+            std::string const& compressionMethodStr = arg.substr(31);
+            if (compressionMethodStr == "none" ||
+                compressionMethodStr == "store") {
+              compress = cmSystemTools::TarCompressNone;
+              ++nCompress;
+            } else if (compressionMethodStr == "deflate" ||
+                       compressionMethodStr == "gzip") {
+              compress = cmSystemTools::TarCompressGZip;
+              ++nCompress;
+            } else if (compressionMethodStr == "bzip2") {
+              compress = cmSystemTools::TarCompressBZip2;
+              ++nCompress;
+            } else if (compressionMethodStr == "lzma") {
+              compress = cmSystemTools::TarCompressLZMA;
+              ++nCompress;
+            } else if (compressionMethodStr == "lzma2" ||
+                       compressionMethodStr == "xz") {
+              compress = cmSystemTools::TarCompressXZ;
+              ++nCompress;
+            } else if (compressionMethodStr == "zstd") {
+              compress = cmSystemTools::TarCompressZstd;
+              ++nCompress;
+            } else if (compressionMethodStr == "ppmd") {
+              compress = cmSystemTools::TarCompressPPMd;
+              ++nCompress;
+            } else {
+              cmSystemTools::Error(
+                cmStrCat("Unknown --cmake-tar-compression-method value: '",
+                         compressionMethodStr, '\''));
+              return 1;
+            }
           } else if (cmHasLiteralPrefix(arg, "--files-from=")) {
             std::string const& files_from = arg.substr(13);
             if (!cmTarFilesFrom(files_from, files)) {
@@ -1645,16 +2055,33 @@
           }
         }
       }
-      if ((format == "7zip" || format == "zip") && nCompress > 0) {
-        cmSystemTools::Error("Can not use compression flags with format: " +
-                             format);
-        return 1;
-      }
       if (nCompress > 1) {
         cmSystemTools::Error("Can only compress a tar file one way; "
                              "at most one flag of z, j, or J may be used");
         return 1;
       }
+      if (compressionLevelFlagPassed) {
+        if (nCompress == 0 && format != "zip" && format != "7zip") {
+          cmSystemTools::Error("Can not use --cmake-tar-compression-level "
+                               "without compression algorithm selection");
+          return 1;
+        }
+
+        constexpr int minCompressionLevel = 0;
+        int maxCompressionLevel = 9;
+        if (compress == cmSystemTools::TarCompressZstd && format != "zip") {
+          maxCompressionLevel = 19;
+        }
+
+        if (compressionLevel < minCompressionLevel ||
+            compressionLevel > maxCompressionLevel) {
+          cmSystemTools::Error(cmStrCat(
+            "Compression level must be between ", minCompressionLevel, " and ",
+            maxCompressionLevel, ". Got ", compressionLevel));
+          return 1;
+        }
+      }
+
       if (action == cmSystemTools::TarActionList) {
         if (!cmSystemTools::ListTar(outFile, files, verbose)) {
           cmSystemTools::Error("Problem listing tar: " + outFile);
@@ -1665,14 +2092,16 @@
           std::cerr << "tar: No files or directories specified\n";
         }
         if (!cmSystemTools::CreateTar(outFile, files, {}, compress, verbose,
-                                      mtime, format)) {
-          cmSystemTools::Error("Problem creating tar: " + outFile);
+                                      mtime, format, compressionLevel,
+                                      numThreads)) {
+          cmSystemTools::Error(cmStrCat("Problem creating tar:\n  ", outFile));
           return 1;
         }
       } else if (action == cmSystemTools::TarActionExtract) {
         if (!cmSystemTools::ExtractTar(outFile, files, extractTimestamps,
                                        verbose)) {
-          cmSystemTools::Error("Problem extracting tar: " + outFile);
+          cmSystemTools::Error(
+            cmStrCat("Problem extracting tar:\n  ", outFile));
           return 1;
         }
 #ifdef _WIN32
@@ -1699,6 +2128,182 @@
       return 0;
     }
 
+    // bin2c
+    if (args[1] == "bin2c"_s) {
+      auto const usage = []() {
+        std::cerr << "bin2c Usage: -E bin2c "
+                     "[<options>...] "
+                     "[--] [<input-file> [<output-file>]]\n";
+        return 1;
+      };
+      auto const isFilename = [](std::string const& arg) -> bool {
+        return arg == "-"_s || !cmHasLiteralPrefix(arg, "-");
+      };
+
+      static char const validPlaceholderChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                                  "abcdefghijklmnopqrstuvwxyz"
+                                                  "0123456789/_.+-";
+
+      std::string inputFile = "-";
+      std::string outputFile = "-";
+      cm::optional<cm::string_view> templateFilename;
+      cm::optional<cm::string_view> templateArrayPlaceholder;
+      cm::optional<cm::string_view> templateLengthPlaceholder;
+      bool printTrailingComma = false;
+      bool printSigned = false;
+      auto base = Bin2CBase::Hex;
+
+      using CommandArgument =
+        cmCommandLineArgument<bool(std::string const& value)>;
+      std::vector<CommandArgument> arguments = {
+        CommandArgument{ "--template-file", CommandArgument::Values::One,
+                         [&templateFilename](std::string const& arg) -> bool {
+                           templateFilename = arg;
+                           return true;
+                         } },
+        CommandArgument{
+          "--template-array-placeholder", CommandArgument::Values::One,
+          [&templateArrayPlaceholder](std::string const& arg) -> bool {
+            if (arg.find_first_not_of(validPlaceholderChars) !=
+                std::string::npos) {
+              std::cerr << "Invalid array placeholder name: \"" << arg
+                        << "\"\n";
+              return false;
+            }
+            templateArrayPlaceholder = arg;
+            return true;
+          } },
+        CommandArgument{
+          "--template-length-placeholder", CommandArgument::Values::One,
+          [&templateLengthPlaceholder](std::string const& arg) -> bool {
+            if (arg.find_first_not_of(validPlaceholderChars) !=
+                std::string::npos) {
+              std::cerr << "Invalid length placeholder name: \"" << arg
+                        << "\"\n";
+              return false;
+            }
+            templateLengthPlaceholder = arg;
+            return true;
+          } },
+        CommandArgument{ "--trailing-comma", CommandArgument::Values::Zero,
+                         CommandArgument::setToTrue(printTrailingComma) },
+        CommandArgument{ "--signed", CommandArgument::Values::Zero,
+                         CommandArgument::setToTrue(printSigned) },
+        CommandArgument{ "--decimal", CommandArgument::Values::Zero,
+                         [&base](std::string const&) -> bool {
+                           base = Bin2CBase::Decimal;
+                           return true;
+                         } },
+      };
+
+      size_t i;
+      for (i = 2; i < args.size(); i++) {
+        bool matched = false;
+        auto const& arg = args[i];
+        if (arg == "--"_s) {
+          i++;
+          break;
+        }
+        for (auto const& argument : arguments) {
+          if (argument.matches(arg)) {
+            matched = true;
+            if (!argument.parse(arg, i, args)) {
+              std::cerr << "\n";
+              return usage();
+            }
+            break;
+          }
+        }
+
+        if (isFilename(arg)) {
+          break;
+        }
+        if (!matched) {
+          return usage();
+        }
+      }
+
+      if (i < args.size() - 2) {
+        return usage();
+      }
+      if (i < args.size()) {
+        if (!isFilename(args[i])) {
+          return usage();
+        }
+        inputFile = args[i];
+        i++;
+      }
+      if (i < args.size()) {
+        if (!isFilename(args[i])) {
+          return usage();
+        }
+        outputFile = args[i];
+        i++;
+      }
+
+      cm::optional<Bin2CTemplateFile> templateFile;
+      cmsys::ifstream templateStream;
+      if (templateFilename) {
+        templateStream.open(templateFilename->data());
+        if (!templateStream) {
+          std::cerr << "Could not open template file for reading: \""
+                    << *templateFilename << "\"\n";
+          return 1;
+        }
+        templateFile =
+          Bin2CTemplateFile{ &templateStream,
+                             templateArrayPlaceholder.value_or("array"_s),
+                             templateLengthPlaceholder.value_or("length"_s) };
+      } else {
+        if (templateArrayPlaceholder) {
+          std::cerr << "Cannot use --template-array-placeholder without "
+                       "--template-file\n\n";
+          return usage();
+        }
+        if (templateLengthPlaceholder) {
+          std::cerr << "Cannot use --template-length-placeholder without "
+                       "--template-file\n\n";
+          return usage();
+        }
+      }
+
+      std::istream* sin = &std::cin;
+      cmsys::ifstream fin;
+      if (inputFile != "-"_s) {
+        fin.open(inputFile.c_str(), std::ios::in | std::ios::binary);
+        if (!fin) {
+          std::cerr << "Could not open file for reading: \"" << inputFile
+                    << "\"\n";
+          return 1;
+        }
+        sin = &fin;
+#ifdef _WIN32
+      } else {
+        _setmode(fileno(stdin), _O_BINARY);
+#endif
+      }
+
+      std::ostream* sout = &std::cout;
+      cmGeneratedFileStream fout;
+      if (outputFile != "-"_s) {
+        fout.Open(outputFile);
+        if (!fout) {
+          std::cerr << "Could not open file for writing: \"" << outputFile
+                    << "\"\n";
+          return 1;
+        }
+        fout.SetCopyIfDifferent(true);
+        sout = &fout;
+      }
+
+      if (!Bin2C(*sout, *sin, templateFile, printTrailingComma, printSigned,
+                 base)) {
+        return 1;
+      }
+
+      return 0;
+    }
+
     if (args[1] == "server") {
       cmSystemTools::Error(
         "CMake server mode has been removed in favor of the file-api.");
@@ -1752,7 +2357,7 @@
       }
       // Create a cmake object instance to process dependencies.
       // All we need is the `set` command.
-      cmake cm(cmake::RoleScript, cmState::Unknown);
+      cmake cm(cmState::Role::Script);
       std::string homeDir;
       std::string startDir;
       std::string homeOutDir;
@@ -1796,8 +2401,21 @@
   int retval = 0;
 
   for (auto const& filename : cmMakeRange(args).advance(2)) {
-    // Cannot compute sum of a directory
-    if (cmSystemTools::FileIsDirectory(filename)) {
+    if (filename == "-") {
+#ifdef _WIN32
+      _setmode(fileno(stdin), _O_BINARY);
+#endif
+      cmCryptoHash hasher(algo);
+      std::string value = hasher.HashStream(std::cin);
+      if (value.empty()) {
+        // To mimic "md5sum/shasum" behavior in a shell:
+        std::cerr << filename << ": No such file or directory\n";
+        retval++;
+      } else {
+        std::cout << value << "  " << filename << '\n';
+      }
+    } else if (cmSystemTools::FileIsDirectory(filename)) {
+      // Cannot compute sum of a directory
       std::cerr << "Error: " << filename << " is a directory\n";
       retval++;
     } else {
@@ -2120,7 +2738,7 @@
     return 1;
   }
   if (process.GetStatus(0).ExitStatus != 0) {
-    cmUVPipeIStream errorStream(process.GetLoop(), process.ErrorStream());
+    cmUVIStream errorStream(process.ErrorStream());
     std::cerr << errorStream.rdbuf();
 
     return 1;
@@ -2245,7 +2863,7 @@
     return result;
   }
   if (process.GetStatus(0).ExitStatus != 0) {
-    cmUVPipeIStream errorStream(process.GetLoop(), process.ErrorStream());
+    cmUVIStream errorStream(process.ErrorStream());
     std::cerr << errorStream.rdbuf();
     return 1;
   }
@@ -2404,13 +3022,13 @@
   // Parse our own arguments.
   std::string intDir;
   auto arg = argBeg;
-  while (arg != argEnd && cmHasLiteralPrefix(*arg, "-")) {
+  while (arg != argEnd && cmHasPrefix(*arg, '-')) {
     if (*arg == "--") {
       ++arg;
       break;
     }
     if (*arg == "--manifests") {
-      for (++arg; arg != argEnd && !cmHasLiteralPrefix(*arg, "-"); ++arg) {
+      for (++arg; arg != argEnd && !cmHasPrefix(*arg, '-'); ++arg) {
         this->UserManifests.push_back(*arg);
       }
     } else if (cmHasLiteralPrefix(*arg, "--intdir=")) {
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt
index 08494b9..68e122e 100644
--- a/Source/kwsys/CMakeLists.txt
+++ b/Source/kwsys/CMakeLists.txt
@@ -159,6 +159,7 @@
   set(KWSYS_USE_FStream 1)
   set(KWSYS_USE_Encoding 1)
   set(KWSYS_USE_Status 1)
+  set(KWSYS_USE_String 1)
 endif()
 if(KWSYS_USE_Glob)
   set(KWSYS_USE_Directory 1)
@@ -166,6 +167,7 @@
   set(KWSYS_USE_RegularExpression 1)
   set(KWSYS_USE_FStream 1)
   set(KWSYS_USE_Encoding 1)
+  set(KWSYS_USE_String 1)
 endif()
 if(KWSYS_USE_Process)
   set(KWSYS_USE_System 1)
@@ -179,6 +181,7 @@
 endif()
 if(KWSYS_USE_System)
   set(KWSYS_USE_Encoding 1)
+  set(KWSYS_USE_String 1)
 endif()
 if(KWSYS_USE_Directory)
   set(KWSYS_USE_Encoding 1)
@@ -913,6 +916,7 @@
     # C tests
     set(KWSYS_C_TESTS
       testEncode.c
+      testString.c
       )
     if(KWSYS_STANDALONE)
       set(KWSYS_C_TESTS ${KWSYS_C_TESTS} testFail.c)
diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx
index b23c624..fae7761 100644
--- a/Source/kwsys/Directory.cxx
+++ b/Source/kwsys/Directory.cxx
@@ -184,7 +184,7 @@
   delete[] buf;
 
   if (srchHandle == INVALID_HANDLE_VALUE) {
-    Status status = Status::POSIX_errno();
+    Status status = Status::Windows_GetLastError();
     if (errorMessage) {
       *errorMessage = status.GetString();
     }
@@ -198,7 +198,7 @@
   } while (FindNextFileW(srchHandle, &data));
   this->Internal->Path = name;
   if (!FindClose(srchHandle)) {
-    Status status = Status::POSIX_errno();
+    Status status = Status::Windows_GetLastError();
     if (errorMessage) {
       *errorMessage = status.GetString();
     }
diff --git a/Source/kwsys/EncodingCXX.cxx b/Source/kwsys/EncodingCXX.cxx
index 7bf4681..885a1f7 100644
--- a/Source/kwsys/EncodingCXX.cxx
+++ b/Source/kwsys/EncodingCXX.cxx
@@ -9,12 +9,14 @@
 #include "kwsysPrivate.h"
 #include KWSYS_HEADER(Encoding.hxx)
 #include KWSYS_HEADER(Encoding.h)
+#include KWSYS_HEADER(String.h)
 
 // Work-around CMake dependency scanning limitation.  This must
 // duplicate the above list of headers.
 #if 0
 #  include "Encoding.h.in"
 #  include "Encoding.hxx.in"
+#  include "String.h"
 #endif
 
 #include <cstdlib>
@@ -29,7 +31,6 @@
 #if defined(_WIN32)
 #  include <windows.h>
 
-#  include <ctype.h>
 #  include <shellapi.h>
 #endif
 
@@ -248,7 +249,7 @@
    * previous size workaround. */
   wfull_len = static_cast<DWORD>(wcslen(&wfull[0]));
 
-  if (wfull_len >= 2 && isalpha(wfull[0]) &&
+  if (wfull_len >= 2 && kwsysString_isalpha(wfull[0]) &&
       wfull[1] == L':') { /* C:\Foo\bar\FooBar.txt */
     return L"\\\\?\\" + std::wstring(&wfull[0]);
   } else if (wfull_len >= 2 && wfull[0] == L'\\' &&
@@ -259,7 +260,7 @@
           wfull[6] == L'C' &&
           wfull[7] == L'\\') { /* \\?\UNC\Foo\bar\FooBar.txt */
         return std::wstring(&wfull[0]);
-      } else if (wfull_len >= 6 && isalpha(wfull[4]) &&
+      } else if (wfull_len >= 6 && kwsysString_isalpha(wfull[4]) &&
                  wfull[5] == L':') { /* \\?\C:\Foo\bar\FooBar.txt */
         return std::wstring(&wfull[0]);
       } else if (wfull_len >= 5) { /* \\?\Foo\bar\FooBar.txt */
@@ -267,7 +268,7 @@
       }
     } else if (wfull_len >= 4 && wfull[2] == L'.' &&
                wfull[3] == L'\\') { /* Starts with \\.\ a device name */
-      if (wfull_len >= 6 && isalpha(wfull[4]) &&
+      if (wfull_len >= 6 && kwsysString_isalpha(wfull[4]) &&
           wfull[5] == L':') { /* \\.\C:\Foo\bar\FooBar.txt */
         return L"\\\\?\\" + std::wstring(&wfull[4]);
       } else if (wfull_len >=
diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx
index e2af4ec..3ac75f6 100644
--- a/Source/kwsys/Glob.cxx
+++ b/Source/kwsys/Glob.cxx
@@ -8,6 +8,7 @@
 #include KWSYS_HEADER(RegularExpression.hxx)
 #include KWSYS_HEADER(SystemTools.hxx)
 #include KWSYS_HEADER(Directory.hxx)
+#include KWSYS_HEADER(String.h)
 
 // Work-around CMake dependency scanning limitation.  This must
 // duplicate the above list of headers.
@@ -16,6 +17,7 @@
 #  include "Directory.hxx.in"
 #  include "Glob.hxx.in"
 #  include "RegularExpression.hxx.in"
+#  include "String.h.in"
 #  include "SystemTools.hxx.in"
 #endif
 
@@ -23,7 +25,6 @@
 #include <string>
 #include <vector>
 
-#include <cctype>
 #include <cstdio>
 #include <cstring>
 namespace KWSYS_NAMESPACE {
@@ -162,7 +163,7 @@
         // On case-insensitive systems file names are converted to lower
         // case before matching.
         if (!preserve_case) {
-          ch = tolower(ch);
+          ch = kwsysString_tolower(ch);
         }
       }
 #endif
diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c
index a918b8d..8c22b4e 100644
--- a/Source/kwsys/ProcessUNIX.c
+++ b/Source/kwsys/ProcessUNIX.c
@@ -54,7 +54,6 @@
 #endif
 
 #include <assert.h>    /* assert */
-#include <ctype.h>     /* isspace */
 #include <dirent.h>    /* DIR, dirent */
 #include <errno.h>     /* errno */
 #include <fcntl.h>     /* fcntl */
@@ -2502,7 +2501,8 @@
    corresponding parsing format string.  The parsing format should
    have two integers to store: the pid and then the ppid.  */
 #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) ||       \
-  defined(__OpenBSD__) || defined(__GLIBC__) || defined(__GNU__)
+  defined(__NetBSD__) || defined(__OpenBSD__) || defined(__GLIBC__) ||        \
+  defined(__GNU__)
 #  define KWSYSPE_PS_COMMAND "ps axo pid,ppid"
 #  define KWSYSPE_PS_FORMAT "%d %d\n"
 #elif defined(__sun) && (defined(__SVR4) || defined(__svr4__)) /* Solaris */
diff --git a/Source/kwsys/String.c b/Source/kwsys/String.c
index 7fd159b..0ccf38d 100644
--- a/Source/kwsys/String.c
+++ b/Source/kwsys/String.c
@@ -17,84 +17,130 @@
 #    include "String.h.in"
 #  endif
 
-/* Select an implementation for strcasecmp.  */
-#  if defined(_MSC_VER)
-#    define KWSYS_STRING_USE_STRICMP
-#    include <string.h>
-#  elif defined(__GNUC__)
-#    define KWSYS_STRING_USE_STRCASECMP
-#    include <strings.h>
-#  else
-/* Table to convert upper case letters to lower case and leave all
-   other characters alone.  */
-static char kwsysString_strcasecmp_tolower[] = {
-  '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', '\010',
-  '\011', '\012', '\013', '\014', '\015', '\016', '\017', '\020', '\021',
-  '\022', '\023', '\024', '\025', '\026', '\027', '\030', '\031', '\032',
-  '\033', '\034', '\035', '\036', '\037', '\040', '\041', '\042', '\043',
-  '\044', '\045', '\046', '\047', '\050', '\051', '\052', '\053', '\054',
-  '\055', '\056', '\057', '\060', '\061', '\062', '\063', '\064', '\065',
-  '\066', '\067', '\070', '\071', '\072', '\073', '\074', '\075', '\076',
-  '\077', '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
-  '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', '\160',
-  '\161', '\162', '\163', '\164', '\165', '\166', '\167', '\170', '\171',
-  '\172', '\133', '\134', '\135', '\136', '\137', '\140', '\141', '\142',
-  '\143', '\144', '\145', '\146', '\147', '\150', '\151', '\152', '\153',
-  '\154', '\155', '\156', '\157', '\160', '\161', '\162', '\163', '\164',
-  '\165', '\166', '\167', '\170', '\171', '\172', '\173', '\174', '\175',
-  '\176', '\177', '\200', '\201', '\202', '\203', '\204', '\205', '\206',
-  '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
-  '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230',
-  '\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241',
-  '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252',
-  '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263',
-  '\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274',
-  '\275', '\276', '\277', '\300', '\301', '\302', '\303', '\304', '\305',
-  '\306', '\307', '\310', '\311', '\312', '\313', '\314', '\315', '\316',
-  '\317', '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
-  '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', '\340',
-  '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351',
-  '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362',
-  '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373',
-  '\374', '\375', '\376', '\377'
-};
-#  endif
+#  include <ctype.h>
 
-/*--------------------------------------------------------------------------*/
-int kwsysString_strcasecmp(char const* lhs, char const* rhs)
+int kwsysString_isalnum(char c)
 {
-#  if defined(KWSYS_STRING_USE_STRICMP)
-  return _stricmp(lhs, rhs);
-#  elif defined(KWSYS_STRING_USE_STRCASECMP)
-  return strcasecmp(lhs, rhs);
-#  else
-  char const* const lower = kwsysString_strcasecmp_tolower;
-  unsigned char const* us1 = (unsigned char const*)lhs;
-  unsigned char const* us2 = (unsigned char const*)rhs;
-  int result;
-  while ((result = lower[*us1] - lower[*us2++], result == 0) && *us1++) {
-  }
-  return result;
-#  endif
+  return (kwsysString_isalpha(c) | /* bitwise-or to avoid branching.  */
+          kwsysString_isdigit(c));
 }
 
-/*--------------------------------------------------------------------------*/
+int kwsysString_isalpha(char c)
+{
+  return (kwsysString_islower(c) | /* bitwise-or to avoid branching.  */
+          kwsysString_isupper(c));
+}
+
+int kwsysString_isascii(char c)
+{
+  unsigned char const uc = (unsigned char)c;
+  return (uc & 0x80) ^ 0x80;
+}
+
+int kwsysString_isblank(char c)
+{
+  unsigned char const uc = (unsigned char)c;
+  return uc < 0x80 && isblank(uc);
+}
+
+int kwsysString_iscntrl(char c)
+{
+  unsigned char const uc = (unsigned char)c;
+  return uc < 0x80 && iscntrl(uc);
+}
+
+int kwsysString_isdigit(char c)
+{
+  unsigned char const uc = (unsigned char)c;
+  /* Push '0-9' to 246-255 so integer division by 246 is 1 only for them.  */
+  return ((uc + 246 - '0') & 0xFF) / 246;
+}
+
+int kwsysString_isgraph(char c)
+{
+  unsigned char const uc = (unsigned char)c;
+  return uc < 0x80 && isgraph(uc);
+}
+
+int kwsysString_islower(char c)
+{
+  unsigned char const uc = (unsigned char)c;
+  /* Push 'a-z' to 230-255 so integer division by 230 is 1 only for them.  */
+  return ((uc + 230 - 'a') & 0xFF) / 230;
+}
+
+int kwsysString_isprint(char c)
+{
+  unsigned char const uc = (unsigned char)c;
+  /* Push 32-126 to 161-255 so integer division by 161 is 1 only for them.  */
+  return ((uc + 161 - ' ') & 0xFF) / 161;
+}
+
+int kwsysString_ispunct(char c)
+{
+  unsigned char const uc = (unsigned char)c;
+  return uc < 0x80 && ispunct(uc);
+}
+
+int kwsysString_isspace(char c)
+{
+  unsigned char const uc = (unsigned char)c;
+  return uc < 0x80 && isspace(uc);
+}
+
+int kwsysString_isupper(char c)
+{
+  unsigned char const uc = (unsigned char)c;
+  /* Push 'A-Z' to 230-255 so integer division by 230 is 1 only for them.  */
+  return ((uc + 230 - 'A') & 0xFF) / 230;
+}
+
+int kwsysString_isxdigit(char c)
+{
+  unsigned char const uc = (unsigned char)c;
+  return (
+    /* Push '0-9' to 246-255 so integer division by 246 is 1 only for them.  */
+    (((uc + 246 - '0') & 0xFF) / 246) | /* bitwise-or to avoid branching.    */
+    /* Push 'A-F' to 250-255 so integer division by 250 is 1 only for them.  */
+    (((uc + 250 - 'A') & 0xFF) / 250) | /* bitwise-or to avoid branching.    */
+    /* Push 'a-f' to 250-255 so integer division by 250 is 1 only for them.  */
+    (((uc + 250 - 'a') & 0xFF) / 250));
+}
+
+unsigned char kwsysString_tolower(char c)
+{
+  unsigned char const uc = (unsigned char)c;
+  /* Push 'A-Z' to 230-255 so integer division by 230 is 1 only for them.  */
+  return (unsigned char)(uc ^ ((((uc + 230 - 'A') & 0xFF) / 230) << 5));
+}
+
+unsigned char kwsysString_toupper(char c)
+{
+  unsigned char const uc = (unsigned char)c;
+  /* Push 'a-z' to 230-255 so integer division by 230 is 1 only for them.  */
+  return (unsigned char)(uc ^ ((((uc + 230 - 'a') & 0xFF) / 230) << 5));
+}
+
+int kwsysString_strcasecmp(char const* lhs, char const* rhs)
+{
+  int result;
+  while ((result = kwsysString_tolower(*lhs) - kwsysString_tolower(*rhs++)) ==
+           0 &&
+         *lhs++) {
+  }
+  return result;
+}
+
 int kwsysString_strncasecmp(char const* lhs, char const* rhs, size_t n)
 {
-#  if defined(KWSYS_STRING_USE_STRICMP)
-  return _strnicmp(lhs, rhs, n);
-#  elif defined(KWSYS_STRING_USE_STRCASECMP)
-  return strncasecmp(lhs, rhs, n);
-#  else
-  char const* const lower = kwsysString_strcasecmp_tolower;
-  unsigned char const* us1 = (unsigned char const*)lhs;
-  unsigned char const* us2 = (unsigned char const*)rhs;
   int result = 0;
-  while (n && (result = lower[*us1] - lower[*us2++], result == 0) && *us1++) {
+  while (n &&
+         (result = kwsysString_tolower(*lhs) - kwsysString_tolower(*rhs++)) ==
+           0 &&
+         *lhs++) {
     --n;
   }
   return result;
-#  endif
 }
 
 #endif /* KWSYS_STRING_C */
diff --git a/Source/kwsys/String.h.in b/Source/kwsys/String.h.in
index 6931051..abc74a6 100644
--- a/Source/kwsys/String.h.in
+++ b/Source/kwsys/String.h.in
@@ -16,6 +16,21 @@
 #  define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
 #endif
 #if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#  define kwsysString_isalnum kwsys_ns(String_isalnum)
+#  define kwsysString_isalpha kwsys_ns(String_isalpha)
+#  define kwsysString_isascii kwsys_ns(String_isascii)
+#  define kwsysString_isblank kwsys_ns(String_isblank)
+#  define kwsysString_iscntrl kwsys_ns(String_iscntrl)
+#  define kwsysString_isdigit kwsys_ns(String_isdigit)
+#  define kwsysString_isgraph kwsys_ns(String_isgraph)
+#  define kwsysString_islower kwsys_ns(String_islower)
+#  define kwsysString_isprint kwsys_ns(String_isprint)
+#  define kwsysString_ispunct kwsys_ns(String_ispunct)
+#  define kwsysString_isspace kwsys_ns(String_isspace)
+#  define kwsysString_isupper kwsys_ns(String_isupper)
+#  define kwsysString_isxdigit kwsys_ns(String_isxdigit)
+#  define kwsysString_tolower kwsys_ns(String_tolower)
+#  define kwsysString_toupper kwsys_ns(String_toupper)
 #  define kwsysString_strcasecmp kwsys_ns(String_strcasecmp)
 #  define kwsysString_strncasecmp kwsys_ns(String_strncasecmp)
 #endif
@@ -24,6 +39,51 @@
 extern "C" {
 #endif
 
+/** Locale-independent ASCII isalnum.  */
+kwsysEXPORT int kwsysString_isalnum(char c);
+
+/** Locale-independent ASCII isalpha.  */
+kwsysEXPORT int kwsysString_isalpha(char c);
+
+/** Locale-independent ASCII isascii.  */
+kwsysEXPORT int kwsysString_isascii(char c);
+
+/** Locale-independent ASCII isblank.  */
+kwsysEXPORT int kwsysString_isblank(char c);
+
+/** Locale-independent ASCII iscntrl.  */
+kwsysEXPORT int kwsysString_iscntrl(char c);
+
+/** Locale-independent ASCII isdigit.  */
+kwsysEXPORT int kwsysString_isdigit(char c);
+
+/** Locale-independent ASCII isgraph.  */
+kwsysEXPORT int kwsysString_isgraph(char c);
+
+/** Locale-independent ASCII islower.  */
+kwsysEXPORT int kwsysString_islower(char c);
+
+/** Locale-independent ASCII isprint.  */
+kwsysEXPORT int kwsysString_isprint(char c);
+
+/** Locale-independent ASCII ispunct.  */
+kwsysEXPORT int kwsysString_ispunct(char c);
+
+/** Locale-independent ASCII isspace.  */
+kwsysEXPORT int kwsysString_isspace(char c);
+
+/** Locale-independent ASCII isupper.  */
+kwsysEXPORT int kwsysString_isupper(char c);
+
+/** Locale-independent ASCII isxdigit.  */
+kwsysEXPORT int kwsysString_isxdigit(char c);
+
+/** Locale-independent ASCII tolower.  */
+kwsysEXPORT unsigned char kwsysString_tolower(char c);
+
+/** Locale-independent ASCII toupper.  */
+kwsysEXPORT unsigned char kwsysString_toupper(char c);
+
 /**
  * Compare two strings ignoring the case of the characters.  The
  * integer returned is negative, zero, or positive if the first string
@@ -49,6 +109,21 @@
 #  undef kwsys_ns
 #  undef kwsysEXPORT
 #  if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+#    undef kwsysString_isalnum
+#    undef kwsysString_isalpha
+#    undef kwsysString_isascii
+#    undef kwsysString_isblank
+#    undef kwsysString_iscntrl
+#    undef kwsysString_isdigit
+#    undef kwsysString_isgraph
+#    undef kwsysString_islower
+#    undef kwsysString_isprint
+#    undef kwsysString_ispunct
+#    undef kwsysString_isspace
+#    undef kwsysString_isupper
+#    undef kwsysString_isxdigit
+#    undef kwsysString_tolower
+#    undef kwsysString_toupper
 #    undef kwsysString_strcasecmp
 #    undef kwsysString_strncasecmp
 #  endif
diff --git a/Source/kwsys/System.c b/Source/kwsys/System.c
index 11257cd..cb7fc2d 100644
--- a/Source/kwsys/System.c
+++ b/Source/kwsys/System.c
@@ -1,15 +1,16 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
 #include "kwsysPrivate.h"
+#include KWSYS_HEADER(String.h)
 #include KWSYS_HEADER(System.h)
 
 /* Work-around CMake dependency scanning limitation.  This must
    duplicate the above list of headers.  */
 #if 0
+#  include "String.h.in"
 #  include "System.h.in"
 #endif
 
-#include <ctype.h>  /* isspace */
 #include <stddef.h> /* ptrdiff_t */
 #include <stdlib.h> /* malloc, free */
 #include <string.h> /* memcpy */
@@ -148,7 +149,7 @@
           in_argument = 1;
         }
       }
-    } else if (isspace((unsigned char)*c)) {
+    } else if (kwsysString_isspace(*c)) {
       if (in_argument) {
         if (in_single || in_double) {
           /* This space belongs to a quoted argument.  */
diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx
index a11487d..0a472d3 100644
--- a/Source/kwsys/SystemInformation.cxx
+++ b/Source/kwsys/SystemInformation.cxx
@@ -28,6 +28,7 @@
 // https://msdn.microsoft.com/en-us/library/ms683219(VS.85).aspx
 
 #include "kwsysPrivate.h"
+#include KWSYS_HEADER(String.h)
 #include KWSYS_HEADER(SystemInformation.hxx)
 #include KWSYS_HEADER(Process.h)
 
@@ -35,6 +36,7 @@
 // duplicate the above list of headers.
 #if 0
 #  include "Process.h.in"
+#  include "String.h.in"
 #  include "SystemInformation.hxx.in"
 #endif
 
@@ -165,7 +167,6 @@
 #  undef KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP
 #endif
 
-#include <cctype> // int isdigit(int c);
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
@@ -4131,6 +4132,10 @@
   this->TotalPhysicalMemory = tp >> 10 >> 10;
   this->AvailableVirtualMemory = av >> 10 >> 10;
   this->AvailablePhysicalMemory = ap >> 10 >> 10;
+
+  // The virtual WinAPI memory contains both physical memory and page file.
+  this->TotalVirtualMemory -= this->TotalPhysicalMemory;
+  this->AvailableVirtualMemory -= this->AvailablePhysicalMemory;
   return true;
 #else
   return false;
@@ -4163,11 +4168,11 @@
     char majorChar = unameInfo.release[0];
     char minorChar = unameInfo.release[2];
 
-    if (isdigit(majorChar)) {
+    if (kwsysString_isdigit(majorChar)) {
       linuxMajor = majorChar - '0';
     }
 
-    if (isdigit(minorChar)) {
+    if (kwsysString_isdigit(minorChar)) {
       linuxMinor = minorChar - '0';
     }
   }
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index 9d4e40b..7e23c16 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -25,6 +25,7 @@
 #include KWSYS_HEADER(FStream.hxx)
 #include KWSYS_HEADER(Encoding.h)
 #include KWSYS_HEADER(Encoding.hxx)
+#include KWSYS_HEADER(String.h)
 
 #include <algorithm>
 #include <fstream>
@@ -43,9 +44,11 @@
 // duplicate the above list of headers.
 #if 0
 #  include "Directory.hxx.in"
+#  include "Encoding.h.in"
 #  include "Encoding.hxx.in"
 #  include "FStream.hxx.in"
 #  include "RegularExpression.hxx.in"
+#  include "String.h.in"
 #  include "SystemTools.hxx.in"
 #endif
 
@@ -57,7 +60,6 @@
 #  pragma set woff 1375 /* base class destructor not virtual */
 #endif
 
-#include <cctype>
 #include <cerrno>
 #include <cstdio>
 #include <cstdlib>
@@ -320,7 +322,7 @@
     if (nlen < len) {
       // make sure the drive letter is capital
       if (nlen > 1 && buf[1] == ':') {
-        buf[0] = toupper(buf[0]);
+        buf[0] = kwsysString_toupper(buf[0]);
       }
       return buf;
     }
@@ -552,7 +554,7 @@
   casePath = path_components[idx++];
   // make sure drive letter is always upper case
   if (casePath.size() > 1 && casePath[1] == ':') {
-    casePath[0] = toupper(casePath[0]);
+    casePath[0] = kwsysString_toupper(casePath[0]);
   }
   char const* sep = "";
 
@@ -1656,9 +1658,9 @@
     return n;
   }
   n.resize(s.size());
-  n[0] = static_cast<std::string::value_type>(toupper(s[0]));
+  n[0] = static_cast<std::string::value_type>(kwsysString_toupper(s[0]));
   for (size_t i = 1; i < s.size(); i++) {
-    n[i] = static_cast<std::string::value_type>(tolower(s[i]));
+    n[i] = static_cast<std::string::value_type>(kwsysString_tolower(s[i]));
   }
   return n;
 }
@@ -1668,16 +1670,9 @@
 {
   std::string n(s);
   for (size_t i = 0; i < s.size(); i++) {
-#if defined(_MSC_VER) && defined(_MT) && defined(_DEBUG)
-    // MS has an assert that will fail if s[i] < 0; setting
-    // LC_CTYPE using setlocale() does *not* help. Painful.
-    if ((int)s[i] >= 0 && isalpha(s[i]) &&
-        (i == 0 || ((int)s[i - 1] >= 0 && isspace(s[i - 1]))))
-#else
-    if (isalpha(s[i]) && (i == 0 || isspace(s[i - 1])))
-#endif
-    {
-      n[i] = static_cast<std::string::value_type>(toupper(s[i]));
+    if (kwsysString_isalpha(s[i]) &&
+        (i == 0 || kwsysString_isspace(s[i - 1]))) {
+      n[i] = static_cast<std::string::value_type>(kwsysString_toupper(s[i]));
     }
   }
   return n;
@@ -1688,16 +1683,9 @@
 {
   std::string n(s);
   for (size_t i = 0; i < s.size(); i++) {
-#if defined(_MSC_VER) && defined(_MT) && defined(_DEBUG)
-    // MS has an assert that will fail if s[i] < 0; setting
-    // LC_CTYPE using setlocale() does *not* help. Painful.
-    if ((int)s[i] >= 0 && isalpha(s[i]) &&
-        (i == 0 || ((int)s[i - 1] >= 0 && isspace(s[i - 1]))))
-#else
-    if (isalpha(s[i]) && (i == 0 || isspace(s[i - 1])))
-#endif
-    {
-      n[i] = static_cast<std::string::value_type>(tolower(s[i]));
+    if (kwsysString_isalpha(s[i]) &&
+        (i == 0 || kwsysString_isspace(s[i - 1]))) {
+      n[i] = static_cast<std::string::value_type>(kwsysString_tolower(s[i]));
     }
   }
   return n;
@@ -1711,7 +1699,8 @@
     n.reserve(s.size());
     n += s[0];
     for (size_t i = 1; i < s.size(); i++) {
-      if (isupper(s[i]) && !isspace(s[i - 1]) && !isupper(s[i - 1])) {
+      if (kwsysString_isupper(s[i]) && !kwsysString_isspace(s[i - 1]) &&
+          !kwsysString_isupper(s[i - 1])) {
         n += ' ';
       }
       n += s[i];
@@ -1762,26 +1751,16 @@
   return newstr;
 }
 
-// Return a lower case string
-std::string SystemTools::LowerCase(std::string const& s)
+std::string SystemTools::LowerCase(std::string s)
 {
-  std::string n;
-  n.resize(s.size());
-  for (size_t i = 0; i < s.size(); i++) {
-    n[i] = static_cast<std::string::value_type>(tolower(s[i]));
-  }
-  return n;
+  std::transform(s.begin(), s.end(), s.begin(), kwsysString_tolower);
+  return s;
 }
 
-// Return a lower case string
-std::string SystemTools::UpperCase(std::string const& s)
+std::string SystemTools::UpperCase(std::string s)
 {
-  std::string n;
-  n.resize(s.size());
-  for (size_t i = 0; i < s.size(); i++) {
-    n[i] = static_cast<std::string::value_type>(toupper(s[i]));
-  }
-  return n;
+  std::transform(s.begin(), s.end(), s.begin(), kwsysString_toupper);
+  return s;
 }
 
 // Count char in string
@@ -2005,7 +1984,7 @@
     if (*cur++ == '%') {
       // Skip "%%" since it doesn't correspond to a va_arg.
       if (*cur != '%') {
-        while (!int(isalpha(*cur))) {
+        while (!kwsysString_isalpha(*cur)) {
           ++cur;
         }
         switch (*cur) {
@@ -2273,7 +2252,7 @@
   // source and destination are files so do a copy if source is newer
   // Check if source file exists first
   if (!SystemTools::FileExists(source)) {
-    return CopyStatus{ Status::POSIX_errno(), CopyStatus::SourcePath };
+    return CopyStatus{ Status::POSIX(ENOENT), CopyStatus::SourcePath };
   }
   // If destination doesn't exist, always copy
   if (!SystemTools::FileExists(destination)) {
@@ -2743,8 +2722,8 @@
   int lc;
   int rc;
   do {
-    lc = tolower(*l++);
-    rc = tolower(*r++);
+    lc = kwsysString_tolower(*l++);
+    rc = kwsysString_tolower(*r++);
   } while (lc == rc && lc);
   return lc - rc;
 }
@@ -4115,12 +4094,33 @@
 #endif
 }
 
+std::tm SystemTools::LocalTime(std::time_t timep)
+{
+  std::tm out;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  localtime_s(&out, &timep);
+#else
+  localtime_r(&timep, &out);
+#endif
+  return out;
+}
+
+std::tm SystemTools::GMTime(std::time_t timep)
+{
+  std::tm out;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  gmtime_s(&out, &timep);
+#else
+  gmtime_r(&timep, &out);
+#endif
+  return out;
+}
+
 std::string SystemTools::GetCurrentDateTime(char const* format)
 {
   char buf[1024];
-  time_t t;
-  time(&t);
-  strftime(buf, sizeof(buf), format, localtime(&t));
+  tm const t = LocalTime(std::time(nullptr));
+  strftime(buf, sizeof(buf), format, &t);
   return std::string(buf);
 }
 
diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in
index a902ab6..796924e 100644
--- a/Source/kwsys/SystemTools.hxx.in
+++ b/Source/kwsys/SystemTools.hxx.in
@@ -6,6 +6,7 @@
 #include <@KWSYS_NAMESPACE@/Configure.hxx>
 #include <@KWSYS_NAMESPACE@/Status.hxx>
 
+#include <ctime>
 #include <iosfwd>
 #include <map>
 #include <string>
@@ -132,15 +133,11 @@
    */
   static std::string UnCapitalizedWords(std::string const&);
 
-  /**
-   * Return a lower case string
-   */
-  static std::string LowerCase(std::string const&);
+  /** Return a lower-case string.  */
+  static std::string LowerCase(std::string);
 
-  /**
-   * Return a lower case string
-   */
-  static std::string UpperCase(std::string const&);
+  /** Return an upper-case string.  */
+  static std::string UpperCase(std::string);
 
   /**
    * Count char in string
@@ -861,6 +858,12 @@
    *  -----------------------------------------------------------------
    */
 
+  /** Get time as local time (thread-safe).  */
+  static std::tm LocalTime(std::time_t timep);
+
+  /** Get time as UTC time (thread-safe).  */
+  static std::tm GMTime(std::time_t timep);
+
   /** Get current time in seconds since Posix Epoch (Jan 1, 1970).  */
   static double GetTime();
 
diff --git a/Source/kwsys/testString.c b/Source/kwsys/testString.c
new file mode 100644
index 0000000..b6a1e84
--- /dev/null
+++ b/Source/kwsys/testString.c
@@ -0,0 +1,134 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(String.h)
+
+/* Work-around CMake dependency scanning limitation.  This must
+   duplicate the above list of headers.  */
+#if 0
+#  include "String.h.in"
+#endif
+
+#include <ctype.h>
+#include <locale.h>
+#include <stdio.h>
+
+#ifdef _WIN32
+static int isprint_posix(int c)
+{
+  return isprint(c) && c != '\t';
+}
+#  define isprint isprint_posix
+#endif
+
+#define MAKE_testString_(isXXXXX)                                             \
+  static int testString_##isXXXXX(void)                                       \
+  {                                                                           \
+    int i = 0;                                                                \
+    for (; i < 128; ++i) {                                                    \
+      if (!!isXXXXX(i) != !!kwsysString_##isXXXXX((char)i)) {                 \
+        printf(#isXXXXX "(%d) failed: %d\n", i,                               \
+               kwsysString_##isXXXXX((char)i));                               \
+        return 1;                                                             \
+      }                                                                       \
+    }                                                                         \
+    for (; i < 256; ++i) {                                                    \
+      if (kwsysString_##isXXXXX((char)i)) {                                   \
+        printf(#isXXXXX "(%d) failed: %d\n", i,                               \
+               kwsysString_##isXXXXX((char)i));                               \
+        return 1;                                                             \
+      }                                                                       \
+    }                                                                         \
+    return 0;                                                                 \
+  }                                                                           \
+  static int testString_##isXXXXX(void)
+
+MAKE_testString_(isalnum);
+MAKE_testString_(isalpha);
+MAKE_testString_(isascii);
+MAKE_testString_(isblank);
+MAKE_testString_(iscntrl);
+MAKE_testString_(isdigit);
+MAKE_testString_(isgraph);
+MAKE_testString_(islower);
+MAKE_testString_(isprint);
+MAKE_testString_(ispunct);
+MAKE_testString_(isspace);
+MAKE_testString_(isupper);
+MAKE_testString_(isxdigit);
+
+static int testString_tolower(void)
+{
+  int i = 0;
+  int j;
+  for (; i < 'A'; ++i) {
+    if ((j = kwsysString_tolower((char)i)) != i) {
+      printf("tolower(%d) failed: %d\n", i, j);
+      return 1;
+    }
+  }
+  for (; i <= 'Z'; ++i) {
+    if ((j = kwsysString_tolower((char)i)) != i + 32) {
+      printf("tolower(%d) failed: %d\n", i, j);
+      return 1;
+    }
+  }
+  for (; i < 256; ++i) {
+    if ((j = kwsysString_tolower((char)i)) != i) {
+      printf("tolower(%d) failed: %d\n", i, j);
+      return 1;
+    }
+  }
+  return 0;
+}
+
+static int testString_toupper(void)
+{
+  int i = 0;
+  int j;
+  for (; i < 'a'; ++i) {
+    if ((j = kwsysString_toupper((char)i)) != i) {
+      printf("toupper(%d) failed: %d\n", i, j);
+      return 1;
+    }
+  }
+  for (; i <= 'z'; ++i) {
+    if ((j = kwsysString_toupper((char)i)) != i - 32) {
+      printf("toupper(%d) failed: %d\n", i, j);
+      return 1;
+    }
+  }
+  for (; i < 256; ++i) {
+    if ((j = kwsysString_toupper((char)i)) != i) {
+      printf("toupper(%d) failed: %d\n", i, j);
+      return 1;
+    }
+  }
+  return 0;
+}
+
+int testString(int argc, char* argv[])
+{
+  int result = 0;
+  (void)argc;
+  (void)argv;
+  setlocale(LC_CTYPE, "");
+
+  result |= testString_isalnum();
+  result |= testString_isalpha();
+  result |= testString_isascii();
+  result |= testString_isblank();
+  result |= testString_iscntrl();
+  result |= testString_isdigit();
+  result |= testString_isgraph();
+  result |= testString_islower();
+  result |= testString_isprint();
+  result |= testString_ispunct();
+  result |= testString_isspace();
+  result |= testString_isupper();
+  result |= testString_isxdigit();
+  result |= testString_tolower();
+  result |= testString_toupper();
+
+  return result;
+}
diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx
index dff9dd6..b94b8f6 100644
--- a/Source/kwsys/testSystemTools.cxx
+++ b/Source/kwsys/testSystemTools.cxx
@@ -534,6 +534,21 @@
 {
   bool res = true;
 
+  // Case conversion should only affect ASCII bytes.
+  // Test using a UTF-8 Copyright Symbol because its leading byte
+  // is transformed by MSVC's tolower in a US-ASCII locale.
+  static std::string const sampleUTF8 = "y\xC2\xA9Z"; // Copyright Symbol
+  if (kwsys::SystemTools::LowerCase(sampleUTF8) != "y\xC2\xA9z") {
+    std::cerr << "Problem with LowerCase " << '"' << sampleUTF8 << '"'
+              << std::endl;
+    res = false;
+  }
+  if (kwsys::SystemTools::UpperCase(sampleUTF8) != "Y\xC2\xA9Z") {
+    std::cerr << "Problem with UpperCase " << '"' << sampleUTF8 << '"'
+              << std::endl;
+    res = false;
+  }
+
   std::string test = "mary had a little lamb.";
   if (kwsys::SystemTools::CapitalizedWords(test) !=
       "Mary Had A Little Lamb.") {
diff --git a/Templates/TestDriver.cxx.in b/Templates/TestDriver.cxx.in
index 0ccecfd..e7693e2 100644
--- a/Templates/TestDriver.cxx.in
+++ b/Templates/TestDriver.cxx.in
@@ -66,7 +66,7 @@
   }
   strcpy(new_string, string);  /* NOLINT */
   for (p = new_string; *p != 0; ++p) {
-    *p = CM_CAST(char, tolower(*p));
+    *p = CM_CAST(char, tolower(CM_CAST(unsigned char, *p)));
   }
   return new_string;
 }
diff --git a/Tests/CMakeGUI/CMakeGUITest.cmake b/Tests/CMakeGUI/CMakeGUITest.cmake
index 9e2c8cc..b3df6d1 100644
--- a/Tests/CMakeGUI/CMakeGUITest.cmake
+++ b/Tests/CMakeGUI/CMakeGUITest.cmake
@@ -1,3 +1,6 @@
+# Avoid QtTest library timeouts before ctest's timeout.
+set(ENV{QTEST_FUNCTION_TIMEOUT} 3600000)
+
 function(run_cmake_gui_test name)
   if(DEFINED ENV{CMakeGUITest_TEST_FILTER} AND NOT name MATCHES "$ENV{CMakeGUITest_TEST_FILTER}")
     return()
@@ -31,6 +34,18 @@
   if(EXISTS "${_cmakepresets_in}")
     configure_file("${_cmakepresets_in}" "${_workdir}/src/CMakePresets.json" @ONLY)
   endif()
+  set(_instrumentation_files
+    "${_srcdir}/main.cxx"
+    "${_srcdir}/lib.h"
+    "${_srcdir}/lib.cxx"
+    "${_srcdir}/callback.cmake"
+  )
+  foreach(_instrumentation_file IN LISTS _instrumentation_files)
+    if(EXISTS "${_instrumentation_file}.in")
+      cmake_path(GET _instrumentation_file FILENAME _instrumentation_file_name)
+      configure_file("${_instrumentation_file}.in" "${_workdir}/src/${_instrumentation_file_name}" @ONLY)
+    endif()
+  endforeach()
   if(_rcgt_DO_CONFIGURE)
     if(NOT _rcgt_GENERATOR)
       set(_rcgt_GENERATOR "${CMakeGUITest_GENERATOR}")
@@ -167,3 +182,11 @@
     "--preset=noExist"
   )
 run_cmake_gui_test(changingPresets)
+
+if("${CMakeGUITest_GENERATOR}" MATCHES "Make|Ninja|FASTBuild")
+  run_cmake_gui_test(instrumentation)
+  set(instrumentation_build_dir
+    "${CMakeGUITest_BINARY_DIR}/instrumentation/build"
+    )
+  include(${CMAKE_CURRENT_LIST_DIR}/instrumentation/check-data-dir.cmake)
+endif()
diff --git a/Tests/CMakeGUI/CMakeGUITest.cxx b/Tests/CMakeGUI/CMakeGUITest.cxx
index b4777f7..095e378 100644
--- a/Tests/CMakeGUI/CMakeGUITest.cxx
+++ b/Tests/CMakeGUI/CMakeGUITest.cxx
@@ -79,6 +79,28 @@
   QCOMPARE(configureDoneSignalArguments.at(0).toInt(), expectedResult);
 }
 
+void CMakeGUITest::tryGenerate(int expectedResult, int timeout)
+{
+  auto* cmake = this->m_window->findChild<QCMakeThread*>()->cmakeInstance();
+
+  CatchShow catchMessages;
+  catchMessages.setCallback<QMessageBox>([](QMessageBox* box) {
+    if (box->text().contains("Error in generation process")) {
+      box->accept();
+    }
+  });
+
+  QSignalSpy generateDoneSpy(cmake, &QCMake::generateDone);
+  QVERIFY(generateDoneSpy.isValid());
+  QMetaObject::invokeMethod(
+    this->m_window, [this]() { this->m_window->GenerateButton->click(); },
+    Qt::QueuedConnection);
+  QVERIFY(generateDoneSpy.wait(timeout));
+
+  QList<QVariant> generateDoneSignalArguments = generateDoneSpy.takeFirst();
+  QCOMPARE(generateDoneSignalArguments.at(0).toInt(), expectedResult);
+}
+
 void CMakeGUITest::sourceBinaryArgs()
 {
   QFETCH(QString, sourceDir);
@@ -151,6 +173,21 @@
                         << -1;
 }
 
+void CMakeGUITest::instrumentation()
+{
+  this->m_window->SourceDirectory->setText(CMakeGUITest_BINARY_DIR
+                                           "/instrumentation/src");
+  this->m_window->BinaryDirectory->setCurrentText(CMakeGUITest_BINARY_DIR
+                                                  "/instrumentation/build");
+
+  // Wait a bit for everything to update
+  loopSleep();
+
+  this->tryConfigure();
+  this->tryConfigure();
+  this->tryGenerate();
+}
+
 void CMakeGUITest::environment()
 {
   auto* cmake = this->m_window->findChild<QCMakeThread*>()->cmakeInstance();
diff --git a/Tests/CMakeGUI/CMakeGUITest.h b/Tests/CMakeGUI/CMakeGUITest.h
index 829e608..ee58d96 100644
--- a/Tests/CMakeGUI/CMakeGUITest.h
+++ b/Tests/CMakeGUI/CMakeGUITest.h
@@ -16,12 +16,14 @@
   CMakeSetupDialog* m_window = nullptr;
 
   void tryConfigure(int expectedResult = 0, int timeout = 60000);
+  void tryGenerate(int expectedResult = 0, int timeout = 60000);
 
 private slots:
   void sourceBinaryArgs();
   void sourceBinaryArgs_data();
   void simpleConfigure();
   void simpleConfigure_data();
+  void instrumentation();
   void environment();
   void presetArg();
   void presetArg_data();
diff --git a/Tests/CMakeGUI/CMakeLists.txt b/Tests/CMakeGUI/CMakeLists.txt
index d4c9bf8..603134f 100644
--- a/Tests/CMakeGUI/CMakeLists.txt
+++ b/Tests/CMakeGUI/CMakeLists.txt
@@ -2,7 +2,12 @@
 
 get_property(CMake_QT_MAJOR_VERSION TARGET cmake-gui PROPERTY CMake_QT_MAJOR_VERSION)
 
-find_package(Qt${CMake_QT_MAJOR_VERSION}Test REQUIRED)
+find_package(Qt${CMake_QT_MAJOR_VERSION} REQUIRED COMPONENTS
+  Core
+  Gui
+  Test
+  Widgets
+)
 
 if(MSVC)
   # QTBUG-118993: Qt uses deprecated stdext::checked_array_iterator
@@ -45,6 +50,7 @@
     )
 endif()
 add_executable(CMakeGUITest CMakeGUITest.cxx ${MOC_SRCS})
+set_property(TARGET CMakeGUITest PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMake_BIN_DIR}")
 target_link_libraries(CMakeGUITest CMakeGUIMainLib CMakeGUITestLib
   Qt${CMake_QT_MAJOR_VERSION}::Core
   Qt${CMake_QT_MAJOR_VERSION}::Test
diff --git a/Tests/CMakeGUI/instrumentation/CMakeLists.txt.in b/Tests/CMakeGUI/instrumentation/CMakeLists.txt.in
new file mode 100644
index 0000000..ee8f2a1
--- /dev/null
+++ b/Tests/CMakeGUI/instrumentation/CMakeLists.txt.in
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 4.3)
+project(instrumentation)
+
+add_executable(main main.cxx)
+add_library(lib lib.cxx)
+target_link_libraries(main lib)
+
+cmake_instrumentation(
+  API_VERSION 1
+  DATA_VERSION 1
+  CALLBACK ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/callback.cmake
+)
diff --git a/Tests/CMakeGUI/instrumentation/callback.cmake.in b/Tests/CMakeGUI/instrumentation/callback.cmake.in
new file mode 100644
index 0000000..733b15a
--- /dev/null
+++ b/Tests/CMakeGUI/instrumentation/callback.cmake.in
@@ -0,0 +1,2 @@
+file(TOUCH "instrumentation/build/callback-count.txt")
+file(APPEND "instrumentation/build/callback-count.txt" " \n")
diff --git a/Tests/CMakeGUI/instrumentation/check-data-dir.cmake b/Tests/CMakeGUI/instrumentation/check-data-dir.cmake
new file mode 100644
index 0000000..c672453
--- /dev/null
+++ b/Tests/CMakeGUI/instrumentation/check-data-dir.cmake
@@ -0,0 +1,57 @@
+set(instrumentation_v1 "${instrumentation_build_dir}/.cmake/instrumentation/v1")
+
+file(GLOB_RECURSE queries LIST_DIRECTORIES false ${instrumentation_v1}/query/*)
+list(LENGTH queries n_queries)
+
+if (NOT n_queries EQUAL 1)
+  message(FATAL_ERROR "Expected one instrumentation query, got: ${n_queries}")
+endif()
+
+file(GLOB snippets_configure ${instrumentation_v1}/data/configure-*)
+list(LENGTH snippets_configure n_snippets_configure)
+
+if (NOT n_snippets_configure EQUAL 2)
+  message(FATAL_ERROR "Expected two configure snippets, got: ${n_snippets_configure}")
+endif()
+
+file(GLOB snippets_generate ${instrumentation_v1}/data/generate-*)
+list(LENGTH snippets_generate n_snippets_generate)
+
+if (NOT n_snippets_generate EQUAL 1)
+  message(FATAL_ERROR "Expected one generate snippet, got: ${n_snippets_generate}")
+endif()
+
+file(GLOB content ${instrumentation_v1}/data/content/*)
+list(LENGTH content n_content)
+if (NOT n_content EQUAL 1)
+  message(FATAL_ERROR "Expected one content file, got: ${n_content}")
+endif()
+
+# The earliest configure snippet should not have an associated content file,
+# because we immediately re-configured, so the corresponding generation never
+# occurred.
+list(GET snippets_configure 0 first_configure)
+file(READ "${first_configure}" configure_json)
+string(JSON configure_content_file
+  ERROR_VARIABLE configure_content_error
+  GET "${configure_json}" "cmakeContent")
+if (configure_content_error)
+  message(FATAL_ERROR "Failed to get cmakeContent from ${first_configure}: ${configure_content_error}")
+endif()
+if (NOT configure_content_file STREQUAL "")
+  message(FATAL_ERROR "Expected null for cmakeContent in ${first_configure}, got: ${configure_content_file}")
+endif()
+
+execute_process(
+  COMMAND
+    "${CMAKE_CTEST_COMMAND}" --collect-instrumentation
+      "${instrumentation_build_dir}"
+)
+if (NOT EXISTS "${instrumentation_build_dir}/callback-count.txt")
+  message(FATAL_ERROR "Expected a callback output file at: ${instrumentation_build_dir}/callback-count.txt")
+endif()
+file(STRINGS "${instrumentation_build_dir}/callback-count.txt" callback_lines)
+list(LENGTH callback_lines n_callbacks)
+if (NOT n_callbacks EQUAL 1)
+  message(FATAL_ERROR "Expected one callback execution, got: ${n_callbacks}")
+endif()
diff --git a/Tests/CMakeGUI/instrumentation/lib.cxx.in b/Tests/CMakeGUI/instrumentation/lib.cxx.in
new file mode 100644
index 0000000..c912397
--- /dev/null
+++ b/Tests/CMakeGUI/instrumentation/lib.cxx.in
@@ -0,0 +1,4 @@
+int lib()
+{
+  return 0;
+}
diff --git a/Tests/CMakeGUI/instrumentation/lib.h.in b/Tests/CMakeGUI/instrumentation/lib.h.in
new file mode 100644
index 0000000..9f73b0d
--- /dev/null
+++ b/Tests/CMakeGUI/instrumentation/lib.h.in
@@ -0,0 +1 @@
+int lib();
diff --git a/Tests/CMakeGUI/instrumentation/main.cxx.in b/Tests/CMakeGUI/instrumentation/main.cxx.in
new file mode 100644
index 0000000..0362522
--- /dev/null
+++ b/Tests/CMakeGUI/instrumentation/main.cxx.in
@@ -0,0 +1,5 @@
+#include "lib.h"
+int main()
+{
+  return lib();
+}
diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt
index a50936e..cbb7fdf 100644
--- a/Tests/CMakeLib/CMakeLists.txt
+++ b/Tests/CMakeLib/CMakeLists.txt
@@ -1,13 +1,6 @@
 # Render the header file with source path macro
 configure_file(testConfig.h.in testConfig.h @ONLY)
 
-include_directories(
-  ${CMAKE_CURRENT_BINARY_DIR}
-  ${CMake_BINARY_DIR}/Source
-  ${CMake_SOURCE_DIR}/Source
-  ${CMake_SOURCE_DIR}/Source/CTest
-  )
-
 set(CMakeLib_TESTS
   testAssert.cxx
   testArgumentParser.cxx
@@ -25,7 +18,7 @@
   testRange.cxx
   testOptional.cxx
   testPathResolver.cxx
-  testSPDXSerializer.cxx
+  testSpdxSerializer.cxx
   testStdIo.cxx
   testString.cxx
   testStringAlgorithms.cxx
@@ -44,6 +37,7 @@
   testCMExtAlgorithm.cxx
   testCMExtEnumSet.cxx
   testList.cxx
+  testCMFilesystemPath.cxx
   testCMakePath.cxx
   )
 if(CMake_ENABLE_DEBUGGER)
@@ -57,9 +51,6 @@
     testDebuggerThread.cxx
     )
 endif()
-if (CMake_TEST_FILESYSTEM_PATH OR NOT CMake_HAVE_CXX_FILESYSTEM)
-  list(APPEND CMakeLib_TESTS testCMFilesystemPath.cxx)
-endif()
 
 add_executable(testUVProcessChainHelper testUVProcessChainHelper.cxx)
 target_link_libraries(testUVProcessChainHelper CMakeLib)
@@ -81,6 +72,7 @@
 
 create_test_sourcelist(CMakeLib_TEST_SRCS CMakeLibTests.cxx ${CMakeLib_TESTS})
 add_executable(CMakeLibTests ${CMakeLib_TEST_SRCS})
+target_include_directories(CMakeLibTests PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
 target_link_libraries(CMakeLibTests PRIVATE CTestLib CMakeLib)
 if(CMake_BUILD_PCH)
   target_precompile_headers(CMakeLibTests PRIVATE "<iostream>" "<cm3p/uv.h>")
diff --git a/Tests/CMakeLib/testArgumentParser.cxx b/Tests/CMakeLib/testArgumentParser.cxx
index 789ab12..176211d 100644
--- a/Tests/CMakeLib/testArgumentParser.cxx
+++ b/Tests/CMakeLib/testArgumentParser.cxx
@@ -2,6 +2,7 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 
 #include <map>
+#include <set>
 #include <string>
 #include <utility>
 #include <vector>
@@ -294,7 +295,8 @@
   for (auto const& ke : result.GetKeywordErrors()) {
     auto const ki = keywordErrors.find(ke.first);
     ASSERT_TRUE(ki != keywordErrors.end());
-    ASSERT_TRUE(ke.second == ki->second);
+    ASSERT_TRUE(ke.second.size() == 1);
+    ASSERT_TRUE(*ke.second.begin() == ki->second);
   }
 
   return true;
diff --git a/Tests/CMakeLib/testDebuggerVariablesHelper.cxx b/Tests/CMakeLib/testDebuggerVariablesHelper.cxx
index 7359231..aa21c58 100644
--- a/Tests/CMakeLib/testDebuggerVariablesHelper.cxx
+++ b/Tests/CMakeLib/testDebuggerVariablesHelper.cxx
@@ -54,8 +54,7 @@
   std::string currentBinaryDirectory = "c:/CurrentBinaryDirectory")
 {
   Dummies dummies;
-  dummies.CMake =
-    std::make_shared<cmake>(cmake::RoleProject, cmState::Project);
+  dummies.CMake = std::make_shared<cmake>(cmState::Role::Project);
   cmState* state = dummies.CMake->GetState();
   dummies.GlobalGenerator =
     std::make_shared<cmGlobalGenerator>(dummies.CMake.get());
@@ -500,9 +499,10 @@
 {
   auto variablesManager =
     std::make_shared<cmDebugger::cmDebuggerVariablesManager>();
+  auto dummies = CreateDummies("Foo");
 
-  cmake cm(cmake::RoleScript, cmState::Unknown);
-  cmFileSet fileSet(cm, "Foo", "HEADERS", cmFileSetVisibility::Public);
+  cmFileSet fileSet(dummies.Makefile.get(), "Foo", "HEADERS",
+                    cmFileSetVisibility::Public);
   BT<std::string> directory;
   directory.Value = "c:/";
   fileSet.AddDirectoryEntry(directory);
@@ -544,9 +544,10 @@
 {
   auto variablesManager =
     std::make_shared<cmDebugger::cmDebuggerVariablesManager>();
+  auto dummies = CreateDummies("Foo");
 
-  cmake cm(cmake::RoleScript, cmState::Unknown);
-  cmFileSet fileSet(cm, "Foo", "HEADERS", cmFileSetVisibility::Public);
+  cmFileSet fileSet(dummies.Makefile.get(), "Foo", "HEADERS",
+                    cmFileSetVisibility::Public);
   BT<std::string> directory;
   directory.Value = "c:/";
   fileSet.AddDirectoryEntry(directory);
diff --git a/Tests/CMakeLib/testPathResolver.cxx b/Tests/CMakeLib/testPathResolver.cxx
index d5cee74..ce759e5 100644
--- a/Tests/CMakeLib/testPathResolver.cxx
+++ b/Tests/CMakeLib/testPathResolver.cxx
@@ -9,7 +9,7 @@
 #include <utility>
 
 #ifdef _WIN32
-#  include <cctype>
+#  include <cmsys/String.h>
 #endif
 
 #include <cmsys/Status.hxx>
@@ -92,7 +92,7 @@
   std::string GetWorkingDirectoryOnDrive(char letter) override
   {
     std::string result;
-    auto i = this->WorkDirOnDrive.find(std::tolower(letter));
+    auto i = this->WorkDirOnDrive.find(cmsysString_tolower(letter));
     if (i != this->WorkDirOnDrive.end()) {
       result = i->second;
     }
diff --git a/Tests/CMakeLib/testSPDXSerializer.cxx b/Tests/CMakeLib/testSPDXSerializer.cxx
deleted file mode 100644
index 14f9f7e..0000000
--- a/Tests/CMakeLib/testSPDXSerializer.cxx
+++ /dev/null
@@ -1,648 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file LICENSE.rst or https://cmake.org/licensing for details.  */
-#include <iostream>
-#include <string>
-#include <vector>
-
-#include <cm/optional>
-
-#include <cm3p/json/reader.h>
-#include <cm3p/json/value.h>
-
-#include "cmSPDXSerializer.h"
-
-namespace {
-
-std::string const nonOptional(R"================({
-  "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld",
-  "@graph": [
-    {
-      "@id": "_:contentIdentifier_0",
-      "contentIdentifierType": "INVALID_CONTENT_IDENTIFIER_TYPE_ID",
-      "contentIdentifierValue": "",
-      "type": "ContentIdentifier"
-    },
-    {
-      "@id": "_:creationInfo_0",
-      "created": "",
-      "createdBy": [],
-      "type": "CreationInfo"
-    },
-    {
-      "@id": "_:creationInfo_1",
-      "created": "",
-      "createdBy": [],
-      "type": "CreationInfo"
-    },
-    {
-      "@id": "_:dictionaryEntry_0",
-      "key": "",
-      "type": "DictionaryEntry"
-    },
-    {
-      "@id": "_:externalIdentifier_0",
-      "externalIdentifierType": "INVALID_EXTERNAL_IDENTIFIER_TYPE_ID",
-      "identifier": "",
-      "type": "ExternalIdentifier"
-    },
-    {
-      "@id": "_:externalMap_0",
-      "externalSpdxId": "",
-      "type": "ExternalMap"
-    },
-    {
-      "@id": "_:externalRef_0",
-      "type": "ExternalRef"
-    },
-    {
-      "@id": "_:hash_0",
-      "algorithm": "INVALID_HASH_TYPE_ID",
-      "hashValue": "",
-      "type": "Hash"
-    },
-    {
-      "@id": "_:namespaceMap_0",
-      "namespace": "",
-      "prefix": "",
-      "type": "NamespaceMap"
-    },
-    {
-      "@id": "_:packageVerificationCode_0",
-      "algorithm": "INVALID_HASH_TYPE_ID",
-      "hashValue": "",
-      "type": "PackageVerificationCode"
-    },
-    {
-      "@id": "_:positiveIntegerRange_0",
-      "beginIntegerRange": 0,
-      "endIntegerRange": 0,
-      "type": "PositiveIntegerRange"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd0",
-      "type": "Agent"
-    },
-    {
-      "annotationType": "INVALID_ANNOTATION_TYPE_ID",
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd1",
-      "subject": "",
-      "type": "Annotation"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd10",
-      "type": "SpdxDocument"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd11",
-      "type": "Tool"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd12",
-      "type": "File"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd13",
-      "type": "Package"
-    },
-    {
-      "context": "",
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd14",
-      "type": "Sbom"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "snippetFromFile": "",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd15",
-      "type": "Snippet"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "licenseExpression": "",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd16",
-      "type": "LicenseExpression"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "licenseText": "",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd17",
-      "type": "SimpleLicensingText"
-    },
-    {
-      "context": "",
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd2",
-      "type": "Bom"
-    },
-    {
-      "context": "",
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd3",
-      "type": "Bundle"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd4",
-      "type": "IndividualElement"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "from": "",
-      "relationshipType": "INVALID_RELATIONSHIP_TYPE_ID",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd5",
-      "to": [],
-      "type": "LifecycleScopedRelationship"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd6",
-      "type": "Organization"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd7",
-      "type": "Person"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "from": "",
-      "relationshipType": "INVALID_RELATIONSHIP_TYPE_ID",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd8",
-      "to": [],
-      "type": "Relationship"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd9",
-      "type": "SoftwareAgent"
-    }
-  ]
-})================");
-
-std::string const Optional(R"================({
-  "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld",
-  "@graph": [
-    {
-      "@id": "_:contentIdentifier_0",
-      "contentIdentifierType": "gitoid",
-      "contentIdentifierValue": "ContentIdentifierValue",
-      "type": "ContentIdentifier"
-    },
-    {
-      "@id": "_:creationInfo_0",
-      "created": "",
-      "createdBy": [],
-      "type": "CreationInfo"
-    },
-    {
-      "@id": "_:creationInfo_1",
-      "Comment": "Comment",
-      "created": "Created",
-      "createdBy": [
-        "testRef"
-      ],
-      "createdUsing": [
-        "testRef"
-      ],
-      "type": "CreationInfo"
-    },
-    {
-      "@id": "_:dictionaryEntry_0",
-      "key": "Key",
-      "type": "DictionaryEntry",
-      "value": "Value"
-    },
-    {
-      "@id": "_:externalIdentifier_0",
-      "comment": "Comment",
-      "externalIdentifierType": "other",
-      "identifier": "Identifier",
-      "identifierLocator": [
-        "IdentifierLocator"
-      ],
-      "issuingAuthority": "IssuingAuthority",
-      "type": "ExternalIdentifier"
-    },
-    {
-      "@id": "_:externalMap_0",
-      "definingArtifact": "testRef",
-      "externalSpdxId": "ExternalSpdxId",
-      "integrityMethod": [
-        "testRef"
-      ],
-      "locationHint": "LocationHint",
-      "type": "ExternalMap"
-    },
-    {
-      "@id": "_:externalRef_0",
-      "comment": "Comment",
-      "contentType": "ContentType",
-      "externalRefType": "other",
-      "locator": [
-        "Locator"
-      ],
-      "type": "ExternalRef"
-    },
-    {
-      "@id": "_:hash_0",
-      "algorithm": "other",
-      "hashValue": "HashValue",
-      "type": "Hash"
-    },
-    {
-      "@id": "_:namespaceMap_0",
-      "namespace": "Namespace",
-      "prefix": "Namespace",
-      "type": "NamespaceMap"
-    },
-    {
-      "@id": "_:packageVerificationCode_0",
-      "algorithm": "other",
-      "hashValue": "HashValue",
-      "type": "PackageVerificationCode"
-    },
-    {
-      "@id": "_:positiveIntegerRange_0",
-      "beginIntegerRange": 1,
-      "endIntegerRange": 2,
-      "type": "PositiveIntegerRange"
-    },
-    {
-      "comment": "Comment",
-      "creationInfo": "_:creationInfo_0",
-      "description": "Description",
-      "extension": [
-        "testRef"
-      ],
-      "externalIdentifier": [
-        "testRef"
-      ],
-      "externalRef": [
-        "testRef"
-      ],
-      "name": "Name",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd0",
-      "summary": "Summary",
-      "type": "Agent",
-      "verifiedUsing": [
-        "testRef"
-      ]
-    },
-    {
-      "annotationType": "other",
-      "contentType": "ContentType",
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd1",
-      "statement": "Statement",
-      "subject": "testRef",
-      "type": "Annotation"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "dataLicense": "testRef",
-      "externalMap": "testRef",
-      "namespaceMap": "testRef",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd10",
-      "type": "SpdxDocument"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd11",
-      "type": "Tool"
-    },
-    {
-      "additionalPurpose": [
-        "other"
-      ],
-      "attributionText": "AttributionText",
-      "contentIdentifier": "testRef",
-      "contentType": "ContentType",
-      "copyrightText": "CopyrightText",
-      "creationInfo": "_:creationInfo_0",
-      "fileKind": "file",
-      "primaryPurpose": "file",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd12",
-      "type": "File"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "downloadLocation": "DownloadLocation",
-      "homePage": "HomePage",
-      "packageUrl": "PackageUrl",
-      "packageVersion": "PackageVersion",
-      "sourceInfo": "SourceInfo",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd13",
-      "type": "Package"
-    },
-    {
-      "context": "",
-      "creationInfo": "_:creationInfo_0",
-      "sbomType": [
-        "build"
-      ],
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd14",
-      "type": "Sbom"
-    },
-    {
-      "byteRange": "testRef",
-      "creationInfo": "_:creationInfo_0",
-      "lineRange": "testRef",
-      "snippetFromFile": "testRef",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd15",
-      "type": "Snippet"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "customIdToUri": [
-        "testRef"
-      ],
-      "licenseExpression": "LicenseExpression",
-      "licenseListVersion": "LicenseListVersion",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd16",
-      "type": "LicenseExpression"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "licenseText": "LicenseText",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd17",
-      "type": "SimpleLicensingText"
-    },
-    {
-      "context": "Context",
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd2",
-      "type": "Bom"
-    },
-    {
-      "context": "",
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd3",
-      "type": "Bundle"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd4",
-      "type": "IndividualElement"
-    },
-    {
-      "completeness": "noAssertion",
-      "creationInfo": "_:creationInfo_0",
-      "endTime": "EndTime",
-      "from": "testRef",
-      "relationshipType": "other",
-      "scope": "other",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd5",
-      "startTime": "StartTime",
-      "to": [
-        "testRef"
-      ],
-      "type": "LifecycleScopedRelationship"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd6",
-      "type": "Organization"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd7",
-      "type": "Person"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "from": "",
-      "relationshipType": "INVALID_RELATIONSHIP_TYPE_ID",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd8",
-      "to": [],
-      "type": "Relationship"
-    },
-    {
-      "creationInfo": "_:creationInfo_0",
-      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd9",
-      "type": "SoftwareAgent"
-    }
-  ]
-})================");
-}
-
-int testNonOptional()
-{
-  cmSPDXSimpleGraph graph("https://cmake.org/testSPDXSerialization-gnrtd");
-
-  // Core
-  graph.insert<cmSPDXAgent>();
-  graph.insert<cmSPDXAnnotation>();
-  graph.insert<cmSPDXBom>();
-  graph.insert<cmSPDXBundle>();
-  graph.insert<cmSPDXCreationInfo>();
-  graph.insert<cmSPDXDictionaryEntry>();
-  graph.insert<cmSPDXExternalIdentifier>();
-  graph.insert<cmSPDXExternalMap>();
-  graph.insert<cmSPDXExternalRef>();
-  graph.insert<cmSPDXHash>();
-  graph.insert<cmSPDXIndividualElement>();
-  graph.insert<cmSPDXLifecycleScopedRelationship>();
-  graph.insert<cmSPDXNamespaceMap>();
-  graph.insert<cmSPDXOrganization>();
-  graph.insert<cmSPDXPackageVerificationCode>();
-  graph.insert<cmSPDXPerson>();
-  graph.insert<cmSPDXPositiveIntegerRange>();
-  graph.insert<cmSPDXRelationship>();
-  graph.insert<cmSPDXSoftwareAgent>();
-  graph.insert<cmSPDXSpdxDocument>();
-  graph.insert<cmSPDXTool>();
-
-  // Software
-  graph.insert<cmSPDXContentIdentifier>();
-  graph.insert<cmSPDXFile>();
-  graph.insert<cmSPDXPackage>();
-  graph.insert<cmSPDXSbom>();
-  graph.insert<cmSPDXSnippet>();
-
-  // SimpleLicensing
-  graph.insert<cmSPDXLicenseExpression>();
-  graph.insert<cmSPDXSimpleLicensingText>();
-
-  Json::Value root;
-  Json::Reader().parse(nonOptional.c_str(), root);
-
-  std::cout << "NonOptional SPDX:";
-  std::cout << "\nConstructed Graph: " << graph.toJsonLD().toStyledString();
-  std::cout << "\nComparison Graph:" << root.toStyledString() << "\n";
-
-  // Convert to string to disregard differences in number signedness
-  return root.toStyledString() == graph.toJsonLD().toStyledString();
-};
-
-int testOptional()
-{
-  cmSPDXSimpleGraph graph("https://cmake.org/testSPDXSerialization-gnrtd");
-
-  cmSPDXIdentifierReference ident("testRef");
-
-  // Core
-  auto& agent = graph.insert<cmSPDXAgent>();
-  agent.Comment = "Comment";
-  agent.Description = "Description";
-  agent.Extension.emplace().push_back(ident);
-  agent.ExternalIdentifier.emplace().push_back(ident);
-  agent.ExternalRef.emplace().push_back(ident);
-  agent.Name = "Name";
-  agent.Summary = "Summary";
-  agent.VerifiedUsing.emplace().push_back(ident);
-
-  auto& annotation = graph.insert<cmSPDXAnnotation>();
-  annotation.AnnotationType = cmSPDXAnnotationType::OTHER;
-  annotation.ContentType = "ContentType";
-  annotation.Statement = "Statement";
-  annotation.Subject = ident;
-
-  auto& bom = graph.insert<cmSPDXBom>();
-  bom.Context = "Context";
-
-  graph.insert<cmSPDXBundle>();
-
-  auto& creationInfo = graph.insert<cmSPDXCreationInfo>();
-  creationInfo.Comment = "Comment";
-  creationInfo.Created = "Created";
-  creationInfo.CreatedBy.push_back(ident);
-  creationInfo.CreatedUsing.emplace().push_back(ident);
-
-  auto& dictionaryEntry = graph.insert<cmSPDXDictionaryEntry>();
-  dictionaryEntry.Key = "Key";
-  dictionaryEntry.Value = "Value";
-
-  auto& externalIdentifier = graph.insert<cmSPDXExternalIdentifier>();
-  externalIdentifier.Comment = "Comment";
-  externalIdentifier.ExternalIdentifierType =
-    cmSPDXExternalIdentifierType::OTHER;
-  externalIdentifier.Identifier = "Identifier";
-  externalIdentifier.IdentifierLocator.emplace().push_back(
-    "IdentifierLocator");
-  externalIdentifier.IssuingAuthority = "IssuingAuthority";
-
-  auto& externalMap = graph.insert<cmSPDXExternalMap>();
-  externalMap.DefiningArtifact = ident;
-  externalMap.ExternalSpdxId = "ExternalSpdxId";
-  externalMap.LocationHint = "LocationHint";
-  externalMap.IntegrityMethod.emplace().push_back(ident);
-
-  auto& externalRef = graph.insert<cmSPDXExternalRef>();
-  externalRef.Comment = "Comment";
-  externalRef.ContentType = "ContentType";
-  externalRef.ExternalRefType = cmSPDXExternalRefType::OTHER;
-  externalRef.Locator.emplace().push_back("Locator");
-
-  auto& hash = graph.insert<cmSPDXHash>();
-  hash.Algorithm = cmSPDXHashAlgorithm::OTHER;
-  hash.HashValue = "HashValue";
-
-  graph.insert<cmSPDXIndividualElement>();
-
-  auto& lifecycleScopedRelationship =
-    graph.insert<cmSPDXLifecycleScopedRelationship>();
-  lifecycleScopedRelationship.Completeness =
-    cmSPDXRelationshipCompletenessType::NO_ASSERTION;
-  lifecycleScopedRelationship.EndTime = "EndTime";
-  lifecycleScopedRelationship.From = ident;
-  lifecycleScopedRelationship.RelationshipType = cmSPDXRelationshipType::OTHER;
-  lifecycleScopedRelationship.StartTime = "StartTime";
-  lifecycleScopedRelationship.To.push_back(ident);
-  lifecycleScopedRelationship.Scope = cmSPDXLifecycleScopeType::OTHER;
-
-  auto& namespaceMap = graph.insert<cmSPDXNamespaceMap>();
-  namespaceMap.Namespace = "Namespace";
-  namespaceMap.Prefix = "Prefix";
-
-  graph.insert<cmSPDXOrganization>();
-
-  auto& packageVerificationCode =
-    graph.insert<cmSPDXPackageVerificationCode>();
-  packageVerificationCode.Algorithm = cmSPDXHashAlgorithm::OTHER;
-  packageVerificationCode.HashValue = "HashValue";
-  packageVerificationCode.PackageVerificationCodeExcludedFile.emplace()
-    .push_back("PacakgeVerificationCodeExcludeFile");
-
-  graph.insert<cmSPDXPerson>();
-
-  auto& positiveIntegerRange = graph.insert<cmSPDXPositiveIntegerRange>();
-  positiveIntegerRange.BeginIntegerRange = 1;
-  positiveIntegerRange.EndIntegerRange = 2;
-
-  graph.insert<cmSPDXRelationship>();
-
-  graph.insert<cmSPDXSoftwareAgent>();
-
-  auto& spdxDocument = graph.insert<cmSPDXSpdxDocument>();
-  spdxDocument.DataLicense = ident;
-  spdxDocument.ExternalMap = ident;
-  spdxDocument.NamespaceMap = ident;
-
-  graph.insert<cmSPDXTool>();
-
-  // Software
-  auto& contentIdentifier = graph.insert<cmSPDXContentIdentifier>();
-  contentIdentifier.ContentIdentifierType =
-    cmSPDXContentIdentifierType::GITOID;
-  contentIdentifier.ContentIdentifierValue = "ContentIdentifierValue";
-
-  auto& file = graph.insert<cmSPDXFile>();
-  file.AdditionalPurpose.emplace().push_back(cmSPDXSoftwarePurpose::OTHER);
-  file.AttributionText = "AttributionText";
-  file.ContentIdentifier = ident;
-  file.CopyrightText = "CopyrightText";
-  file.PrimaryPurpose = cmSPDXSoftwarePurpose::FILE;
-  file.ContentType = "ContentType";
-  file.FileKind = cmSPDXFileKindType::FILE;
-
-  auto& package = graph.insert<cmSPDXPackage>();
-  package.DownloadLocation = "DownloadLocation";
-  package.HomePage = "HomePage";
-  package.PackageUrl = "PackageUrl";
-  package.PackageVersion = "PackageVersion";
-  package.SourceInfo = "SourceInfo";
-
-  auto& sbom = graph.insert<cmSPDXSbom>();
-  sbom.SbomType.emplace().push_back(cmSPDXSbomType::BUILD);
-
-  auto& snippet = graph.insert<cmSPDXSnippet>();
-  snippet.ByteRange = ident;
-  snippet.LineRange = ident;
-  snippet.SnippetFromFile = ident;
-
-  // SimpleLicensing
-  auto& licenseExpression = graph.insert<cmSPDXLicenseExpression>();
-  licenseExpression.CustomIdToUri.emplace().push_back(ident);
-  licenseExpression.LicenseExpression = "LicenseExpression";
-  licenseExpression.LicenseListVersion = "LicenseListVersion";
-
-  auto& simpleLicensingText = graph.insert<cmSPDXSimpleLicensingText>();
-  simpleLicensingText.LicenseText = "LicenseText";
-
-  Json::Value root;
-  Json::Reader().parse(Optional.c_str(), root);
-
-  std::cout << "Optional SPDX:";
-  std::cout << "\nConstructed Graph: " << graph.toJsonLD().toStyledString();
-  std::cout << "\nComparison Graph:" << root.toStyledString() << "\n";
-
-  // Convert to string to disregard differences in number signedness
-  return root.toStyledString() == graph.toJsonLD().toStyledString();
-};
-
-int testSPDXSerializer(int /* argc */, char* /* argv */[])
-{
-  if (!testNonOptional())
-    return -1;
-
-  if (!testOptional())
-    return -1;
-
-  return 0;
-}
diff --git a/Tests/CMakeLib/testSpdxSerializer.cxx b/Tests/CMakeLib/testSpdxSerializer.cxx
new file mode 100644
index 0000000..7a5f6be
--- /dev/null
+++ b/Tests/CMakeLib/testSpdxSerializer.cxx
@@ -0,0 +1,84 @@
+
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+
+#include <cm3p/json/value.h>
+
+#include "cmSbomObject.h"
+#include "cmSpdx.h"
+#include "cmSpdxSerializer.h"
+
+#include "testCommon.h"
+
+namespace {
+
+bool testSerializeSpdxJson()
+{
+
+  auto constexpr contextUrl = "https://spdx.org/rdf/3.0.1/spdx-context.jsonld";
+
+  cmSbomDocument doc;
+  doc.Context = contextUrl;
+
+  cmSpdxDocument spdxValue;
+  spdxValue.SpdxId = "_:SPDXRef-Document";
+  spdxValue.DataLicense = "CC0-1.0";
+  auto spdx = insert_back(doc.Graph, std::move(spdxValue));
+
+  {
+    cmSpdxCreationInfo ci;
+    ci.SpdxId = "_:SPDXRef-CreationInfo";
+    ci.SpecVersion = "3.0.1";
+    spdx->CreationInfo = std::move(ci);
+  }
+
+  {
+    cmSpdxPackage pkg;
+    pkg.Name = "sample-package";
+    pkg.SpdxId = "_:SPDXRef-Package";
+
+    spdx->RootElements.emplace_back(std::move(pkg));
+  }
+
+  {
+    cmSpdxSerializer serializer;
+    doc.Serialize(serializer);
+    auto value = serializer.GetJson();
+
+    ASSERT_TRUE(value.isObject());
+
+    Json::Value const& context = value["@context"];
+    ASSERT_EQUAL(context.asString(), contextUrl);
+
+    Json::Value const& graph = value["@graph"];
+    ASSERT_TRUE(graph.isArray());
+
+    Json::Value const& docValue = graph[0];
+    ASSERT_TRUE(docValue.isObject());
+    ASSERT_EQUAL(docValue["type"].asString(), "SpdxDocument");
+    ASSERT_EQUAL(docValue["spdxId"].asString(), "_:SPDXRef-Document");
+
+    auto const& creationInfo = docValue["creationInfo"];
+    ASSERT_EQUAL(creationInfo["@id"].asString(), "_:SPDXRef-CreationInfo");
+    ASSERT_EQUAL(creationInfo["type"].asString(), "CreationInfo");
+
+    auto const& package = docValue["rootElement"][0];
+    ASSERT_EQUAL(package["type"].asString(), "software_Package");
+    ASSERT_EQUAL(package["spdxId"].asString(), "_:SPDXRef-Package");
+  }
+
+  return true;
+}
+
+} // namespace
+
+int testSpdxSerializer(int /*unused*/, char* /*unused*/[])
+{
+  return runTests({ testSerializeSpdxJson });
+}
diff --git a/Tests/CMakeLib/testSystemTools.cxx b/Tests/CMakeLib/testSystemTools.cxx
index 3581474..d34f710 100644
--- a/Tests/CMakeLib/testSystemTools.cxx
+++ b/Tests/CMakeLib/testSystemTools.cxx
@@ -96,6 +96,50 @@
   return true;
 }
 
+static bool testRelativeIfUnder()
+{
+  std::cout << "testRelativeIfUnder()\n";
+
+  std::string result = cmSystemTools::RelativeIfUnder("/a/b", "/a/b");
+  if (result != ".") {
+    std::cout << "cmSystemTools::RelativeIfUnder failed on /a/b, /a/b: "
+              << result << "\n";
+    return false;
+  }
+  result = cmSystemTools::RelativeIfUnder("/a/b", "/a/b/c/d");
+  if (result != "c/d") {
+    std::cout << "cmSystemTools::RelativeIfUnder failed on /a/b, /a/b/c/d: "
+              << result << "\n";
+    return false;
+  }
+  result = cmSystemTools::RelativeIfUnder("/d/f/", "/a/b/c/d");
+  if (result != "/a/b/c/d") {
+    std::cout << "cmSystemTools::RelativeIfUnder failed on /d/f/, /a/b/c/d: "
+              << result << "\n";
+    return false;
+  }
+  result = cmSystemTools::RelativeIfUnder("/", "/a/b");
+  if (result != "a/b") {
+    std::cout << "cmSystemTools::RelativeIfUnder failed on /, /a/b: " << result
+              << "\n";
+    return false;
+  }
+  result = cmSystemTools::RelativeIfUnder("I:/", "I:/CMakeLists.txt");
+  if (result != "CMakeLists.txt") {
+    std::cout
+      << "cmSystemTools::RelativeIfUnder failed on I:/, I:/CMakeLists.txt: "
+      << result << "\n";
+    return false;
+  }
+  result = cmSystemTools::RelativeIfUnder("", "/a/b");
+  if (result != "/a/b") {
+    std::cout << "cmSystemTools::RelativeIfUnder failed on \"\", /a/b: "
+              << result << "\n";
+    return false;
+  }
+  return true;
+}
+
 static bool testMakeTempDirectory()
 {
   std::cout << "testMakeTempDirectory()\n";
@@ -124,6 +168,7 @@
     testUpperCase,
     testVersionCompare,
     testStrVersCmp,
+    testRelativeIfUnder,
     testMakeTempDirectory,
   });
 }
diff --git a/Tests/CMakeLib/testUVProcessChain.cxx b/Tests/CMakeLib/testUVProcessChain.cxx
index 8ac16b2..de4e9ff 100644
--- a/Tests/CMakeLib/testUVProcessChain.cxx
+++ b/Tests/CMakeLib/testUVProcessChain.cxx
@@ -306,17 +306,17 @@
     return false;
   }
 
-  if (chain->OutputStream() < 0) {
+  if (!chain->OutputStream()) {
     std::cout << "OutputStream() was invalid, expecting valid" << std::endl;
     return false;
   }
-  if (chain->ErrorStream() < 0) {
+  if (!chain->ErrorStream()) {
     std::cout << "ErrorStream() was invalid, expecting valid" << std::endl;
     return false;
   }
 
-  cmUVPipeIStream output(chain->GetLoop(), chain->OutputStream());
-  cmUVPipeIStream error(chain->GetLoop(), chain->ErrorStream());
+  cmUVIStream output(chain->OutputStream());
+  cmUVIStream error(chain->ErrorStream());
 
   if (!checkOutput(output, error)) {
     return false;
@@ -338,21 +338,16 @@
     return false;
   }
 
-  if (chain->OutputStream() < 0) {
+  if (!chain->OutputStream()) {
     std::cout << "OutputStream() was invalid, expecting valid" << std::endl;
     return false;
   }
-  if (chain->ErrorStream() < 0) {
-    std::cout << "ErrorStream() was invalid, expecting valid" << std::endl;
-    return false;
-  }
-  if (chain->OutputStream() != chain->ErrorStream()) {
-    std::cout << "OutputStream() and ErrorStream() expected to be the same"
-              << std::endl;
+  if (chain->ErrorStream()) {
+    std::cout << "ErrorStream() was valid, expecting invalid" << std::endl;
     return false;
   }
 
-  cmUVPipeIStream mergedStream(chain->GetLoop(), chain->OutputStream());
+  cmUVIStream mergedStream(chain->OutputStream());
 
   std::string merged = getInput(mergedStream);
   auto qemuErrorPos = merged.find("qemu:");
@@ -412,11 +407,11 @@
     return false;
   }
 
-  if (chain->OutputStream() >= 0) {
+  if (chain->OutputStream()) {
     std::cout << "OutputStream() was valid, expecting invalid" << std::endl;
     return false;
   }
-  if (chain->ErrorStream() >= 0) {
+  if (chain->ErrorStream()) {
     std::cout << "ErrorStream() was valid, expecting invalid" << std::endl;
     return false;
   }
@@ -460,11 +455,11 @@
     return false;
   }
 
-  if (chain->OutputStream() >= 0) {
+  if (chain->OutputStream()) {
     std::cout << "OutputStream() was valid, expecting invalid" << std::endl;
     return false;
   }
-  if (chain->ErrorStream() >= 0) {
+  if (chain->ErrorStream()) {
     std::cout << "ErrorStream() was valid, expecting invalid" << std::endl;
     return false;
   }
@@ -487,7 +482,7 @@
     return false;
   }
 
-  cmUVPipeIStream output(chain.GetLoop(), chain.OutputStream());
+  cmUVIStream output(chain.OutputStream());
   auto cwd = getInput(output);
   if (!cmHasLiteralSuffix(cwd, "/Tests/CMakeLib")) {
     std::cout << "Working directory was \"" << cwd
@@ -514,7 +509,7 @@
     return false;
   }
 
-  cmUVPipeIStream output(chain.GetLoop(), chain.OutputStream());
+  cmUVIStream output(chain.OutputStream());
   auto cwd = getInput(output);
   if (!cmHasLiteralSuffix(cwd, "/Tests")) {
     std::cout << "Working directory was \"" << cwd
@@ -649,7 +644,7 @@
     return false;
   }
 
-  cmUVPipeIStream stream(chain.GetLoop(), chain.OutputStream());
+  cmUVIStream stream(chain.OutputStream());
   std::string output = getInput(stream);
   if (output != "HELO WRD!") {
     std::cout << "Output was \"" << output << "\", expected \"HELO WRD!\""
@@ -700,7 +695,7 @@
     return false;
   }
 
-  cmUVPipeIStream stream(chain.GetLoop(), chain.OutputStream());
+  cmUVIStream stream(chain.OutputStream());
   std::string output = getInput(stream);
   if (output != "HELLO world!") {
     std::cout << "Output was \"" << output << "\", expected \"HELLO world!\""
diff --git a/Tests/CMakeLib/testUVProcessChainHelper.cxx b/Tests/CMakeLib/testUVProcessChainHelper.cxx
index 29ee765..50ad761 100644
--- a/Tests/CMakeLib/testUVProcessChainHelper.cxx
+++ b/Tests/CMakeLib/testUVProcessChainHelper.cxx
@@ -1,4 +1,3 @@
-#include <cctype>
 #include <chrono>
 #include <cstdlib>
 #include <iostream>
@@ -7,6 +6,7 @@
 #include <string>
 #include <thread>
 
+#include "cmsys/String.h"
 #include "cmsys/SystemTools.hxx"
 
 #ifdef _WIN32
@@ -41,7 +41,7 @@
     std::this_thread::sleep_for(std::chrono::milliseconds(12000));
     std::string input = getStdin();
     for (auto& c : input) {
-      c = static_cast<char>(std::toupper(c));
+      c = static_cast<char>(cmsysString_toupper(c));
     }
     std::cout << input << std::flush;
     std::cerr << "2" << std::flush;
diff --git a/Tests/CMakeLib/testUVStreambuf.cxx b/Tests/CMakeLib/testUVStreambuf.cxx
index d53eab3..a901ab2 100644
--- a/Tests/CMakeLib/testUVStreambuf.cxx
+++ b/Tests/CMakeLib/testUVStreambuf.cxx
@@ -443,7 +443,7 @@
   return success;
 }
 
-bool testUVPipeIStream()
+bool testUVIStream()
 {
   int pipe[] = { -1, -1 };
   if (cmGetPipes(pipe) < 0) {
@@ -464,8 +464,11 @@
   buf.len = str.length();
   uv_write(&writeReq, pipeSink, &buf, 1, nullptr);
   uv_run(loop, UV_RUN_DEFAULT);
+  cm::uv_pipe_ptr pipeSource;
+  pipeSource.init(*loop, 0);
+  uv_pipe_open(pipeSource, pipe[0]);
 
-  cmUVPipeIStream pin(*loop, pipe[0]);
+  cmUVIStream pin(pipeSource);
   std::string line;
   std::getline(pin, line);
   if (line != "Hello world!") {
@@ -593,8 +596,8 @@
     return -1;
   }
 
-  if (!testUVPipeIStream()) {
-    std::cout << "While executing testUVPipeIStream().\n";
+  if (!testUVIStream()) {
+    std::cout << "While executing testUVIStream().\n";
     return -1;
   }
 
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 2ead810..5c2a6e6 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -80,6 +80,11 @@
 configure_file(${CMake_SOURCE_DIR}/Tests/EnforceConfig.cmake.in
                ${CMake_BINARY_DIR}/Tests/EnforceConfig.cmake @ONLY)
 
+# Fuzzing targets (outside BUILD_TESTING for OSS-Fuzz compatibility)
+if(CMake_BUILD_FUZZING AND NOT CMake_TEST_EXTERNAL_CMAKE)
+  add_subdirectory(Fuzzing)
+endif()
+
 # Testing
 if(BUILD_TESTING)
   set(CMake_TEST_DEVENV "")
@@ -157,24 +162,38 @@
   # Look for git to use for tests.
   find_program(GIT_EXECUTABLE NAMES git)
 
-  # Look for rpmbuild to use for tests.
-  # The tool does not work with spaces in the path.
-  if(NOT CMAKE_CURRENT_BINARY_DIR MATCHES " ")
-    find_program(RPMBUILD_EXECUTABLE NAMES rpmbuild)
-  else()
-    set(RPMBUILD_EXECUTABLE "RPMBUILD_EXECUTABLE-NOTFOUND")
+  if(NOT DEFINED CMake_TEST_CPACK_RPM)
+    # Look for rpmbuild to use for tests.
+    # The tool does not work with spaces in the path.
+    if(NOT CMAKE_CURRENT_BINARY_DIR MATCHES " ")
+      find_program(RPMBUILD_EXECUTABLE NAMES rpmbuild)
+    else()
+      set(RPMBUILD_EXECUTABLE "RPMBUILD_EXECUTABLE-NOTFOUND")
+    endif()
+    if(RPMBUILD_EXECUTABLE)
+      set(CMake_TEST_CPACK_RPM 1)
+    else()
+      set(CMake_TEST_CPACK_RPM 0)
+    endif()
   endif()
 
-  if(RPMBUILD_EXECUTABLE)
+  if(CMake_TEST_CPACK_RPM)
     set(CPACK_BINARY_RPM ON)
   else()
     set(CPACK_BINARY_RPM OFF)
   endif()
 
-  # Look for dpkg to use for tests.
-  find_program(DPKG_EXECUTABLE NAMES dpkg)
+  if(NOT DEFINED CMake_TEST_CPACK_DEB)
+    # Look for dpkg to use for tests.
+    find_program(DPKG_EXECUTABLE NAMES dpkg)
+    if(DPKG_EXECUTABLE)
+      set(CMake_TEST_CPACK_DEB 1)
+    else()
+      set(CMake_TEST_CPACK_DEB 0)
+    endif()
+  endif()
 
-  if(DPKG_EXECUTABLE)
+  if(CMake_TEST_CPACK_DEB)
     set(CPACK_BINARY_DEB ON)
   else()
     set(CPACK_BINARY_DEB OFF)
@@ -442,6 +461,10 @@
       ADD_TEST_MACRO(SwiftMixLib Swifty)
     endif()
   endif()
+  if(CMake_TEST_Rust)
+    ADD_TEST_MACRO(RustOnly RustOnly)
+    ADD_TEST_MACRO(RustMix RustMix)
+  endif()
   if(CMAKE_Fortran_COMPILER)
     ADD_TEST_MACRO(FortranOnly FortranOnly)
     set_property(TEST FortranOnly APPEND PROPERTY LABELS "Fortran")
@@ -747,44 +770,6 @@
     )
   endif()
 
-  add_test(LinkFlags-prepare
-    ${CMAKE_CTEST_COMMAND} -C \${CTEST_CONFIGURATION_TYPE}
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/LinkFlags"
-    "${CMake_BINARY_DIR}/Tests/LinkFlags"
-    ${build_generator_args}
-    --build-project LinkFlags
-    --build-target LinkFlags
-    --build-options
-      -DTEST_CONFIG=\${CTEST_CONFIGURATION_TYPE}
-    )
-  list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/LinkFlags")
-
-  macro(ADD_LINK_FLAGS_TEST name depends)
-    add_test(LinkFlags-${name}
-      ${CMAKE_CMAKE_COMMAND} --build "${CMake_BINARY_DIR}/Tests/LinkFlags"
-      --target LinkFlags_${name} --config \${CTEST_CONFIGURATION_TYPE}
-      )
-    set_tests_properties(LinkFlags-${name} PROPERTIES
-      PASS_REGULAR_EXPRESSION "BADFLAG" DEPENDS LinkFlags-${depends})
-  endmacro()
-  ADD_LINK_FLAGS_TEST(lib prepare)
-  ADD_LINK_FLAGS_TEST(dll lib)
-  ADD_LINK_FLAGS_TEST(mod dll)
-  ADD_LINK_FLAGS_TEST(exe mod)
-  ADD_LINK_FLAGS_TEST(lib_config exe)
-  ADD_LINK_FLAGS_TEST(dll_config lib_config)
-  ADD_LINK_FLAGS_TEST(mod_config dll_config)
-  ADD_LINK_FLAGS_TEST(exe_config mod_config)
-  ADD_LINK_FLAGS_TEST(lib_flags exe_config)
-  ADD_LINK_FLAGS_TEST(dll_flags lib_flags)
-  ADD_LINK_FLAGS_TEST(mod_flags dll_flags)
-  ADD_LINK_FLAGS_TEST(exe_flags mod_flags)
-  ADD_LINK_FLAGS_TEST(lib_flags_config exe_flags)
-  ADD_LINK_FLAGS_TEST(dll_flags_config lib_flags_config)
-  ADD_LINK_FLAGS_TEST(mod_flags_config dll_flags_config)
-  ADD_LINK_FLAGS_TEST(exe_flags_config mod_flags_config)
-
   # test for correct sub-project generation
   # not implemented in Xcode or Ninja
   if(NOT CMAKE_GENERATOR MATCHES "Xcode|Ninja|FASTBuild")
@@ -1205,7 +1190,7 @@
     endforeach()
 
     # debian specific
-    if(DPKG_EXECUTABLE)
+    if(CMake_TEST_CPACK_DEB)
       unset(CPackRun_CPackDEBConfiguration_ALL_CONFIGS)
       set(DEB_TEST_NAMES "CPackComponentsDEB")
       set(DEB_CONFIGURATIONS_TO_TEST "components-lintian-dpkgdeb-checks"
@@ -1566,10 +1551,6 @@
     add_subdirectory(UseSWIG)
   endif()
 
-  if(CMake_TEST_FindRuby)
-    add_subdirectory(FindRuby)
-  endif()
-
   add_subdirectory(FindThreads)
 
   # Matlab module
@@ -3036,25 +3017,6 @@
     PASS_REGULAR_EXPRESSION "0 tests failed out of 3")
 
   configure_file(
-    "${CMake_SOURCE_DIR}/Tests/CTestTestTimeout/test.cmake.in"
-    "${CMake_BINARY_DIR}/Tests/CTestTestTimeout/test.cmake"
-    @ONLY ESCAPE_QUOTES)
-  add_test(CTestTestTimeout ${CMAKE_CTEST_COMMAND}
-    -C "\${CTestTest_CONFIG}"
-    -S "${CMake_BINARY_DIR}/Tests/CTestTestTimeout/test.cmake" -V
-    --output-log "${CMake_BINARY_DIR}/Tests/CTestTestTimeout/testOutput.log"
-    )
-  set_tests_properties(CTestTestTimeout PROPERTIES
-    PASS_REGULAR_EXPRESSION "TestTimeout *\\.+ *\\*\\*\\*Timeout.*TestSleep *\\.+ *Passed.*timeout correctly killed child")
-
-  add_test(
-    NAME CTestTestRerunFailed
-    COMMAND ${CMAKE_CTEST_COMMAND} --rerun-failed)
-  set_tests_properties(CTestTestRerunFailed PROPERTIES
-    PASS_REGULAR_EXPRESSION "1/1 Test #1: TestTimeout" DEPENDS CTestTestTimeout
-    WORKING_DIRECTORY ${CMake_BINARY_DIR}/Tests/CTestTestTimeout)
-
-  configure_file(
     "${CMake_SOURCE_DIR}/Tests/CTestTestDepends/test.cmake.in"
     "${CMake_BINARY_DIR}/Tests/CTestTestDepends/test.cmake"
     @ONLY ESCAPE_QUOTES)
@@ -3283,6 +3245,11 @@
     set(JavaExportImport_BUILD_OPTIONS -DCMake_TEST_NESTED_MAKE_PROGRAM:FILEPATH=${CMake_TEST_EXPLICIT_MAKE_PROGRAM})
     ADD_TEST_MACRO(JavaExportImport JavaExportImport)
 
+    if("${Java_VERSION}" VERSION_GREATER_EQUAL 9)
+      set(JavaModExportImport_BUILD_OPTIONS -DCMake_TEST_NESTED_MAKE_PROGRAM:FILEPATH=${CMake_TEST_EXPLICIT_MAKE_PROGRAM})
+      ADD_TEST_MACRO(JavaModExportImport JavaModExportImport)
+    endif()
+
     get_filename_component(JAVACPATH ${Java_JAVAC_EXECUTABLE} REALPATH)
     get_filename_component(JNIPATH ${JAVACPATH} PATH)
     find_file(JNI_H jni.h
@@ -3353,75 +3320,6 @@
     endif()
   endif()
 
-  # add some cross compiler tests, for now only with makefile based generators
-  if(CMAKE_GENERATOR MATCHES "Makefiles")
-
-    # if sdcc is found, build the SimpleCOnly project with sdcc
-    find_program(SDCC_EXECUTABLE sdcc)
-    mark_as_advanced(SDCC_EXECUTABLE)
-    if(SDCC_EXECUTABLE)
-      add_test(SimpleCOnly_sdcc ${CMAKE_CTEST_COMMAND}
-        --build-and-test
-        "${CMake_SOURCE_DIR}/Tests/SimpleCOnly"
-        "${CMake_BINARY_DIR}/Tests/SimpleCOnly_sdcc"
-        ${build_generator_args}
-        --build-project SimpleC
-        --build-options
-          "-DCMAKE_SYSTEM_NAME=Generic"
-          "-DCMAKE_C_COMPILER=${SDCC_EXECUTABLE}")
-      list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/SimpleCOnly_sdcc")
-    endif()
-
-    # If a Linux -> MinGW cross compiler is found then try it
-    find_program(MINGW_CC_LINUX2WIN_EXECUTABLE i586-mingw32msvc-gcc)
-    find_program(MINGW_CXX_LINUX2WIN_EXECUTABLE i586-mingw32msvc-g++)
-    find_program(MINGW_RC_LINUX2WIN_EXECUTABLE i586-mingw32msvc-windres)
-    mark_as_advanced(MINGW_CC_LINUX2WIN_EXECUTABLE MINGW_CXX_LINUX2WIN_EXECUTABLE MINGW_RC_LINUX2WIN_EXECUTABLE)
-    if(MINGW_CC_LINUX2WIN_EXECUTABLE AND MINGW_CXX_LINUX2WIN_EXECUTABLE AND MINGW_RC_LINUX2WIN_EXECUTABLE)
-      add_test(Simple_Mingw_Linux2Win ${CMAKE_CTEST_COMMAND}
-        --build-and-test
-        "${CMake_SOURCE_DIR}/Tests/Simple"
-        "${CMake_BINARY_DIR}/Tests/Simple_Mingw_Linux2Win"
-        ${build_generator_args}
-        --build-project Simple
-        --build-options
-          "-DCMAKE_SYSTEM_NAME=Windows"
-          "-DCMAKE_C_COMPILER=${MINGW_CC_LINUX2WIN_EXECUTABLE}"
-          "-DCMAKE_CXX_COMPILER=${MINGW_CXX_LINUX2WIN_EXECUTABLE}"
-          "-DCMAKE_RC_COMPILER=${MINGW_RC_LINUX2WIN_EXECUTABLE}"
-        )
-      list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Simple_Mingw_Linux2Win")
-    endif()
-  endif()
-
-  if(CMAKE_TEST_PROJECT_CSE_DIR)
-    set(script "${CMAKE_TEST_PROJECT_CSE_DIR}/BuildProjectCSE.cmake")
-    if(NOT EXISTS "${script}")
-      set(script "${CMAKE_TEST_PROJECT_CSE_DIR}/cse_build.cmake")
-    endif()
-    if(NOT EXISTS "${script}")
-      message("warning: CMAKE_TEST_PROJECT_CSE_DIR set, but no build script found...")
-    endif()
-
-    add_test(BuildCSE ${CMAKE_CTEST_COMMAND} -V -S "${script}")
-    set_tests_properties(BuildCSE PROPERTIES TIMEOUT 5400)
-  endif()
-
-  if(CMAKE_TEST_PLPLOT_DIR)
-    add_test(plplot ${CMAKE_CTEST_COMMAND} -V -S ${CMAKE_TEST_PLPLOT_DIR}/../../EasyDashboardScripts/plplot.cmake)
-    set_tests_properties ( plplot PROPERTIES TIMEOUT 5400)
-  endif()
-
-  if(CMAKE_TEST_CHICKEN_DIR)
-    add_test(Chicken ${CMAKE_CTEST_COMMAND} -V -S ${CMAKE_TEST_CHICKEN_DIR}/../../EasyDashboardScripts/Chicken.cmake)
-    set_tests_properties(Chicken PROPERTIES TIMEOUT 5400)
-  endif()
-
-  if(CMAKE_TEST_KDELIBS_ALPHA_1_DIR)
-    add_test(KDELibsAlpha1 ${CMAKE_CTEST_COMMAND} -V -S ${CMAKE_TEST_KDELIBS_ALPHA_1_DIR}/../../EasyDashboardScripts/kdelibs.cmake)
-    set_tests_properties(KDELibsAlpha1 PROPERTIES TIMEOUT 5400)
-  endif()
-
   # Define a set of "contract" tests, each activated by a cache entry
   # named "CMake_TEST_CONTRACT_<project>".  For each Contract test,
   # the project should provide a directory with a CMakeLists.txt file
diff --git a/Tests/CTestCoverageCollectGCOV/test.cmake.in b/Tests/CTestCoverageCollectGCOV/test.cmake.in
index c19c5c2..66f1703 100644
--- a/Tests/CTestCoverageCollectGCOV/test.cmake.in
+++ b/Tests/CTestCoverageCollectGCOV/test.cmake.in
@@ -197,3 +197,65 @@
 else()
   message(FATAL_ERROR "FAILED: expected:\n${expected_out}\nGot:\n${out}")
 endif()
+
+#------------------------------------------------------------------------------#
+# Test 6: with optional argument: TARBALL_COMPRESSION "LZMA"
+#------------------------------------------------------------------------------#
+
+set(tar_file ${CTEST_BINARY_DIRECTORY}/gcov.lzma)
+ctest_coverage_collect_gcov(
+  TARBALL "${tar_file}"
+  TARBALL_COMPRESSION "LZMA"
+  SOURCE "${CTEST_SOURCE_DIRECTORY}"
+  BUILD "${CTEST_BINARY_DIRECTORY}"
+  GCOV_COMMAND "${CMAKE_COMMAND}"
+  GCOV_OPTIONS -P "@CMake_SOURCE_DIR@/Tests/CTestCoverageCollectGCOV/fakegcov.cmake")
+file(REMOVE_RECURSE "${CTEST_BINARY_DIRECTORY}/uncovered")
+
+execute_process(COMMAND
+  ${CMAKE_COMMAND} -E tar tf ${tar_file}
+  OUTPUT_VARIABLE out
+  WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
+  OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+
+string(REPLACE "\n" ";" out "${out}")
+to_relative_paths(out "${out}")
+list(SORT out)
+
+if("${out}" STREQUAL "${expected_out}")
+  message("PASSED with correct output: ${out}")
+else()
+  message(FATAL_ERROR "FAILED: expected:\n${expected_out}\nGot:\n${out}")
+endif()
+
+#------------------------------------------------------------------------------#
+# Test 7: with optional argument: TARBALL_COMPRESSION "LZMA2"
+#------------------------------------------------------------------------------#
+
+set(tar_file ${CTEST_BINARY_DIRECTORY}/gcov-lzma2.txz)
+ctest_coverage_collect_gcov(
+  TARBALL "${tar_file}"
+  TARBALL_COMPRESSION "LZMA2"
+  SOURCE "${CTEST_SOURCE_DIRECTORY}"
+  BUILD "${CTEST_BINARY_DIRECTORY}"
+  GCOV_COMMAND "${CMAKE_COMMAND}"
+  GCOV_OPTIONS -P "@CMake_SOURCE_DIR@/Tests/CTestCoverageCollectGCOV/fakegcov.cmake")
+file(REMOVE_RECURSE "${CTEST_BINARY_DIRECTORY}/uncovered")
+
+execute_process(COMMAND
+  ${CMAKE_COMMAND} -E tar tf ${tar_file}
+  OUTPUT_VARIABLE out
+  WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
+  OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+
+string(REPLACE "\n" ";" out "${out}")
+to_relative_paths(out "${out}")
+list(SORT out)
+
+if("${out}" STREQUAL "${expected_out}")
+  message("PASSED with correct output: ${out}")
+else()
+  message(FATAL_ERROR "FAILED: expected:\n${expected_out}\nGot:\n${out}")
+endif()
diff --git a/Tests/CTestTestTimeout/CMakeLists.txt b/Tests/CTestTestTimeout/CMakeLists.txt
deleted file mode 100644
index f46d3e2..0000000
--- a/Tests/CTestTestTimeout/CMakeLists.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-project(CTestTestTimeout)
-include(CTest)
-
-if(NOT TIMEOUT)
-  # Give the process time to load and start running.
-  set(TIMEOUT 4)
-endif()
-
-add_definitions(-DTIMEOUT=${TIMEOUT})
-add_executable (Sleep sleep.c)
-
-add_test(NAME TestTimeout
-  COMMAND ${CMAKE_COMMAND} -D Sleep=$<TARGET_FILE:Sleep>
-                           -D Log=${CMAKE_CURRENT_BINARY_DIR}/timeout.log
-                           -P ${CMAKE_CURRENT_SOURCE_DIR}/timeout.cmake
-  )
-set_tests_properties(TestTimeout PROPERTIES TIMEOUT ${TIMEOUT})
-
-add_test(NAME TestSleep COMMAND Sleep)
-set_tests_properties(TestSleep PROPERTIES DEPENDS TestTimeout)
diff --git a/Tests/CTestTestTimeout/CTestConfig.cmake b/Tests/CTestTestTimeout/CTestConfig.cmake
deleted file mode 100644
index bd265f9..0000000
--- a/Tests/CTestTestTimeout/CTestConfig.cmake
+++ /dev/null
@@ -1,4 +0,0 @@
-set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT")
-set(CTEST_DROP_METHOD "http")
-set(CTEST_DROP_SITE "open.cdash.org")
-set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard")
diff --git a/Tests/CTestTestTimeout/sleep.c b/Tests/CTestTestTimeout/sleep.c
deleted file mode 100644
index ebe1274..0000000
--- a/Tests/CTestTestTimeout/sleep.c
+++ /dev/null
@@ -1,21 +0,0 @@
-#if defined(_WIN32)
-#  include <windows.h>
-#else
-#  include <unistd.h>
-#endif
-
-#include <stdio.h>
-
-int main(void)
-{
-  fprintf(stderr, "before sleep\n");
-  fflush(stderr); /* should not be needed, but just in case */
-#if defined(_WIN32)
-  Sleep((TIMEOUT + 4) * 1000);
-#else
-  sleep((TIMEOUT + 4));
-#endif
-  fprintf(stderr, "after sleep\n");
-  fflush(stderr); /* should not be needed, but just in case */
-  return 0;
-}
diff --git a/Tests/CTestTestTimeout/test.cmake.in b/Tests/CTestTestTimeout/test.cmake.in
deleted file mode 100644
index c07d724..0000000
--- a/Tests/CTestTestTimeout/test.cmake.in
+++ /dev/null
@@ -1,40 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-
-# Settings:
-set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
-set(CTEST_SITE                          "@SITE@")
-set(CTEST_BUILD_NAME                    "CTestTest-@BUILDNAME@-Timeout")
-
-set(CTEST_SOURCE_DIRECTORY              "@CMake_SOURCE_DIR@/Tests/CTestTestTimeout")
-set(CTEST_BINARY_DIRECTORY              "@CMake_BINARY_DIR@/Tests/CTestTestTimeout")
-set(CTEST_CVS_COMMAND                   "@CVSCOMMAND@")
-set(CTEST_CMAKE_GENERATOR               "@CMAKE_GENERATOR@")
-set(CTEST_CMAKE_GENERATOR_PLATFORM      "@CMAKE_GENERATOR_PLATFORM@")
-set(CTEST_CMAKE_GENERATOR_TOOLSET       "@CMAKE_GENERATOR_TOOLSET@")
-set(CTEST_BUILD_CONFIGURATION           "$ENV{CMAKE_CONFIG_TYPE}")
-set(CTEST_COVERAGE_COMMAND              "@COVERAGE_COMMAND@")
-set(CTEST_NOTES_FILES                   "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
-
-#CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
-
-file(WRITE "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt" "
-TIMEOUT:STRING=@CTestTestTimeout_TIME@
-")
-
-CTEST_START(Experimental)
-CTEST_CONFIGURE(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
-CTEST_BUILD(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
-CTEST_TEST(BUILD "${CTEST_BINARY_DIRECTORY}" RETURN_VALUE res)
-
-set(log ${CTEST_BINARY_DIRECTORY}/timeout.log)
-if(EXISTS "${log}")
-  # Verify that the timeout test did not finish sleeping.
-  file(STRINGS "${log}" after_sleep REGEX "after sleep")
-  if(after_sleep)
-    message(FATAL_ERROR "Log indicates timeout did not kill child.")
-  else()
-    message(STATUS "Log indicates timeout correctly killed child.")
-  endif()
-else()
-  message(FATAL_ERROR "Log does not exist:\n  ${log}")
-endif()
diff --git a/Tests/CTestTestTimeout/timeout.cmake b/Tests/CTestTestTimeout/timeout.cmake
deleted file mode 100644
index ba2f58b..0000000
--- a/Tests/CTestTestTimeout/timeout.cmake
+++ /dev/null
@@ -1,6 +0,0 @@
-# Remove the log file.
-file(REMOVE ${Log})
-
-# Run a child that sleeps longer than the timeout of this test.
-# Log its output so check.cmake can verify it dies.
-execute_process(COMMAND ${Sleep} ERROR_FILE ${Log})
diff --git a/Tests/CompileDefinitions/runtest.c b/Tests/CompileDefinitions/runtest.c
index 37317b8..3527854 100644
--- a/Tests/CompileDefinitions/runtest.c
+++ b/Tests/CompileDefinitions/runtest.c
@@ -11,7 +11,7 @@
   char build_config_name[] = BUILD_CONFIG_NAME;
   char* c;
   for (c = build_config_name; *c; ++c) {
-    *c = (char)tolower((int)*c);
+    *c = (char)tolower((unsigned char)*c);
   }
   fprintf(stderr, "build_config_name=\"%s\"\n", build_config_name);
 #ifdef TEST_CONFIG_DEBUG
diff --git a/Tests/Cuda/Bin2C/CMakeLists.txt b/Tests/Cuda/Bin2C/CMakeLists.txt
new file mode 100644
index 0000000..cad6ccb
--- /dev/null
+++ b/Tests/Cuda/Bin2C/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 4.2)
+project(Bin2C CXX)
+
+# Goal for this example:
+# Validate that we can use CUDAToolkit bin2c
+find_package(CUDAToolkit REQUIRED)
+
+add_executable(generate generate.cpp)
+add_custom_command(
+  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/binary.bin
+  COMMAND generate ${CMAKE_CURRENT_BINARY_DIR}/binary.bin
+  )
+add_custom_command(
+  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/binary.h
+  COMMAND CUDA::bin2c ${CMAKE_CURRENT_BINARY_DIR}/binary.bin > ${CMAKE_CURRENT_BINARY_DIR}/binary.h
+  DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/binary.bin
+  )
+add_executable(CudaBin2C verify.cpp ${CMAKE_CURRENT_BINARY_DIR}/binary.h)
+target_include_directories(CudaBin2C PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
diff --git a/Tests/Cuda/Bin2C/generate.cpp b/Tests/Cuda/Bin2C/generate.cpp
new file mode 100644
index 0000000..c8b2d3e
--- /dev/null
+++ b/Tests/Cuda/Bin2C/generate.cpp
@@ -0,0 +1,18 @@
+#include <fstream>
+#include <ios>
+
+static unsigned char const contents[] = {
+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+};
+
+int main(int argc, char** argv)
+{
+  if (argc != 2) {
+    return 1;
+  }
+
+  std::ofstream fout(argv[1], std::ios::out | std::ios::binary);
+  fout.write(reinterpret_cast<char const*>(contents), sizeof(contents));
+
+  return 0;
+}
diff --git a/Tests/Cuda/Bin2C/verify.cpp b/Tests/Cuda/Bin2C/verify.cpp
new file mode 100644
index 0000000..8eafb39
--- /dev/null
+++ b/Tests/Cuda/Bin2C/verify.cpp
@@ -0,0 +1,18 @@
+#include <cstdlib>
+
+#include "binary.h"
+
+int main()
+{
+  if (sizeof(imageBytes) != 8) {
+    return 1;
+  }
+
+  for (size_t i = 0; i < 8; i++) {
+    if (imageBytes[i] != i) {
+      return 1;
+    }
+  }
+
+  return 0;
+}
diff --git a/Tests/Cuda/CMakeLists.txt b/Tests/Cuda/CMakeLists.txt
index c1952c5..a355a4d 100644
--- a/Tests/Cuda/CMakeLists.txt
+++ b/Tests/Cuda/CMakeLists.txt
@@ -31,3 +31,4 @@
 endif()
 
 add_cuda_test_macro(Cuda.WithC CudaWithC)
+add_cuda_test_macro(Cuda.Bin2C CudaBin2C)
diff --git a/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/CMakeLists.txt b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/CMakeLists.txt
index d1c4ff2..4f6a953 100644
--- a/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/CMakeLists.txt
+++ b/Tests/ExportImport/Import/install-RUNTIME_DEPENDENCIES/CMakeLists.txt
@@ -1,4 +1,5 @@
 set(CMAKE_SKIP_RPATH OFF)
+cmake_policy(SET CMP0207 NEW)
 
 # Import targets from the install tree.
 include(${Import_BINARY_DIR}/../Root/install-RUNTIME_DEPENDENCY_SET/targets.cmake)
diff --git a/Tests/FindPackageCpsTest/CMakeLists.txt b/Tests/FindPackageCpsTest/CMakeLists.txt
index 9d32c37..232c7d8 100644
--- a/Tests/FindPackageCpsTest/CMakeLists.txt
+++ b/Tests/FindPackageCpsTest/CMakeLists.txt
@@ -1,8 +1,6 @@
 cmake_minimum_required(VERSION 3.31)
 project(FindPackageCpsTest)
 
-set(CMAKE_EXPERIMENTAL_FIND_CPS_PACKAGES "e82e467b-f997-4464-8ace-b00808fff261")
-
 # Protect tests from running inside the default install prefix.
 set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/NotDefaultPrefix")
 
@@ -29,6 +27,13 @@
   endif()
 endfunction()
 
+function(expect_property TARGET PROPERTY DESCRIPTION EXPECTED)
+  get_target_property(actual ${TARGET} ${PROPERTY})
+  if(NOT "${actual}" STREQUAL "${EXPECTED}")
+    message(SEND_ERROR "${TARGET} has wrong ${DESCRIPTION} '${actual}' !")
+  endif()
+endfunction()
+
 function(test_version PACKAGE LITERAL COUNT MAJOR MINOR PATCH TWEAK)
   if(NOT ${PACKAGE}_FOUND)
     message(SEND_ERROR "${PACKAGE} not found !")
@@ -47,6 +52,13 @@
   test_version(${PACKAGE} "${VERSION}" 0 0 0 0 0)
 endfunction()
 
+function(expect_global TARGET VALUE)
+  get_target_property(global "${TARGET}" IMPORTED_GLOBAL)
+  if((VALUE AND NOT global) OR (NOT VALUE AND global))
+    message(SEND_ERROR "${TARGET} has wrong IMPORTED_GLOBAL '${global}' !")
+  endif()
+endfunction()
+
 ###############################################################################
 # Test a basic package search.
 # It should NOT find the package's CMake package file.
@@ -71,6 +83,7 @@
 
 ###############################################################################
 # Test finding a package whose CPS file is in the package prefix root.
+
 set(RootTest_DIR "${CMAKE_CURRENT_SOURCE_DIR}/RootTest")
 find_package(RootTest)
 if(NOT RootTest_FOUND)
@@ -159,19 +172,27 @@
 elseif(NOT TARGET Foo::Empty)
   message(SEND_ERROR "Foo::Empty missing !")
 else()
-  get_property(pt_includes
-    TARGET Foo::PrefixTest PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
-  if(NOT "${pt_includes}" STREQUAL "$<$<CONFIG:default>:${CMAKE_CURRENT_SOURCE_DIR}/include>" )
-    message(SEND_ERROR "Foo::PrefixTest has wrong includes '${pt_includes}' !")
-  endif()
-  set(pt_includes)
+  expect_property(
+    Foo::PrefixTest INTERFACE_INCLUDE_DIRECTORIES "includes"
+    "$<$<CONFIG:default>:${CMAKE_CURRENT_SOURCE_DIR}/include>")
 
-  get_property(rt_includes
-    TARGET Foo::RelativeTest PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
-  if(NOT "${rt_includes}" STREQUAL "$<$<CONFIG:default>:${CMAKE_CURRENT_SOURCE_DIR}/cps/../include>")
-    message(SEND_ERROR "Foo::RelativeTest has wrong includes '${rt_includes}' !")
-  endif()
-  set(rt_includes)
+  expect_property(
+    Foo::RelativeTest INTERFACE_INCLUDE_DIRECTORIES "includes"
+    "$<$<CONFIG:default>:${CMAKE_CURRENT_SOURCE_DIR}/cps/../include>")
+
+  expect_global(Foo::Empty FALSE)
+endif()
+
+###############################################################################
+# Test importing into global scope.
+
+find_package(Global CONFIG GLOBAL)
+if(NOT Global_FOUND)
+  message(SEND_ERROR "Global not found !")
+elseif(NOT TARGET Global::Target)
+  message(SEND_ERROR "Global::Target missing !")
+else()
+  expect_global(Foo::Empty FALSE)
 endif()
 
 ###############################################################################
@@ -196,9 +217,24 @@
 
 find_package(RequiresTest CONFIG REQUIRED)
 
-add_library(requires-test STATIC requires-test.cxx)
+add_executable(requires-test requires-test.cxx)
 target_link_libraries(requires-test RequiresTest::Indirect)
 
+add_executable(requires-test-compile_only requires-test.cxx)
+target_link_libraries(requires-test-compile_only RequiresTest::CompileOnly)
+
+expect_property(
+  RequiresTest::Other INTERFACE_LINK_LIBRARIES
+  "link libraries" "every-config;$<$<CONFIG:test>:test-config>")
+
+expect_property(
+  RequiresTest::Other IMPORTED_LINK_DEPENDENT_LIBRARIES
+  "dyld requirements (any config)" "RequiresTest::Private1")
+
+expect_property(
+  RequiresTest::Other IMPORTED_LINK_DEPENDENT_LIBRARIES_TEST
+  "dyld requirements ('TEST' config)" "RequiresTest::Private2")
+
 ###############################################################################
 # Test importing of (language-specific) include paths.
 
@@ -319,16 +355,10 @@
 elseif(NOT TARGET DefaultConfigurationsTest::Target2)
   message(SEND_ERROR "DefaultConfigurationsTest::Target2 missing !")
 else()
-  get_property(dct1_configs
-    TARGET DefaultConfigurationsTest::Target1 PROPERTY IMPORTED_CONFIGURATIONS)
-  if(NOT "${dct1_configs}" STREQUAL "DEFAULT;TEST")
-    message(SEND_ERROR "DefaultConfigurationsTest::Target1 has wrong configurations '${dct1_configs}' !")
-  endif()
-  get_property(dct2_configs
-    TARGET DefaultConfigurationsTest::Target2 PROPERTY IMPORTED_CONFIGURATIONS)
-  if(NOT "${dct2_configs}" STREQUAL "TEST")
-    message(SEND_ERROR "DefaultConfigurationsTest::Target2 has wrong configurations '${dct2_configs}' !")
-  endif()
-  set(dct1_configs)
-  set(dct2_configs)
+  expect_property(
+    DefaultConfigurationsTest::Target1 IMPORTED_CONFIGURATIONS
+    "configurations" "DEFAULT;TEST")
+  expect_property(
+    DefaultConfigurationsTest::Target2 IMPORTED_CONFIGURATIONS
+    "configurations" "TEST")
 endif()
diff --git a/Tests/FindPackageCpsTest/cps/RequiresTest.cps b/Tests/FindPackageCpsTest/cps/RequiresTest.cps
index 736e25c..3a6affb 100644
--- a/Tests/FindPackageCpsTest/cps/RequiresTest.cps
+++ b/Tests/FindPackageCpsTest/cps/RequiresTest.cps
@@ -1,5 +1,5 @@
 {
-  "cps_version": "0.13",
+  "cps_version": "0.14.0",
   "name": "RequiresTest",
   "cps_path": "@prefix@/cps",
   "components": {
@@ -14,6 +14,36 @@
           "ANSWER": 42
         }
       }
+    },
+    "CompileOnly": {
+      "type": "interface",
+      "compile_requires": [ ":BrokenLibrary" ]
+    },
+    "BrokenLibrary": {
+      "type": "archive",
+      "location": "@prefix@/lib/does-not-exist.a",
+      "definitions": {
+        "*": {
+          "ANSWER": 42
+        }
+      }
+    },
+    "Private1": {
+      "type": "dylib"
+    },
+    "Private2": {
+      "type": "dylib"
+    },
+    "Other": {
+      "type": "dylib",
+      "link_libraries": [ "every-config" ],
+      "dyld_requires": [ ":Private1" ],
+      "configurations": {
+        "test": {
+          "link_libraries": [ "test-config" ],
+          "dyld_requires": [ ":Private2" ]
+        }
+      }
     }
   }
 }
diff --git a/Tests/FindPackageCpsTest/cps/global.cps b/Tests/FindPackageCpsTest/cps/global.cps
new file mode 100644
index 0000000..ecc6e6a
--- /dev/null
+++ b/Tests/FindPackageCpsTest/cps/global.cps
@@ -0,0 +1,10 @@
+{
+  "cps_version": "0.13",
+  "name": "Global",
+  "cps_path": "@prefix@/cps",
+  "components": {
+    "Target": {
+      "type": "interface"
+    }
+  }
+}
diff --git a/Tests/FindPackageCpsTest/requires-test.cxx b/Tests/FindPackageCpsTest/requires-test.cxx
index 39d649c..6f52bd6 100644
--- a/Tests/FindPackageCpsTest/requires-test.cxx
+++ b/Tests/FindPackageCpsTest/requires-test.cxx
@@ -5,3 +5,8 @@
 #    error ANSWER has the wrong value
 #  endif
 #endif
+
+int main()
+{
+  return 0;
+}
diff --git a/Tests/FindRuby/CMakeLists.txt b/Tests/FindRuby/CMakeLists.txt
deleted file mode 100644
index a6de4d6..0000000
--- a/Tests/FindRuby/CMakeLists.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-if(CMake_TEST_FindRuby)
-
-  # Looks for ruby >=1.9.9, which is true on any Ubuntu (that installs it) or macOS (> 10.9)
-  add_test(NAME FindRuby.Test COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindRuby/Test"
-    "${CMake_BINARY_DIR}/Tests/FindRuby/Test"
-    ${build_generator_args}
-    --build-project TestRuby
-    --build-options ${build_options}
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
-
-  # Looks for ruby >= 50.1.0, which should logically fail
-  add_test(NAME FindRuby.Fail COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindRuby/Fail"
-    "${CMake_BINARY_DIR}/Tests/FindRuby/Fail"
-    ${build_generator_args}
-    --build-project TestRubyFail
-    --build-options ${build_options}
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
-  set_tests_properties(FindRuby.Fail PROPERTIES
-    PASS_REGULAR_EXPRESSION "Could NOT find Ruby.*(Required[ \n]+is[ \n]+at[ \n]+least[ \n]+version[ \n]*\"[0-9]+\\.[0-9]+\\.[0-9]+\")")
-
-  # Looks for 1.9.9 EXACTLY, which unlike the "FindRuby" test above will fail on every machine
-  # since this version doesn't exist (ruby goes from 1.9.3 to 2.0.0)
-  add_test(NAME FindRuby.FailExact COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindRuby/FailExact"
-    "${CMake_BINARY_DIR}/Tests/FindRuby/FailExact"
-    ${build_generator_args}
-    --build-project TestRubyFailExact
-    --build-options ${build_options}
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
-  set_tests_properties(FindRuby.FailExact PROPERTIES
-    PASS_REGULAR_EXPRESSION "Could NOT find Ruby.*Required[ \n]+is[ \n]+exact[ \n]+version[ \n]+\"1\\.9\\.9\"")
-
-  # RBENV specific test
-  if(CMake_TEST_FindRuby_RBENV)
-    add_test(NAME FindRuby.Rbenv COMMAND
-      ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-      --build-and-test
-      "${CMake_SOURCE_DIR}/Tests/FindRuby/Rbenv"
-      "${CMake_BINARY_DIR}/Tests/FindRuby/Rbenv"
-      ${build_generator_args}
-      --build-project TestRBENV
-      --build-options ${build_options}
-      --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-      )
-  endif()
-
-  # RVM specific test
-  if(CMake_TEST_FindRuby_RVM)
-    add_test(NAME FindRuby.Rvm COMMAND
-      ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-      --build-and-test
-      "${CMake_SOURCE_DIR}/Tests/FindRuby/Rvm"
-      "${CMake_BINARY_DIR}/Tests/FindRuby/Rvm"
-      ${build_generator_args}
-      --build-project TestRVM
-      --build-options ${build_options}
-      --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-      )
-  endif()
-endif()
diff --git a/Tests/FindRuby/Fail/CMakeLists.txt b/Tests/FindRuby/Fail/CMakeLists.txt
deleted file mode 100644
index 9185ba5..0000000
--- a/Tests/FindRuby/Fail/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-cmake_minimum_required(VERSION 3.17)
-project(TestRubyFail LANGUAGES NONE)
-
-# Should always fail since there is NO ruby 50.1.0 yet.
-find_package(Ruby 50.1.0 REQUIRED)
diff --git a/Tests/FindRuby/FailExact/CMakeLists.txt b/Tests/FindRuby/FailExact/CMakeLists.txt
deleted file mode 100644
index 1ebc0ae..0000000
--- a/Tests/FindRuby/FailExact/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-cmake_minimum_required(VERSION 3.17)
-project(TestRubyFailExact LANGUAGES NONE)
-
-# Should always fail since there is NO ruby 1.9.9 (goes from 1.9.3 to 2.0.0)
-find_package(Ruby 1.9.9 EXACT REQUIRED)
-if (NOT Ruby_FOUND)
-  message (FATAL_ERROR "Failed to find Ruby 1.9.9")
-endif()
diff --git a/Tests/FindRuby/Rbenv/CMakeLists.txt b/Tests/FindRuby/Rbenv/CMakeLists.txt
deleted file mode 100644
index 3994c68..0000000
--- a/Tests/FindRuby/Rbenv/CMakeLists.txt
+++ /dev/null
@@ -1,77 +0,0 @@
-cmake_minimum_required(VERSION 3.31)
-project(TestRBENV LANGUAGES NONE)
-
-include(CTest)
-
-# Test environment has RBENV_ROOT setup
-find_program (rbenv
-        NAMES rbenv
-        NAMES_PER_DIR
-        PATHS "$ENV{HOME}/.rbenv/bin/rbenv" ENV RBENV_ROOT
-        PATH_SUFFIXES bin Scripts
-        NO_CACHE)
-execute_process (COMMAND "${rbenv}" "which" "ruby"
-        RESULT_VARIABLE result
-        OUTPUT_VARIABLE RBENV_RUBY
-        ERROR_QUIET
-        OUTPUT_STRIP_TRAILING_WHITESPACE)
-
-# Make sure we found a valid Ruby interpreter
-if(NOT RBENV_RUBY)
-  message(FATAL_ERROR "Unable to find RBENV using RBENV_ROOT ${RBENV_ROOT}")
-endif()
-
-# Get the version of rbenv Ruby
-execute_process (COMMAND "${RBENV_RUBY}" -e "puts RUBY_VERSION"
-  RESULT_VARIABLE result
-  OUTPUT_VARIABLE RBENV_RUBY_VERSION
-  ERROR_QUIET
-  OUTPUT_STRIP_TRAILING_WHITESPACE)
-
-if (result)
-  message (FATAL_ERROR "Unable to detect rbenv ruby version from '${RBENV_RUBY}': ${RBENV_RUBY_VERSION}")
-endif()
-
-# Find system Ruby
-execute_process(COMMAND "${CMAKE_COMMAND}" -E env PATH=/usr/bin:/bin "which" "ruby"
-                RESULT_VARIABLE result
-                OUTPUT_VARIABLE SYSTEM_RUBY
-                ERROR_QUIET
-                OUTPUT_STRIP_TRAILING_WHITESPACE)
-
-if (SYSTEM_RUBY MATCHES "${RBENV_RUBY}")
-  message(FATAL_ERROR "System Ruby (${SYSTEM_RUBY}) matches rbenv Ruby (${RBENV_RUBY})")
-endif()
-
-# Get version of the system Ruby
-execute_process (COMMAND "${SYSTEM_RUBY}" -e "puts RUBY_VERSION"
-                 RESULT_VARIABLE result
-                 OUTPUT_VARIABLE SYSTEM_RUBY_VERSION
-                 ERROR_QUIET
-                 OUTPUT_STRIP_TRAILING_WHITESPACE)
-
-if (result)
-  message (FATAL_ERROR "Unable to detect system ruby version from '${SYSTEM_RUBY}': ${SYSTEM_RUBY_VERSION}")
-endif()
-
-if(SYSTEM_RUBY_VERSION VERSION_EQUAL RBENV_RUBY_VERSION)
-  message(FATAL_ERROR "Your RBENV Ruby Version and standard ruby version are the same (${RBENV_RUBY_VERSION}).")
-endif()
-
-message(STATUS "Found standard Ruby (${SYSTEM_RUBY_VERSION}): ${SYSTEM_RUBY}")
-message(STATUS "Found rbenv Ruby (${RBENV_RUBY_VERSION}): ${RBENV_RUBY}")
-
-add_test(NAME FindRuby.RbenvDefault
-        COMMAND "${CMAKE_COMMAND}" -E env "RBENV_ROOT=$ENV{RBENV_ROOT}"
-                "${CMAKE_COMMAND}"  "-DRBENV_RUBY=${RBENV_RUBY}" "-DSYSTEM_RUBY=${SYSTEM_RUBY}" "-DRBENV_RUBY_VERSION=${RBENV_RUBY_VERSION}" "-DSYSTEM_RUBY_VERSION=${SYSTEM_RUBY_VERSION}"
-                -P "${CMAKE_CURRENT_LIST_DIR}/RbenvDefault.cmake")
-
-add_test(NAME FindRuby.RbenvOnly
-         COMMAND "${CMAKE_COMMAND}" -E env "RBENV_ROOT=$ENV{RBENV_ROOT}"
-                 "${CMAKE_COMMAND}"  "-DRBENV_RUBY=${RBENV_RUBY}" "-DSYSTEM_RUBY=${SYSTEM_RUBY}" "-DRBENV_RUBY_VERSION=${RBENV_RUBY_VERSION}" "-DSYSTEM_RUBY_VERSION=${SYSTEM_RUBY_VERSION}"
-                 -P "${CMAKE_CURRENT_LIST_DIR}/RbenvOnly.cmake")
-
-add_test(NAME FindRuby.RbenvStandard
-        COMMAND "${CMAKE_COMMAND}" -E env "RBENV_ROOT=$ENV{RBENV_ROOT}"
-                "${CMAKE_COMMAND}"  "-DRBENV_RUBY=${RBENV_RUBY}" "-DSYSTEM_RUBY=${SYSTEM_RUBY}" "-DRBENV_RUBY_VERSION=${RBENV_RUBY_VERSION}" "-DSYSTEM_RUBY_VERSION=${SYSTEM_RUBY_VERSION}"
-                -P "${CMAKE_CURRENT_LIST_DIR}/RbenvStandard.cmake")
diff --git a/Tests/FindRuby/Rbenv/RbenvStandard.cmake b/Tests/FindRuby/Rbenv/RbenvStandard.cmake
deleted file mode 100644
index 75cff89..0000000
--- a/Tests/FindRuby/Rbenv/RbenvStandard.cmake
+++ /dev/null
@@ -1,29 +0,0 @@
-set(CMAKE_FIND_LIBRARY_PREFIXES "")
-set(CMAKE_FIND_LIBRARY_SUFFIXES "")
-
-set (Ruby_FIND_VIRTUALENV STANDARD)
-unset(ENV{MY_RUBY_HOME}) # Suppress RVM code path for this test.
-
-# We should find the standard Ruby
-unset(Ruby_EXECUTABLE CACHE)
-unset(RUBY_EXECUTABLE) # compatibility variable
-find_package (Ruby QUIET)
-if (NOT Ruby_EXECUTABLE STREQUAL "${SYSTEM_RUBY}")
-  message (FATAL_ERROR "Failed to find standard Ruby: ${Ruby_EXECUTABLE}")
-endif()
-
-# We should not find the rbenv Ruby or standard Ruby
-unset(Ruby_EXECUTABLE CACHE)
-unset(RUBY_EXECUTABLE) # compatibility variable
-find_package (Ruby ${RBENV_RUBY_VERSION} EXACT QUIET)
-if (NOT Ruby_EXECUTABLE STREQUAL "Ruby_EXECUTABLE-NOTFOUND")
-  message (FATAL_ERROR "Incorrectly found rbenv Ruby: ${Ruby_EXECUTABLE}")
-endif()
-
-# We should find standard Ruby
-unset(Ruby_EXECUTABLE CACHE)
-unset(RUBY_EXECUTABLE) # compatibility variable
-find_package (Ruby ${SYSTEM_RUBY_VERSION} EXACT QUIET)
-if (NOT Ruby_EXECUTABLE MATCHES "${SYSTEM_RUBY}")
-  message (FATAL_ERROR "Failed to find standard Ruby: ${Ruby_EXECUTABLE}")
-endif()
diff --git a/Tests/FindRuby/Rvm/CMakeLists.txt b/Tests/FindRuby/Rvm/CMakeLists.txt
deleted file mode 100644
index 14bdbec..0000000
--- a/Tests/FindRuby/Rvm/CMakeLists.txt
+++ /dev/null
@@ -1,75 +0,0 @@
-cmake_minimum_required(VERSION 3.17)
-project(TestRVM LANGUAGES NONE)
-
-include(CTest)
-
-# To run this test, you need to have at least one RVM ruby installed
-# and to ensure that the env variable 'MY_RUBY_HOME' is set to a valid RVM ruby when you run the test
-# (which is the case if you have done `rvm use x.y.z`, but could be manually set too)
-
-# Properly using rvm would require sourcing a shell script, eg `source "$HOME/.rvm/scripts/rvm"`
-# Instead, I'll just rely on the env variable MY_RUBY_HOME
-set(MY_RUBY_HOME "$ENV{MY_RUBY_HOME}")
-if(NOT MY_RUBY_HOME)
-  message(FATAL_ERROR "Env variable MY_RUBY_HOME should be set to a valid RVM ruby location, or you should call `rvm use x.y.z` before")
-endif()
-execute_process (COMMAND "${MY_RUBY_HOME}/bin/ruby" -e "puts RUBY_VERSION"
-                 RESULT_VARIABLE result
-                 OUTPUT_VARIABLE RVM_RUBY_VERSION
-                 ERROR_QUIET
-                 OUTPUT_STRIP_TRAILING_WHITESPACE)
-
-if (result)
-  message (FATAL_ERROR "Unable to detect RVM ruby version from `${MY_RUBY_HOME}/bin/ruby`: ${RVM_RUBY_VERSION}")
-endif()
-
-execute_process(COMMAND "${CMAKE_COMMAND}" -E env --unset=MY_RUBY_HOME PATH=/usr/bin:/bin
-                        "which" "ruby"
-                 RESULT_VARIABLE result
-                 OUTPUT_VARIABLE SYSTEM_RUBY
-                 ERROR_QUIET
-                 OUTPUT_STRIP_TRAILING_WHITESPACE)
-
-if (SYSTEM_RUBY MATCHES "^${MY_RUBY_HOME}/.+")
-  message(FATAL_ERROR "Unable to find system ruby, found ${SYSTEM_RUBY} which is part of MY_RUBY_HOME=${MY_RUBY_HOME}")
-endif()
-
-# Check version of the system ruby executable.
-execute_process (COMMAND "${SYSTEM_RUBY}" -e "puts RUBY_VERSION"
-                 RESULT_VARIABLE result
-                 OUTPUT_VARIABLE SYSTEM_RUBY_VERSION
-                 ERROR_QUIET
-                 OUTPUT_STRIP_TRAILING_WHITESPACE)
-
-if (result)
-  message (FATAL_ERROR "Unable to detect system ruby version from '${SYSTEM_RUBY}': ${SYSTEM_RUBY_VERSION}")
-endif()
-
-if(SYSTEM_RUBY_VERSION VERSION_EQUAL RVM_RUBY_VERSION)
-  message(FATAL_ERROR "Your RVM Ruby Version and your System ruby version are the same (${RVM_RUBY_VERSION}).")
-endif()
-
-message("Found System Ruby (${SYSTEM_RUBY_VERSION}): ${SYSTEM_RUBY}")
-message("Found  RVM   Ruby (${RVM_RUBY_VERSION}): ${MY_RUBY_HOME}/bin/ruby")
-
-add_test(NAME FindRuby.RvmDefault
-         COMMAND "${CMAKE_COMMAND}" -E env "MY_RUBY_HOME=${MY_RUBY_HOME}"
-                 "${CMAKE_COMMAND}" "-DRUBY_HOME=${MY_RUBY_HOME}"
-                 -P "${CMAKE_CURRENT_LIST_DIR}/RvmDefault.cmake")
-
-add_test(NAME FindRuby.RvmOnly
-  COMMAND "${CMAKE_COMMAND}" -E env --unset=PATH
-                                    "MY_RUBY_HOME=${MY_RUBY_HOME}"
-          "${CMAKE_COMMAND}" "-DRUBY_HOME=${MY_RUBY_HOME}"
-                 "-DRVM_RUBY_VERSION=${RVM_RUBY_VERSION}" "-DSYSTEM_RUBY_VERSION=${SYSTEM_RUBY_VERSION}"
-                 -P "${CMAKE_CURRENT_LIST_DIR}/RvmOnly.cmake")
-add_test(NAME FindRuby.UnsetRvmOnly
-         COMMAND "${CMAKE_COMMAND}" -E env --unset=MY_RUBY_HOME "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"
-                 "${CMAKE_COMMAND}" "-DRVM_RUBY_VERSION=${RVM_RUBY_VERSION}" "-DSYSTEM_RUBY_VERSION=${SYSTEM_RUBY_VERSION}"
-                 -P "${CMAKE_CURRENT_LIST_DIR}/RvmOnly.cmake")
-
-add_test(NAME FindRuby.RvmStandard
-         COMMAND "${CMAKE_COMMAND}" -E env "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"
-                                           "MY_RUBY_HOME=${MY_RUBY_HOME}"
-                 "${CMAKE_COMMAND}" "-DRUBY_HOME=${MY_RUBY_HOME}"
-                 -P "${CMAKE_CURRENT_LIST_DIR}/RvmStandard.cmake")
diff --git a/Tests/FindRuby/Rvm/RvmDefault.cmake b/Tests/FindRuby/Rvm/RvmDefault.cmake
deleted file mode 100644
index a66b911..0000000
--- a/Tests/FindRuby/Rvm/RvmDefault.cmake
+++ /dev/null
@@ -1,17 +0,0 @@
-set(CMAKE_FIND_LIBRARY_PREFIXES "")
-set(CMAKE_FIND_LIBRARY_SUFFIXES "")
-
-find_package (Ruby 2.1.1 REQUIRED)
-if (NOT RUBY_EXECUTABLE MATCHES "^${RUBY_HOME}/.+")
-  message (FATAL_ERROR "Failed to use RVM environment: ${RUBY_EXECUTABLE}, ${RUBY_HOME}")
-endif()
-
-find_package (Ruby 2.1 REQUIRED)
-if (NOT RUBY_EXECUTABLE MATCHES "^${RUBY_HOME}/.+")
-  message (FATAL_ERROR "Failed to use RVM environment: ${RUBY_EXECUTABLE}, ${RUBY_HOME}")
-endif()
-
-find_package (Ruby REQUIRED)
-if (NOT RUBY_EXECUTABLE MATCHES "^${RUBY_HOME}/.+")
-  message (FATAL_ERROR "Failed to use RVM environment: ${RUBY_EXECUTABLE}, ${RUBY_HOME}")
-endif()
diff --git a/Tests/FindRuby/Rvm/RvmOnly.cmake b/Tests/FindRuby/Rvm/RvmOnly.cmake
deleted file mode 100644
index d47a880..0000000
--- a/Tests/FindRuby/Rvm/RvmOnly.cmake
+++ /dev/null
@@ -1,38 +0,0 @@
-set(CMAKE_FIND_LIBRARY_PREFIXES "")
-set(CMAKE_FIND_LIBRARY_SUFFIXES "")
-
-set(Ruby_FIND_VIRTUALENV ONLY)
-set(Ruby_RBENV_EXECUTABLE "") # Suppress rbenv code path for this test.
-
-# Test: FindRuby.RvmOnly
-if (RUBY_HOME)
-  # => Trying to find exactly system ruby using ONLY virtual environment should fail
-  find_package (Ruby ${SYSTEM_RUBY_VERSION} EXACT QUIET)
-  if(Ruby_FOUND)
-    message (FATAL_ERROR "Ruby unexpectedly found.")
-  endif()
-  # And should work to find the rvm version
-  find_package (Ruby ${RVM_RUBY_VERSION} EXACT QUIET)
-  if(Ruby_FOUND)
-    message (FATAL_ERROR "Ruby unexpectedly found.")
-  endif()
-endif()
-
-
-# Test: FindRuby.UnsetRvmOnly
-if (NOT RUBY_HOME)
-
-  # If ENV{MY_RUBY_HOME} isn't defined and Ruby_FIND_VIRTUALENV is set to ONLY
-  # then Ruby should not be found
-
-  find_package (Ruby ${RVM_RUBY_VERSION} EXACT QUIET)
-  if(Ruby_FOUND)
-    message (FATAL_ERROR "RVM Ruby unexpectedly found.")
-  endif()
-
-  # it should *not* find the system ruby
-  find_package (Ruby ${SYSTEM_RUBY_VERSION} EXACT QUIET)
-  if(Ruby_FOUND)
-    message (FATAL_ERROR "Ruby unexpectedly found.")
-  endif()
-endif()
diff --git a/Tests/FindRuby/Rvm/RvmStandard.cmake b/Tests/FindRuby/Rvm/RvmStandard.cmake
deleted file mode 100644
index 26befdb7..0000000
--- a/Tests/FindRuby/Rvm/RvmStandard.cmake
+++ /dev/null
@@ -1,9 +0,0 @@
-set(CMAKE_FIND_LIBRARY_PREFIXES "")
-set(CMAKE_FIND_LIBRARY_SUFFIXES "")
-
-set (Ruby_FIND_VIRTUALENV STANDARD)
-find_package (Ruby REQUIRED)
-
-if (RUBY_EXECUTABLE MATCHES "^${RUBY_HOME}/.+")
-  message (FATAL_ERROR "RVM ruby unexpectedly found at ${RUBY_EXECUTABLE}, matches ${RUBY_HOME}")
-endif()
diff --git a/Tests/FindRuby/Test/CMakeLists.txt b/Tests/FindRuby/Test/CMakeLists.txt
deleted file mode 100644
index fb5ae37..0000000
--- a/Tests/FindRuby/Test/CMakeLists.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-cmake_minimum_required(VERSION 3.17)
-project(TestRuby LANGUAGES C)
-include(CTest)
-
-cmake_policy(SET CMP0185 NEW)
-
-find_package(Ruby 1.9.9 REQUIRED)
-if (NOT Ruby_FOUND)
-  message (FATAL_ERROR "Failed to find Ruby >=1.9.9")
-endif()
-
-foreach(var_CMP0185
-    RUBY_EXECUTABLE
-    RUBY_INCLUDE_DIRS
-    RUBY_LIBRARY
-    RUBY_VERSION
-    )
-  if(DEFINED ${var_CMP0185})
-    message(FATAL_ERROR "Pre-CMP0185 result variable is set: ${var_CMP0185}")
-  endif()
-endforeach()
-
-add_executable(ruby_version ruby_version.c)
-target_include_directories(ruby_version PRIVATE ${Ruby_INCLUDE_DIRS})
-target_link_libraries(ruby_version PRIVATE ${Ruby_LIBRARIES})
-
-add_test(NAME ruby_version COMMAND ruby_version)
diff --git a/Tests/FindSQLite3/Test/CMakeLists.txt b/Tests/FindSQLite3/Test/CMakeLists.txt
index 95b8482..8704e8f 100644
--- a/Tests/FindSQLite3/Test/CMakeLists.txt
+++ b/Tests/FindSQLite3/Test/CMakeLists.txt
@@ -7,7 +7,7 @@
 add_definitions(-DCMAKE_EXPECTED_SQLite3_VERSION="${SQLite3_VERSION}")
 
 add_executable(test_tgt main.c)
-target_link_libraries(test_tgt SQLite::SQLite3)
+target_link_libraries(test_tgt SQLite3::SQLite3)
 add_test(NAME test_tgt COMMAND test_tgt)
 
 add_executable(test_var main.c)
diff --git a/Tests/FortranC/CMakeLists.txt b/Tests/FortranC/CMakeLists.txt
index 0c7d9c3..59493e7 100644
--- a/Tests/FortranC/CMakeLists.txt
+++ b/Tests/FortranC/CMakeLists.txt
@@ -3,7 +3,7 @@
 
 # Skip this test for compilers not known to be compatible.
 if(NOT (CMAKE_C_COMPILER_ID STREQUAL CMAKE_Fortran_COMPILER_ID OR
-        "${CMAKE_C_COMPILER_ID}-${CMAKE_Fortran_COMPILER_ID}" MATCHES "^(MSVC-Intel|(GNU|Clang)-(LLVMFlang|LFortran))$"))
+        "${CMAKE_C_COMPILER_ID}-${CMAKE_Fortran_COMPILER_ID}" MATCHES "^(MSVC-(Intel|IntelLLVM)|(GNU|Clang)-(LLVMFlang|LFortran))$"))
   message(STATUS "${CMAKE_C_COMPILER_ID} C and ${CMAKE_Fortran_COMPILER_ID} Fortran not known to be compatible!")
   return()
 endif()
diff --git a/Tests/FortranOnly/CMakeLists.txt b/Tests/FortranOnly/CMakeLists.txt
index d181ad5..a0c299d 100644
--- a/Tests/FortranOnly/CMakeLists.txt
+++ b/Tests/FortranOnly/CMakeLists.txt
@@ -200,7 +200,9 @@
 endif()
 
 # Test that we are safe from infinite include recursion in dependency scanner
-# (SunPro Fortran compiler does not support recursive inclusion)
-if (NOT CMAKE_Fortran_COMPILER_ID STREQUAL "SunPro")
+if (# The SunPro Fortran compiler does not support recursive inclusion
+    NOT CMAKE_Fortran_COMPILER_ID STREQUAL "SunPro"
+    # The Intel Fortran VS integration overflows its stack.
+    AND NOT CMAKE_GENERATOR MATCHES "Visual Studio")
   add_executable(test_include_loop test_include_loop.F)
 endif()
diff --git a/Tests/Fuzzing/CMakeLists.txt b/Tests/Fuzzing/CMakeLists.txt
new file mode 100644
index 0000000..7e50621
--- /dev/null
+++ b/Tests/Fuzzing/CMakeLists.txt
@@ -0,0 +1,99 @@
+# Fuzzing targets for CMake
+# See README.rst for documentation.
+
+# Determine fuzzing engine
+# OSS-Fuzz sets LIB_FUZZING_ENGINE, otherwise use libFuzzer
+if(DEFINED ENV{LIB_FUZZING_ENGINE})
+  set(FUZZING_ENGINE $ENV{LIB_FUZZING_ENGINE})
+  set(FUZZING_ENGINE_FOUND TRUE)
+elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+  # Check if libFuzzer is available (needs both compile and link flags)
+  include(CheckCXXSourceCompiles)
+  set(CMAKE_REQUIRED_FLAGS "-fsanitize=fuzzer")
+  set(CMAKE_REQUIRED_LINK_OPTIONS "-fsanitize=fuzzer")
+  check_cxx_source_compiles("extern \"C\" int LLVMFuzzerTestOneInput(const char *data, long size) { return 0; }" HAVE_LIBFUZZER)
+  unset(CMAKE_REQUIRED_FLAGS)
+  unset(CMAKE_REQUIRED_LINK_OPTIONS)
+  if(HAVE_LIBFUZZER)
+    set(FUZZING_ENGINE "-fsanitize=fuzzer")
+    set(FUZZING_ENGINE_FOUND TRUE)
+  endif()
+endif()
+
+if(NOT FUZZING_ENGINE_FOUND)
+  message(FATAL_ERROR "No fuzzing engine found. CMake_BUILD_FUZZING requires libFuzzer or LIB_FUZZING_ENGINE.")
+endif()
+
+# Common link libraries
+set(FUZZER_LINK_LIBS
+  CMakeLib
+)
+
+# Macro to add a fuzzer target
+macro(add_fuzzer name source)
+  add_executable(${name} ${source})
+  target_link_libraries(${name} PRIVATE ${FUZZER_LINK_LIBS})
+
+  # If using libFuzzer directly, add the flag
+  if(FUZZING_ENGINE STREQUAL "-fsanitize=fuzzer")
+    target_compile_options(${name} PRIVATE -fsanitize=fuzzer)
+    target_link_options(${name} PRIVATE -fsanitize=fuzzer)
+  else()
+    # OSS-Fuzz provides engine as a library
+    target_link_libraries(${name} PRIVATE ${FUZZING_ENGINE})
+  endif()
+
+  # Ensure we don't apply clang-tidy to fuzzers
+  set_property(TARGET ${name} PROPERTY C_CLANG_TIDY "")
+  set_property(TARGET ${name} PROPERTY CXX_CLANG_TIDY "")
+endmacro()
+
+# Existing fuzzer from OSS-Fuzz integration
+add_fuzzer(xml_parser_fuzzer xml_parser_fuzzer.cc)
+
+message(STATUS "Fuzzing targets enabled with engine: ${FUZZING_ENGINE}")
+
+# CMakeLists.txt lexer fuzzer
+add_fuzzer(cmListFileLexerFuzzer cmListFileLexerFuzzer.cxx)
+
+# CMakeLists.txt parser fuzzer
+add_fuzzer(cmListFileParserFuzzer cmListFileParserFuzzer.cxx)
+
+# Generator expression fuzzer
+add_fuzzer(cmGeneratorExpressionFuzzer cmGeneratorExpressionFuzzer.cxx)
+
+# Math expression parser fuzzer
+add_fuzzer(cmExprParserFuzzer cmExprParserFuzzer.cxx)
+
+# pkg-config parser fuzzer
+add_fuzzer(cmPkgConfigParserFuzzer cmPkgConfigParserFuzzer.cxx)
+
+# JSON parser fuzzer
+add_fuzzer(cmJSONParserFuzzer cmJSONParserFuzzer.cxx)
+
+# GCC dependency file fuzzer
+add_fuzzer(cmGccDepfileFuzzer cmGccDepfileFuzzer.cxx)
+
+# String algorithms fuzzer
+add_fuzzer(cmStringAlgorithmsFuzzer cmStringAlgorithmsFuzzer.cxx)
+
+# Version parser fuzzer
+add_fuzzer(cmVersionFuzzer cmVersionFuzzer.cxx)
+
+# CMake path fuzzer
+add_fuzzer(cmCMakePathFuzzer cmCMakePathFuzzer.cxx)
+
+# File glob fuzzer
+add_fuzzer(cmGlobFuzzer cmGlobFuzzer.cxx)
+
+# ELF binary parser fuzzer
+add_fuzzer(cmELFFuzzer cmELFFuzzer.cxx)
+
+# Archive extraction fuzzer
+add_fuzzer(cmArchiveExtractFuzzer cmArchiveExtractFuzzer.cxx)
+
+# File lock fuzzer
+add_fuzzer(cmFileLockFuzzer cmFileLockFuzzer.cxx)
+
+# CMake script fuzzer
+add_fuzzer(cmScriptFuzzer cmScriptFuzzer.cxx)
diff --git a/Tests/Fuzzing/README.rst b/Tests/Fuzzing/README.rst
index 15dc5f6..dd9fe98 100644
--- a/Tests/Fuzzing/README.rst
+++ b/Tests/Fuzzing/README.rst
@@ -1,8 +1,62 @@
-The fuzzers in this directory are run continuously through OSS-fuzz.
-All fuzzers are implemented by way of the `libFuzzer engine`_.
+CMake Fuzzing Suite
+===================
 
-The link to the OSS-fuzz integration can be found here: (pending)
-All email addresses in the ``project.yaml`` file on OSS-fuzz will have access
-to detailed bug reports and will be notified via email if/when bugs are found.
+This directory contains fuzz targets for testing CMake with coverage-guided
+fuzzing. These fuzzers are integrated with `OSS-Fuzz`_ for continuous fuzzing.
 
-.. _`libFuzzer Engine`: https://llvm.org/docs/LibFuzzer.html
+All fuzzers are implemented using the `libFuzzer engine`_.
+
+.. _`OSS-Fuzz`: https://github.com/google/oss-fuzz
+.. _`libFuzzer engine`: https://llvm.org/docs/LibFuzzer.html
+
+Building Locally
+----------------
+
+See `reproducing OSS-Fuzz bugs locally`_ for official instructions from
+OSS-Fuzz on reproducing using Docker.
+
+Unofficially, to build the fuzzers locally with Clang and libFuzzer:
+
+  mkdir build && cd build
+  cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
+        -DCMake_BUILD_FUZZING=ON \
+        -DCMAKE_C_FLAGS="-fsanitize=fuzzer-no-link,address" \
+        -DCMAKE_CXX_FLAGS="-fsanitize=fuzzer-no-link,address" \
+        ..
+  cmake --build .
+
+The above command runs the fuzzers using address sanitizer (ASAN). Fuzzing can
+also be performed using memory (MSAN) or undefined behavior (UBSAN) sanitizers.
+Adjust the ``CMAKE_(C|CXX)_FLAGS`` accordingly using
+``-fsanitizer=fuzzer-no-link,memory`` or
+``-fsanitizer=fuzzer-no-link,undefined``, respectively.
+
+.. _`reproducing OSS-Fuzz bugs locally`: https://google.github.io/oss-fuzz/getting-started/reproducing-bugs-locally/
+
+Seed Corpora
+------------
+
+Each fuzzer has a corresponding seed corpus in ``corpus/<fuzzer_name>/``.
+
+Dictionaries
+------------
+
+Fuzzer dictionaries are provided to improve coverage. Each fuzzer has a
+corresponding ``.dict`` file with format-specific tokens.
+
+Security Considerations
+-----------------------
+
+These fuzzers specifically target security-sensitive code paths:
+
+- **Path traversal**: Archive extraction with ``../`` sequences
+- **Symlink attacks**: File handling with symlinks
+- **Memory safety**: Buffer handling in parsers
+- **Integer overflows**: Size calculations in binary parsers
+
+Bug Reports
+-----------
+
+Security bugs found by OSS-Fuzz are reported to CMake maintainers via the
+OSS-Fuzz security disclosure process. Non-security bugs are filed as public
+issues after a 90-day disclosure window.
diff --git a/Tests/Fuzzing/cmArchiveExtract.dict b/Tests/Fuzzing/cmArchiveExtract.dict
new file mode 100644
index 0000000..44f809b
--- /dev/null
+++ b/Tests/Fuzzing/cmArchiveExtract.dict
@@ -0,0 +1,72 @@
+# Archive Format Dictionary
+
+# Tar magic
+"ustar"
+"ustar  "
+"ustar\x0000"
+
+# Gzip magic
+"\x1f\x8b"
+"\x1f\x8b\x08"
+
+# Bzip2 magic
+"BZ"
+"BZh"
+"BZh9"
+
+# XZ magic
+"\xfd7zXZ\x00"
+
+# Zip magic
+"PK\x03\x04"
+"PK\x01\x02"
+"PK\x05\x06"
+
+# 7z magic
+"7z\xbc\xaf\x27\x1c"
+
+# Tar header fields
+"\x00\x00\x00\x00\x00\x00\x00\x00"
+"0000000"
+"0000644"
+"0000755"
+"0000777"
+"00000000000"
+"        "
+
+# Path traversal (security testing)
+"../"
+"../../"
+"../../../"
+"../../../../"
+"/../"
+"/../../"
+
+# Absolute paths
+"/etc/passwd"
+"/tmp/"
+"/home/"
+"/.."
+
+# Long paths
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+# Symlink indicators
+"1"
+"2"
+
+# File type indicators
+"0"
+"5"
+"L"
+"K"
+
+# Checksum placeholder
+"        "
+
+# Filenames
+"test.txt"
+"file.dat"
+"CMakeLists.txt"
+".hidden"
+"__MACOSX"
diff --git a/Tests/Fuzzing/cmArchiveExtractFuzzer.cxx b/Tests/Fuzzing/cmArchiveExtractFuzzer.cxx
new file mode 100644
index 0000000..a4f66b6
--- /dev/null
+++ b/Tests/Fuzzing/cmArchiveExtractFuzzer.cxx
@@ -0,0 +1,121 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's archive extraction (tar/zip)
+ *
+ * CMake extracts archives via cmSystemTools::ExtractTar. This is a critical
+ * attack surface as malicious archives could contain path traversal sequences
+ * (Zip Slip) or other exploits.
+ *
+ * Coverage targets:
+ * - Archive format detection (tar, gzip, bzip2, xz, zip)
+ * - Path handling during extraction
+ * - Symlink handling
+ * - Large file handling
+ * - Malformed archive recovery
+ *
+ * Security focus:
+ * - Path traversal (../) detection
+ * - Absolute path handling
+ * - Symlink escape attempts
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+#include "cmSystemTools.h"
+
+// Archives can be large but limit for fuzzing
+static constexpr size_t kMinInputSize = 4;          // Minimum magic bytes
+static constexpr size_t kMaxInputSize = 256 * 1024; // 256KB
+
+// Sandbox directory for extraction
+static std::string g_extractDir;
+
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
+{
+  (void)argc;
+  (void)argv;
+
+  // Create a unique extraction directory in /tmp
+  char tmpl[] = "/tmp/cmake_fuzz_extract_XXXXXX";
+  char* dir = mkdtemp(tmpl);
+  if (dir) {
+    g_extractDir = dir;
+  } else {
+    g_extractDir = "/tmp/cmake_fuzz_extract";
+    cmSystemTools::MakeDirectory(g_extractDir);
+  }
+
+  return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size < kMinInputSize || size > kMaxInputSize) {
+    return 0;
+  }
+
+  // Write archive to temp file
+  std::string archiveFile = g_extractDir + "/test_archive";
+  {
+    FILE* fp = fopen(archiveFile.c_str(), "wb");
+    if (!fp) {
+      return 0;
+    }
+    fwrite(data, 1, size, fp);
+    fclose(fp);
+  }
+
+  // Create a fresh extraction subdirectory each time
+  std::string extractSubDir = g_extractDir + "/out";
+  cmSystemTools::RemoveADirectory(extractSubDir);
+  cmSystemTools::MakeDirectory(extractSubDir);
+
+  // Save current directory
+  std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+
+  // Change to extraction directory (cmSystemTools extracts to cwd)
+  if (cmSystemTools::ChangeDirectory(extractSubDir)) {
+    // Try extraction with different options
+    std::vector<std::string> files;
+
+    // Extract without verbose, with timestamps
+    bool result1 = cmSystemTools::ExtractTar(
+      archiveFile, files, cmSystemTools::cmTarExtractTimestamps::Yes, false);
+    (void)result1;
+
+    // Restore directory BEFORE removing (can't remove cwd)
+    cmSystemTools::ChangeDirectory(cwd);
+
+    // Clean up extracted files
+    cmSystemTools::RemoveADirectory(extractSubDir);
+    cmSystemTools::MakeDirectory(extractSubDir);
+
+    // Change back for second extraction
+    if (cmSystemTools::ChangeDirectory(extractSubDir)) {
+      // Extract with verbose, without timestamps
+      files.clear();
+      bool result2 = cmSystemTools::ExtractTar(
+        archiveFile, files, cmSystemTools::cmTarExtractTimestamps::No, true);
+      (void)result2;
+
+      // Restore directory
+      cmSystemTools::ChangeDirectory(cwd);
+    }
+  }
+
+  // Note: A more thorough security check would verify nothing escaped the
+  // sandbox, but for fuzzing we rely on sanitizers to catch path traversal
+
+  // Cleanup
+  cmSystemTools::RemoveADirectory(extractSubDir);
+  cmSystemTools::RemoveFile(archiveFile);
+
+  return 0;
+}
diff --git a/Tests/Fuzzing/cmArchiveExtractFuzzer.options b/Tests/Fuzzing/cmArchiveExtractFuzzer.options
new file mode 100644
index 0000000..4770ed7
--- /dev/null
+++ b/Tests/Fuzzing/cmArchiveExtractFuzzer.options
@@ -0,0 +1,10 @@
+[libfuzzer]
+max_len = 262144
+timeout = 60
+rss_limit_mb = 2048
+
+[afl]
+timeout = 60
+
+[honggfuzz]
+timeout = 60
diff --git a/Tests/Fuzzing/cmCMakePath.dict b/Tests/Fuzzing/cmCMakePath.dict
new file mode 100644
index 0000000..e5a0431
--- /dev/null
+++ b/Tests/Fuzzing/cmCMakePath.dict
@@ -0,0 +1,61 @@
+# CMake path dictionary
+
+# Separators
+"/"
+"\\"
+":"
+
+# Unix paths
+"/usr"
+"/usr/local"
+"/home"
+"/tmp"
+"/var"
+"/etc"
+"/opt"
+"/bin"
+"/lib"
+
+# Windows paths
+"C:"
+"D:"
+"C:\\"
+"Program Files"
+"Windows"
+
+# CMake directories
+"CMakeFiles"
+"cmake"
+"share"
+"lib"
+"include"
+"bin"
+"build"
+"src"
+"source"
+
+# Special paths
+"."
+".."
+"./"
+"../"
+"~"
+
+# Extensions
+".cmake"
+".txt"
+".h"
+".hpp"
+".c"
+".cpp"
+".cxx"
+".a"
+".so"
+".dll"
+".lib"
+
+# CMake files
+"CMakeLists.txt"
+"CMakeCache.txt"
+"cmake_install.cmake"
+"CTestTestfile.cmake"
diff --git a/Tests/Fuzzing/cmCMakePathFuzzer.cxx b/Tests/Fuzzing/cmCMakePathFuzzer.cxx
new file mode 100644
index 0000000..0d0af77
--- /dev/null
+++ b/Tests/Fuzzing/cmCMakePathFuzzer.cxx
@@ -0,0 +1,77 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's path manipulation (cmCMakePath)
+ *
+ * Tests path parsing, normalization, and manipulation operations.
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+
+#include "cmCMakePath.h"
+
+static constexpr size_t kMaxInputSize = 4096;
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  std::string input(reinterpret_cast<char const*>(data), size);
+
+  // Test various path operations
+  cmCMakePath path(input);
+
+  // Basic queries
+  (void)path.IsEmpty();
+  (void)path.HasRootPath();
+  (void)path.HasRootName();
+  (void)path.HasRootDirectory();
+  (void)path.HasRelativePath();
+  (void)path.HasParentPath();
+  (void)path.HasFileName();
+  (void)path.HasStem();
+  (void)path.HasExtension();
+  (void)path.IsAbsolute();
+  (void)path.IsRelative();
+
+  // Component extraction
+  (void)path.GetRootName();
+  (void)path.GetRootDirectory();
+  (void)path.GetRootPath();
+  (void)path.GetRelativePath();
+  (void)path.GetParentPath();
+  (void)path.GetFileName();
+  (void)path.GetExtension();
+  (void)path.GetStem();
+  (void)path.String();
+  (void)path.GenericString();
+
+  // Manipulation
+  cmCMakePath normalized = path.Normal();
+  (void)normalized.String();
+
+  // If we have two paths in input, test operations between them
+  size_t midpoint = size / 2;
+  if (midpoint > 0) {
+    std::string input1(reinterpret_cast<char const*>(data), midpoint);
+    std::string input2(reinterpret_cast<char const*>(data + midpoint),
+                       size - midpoint);
+
+    cmCMakePath path1(input1);
+    cmCMakePath path2(input2);
+
+    // Append operations
+    cmCMakePath appended = path1 / path2;
+    (void)appended.String();
+
+    // Comparison
+    (void)(path1 == path2);
+  }
+
+  return 0;
+}
diff --git a/Tests/Fuzzing/cmELF.dict b/Tests/Fuzzing/cmELF.dict
new file mode 100644
index 0000000..8b3de52
--- /dev/null
+++ b/Tests/Fuzzing/cmELF.dict
@@ -0,0 +1,85 @@
+# ELF File Format Dictionary
+
+# ELF magic number
+"\x7fELF"
+
+# ELF class (32/64 bit)
+"\x01"
+"\x02"
+
+# Data encoding (little/big endian)
+"\x01"
+"\x02"
+
+# ELF version
+"\x01"
+
+# OS/ABI
+"\x00"
+"\x03"
+"\x09"
+
+# Object file types
+"\x00\x00"
+"\x01\x00"
+"\x02\x00"
+"\x03\x00"
+"\x04\x00"
+
+# Machine types
+"\x03\x00"
+"\x3e\x00"
+"\x28\x00"
+"\xb7\x00"
+"\x08\x00"
+
+# Section types
+"\x00\x00\x00\x00"
+"\x01\x00\x00\x00"
+"\x02\x00\x00\x00"
+"\x03\x00\x00\x00"
+"\x04\x00\x00\x00"
+"\x05\x00\x00\x00"
+"\x06\x00\x00\x00"
+"\x07\x00\x00\x00"
+"\x08\x00\x00\x00"
+"\x09\x00\x00\x00"
+"\x0b\x00\x00\x00"
+
+# Dynamic tags
+"\x01\x00\x00\x00"
+"\x0e\x00\x00\x00"
+"\x0f\x00\x00\x00"
+"\x1d\x00\x00\x00"
+
+# Section names
+".text"
+".data"
+".bss"
+".rodata"
+".dynamic"
+".dynsym"
+".dynstr"
+".interp"
+".note"
+".shstrtab"
+".strtab"
+".symtab"
+".rela"
+".rel"
+".plt"
+".got"
+".init"
+".fini"
+
+# String entries
+"RPATH"
+"RUNPATH"
+"SONAME"
+"NEEDED"
+
+# Common library paths
+"/lib"
+"/usr/lib"
+"$ORIGIN"
+"$LIB"
diff --git a/Tests/Fuzzing/cmELFFuzzer.cxx b/Tests/Fuzzing/cmELFFuzzer.cxx
new file mode 100644
index 0000000..64651fd
--- /dev/null
+++ b/Tests/Fuzzing/cmELFFuzzer.cxx
@@ -0,0 +1,147 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's ELF parser
+ *
+ * CMake parses ELF files to extract RPATH, RUNPATH, and SONAME information.
+ * Malformed ELF files from untrusted sources could trigger vulnerabilities.
+ *
+ * Coverage targets:
+ * - ELF header parsing (32-bit and 64-bit)
+ * - Section header parsing
+ * - Dynamic section parsing
+ * - String table extraction
+ * - RPATH/RUNPATH/SONAME extraction
+ *
+ * Performance notes:
+ * - Uses memfd_create on Linux for memory-backed file I/O
+ * - Falls back to temp files on other platforms
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <sstream>
+#include <string>
+
+#include <unistd.h>
+
+#include "cmELF.h"
+
+#ifdef __linux__
+#  include <sys/mman.h>
+#  ifndef MFD_CLOEXEC
+#    define MFD_CLOEXEC 0x0001U
+#  endif
+#endif
+
+// ELF files can be large, but we limit to avoid timeouts
+static constexpr size_t kMinInputSize = 16;         // Minimum ELF header
+static constexpr size_t kMaxInputSize = 512 * 1024; // 512KB
+
+static int g_memfd = -1;
+static std::string g_memfdPath;
+
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
+{
+  (void)argc;
+  (void)argv;
+
+#ifdef __linux__
+  g_memfd = memfd_create("cmake_fuzz_elf", MFD_CLOEXEC);
+  if (g_memfd >= 0) {
+    g_memfdPath = "/proc/self/fd/" + std::to_string(g_memfd);
+  }
+#endif
+  return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  // ELF files need minimum header size
+  if (size < kMinInputSize || size > kMaxInputSize) {
+    return 0;
+  }
+
+  std::string testFile;
+
+#ifdef __linux__
+  if (g_memfd >= 0) {
+    // Use memfd for better performance
+    ftruncate(g_memfd, 0);
+    lseek(g_memfd, 0, SEEK_SET);
+    if (write(g_memfd, data, size) != static_cast<ssize_t>(size)) {
+      return 0;
+    }
+    testFile = g_memfdPath;
+  } else
+#endif
+  {
+    // Fallback to temp file
+    char tmpFile[] = "/tmp/fuzz_elf_XXXXXX";
+    int fd = mkstemp(tmpFile);
+    if (fd < 0) {
+      return 0;
+    }
+    if (write(fd, data, size) != static_cast<ssize_t>(size)) {
+      close(fd);
+      unlink(tmpFile);
+      return 0;
+    }
+    close(fd);
+    testFile = tmpFile;
+  }
+
+  // Parse the ELF file
+  {
+    cmELF elf(testFile.c_str());
+
+    // Check validity
+    if (elf) {
+      // Exercise all the parsing functions
+      (void)elf.GetFileType();
+      (void)elf.GetMachine();
+      (void)elf.GetNumberOfSections();
+      (void)elf.HasDynamicSection();
+      (void)elf.IsMIPS();
+
+      // Try to get string entries
+      std::string soname;
+      elf.GetSOName(soname);
+      (void)elf.GetSOName();
+      (void)elf.GetRPath();
+      (void)elf.GetRunPath();
+
+      // Get dynamic entries
+      auto entries = elf.GetDynamicEntries();
+      if (!entries.empty()) {
+        auto encoded = elf.EncodeDynamicEntries(entries);
+        (void)encoded;
+
+        // Get positions (limit iterations to avoid timeout)
+        for (size_t i = 0; i < entries.size() && i < 100; ++i) {
+          (void)elf.GetDynamicEntryPosition(static_cast<int>(i));
+        }
+      }
+
+      // Print info to exercise that code path
+      std::ostringstream oss;
+      elf.PrintInfo(oss);
+    }
+
+    // Always check error message path
+    (void)elf.GetErrorMessage();
+  }
+
+  // Cleanup temp file (memfd doesn't need cleanup)
+#ifdef __linux__
+  if (g_memfd < 0)
+#endif
+  {
+    unlink(testFile.c_str());
+  }
+
+  return 0;
+}
diff --git a/Tests/Fuzzing/cmELFFuzzer.options b/Tests/Fuzzing/cmELFFuzzer.options
new file mode 100644
index 0000000..71b91a4
--- /dev/null
+++ b/Tests/Fuzzing/cmELFFuzzer.options
@@ -0,0 +1,10 @@
+[libfuzzer]
+max_len = 524288
+timeout = 30
+rss_limit_mb = 1024
+
+[afl]
+timeout = 30
+
+[honggfuzz]
+timeout = 30
diff --git a/Tests/Fuzzing/cmExprParser.dict b/Tests/Fuzzing/cmExprParser.dict
new file mode 100644
index 0000000..0199d89
--- /dev/null
+++ b/Tests/Fuzzing/cmExprParser.dict
@@ -0,0 +1,51 @@
+# CMake Expression Parser Dictionary (math expressions)
+
+# Operators
+"+"
+"-"
+"*"
+"/"
+"%"
+"|"
+"&"
+"^"
+"~"
+"<<"
+">>"
+"("
+")"
+
+# Numbers
+"0"
+"1"
+"2"
+"10"
+"100"
+"1000"
+"-1"
+"-100"
+"0x"
+"0X"
+"0xff"
+"0xFF"
+"0x7fffffff"
+"0xffffffff"
+
+# Hex digits
+"0123456789"
+"abcdef"
+"ABCDEF"
+
+# Large numbers
+"2147483647"
+"2147483648"
+"4294967295"
+"9223372036854775807"
+
+# Edge cases
+"00"
+"0x0"
+"0x00"
+" "
+"\x09"
+"\x0a"
diff --git a/Tests/Fuzzing/cmExprParserFuzzer.cxx b/Tests/Fuzzing/cmExprParserFuzzer.cxx
new file mode 100644
index 0000000..386f890
--- /dev/null
+++ b/Tests/Fuzzing/cmExprParserFuzzer.cxx
@@ -0,0 +1,48 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's math expression parser
+ *
+ * The math() command uses cmExprParserHelper to evaluate mathematical
+ * expressions. This fuzzer tests the expression parser for crashes,
+ * hangs, and undefined behavior.
+ *
+ * Coverage targets:
+ * - Integer arithmetic parsing
+ * - Operator precedence handling
+ * - Parentheses nesting
+ * - Error handling for invalid expressions
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+
+#include "cmExprParserHelper.h"
+
+// Limit input size to prevent DoS via deeply nested expressions
+static constexpr size_t kMaxInputSize = 4096;
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  // Create null-terminated string
+  std::string input(reinterpret_cast<char const*>(data), size);
+
+  cmExprParserHelper helper;
+
+  // Parse with different verbosity levels
+  int result = helper.ParseString(input.c_str(), 0);
+  (void)result;
+
+  // Always check result and error accessors
+  (void)helper.GetResult();
+  (void)helper.GetError();
+  (void)helper.GetWarning();
+
+  return 0;
+}
diff --git a/Tests/Fuzzing/cmFileLock.dict b/Tests/Fuzzing/cmFileLock.dict
new file mode 100644
index 0000000..f1fa0bb
--- /dev/null
+++ b/Tests/Fuzzing/cmFileLock.dict
@@ -0,0 +1,43 @@
+# CMake file lock dictionary
+# Path components
+"/"
+"\\"
+"./"
+"../"
+"~/"
+
+# Common lock file names
+"lock"
+".lock"
+"lockfile"
+".lockfile"
+"cmake.lock"
+"CMakeCache.txt.lock"
+
+# Path patterns
+"/tmp/"
+"/var/lock/"
+"/run/lock/"
+
+# File extensions
+".lock"
+".lck"
+".pid"
+
+# Special paths
+"/dev/null"
+"/dev/zero"
+"NUL"
+"CON"
+"PRN"
+
+# Edge cases (space, dot, dotdot, null, newline, cr)
+" "
+"."
+".."
+"\x00"
+"\x0a"
+"\x0d"
+
+# Long path components
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
diff --git a/Tests/Fuzzing/cmFileLockFuzzer.cxx b/Tests/Fuzzing/cmFileLockFuzzer.cxx
new file mode 100644
index 0000000..33d8d1e
--- /dev/null
+++ b/Tests/Fuzzing/cmFileLockFuzzer.cxx
@@ -0,0 +1,147 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's file(LOCK) command
+ *
+ * The file(LOCK) command manages file locks for synchronization.
+ * This fuzzer tests various lock scenarios and argument combinations.
+ *
+ * Coverage targets:
+ * - Lock acquisition (LOCK)
+ * - Lock release (RELEASE)
+ * - Guard modes (FUNCTION, FILE, PROCESS)
+ * - Timeout handling
+ * - Error paths
+ *
+ * Security focus:
+ * - Symlink handling (CVE for data destruction)
+ * - Path traversal in lock paths
+ * - Race conditions
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+#include <string>
+
+#include <unistd.h>
+
+#include "cmFileLock.h"
+#include "cmFileLockResult.h"
+#include "cmSystemTools.h"
+
+// Limit input size
+static constexpr size_t kMaxInputSize = 4096;
+
+// Sandbox directory
+static std::string g_testDir;
+
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
+{
+  (void)argc;
+  (void)argv;
+
+  // Create unique test directory
+  char tmpl[] = "/tmp/cmake_fuzz_lock_XXXXXX";
+  char* dir = mkdtemp(tmpl);
+  if (dir) {
+    g_testDir = dir;
+  } else {
+    g_testDir = "/tmp/cmake_fuzz_lock";
+    cmSystemTools::MakeDirectory(g_testDir);
+  }
+
+  return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size < 1 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  // Use first byte for flags
+  uint8_t flags = data[0];
+
+  // Create a test file with known content
+  std::string testFile = g_testDir + "/lock_target.txt";
+  std::string lockFile = g_testDir + "/test.lock";
+  char const* testContent = "IMPORTANT DATA - MUST NOT BE TRUNCATED";
+
+  {
+    FILE* fp = fopen(testFile.c_str(), "w");
+    if (!fp)
+      return 0;
+    fputs(testContent, fp);
+    fclose(fp);
+  }
+
+  // Test different scenarios based on fuzz input
+  cmFileLock lock;
+
+  // Vary the lock file path based on remaining input
+  std::string lockPath = lockFile;
+  if (size > 1 && (flags & 0x01)) {
+    // Use part of input as filename suffix (sanitized)
+    size_t nameLen = std::min(size - 1, size_t(32));
+    std::string suffix;
+    for (size_t i = 0; i < nameLen; ++i) {
+      char c = static_cast<char>(data[1 + i]);
+      // Only allow safe filename characters
+      if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+          (c >= '0' && c <= '9') || c == '_' || c == '-') {
+        suffix += c;
+      }
+    }
+    if (!suffix.empty()) {
+      lockPath = g_testDir + "/" + suffix + ".lock";
+    }
+  }
+
+  // Test symlink scenario (security-critical)
+  if (flags & 0x02) {
+    // Create a symlink to the test file
+    std::string symlinkPath = g_testDir + "/symlink.lock";
+    unlink(symlinkPath.c_str());
+    if (symlink(testFile.c_str(), symlinkPath.c_str()) == 0) {
+      lockPath = symlinkPath;
+    }
+  }
+
+  // Determine timeout - use 0 for fuzzing to avoid blocking
+  // (non-zero timeouts would stall the fuzzer)
+  unsigned long timeout = 0;
+
+  // Try to acquire lock
+  cmFileLockResult result = lock.Lock(lockPath, timeout);
+  (void)result.IsOk();
+
+  // Always try to release
+  (void)lock.Release();
+
+  // Security check: Verify test file wasn't truncated
+  {
+    FILE* fp = fopen(testFile.c_str(), "r");
+    if (fp) {
+      char buffer[256] = { 0 };
+      size_t bytesRead = fread(buffer, 1, sizeof(buffer) - 1, fp);
+      fclose(fp);
+
+      if (bytesRead == 0 || strcmp(buffer, testContent) != 0) {
+        // DATA DESTRUCTION DETECTED!
+        fprintf(stderr, "VULNERABILITY: File was truncated or modified!\n");
+        fprintf(stderr, "Expected: '%s'\n", testContent);
+        fprintf(stderr, "Got: '%s' (%zu bytes)\n", buffer, bytesRead);
+        abort();
+      }
+    }
+  }
+
+  // Cleanup
+  unlink(lockPath.c_str());
+  unlink((g_testDir + "/symlink.lock").c_str());
+
+  return 0;
+}
diff --git a/Tests/Fuzzing/cmGccDepfile.dict b/Tests/Fuzzing/cmGccDepfile.dict
new file mode 100644
index 0000000..b51f7d5
--- /dev/null
+++ b/Tests/Fuzzing/cmGccDepfile.dict
@@ -0,0 +1,45 @@
+# GCC depfile dictionary
+
+# Target separator
+":"
+
+# Dependency continuation
+"\\"
+
+# Whitespace
+" "
+"\x09"
+"\x0a"
+
+# Common file extensions
+".o"
+".obj"
+".d"
+".cpp"
+".c"
+".h"
+".hpp"
+".hxx"
+
+# Escape sequences
+"\\ "
+"\\#"
+"\\:"
+
+# Special characters
+"#"
+"$"
+
+# Common paths
+"/usr/include/"
+"/usr/local/include/"
+"../include/"
+"./src/"
+
+# Common headers
+"stdio.h"
+"stdlib.h"
+"string.h"
+"iostream"
+"vector"
+"string"
diff --git a/Tests/Fuzzing/cmGccDepfileFuzzer.cxx b/Tests/Fuzzing/cmGccDepfileFuzzer.cxx
new file mode 100644
index 0000000..d6a2d22
--- /dev/null
+++ b/Tests/Fuzzing/cmGccDepfileFuzzer.cxx
@@ -0,0 +1,76 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's GCC dependency file parser
+ *
+ * GCC generates .d files with make-style dependencies.
+ * This fuzzer tests parsing of these files.
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <string>
+
+#include <unistd.h>
+
+#include "cmGccDepfileReader.h"
+#include "cmSystemTools.h"
+
+static constexpr size_t kMaxInputSize = 256 * 1024;
+static std::string g_testDir;
+
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
+{
+  (void)argc;
+  (void)argv;
+
+  char tmpl[] = "/tmp/cmake_fuzz_depfile_XXXXXX";
+  char* dir = mkdtemp(tmpl);
+  if (dir) {
+    g_testDir = dir;
+  } else {
+    g_testDir = "/tmp/cmake_fuzz_depfile";
+    cmSystemTools::MakeDirectory(g_testDir);
+  }
+
+  return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  // Write input to temp file
+  std::string depFile = g_testDir + "/test.d";
+  {
+    FILE* fp = fopen(depFile.c_str(), "wb");
+    if (!fp)
+      return 0;
+    fwrite(data, 1, size, fp);
+    fclose(fp);
+  }
+
+  // Parse the depfile
+  auto result = cmReadGccDepfile(depFile.c_str());
+
+  // Examine results if parsing succeeded
+  if (result) {
+    for (auto const& entry : *result) {
+      for (auto const& rule : entry.rules) {
+        (void)rule;
+      }
+      for (auto const& path : entry.paths) {
+        (void)path;
+      }
+    }
+  }
+
+  // Clean up
+  unlink(depFile.c_str());
+
+  return 0;
+}
diff --git a/Tests/Fuzzing/cmGeneratorExpression.dict b/Tests/Fuzzing/cmGeneratorExpression.dict
new file mode 100644
index 0000000..b7e615f
--- /dev/null
+++ b/Tests/Fuzzing/cmGeneratorExpression.dict
@@ -0,0 +1,84 @@
+# CMake Generator Expression Dictionary
+
+# Basic syntax
+"$<"
+">"
+":"
+","
+
+# Boolean expressions
+"$<BOOL:"
+"$<AND:"
+"$<OR:"
+"$<NOT:"
+"$<IF:"
+"$<0:"
+"$<1:"
+
+# String operations
+"$<STREQUAL:"
+"$<EQUAL:"
+"$<IN_LIST:"
+"$<LOWER_CASE:"
+"$<UPPER_CASE:"
+"$<MAKE_C_IDENTIFIER:"
+"$<JOIN:"
+"$<REMOVE_DUPLICATES:"
+"$<FILTER:"
+"$<GENEX_EVAL:"
+
+# Version comparisons
+"$<VERSION_LESS:"
+"$<VERSION_GREATER:"
+"$<VERSION_EQUAL:"
+"$<VERSION_LESS_EQUAL:"
+"$<VERSION_GREATER_EQUAL:"
+
+# Target operations
+"$<TARGET_FILE:"
+"$<TARGET_FILE_NAME:"
+"$<TARGET_FILE_DIR:"
+"$<TARGET_FILE_BASE_NAME:"
+"$<TARGET_LINKER_FILE:"
+"$<TARGET_SONAME_FILE:"
+"$<TARGET_PDB_FILE:"
+"$<TARGET_PROPERTY:"
+"$<TARGET_OBJECTS:"
+"$<TARGET_BUNDLE_DIR:"
+"$<TARGET_BUNDLE_CONTENT_DIR:"
+"$<TARGET_EXISTS:"
+"$<TARGET_NAME_IF_EXISTS:"
+"$<TARGET_POLICY:"
+
+# Config/Platform
+"$<CONFIG:"
+"$<PLATFORM_ID:"
+"$<COMPILE_LANGUAGE:"
+"$<LINK_LANGUAGE:"
+"$<COMPILE_LANG_AND_ID:"
+"$<LINK_LANG_AND_ID:"
+"$<C_COMPILER_ID:"
+"$<CXX_COMPILER_ID:"
+"$<CUDA_COMPILER_ID:"
+
+# Interface expressions
+"$<BUILD_INTERFACE:"
+"$<INSTALL_INTERFACE:"
+"$<INSTALL_PREFIX>"
+
+# Output expressions
+"$<TARGET_NAME:"
+"$<LINK_ONLY:"
+"$<COMPILE_ONLY:"
+
+# Special
+"$<ANGLE-R>"
+"$<COMMA>"
+"$<SEMICOLON>"
+
+# Nesting patterns
+"$<$<"
+">>"
+"::"
+",,"
+"$<IF:$<"
diff --git a/Tests/Fuzzing/cmGeneratorExpressionFuzzer.cxx b/Tests/Fuzzing/cmGeneratorExpressionFuzzer.cxx
new file mode 100644
index 0000000..7b54fdc
--- /dev/null
+++ b/Tests/Fuzzing/cmGeneratorExpressionFuzzer.cxx
@@ -0,0 +1,88 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's Generator Expression parser
+ *
+ * Generator expressions ($<...>) are evaluated at build-system generation
+ * time. This fuzzer targets the lexer and static parsing utilities that don't
+ * require full cmake context.
+ *
+ * Coverage targets:
+ * - Generator expression lexer (cmGeneratorExpressionLexer)
+ * - Static parsing/preprocessing functions
+ * - Nested expression handling
+ * - Expression validation
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorExpressionLexer.h"
+
+// Limit input size - genex can be exponential in nested cases
+static constexpr size_t kMaxInputSize = 16 * 1024; // 16KB
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  std::string input(reinterpret_cast<char const*>(data), size);
+
+  // Test the lexer directly
+  {
+    cmGeneratorExpressionLexer lexer;
+    auto tokens = lexer.Tokenize(input);
+    (void)tokens;
+  }
+
+  // Test static utility functions that don't need cmake context
+  {
+    // Find generator expressions
+    auto pos = cmGeneratorExpression::Find(input);
+    (void)pos;
+
+    // Check if starts with genex
+    bool starts = cmGeneratorExpression::StartsWithGeneratorExpression(input);
+    (void)starts;
+
+    // Validate as target name
+    bool valid = cmGeneratorExpression::IsValidTargetName(input);
+    (void)valid;
+
+    // Strip empty list elements
+    std::string stripped =
+      cmGeneratorExpression::StripEmptyListElements(input);
+    (void)stripped;
+
+    // Split expressions
+    std::vector<std::string> output;
+    cmGeneratorExpression::Split(input, output);
+
+    // Preprocess with different contexts
+    std::string preprocessed1 = cmGeneratorExpression::Preprocess(
+      input, cmGeneratorExpression::StripAllGeneratorExpressions);
+    (void)preprocessed1;
+
+    std::string preprocessed2 = cmGeneratorExpression::Preprocess(
+      input, cmGeneratorExpression::BuildInterface);
+    (void)preprocessed2;
+
+    std::string preprocessed3 = cmGeneratorExpression::Preprocess(
+      input, cmGeneratorExpression::InstallInterface);
+    (void)preprocessed3;
+
+    // Collect expressions
+    std::map<std::string, std::vector<std::string>> collected;
+    std::string collResult = cmGeneratorExpression::Collect(input, collected);
+    (void)collResult;
+  }
+
+  return 0;
+}
diff --git a/Tests/Fuzzing/cmGlob.dict b/Tests/Fuzzing/cmGlob.dict
new file mode 100644
index 0000000..8857326
--- /dev/null
+++ b/Tests/Fuzzing/cmGlob.dict
@@ -0,0 +1,50 @@
+# CMake glob pattern dictionary
+# Basic wildcards
+"*"
+"?"
+"**"
+
+# Character classes
+"[a-z]"
+"[A-Z]"
+"[0-9]"
+"[a-zA-Z]"
+"[a-zA-Z0-9]"
+"[!a-z]"
+"[^a-z]"
+"[]"
+"[]]"
+"[[]"
+
+# Common patterns
+"*.txt"
+"*.cmake"
+"*.c"
+"*.cpp"
+"*.cxx"
+"*.h"
+"*.hpp"
+"*.hxx"
+"**/*.cmake"
+"**/CMakeLists.txt"
+
+# Path separators
+"/"
+"\\"
+"./"
+"../"
+"/"
+
+# Special characters
+"."
+".."
+"~"
+
+# Brace expansion (if supported)
+"{a,b}"
+"{*.c,*.h}"
+
+# Edge cases (space, tab, newline)
+" "
+"\x09"
+"\x0a"
diff --git a/Tests/Fuzzing/cmGlobFuzzer.cxx b/Tests/Fuzzing/cmGlobFuzzer.cxx
new file mode 100644
index 0000000..c9c5bbd
--- /dev/null
+++ b/Tests/Fuzzing/cmGlobFuzzer.cxx
@@ -0,0 +1,69 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's glob/regex matching
+ *
+ * Tests glob pattern matching and regex compilation.
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "cmsys/Glob.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmSystemTools.h"
+
+static constexpr size_t kMaxInputSize = 4096;
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  std::string input(reinterpret_cast<char const*>(data), size);
+
+  // Test glob pattern matching
+  {
+    cmsys::Glob glob;
+    glob.SetRecurse(false);
+    glob.SetRelative("/tmp");
+
+    // Try to find files matching the pattern (safe - just pattern matching)
+    // Don't actually recurse filesystem, just test pattern parsing
+    (void)glob.GetFiles();
+  }
+
+  // Test regex compilation (may throw on invalid patterns)
+  {
+    cmsys::RegularExpression regex;
+    bool compiled = regex.compile(input);
+    if (compiled) {
+      // Test matching against some strings
+      (void)regex.find("test string");
+      (void)regex.find(input);
+      (void)regex.find("");
+    }
+  }
+
+  // Test string matching utilities
+  (void)cmSystemTools::StringStartsWith(input, "CMAKE_");
+  (void)cmSystemTools::StringEndsWith(input, ".cmake");
+
+  // Test simple pattern matching
+  if (size >= 4) {
+    std::string pattern(reinterpret_cast<char const*>(data), size / 2);
+    std::string text(reinterpret_cast<char const*>(data + size / 2),
+                     size - size / 2);
+    // Pattern matching is done through Glob::FindFiles, which we avoid
+    // to prevent filesystem access. Just test string operations.
+    (void)pattern.length();
+    (void)text.length();
+  }
+
+  return 0;
+}
diff --git a/Tests/Fuzzing/cmJSONParser.dict b/Tests/Fuzzing/cmJSONParser.dict
new file mode 100644
index 0000000..05bc533
--- /dev/null
+++ b/Tests/Fuzzing/cmJSONParser.dict
@@ -0,0 +1,72 @@
+# JSON Parser Dictionary
+
+# Structure
+"{"
+"}"
+"["
+"]"
+":"
+","
+
+# Values
+"true"
+"false"
+"null"
+
+# Strings
+"\""
+"\\"
+"\\x0a"
+"\\x0d"
+"\\x09"
+"\\u"
+"\\u0000"
+"\\uFFFF"
+
+# Numbers
+"0"
+"1"
+"-1"
+"0.0"
+"1.0"
+"-1.0"
+"1e10"
+"1E10"
+"1e-10"
+"1e+10"
+"1.5e10"
+
+# Whitespace
+" "
+"\x09"
+"\x0a"
+"\x0d"
+
+# Common CMake preset keys
+"version"
+"cmakeMinimumRequired"
+"configurePresets"
+"buildPresets"
+"testPresets"
+"packagePresets"
+"workflowPresets"
+"name"
+"hidden"
+"inherits"
+"displayName"
+"description"
+"generator"
+"binaryDir"
+"cacheVariables"
+"environment"
+"condition"
+"vendor"
+
+# Common values
+"Ninja"
+"Unix Makefiles"
+"Visual Studio"
+"Debug"
+"Release"
+"RelWithDebInfo"
+"MinSizeRel"
diff --git a/Tests/Fuzzing/cmJSONParserFuzzer.cxx b/Tests/Fuzzing/cmJSONParserFuzzer.cxx
new file mode 100644
index 0000000..e914300
--- /dev/null
+++ b/Tests/Fuzzing/cmJSONParserFuzzer.cxx
@@ -0,0 +1,107 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's JSON parsing (via jsoncpp)
+ *
+ * CMake parses JSON files for CMakePresets.json, compile_commands.json,
+ * and various other configuration files. This fuzzer tests the JSON
+ * parser for crashes and undefined behavior.
+ *
+ * Coverage targets:
+ * - JSON value parsing (strings, numbers, booleans, null)
+ * - Array and object parsing
+ * - Nested structures
+ * - Unicode handling
+ * - Error recovery
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <sstream>
+#include <string>
+
+#include <cm3p/json/reader.h>
+#include <cm3p/json/value.h>
+
+// Limit input size
+static constexpr size_t kMaxInputSize = 256 * 1024; // 256KB
+
+// Recursive helper to access all values (exercises accessor code)
+static void TraverseValue(Json::Value const& value, int depth = 0)
+{
+  // Prevent stack overflow on deeply nested structures
+  if (depth > 100) {
+    return;
+  }
+
+  switch (value.type()) {
+    case Json::nullValue:
+      (void)value.isNull();
+      break;
+    case Json::intValue:
+      (void)value.asInt64();
+      break;
+    case Json::uintValue:
+      (void)value.asUInt64();
+      break;
+    case Json::realValue:
+      (void)value.asDouble();
+      break;
+    case Json::stringValue:
+      (void)value.asString();
+      break;
+    case Json::booleanValue:
+      (void)value.asBool();
+      break;
+    case Json::arrayValue:
+      for (Json::ArrayIndex i = 0; i < value.size() && i < 1000; ++i) {
+        TraverseValue(value[i], depth + 1);
+      }
+      break;
+    case Json::objectValue:
+      for (auto const& name : value.getMemberNames()) {
+        (void)name;
+        TraverseValue(value[name], depth + 1);
+      }
+      break;
+  }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  std::string input(reinterpret_cast<char const*>(data), size);
+
+  Json::Value root;
+  Json::CharReaderBuilder builder;
+  std::string errors;
+
+  std::istringstream stream(input);
+
+  // Try parsing with default settings
+  bool success = Json::parseFromStream(builder, stream, &root, &errors);
+
+  if (success) {
+    // Traverse the parsed structure
+    TraverseValue(root);
+  }
+
+  // Also try with strict mode
+  builder["strictRoot"] = true;
+  builder["allowComments"] = false;
+  builder["allowTrailingCommas"] = false;
+
+  stream.clear();
+  stream.str(input);
+
+  success = Json::parseFromStream(builder, stream, &root, &errors);
+  if (success) {
+    TraverseValue(root);
+  }
+
+  return 0;
+}
diff --git a/Tests/Fuzzing/cmListFileLexer.dict b/Tests/Fuzzing/cmListFileLexer.dict
new file mode 100644
index 0000000..ad3393b
--- /dev/null
+++ b/Tests/Fuzzing/cmListFileLexer.dict
@@ -0,0 +1,108 @@
+# CMake ListFile Lexer Dictionary
+# Keywords and syntax for CMakeLists.txt files
+
+# Common commands
+"cmake_minimum_required"
+"project"
+"add_executable"
+"add_library"
+"target_link_libraries"
+"target_include_directories"
+"target_compile_definitions"
+"target_compile_options"
+"set"
+"unset"
+"if"
+"elseif"
+"else"
+"endif"
+"foreach"
+"endforeach"
+"while"
+"endwhile"
+"function"
+"endfunction"
+"macro"
+"endmacro"
+"return"
+"include"
+"find_package"
+"find_library"
+"find_path"
+"find_program"
+"file"
+"message"
+"option"
+"configure_file"
+"install"
+"add_custom_command"
+"add_custom_target"
+"add_subdirectory"
+"list"
+"string"
+"math"
+"get_property"
+"set_property"
+"get_target_property"
+"set_target_properties"
+"add_definitions"
+"add_dependencies"
+
+# Syntax elements
+"("
+")"
+"\""
+"[["
+"]]"
+"[=["
+"]=]"
+"[==["
+"]==]"
+"#"
+"#[["
+"#]]"
+"\x0a"
+"\x0d\x0a"
+" "
+"\x09"
+"$"
+"{"
+"}"
+"<"
+">"
+";"
+":"
+"@"
+"\\"
+
+# Variables
+"${CMAKE_SOURCE_DIR}"
+"${CMAKE_BINARY_DIR}"
+"${CMAKE_CURRENT_SOURCE_DIR}"
+"${CMAKE_CURRENT_BINARY_DIR}"
+"${PROJECT_NAME}"
+"${PROJECT_SOURCE_DIR}"
+"${PROJECT_BINARY_DIR}"
+"$ENV{}"
+"$CACHE{}"
+
+# Generator expressions
+"$<"
+">:"
+"$<TARGET_FILE:"
+"$<TARGET_PROPERTY:"
+"$<BUILD_INTERFACE:"
+"$<INSTALL_INTERFACE:"
+"$<BOOL:"
+"$<AND:"
+"$<OR:"
+"$<NOT:"
+"$<IF:"
+"$<STREQUAL:"
+"$<VERSION_LESS:"
+"$<CONFIG:"
+
+# BOMs
+"\xef\xbb\xbf"
+"\xff\xfe"
+"\xfe\xff"
diff --git a/Tests/Fuzzing/cmListFileLexerFuzzer.cxx b/Tests/Fuzzing/cmListFileLexerFuzzer.cxx
new file mode 100644
index 0000000..4d3fe76
--- /dev/null
+++ b/Tests/Fuzzing/cmListFileLexerFuzzer.cxx
@@ -0,0 +1,62 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's ListFile lexer (CMakeLists.txt parser)
+ *
+ * This fuzzer targets cmListFileLexer which tokenizes CMakeLists.txt files.
+ * It's a critical attack surface as malicious CMakeLists.txt files could be
+ * encountered when building untrusted projects.
+ *
+ * Coverage targets:
+ * - Token parsing (identifiers, strings, brackets, comments)
+ * - BOM handling (UTF-8, UTF-16, UTF-32)
+ * - Bracket argument/comment parsing
+ * - Error recovery for malformed input
+ */
+
+#include <cstddef>
+#include <cstdint>
+
+#include "cmListFileLexer.h"
+
+// Limit input size to avoid timeouts on complex inputs
+static constexpr size_t kMaxInputSize = 64 * 1024; // 64KB
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  // Skip overly large inputs
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  cmListFileLexer* lexer = cmListFileLexer_New();
+  if (!lexer) {
+    return 0;
+  }
+
+  // Parse from string (not file) for efficiency
+  if (cmListFileLexer_SetString(lexer, reinterpret_cast<char const*>(data),
+                                size)) {
+    // Consume all tokens until EOF or error
+    cmListFileLexer_Token* token;
+    while ((token = cmListFileLexer_Scan(lexer)) != nullptr) {
+      // Access token fields to ensure they're valid
+      (void)token->type;
+      (void)token->text;
+      (void)token->length;
+      (void)token->line;
+      (void)token->column;
+
+      // Get type as string for additional coverage
+      (void)cmListFileLexer_GetTypeAsString(lexer, token->type);
+    }
+
+    // Exercise position tracking
+    (void)cmListFileLexer_GetCurrentLine(lexer);
+    (void)cmListFileLexer_GetCurrentColumn(lexer);
+  }
+
+  cmListFileLexer_Delete(lexer);
+  return 0;
+}
diff --git a/Tests/Fuzzing/cmListFileParserFuzzer.cxx b/Tests/Fuzzing/cmListFileParserFuzzer.cxx
new file mode 100644
index 0000000..4908713
--- /dev/null
+++ b/Tests/Fuzzing/cmListFileParserFuzzer.cxx
@@ -0,0 +1,84 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's list file parser (CMakeLists.txt full parsing)
+ *
+ * This fuzzer tests the complete parsing of CMake files including:
+ * - Command parsing
+ * - Argument handling
+ * - Bracket arguments
+ * - Comments
+ * - Line continuations
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <string>
+
+#include <unistd.h>
+
+#include "cmListFileCache.h"
+#include "cmMessenger.h"
+#include "cmSystemTools.h"
+
+static constexpr size_t kMaxInputSize = 256 * 1024;
+static std::string g_testDir;
+
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
+{
+  (void)argc;
+  (void)argv;
+
+  char tmpl[] = "/tmp/cmake_fuzz_listfile_XXXXXX";
+  char* dir = mkdtemp(tmpl);
+  if (dir) {
+    g_testDir = dir;
+  } else {
+    g_testDir = "/tmp/cmake_fuzz_listfile";
+    cmSystemTools::MakeDirectory(g_testDir);
+  }
+
+  return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  // Write input to temp file
+  std::string testFile = g_testDir + "/CMakeLists.txt";
+  {
+    FILE* fp = fopen(testFile.c_str(), "wb");
+    if (!fp)
+      return 0;
+    fwrite(data, 1, size, fp);
+    fclose(fp);
+  }
+
+  // Create a messenger for error handling
+  cmMessenger messenger;
+
+  // Parse the file
+  cmListFile listFile;
+  cmListFileBacktrace backtrace;
+  if (listFile.ParseFile(testFile.c_str(), &messenger, backtrace)) {
+    // Successfully parsed - examine results
+    for (auto const& func : listFile.Functions) {
+      (void)func.LowerCaseName();
+      (void)func.OriginalName();
+      for (auto const& arg : func.Arguments()) {
+        (void)arg.Value;
+        (void)arg.Delim;
+      }
+    }
+  }
+
+  // Clean up
+  unlink(testFile.c_str());
+
+  return 0;
+}
diff --git a/Tests/Fuzzing/cmPkgConfigParser.dict b/Tests/Fuzzing/cmPkgConfigParser.dict
new file mode 100644
index 0000000..f12af75
--- /dev/null
+++ b/Tests/Fuzzing/cmPkgConfigParser.dict
@@ -0,0 +1,63 @@
+# pkg-config File Dictionary
+
+# Key-value separators
+"="
+":"
+
+# Variable reference
+"${"
+"}"
+
+# Common keywords
+"Name"
+"Description"
+"Version"
+"Requires"
+"Requires.private"
+"Conflicts"
+"Libs"
+"Libs.private"
+"Cflags"
+"URL"
+
+# Common variables
+"prefix"
+"exec_prefix"
+"libdir"
+"includedir"
+"datarootdir"
+"datadir"
+"sysconfdir"
+"sharedstatedir"
+"localstatedir"
+
+# Common values
+"/usr"
+"/usr/local"
+"/usr/lib"
+"/usr/include"
+"-I"
+"-L"
+"-l"
+"-D"
+"-pthread"
+
+# Whitespace
+" "
+"\x09"
+"\x0a"
+"\x0d\x0a"
+
+# Comments
+"#"
+
+# Version operators
+">="
+"<="
+">"
+"<"
+"!="
+
+# Escapes
+"\\"
+"\\$"
diff --git a/Tests/Fuzzing/cmPkgConfigParserFuzzer.cxx b/Tests/Fuzzing/cmPkgConfigParserFuzzer.cxx
new file mode 100644
index 0000000..f4857f4
--- /dev/null
+++ b/Tests/Fuzzing/cmPkgConfigParserFuzzer.cxx
@@ -0,0 +1,59 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's pkg-config file parser
+ *
+ * CMake parses .pc files (pkg-config) when using PkgConfig find module.
+ * Malformed .pc files from untrusted sources could trigger vulnerabilities.
+ *
+ * Coverage targets:
+ * - Variable definitions (key=value)
+ * - Keyword definitions (key: value)
+ * - Variable references (${var})
+ * - Multi-line handling
+ * - Comment handling
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "cmPkgConfigParser.h"
+
+// Limit input size
+static constexpr size_t kMaxInputSize = 64 * 1024; // 64KB
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  // cmPkgConfigParser::Parse takes non-const buffer (may modify in place)
+  std::vector<char> buffer(data, data + size);
+
+  cmPkgConfigParser parser;
+
+  // Parse the input
+  auto result = parser.Parse(buffer.data(), buffer.size());
+  (void)result;
+
+  // Finish parsing
+  result = parser.Finish();
+  (void)result;
+
+  // Access parsed data to exercise accessors
+  auto& entries = parser.Data();
+  for (auto const& entry : entries) {
+    (void)entry.IsVariable;
+    (void)entry.Key;
+    for (auto const& elem : entry.Val) {
+      (void)elem.IsVariable;
+      (void)elem.Data;
+    }
+  }
+
+  return 0;
+}
diff --git a/Tests/Fuzzing/cmScript.dict b/Tests/Fuzzing/cmScript.dict
new file mode 100644
index 0000000..e3890bb
--- /dev/null
+++ b/Tests/Fuzzing/cmScript.dict
@@ -0,0 +1,193 @@
+# CMake script dictionary - comprehensive command coverage
+
+# Basic structure
+"("
+")"
+"\x0a"
+" "
+"\x09"
+
+# Comments
+"#"
+"#[["
+"]]"
+
+# Quotes and brackets
+"\""
+"[["
+"]]"
+"[=["
+"]=]"
+
+# Variable references
+"$"
+"${"
+"}"
+"${}"
+"$ENV{"
+"$CACHE{"
+
+# Generator expressions
+"$<"
+">"
+"$<BOOL:"
+"$<AND:"
+"$<OR:"
+"$<NOT:"
+"$<IF:"
+"$<STREQUAL:"
+"$<VERSION_LESS:"
+"$<TARGET_FILE:"
+
+# Core commands
+"cmake_minimum_required"
+"project"
+"set"
+"unset"
+"message"
+"return"
+"include"
+
+# Variable commands
+"option"
+"mark_as_advanced"
+"separate_arguments"
+
+# Control flow
+"if"
+"elseif"
+"else"
+"endif"
+"foreach"
+"endforeach"
+"while"
+"endwhile"
+"break"
+"continue"
+"function"
+"endfunction"
+"macro"
+"endmacro"
+"block"
+"endblock"
+
+# String operations
+"string"
+"LENGTH"
+"SUBSTRING"
+"FIND"
+"REPLACE"
+"REGEX"
+"MATCH"
+"MATCHALL"
+"TOUPPER"
+"TOLOWER"
+"STRIP"
+"GENEX_STRIP"
+"APPEND"
+"PREPEND"
+"CONCAT"
+"JOIN"
+"COMPARE"
+"MD5"
+"SHA1"
+"SHA256"
+"MAKE_C_IDENTIFIER"
+"RANDOM"
+"TIMESTAMP"
+"UUID"
+"JSON"
+
+# List operations
+"list"
+"GET"
+"APPEND"
+"PREPEND"
+"INSERT"
+"FILTER"
+"REMOVE_ITEM"
+"REMOVE_AT"
+"REMOVE_DUPLICATES"
+"REVERSE"
+"SORT"
+"TRANSFORM"
+"SUBLIST"
+"POP_BACK"
+"POP_FRONT"
+
+# Math
+"math"
+"EXPR"
+
+# File operations
+"file"
+"READ"
+"STRINGS"
+"WRITE"
+"APPEND"
+"GLOB"
+"GLOB_RECURSE"
+"RENAME"
+"REMOVE"
+"MAKE_DIRECTORY"
+"RELATIVE_PATH"
+"TO_CMAKE_PATH"
+"TO_NATIVE_PATH"
+"DOWNLOAD"
+"UPLOAD"
+"COPY"
+"INSTALL"
+"SIZE"
+"READ_SYMLINK"
+"CREATE_LINK"
+"CHMOD"
+"TOUCH"
+"GENERATE"
+"CONFIGURE"
+"ARCHIVE_CREATE"
+"ARCHIVE_EXTRACT"
+
+# Conditionals
+"DEFINED"
+"COMMAND"
+"POLICY"
+"TARGET"
+"TEST"
+"EXISTS"
+"IS_DIRECTORY"
+"IS_SYMLINK"
+"IS_ABSOLUTE"
+"MATCHES"
+"LESS"
+"GREATER"
+"EQUAL"
+"STRLESS"
+"STRGREATER"
+"STREQUAL"
+"VERSION_LESS"
+"VERSION_GREATER"
+"VERSION_EQUAL"
+"AND"
+"OR"
+"NOT"
+"IN_LIST"
+
+# Common values
+"TRUE"
+"FALSE"
+"ON"
+"OFF"
+"YES"
+"NO"
+"STATUS"
+"WARNING"
+"FATAL_ERROR"
+"SEND_ERROR"
+"PARENT_SCOPE"
+"CACHE"
+"FORCE"
+"INTERNAL"
+"STRING"
+"BOOL"
+"PATH"
+"FILEPATH"
diff --git a/Tests/Fuzzing/cmScriptFuzzer.cxx b/Tests/Fuzzing/cmScriptFuzzer.cxx
new file mode 100644
index 0000000..8a7a8ce
--- /dev/null
+++ b/Tests/Fuzzing/cmScriptFuzzer.cxx
@@ -0,0 +1,147 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake script execution
+ *
+ * This fuzzer executes CMake scripts in script mode (-P).
+ * This exercises the majority of CMake's codebase including:
+ * - All built-in commands
+ * - Variable expansion
+ * - Control flow (if, foreach, while, function, macro)
+ * - String/list/file operations
+ * - Generator expressions
+ *
+ * This is the highest-impact fuzzer for coverage.
+ *
+ * Performance notes:
+ * - Uses memfd_create on Linux for memory-backed file I/O
+ * - Falls back to temp files on other platforms
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+#include <unistd.h>
+
+#include "cmCMakePolicyCommand.h"
+#include "cmExecutionStatus.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessenger.h"
+#include "cmState.h"
+#include "cmStateSnapshot.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#ifdef __linux__
+#  include <sys/mman.h>
+#  ifndef MFD_CLOEXEC
+#    define MFD_CLOEXEC 0x0001U
+#  endif
+#endif
+
+static constexpr size_t kMaxInputSize = 256 * 1024;
+static std::string g_testDir;
+static std::string g_scriptFile;
+static bool g_useMemfd = false;
+
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
+{
+  (void)argc;
+  (void)argv;
+
+  // Suppress output during fuzzing (set once at init)
+  cmSystemTools::SetMessageCallback(
+    [](std::string const&, cmMessageMetadata const&) {});
+  cmSystemTools::SetStdoutCallback([](std::string const&) {});
+  cmSystemTools::SetStderrCallback([](std::string const&) {});
+
+  // Create unique test directory (even with memfd, scripts can create files)
+  char tmpl[] = "/tmp/cmake_fuzz_script_XXXXXX";
+  char* dir = mkdtemp(tmpl);
+  if (dir) {
+    g_testDir = dir;
+  } else {
+    g_testDir = "/tmp/cmake_fuzz_script";
+    cmSystemTools::MakeDirectory(g_testDir);
+  }
+
+#ifdef __linux__
+  // Try to use memfd for better performance
+  int fd = memfd_create("cmake_fuzz", MFD_CLOEXEC);
+  if (fd >= 0) {
+    g_useMemfd = true;
+    // Create path via /proc/self/fd
+    g_scriptFile = "/proc/self/fd/" + std::to_string(fd);
+    // Keep fd open - will be reused
+  } else
+#endif
+  {
+    g_scriptFile = g_testDir + "/fuzz_script.cmake";
+  }
+
+  return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+#ifdef __linux__
+  if (g_useMemfd) {
+    // Extract fd from path and write directly
+    int fd = std::atoi(g_scriptFile.c_str() + 14); // "/proc/self/fd/"
+    ftruncate(fd, 0);
+    lseek(fd, 0, SEEK_SET);
+    if (write(fd, data, size) != static_cast<ssize_t>(size)) {
+      return 0;
+    }
+  } else
+#endif
+  {
+    // Write script to temp file
+    FILE* fp = fopen(g_scriptFile.c_str(), "wb");
+    if (!fp)
+      return 0;
+    fwrite(data, 1, size, fp);
+    fclose(fp);
+  }
+
+  // Save CWD in case script uses file(CHDIR)
+  std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+
+  // Create cmake instance for script mode
+  cmake cm(cmState::Role::Script);
+  cm.SetHomeDirectory(g_testDir);
+  cm.SetHomeOutputDirectory(g_testDir);
+
+  // Run the script
+  std::vector<std::string> args;
+  args.push_back("cmake");
+  args.push_back("-P");
+  args.push_back(g_scriptFile);
+
+  (void)cm.Run(args, false);
+
+  // Restore CWD before cleanup (script may have changed it via file(CHDIR))
+  cmSystemTools::ChangeDirectory(cwd);
+
+  // Cleanup temp file (memfd doesn't need cleanup)
+  if (!g_useMemfd) {
+    unlink(g_scriptFile.c_str());
+  }
+
+  // Clean up any files the script may have created in g_testDir
+  // This prevents disk growth and non-determinism from previous iterations
+  cmSystemTools::RemoveADirectory(g_testDir);
+  cmSystemTools::MakeDirectory(g_testDir);
+
+  return 0;
+}
diff --git a/Tests/Fuzzing/cmScriptFuzzer.options b/Tests/Fuzzing/cmScriptFuzzer.options
new file mode 100644
index 0000000..ee5ff09
--- /dev/null
+++ b/Tests/Fuzzing/cmScriptFuzzer.options
@@ -0,0 +1,10 @@
+[libfuzzer]
+max_len = 262144
+timeout = 30
+rss_limit_mb = 2048
+
+[afl]
+timeout = 30
+
+[honggfuzz]
+timeout = 30
diff --git a/Tests/Fuzzing/cmStringAlgorithms.dict b/Tests/Fuzzing/cmStringAlgorithms.dict
new file mode 100644
index 0000000..4b17222
--- /dev/null
+++ b/Tests/Fuzzing/cmStringAlgorithms.dict
@@ -0,0 +1,71 @@
+# String algorithms dictionary
+
+# Whitespace
+" "
+"\x09"
+"\x0a"
+"\x0d"
+"\x0d\x0a"
+
+# CMake separators
+";"
+","
+
+# Quotes
+"\""
+"'"
+
+# Escape sequences
+"\\"
+"\\x0a"
+"\\x09"
+"\\x0d"
+"\\;"
+
+# Variable references
+"$"
+"${"
+"}"
+"${}"
+"$ENV{"
+"$CACHE{"
+
+# Generator expressions
+"$<"
+">"
+"$<AND:"
+"$<OR:"
+"$<NOT:"
+"$<IF:"
+"$<TARGET_FILE:"
+"$<TARGET_PROPERTY:"
+
+# Common CMake variables
+"CMAKE_"
+"CMAKE_SOURCE_DIR"
+"CMAKE_BINARY_DIR"
+"CMAKE_CURRENT_SOURCE_DIR"
+"CMAKE_CURRENT_BINARY_DIR"
+"PROJECT_NAME"
+"PROJECT_SOURCE_DIR"
+"PROJECT_BINARY_DIR"
+
+# List operations
+"APPEND"
+"PREPEND"
+"INSERT"
+"REMOVE"
+"FILTER"
+"TRANSFORM"
+
+# String operations
+"TOUPPER"
+"TOLOWER"
+"STRIP"
+"REPLACE"
+"REGEX"
+"MATCH"
+"SUBSTRING"
+"LENGTH"
+"FIND"
+"COMPARE"
diff --git a/Tests/Fuzzing/cmStringAlgorithmsFuzzer.cxx b/Tests/Fuzzing/cmStringAlgorithmsFuzzer.cxx
new file mode 100644
index 0000000..1503899
--- /dev/null
+++ b/Tests/Fuzzing/cmStringAlgorithmsFuzzer.cxx
@@ -0,0 +1,75 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's string algorithms
+ *
+ * Tests string manipulation, escaping, and processing functions.
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+static constexpr size_t kMaxInputSize = 16 * 1024;
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  std::string input(reinterpret_cast<char const*>(data), size);
+
+  // Test string manipulation functions
+  (void)cmTrimWhitespace(input);
+  (void)cmRemoveQuotes(input);
+  (void)cmEscapeQuotes(input);
+
+  // Test case conversion
+  (void)cmSystemTools::UpperCase(input);
+  (void)cmSystemTools::LowerCase(input);
+
+  // Test tokenization
+  std::vector<std::string> tokens = cmTokenize(input, " \t\n\r");
+  (void)tokens.size();
+
+  // Test with different separators if input is large enough
+  if (size > 4) {
+    std::string sep(reinterpret_cast<char const*>(data), 2);
+    std::string str(reinterpret_cast<char const*>(data + 2), size - 2);
+    std::vector<std::string> parts = cmTokenize(str, sep);
+    (void)parts.size();
+  }
+
+  // Test join operations
+  if (!tokens.empty()) {
+    (void)cmJoin(tokens, ";");
+    (void)cmJoin(tokens, ",");
+  }
+
+  // Test string contains
+  if (size > 2) {
+    std::string haystack(reinterpret_cast<char const*>(data), size / 2);
+    std::string needle(reinterpret_cast<char const*>(data + size / 2),
+                       size - size / 2);
+    (void)cmHasPrefix(haystack, needle);
+    (void)cmHasSuffix(haystack, needle);
+  }
+
+  // Test path operations
+  (void)cmSystemTools::GetFilenameWithoutExtension(input);
+  (void)cmSystemTools::GetFilenameExtension(input);
+  (void)cmSystemTools::GetFilenameName(input);
+  (void)cmSystemTools::GetFilenameLastExtension(input);
+  (void)cmSystemTools::GetFilenamePath(input);
+
+  // Test path normalization
+  (void)cmSystemTools::CollapseFullPath(input);
+
+  return 0;
+}
diff --git a/Tests/Fuzzing/cmVersion.dict b/Tests/Fuzzing/cmVersion.dict
new file mode 100644
index 0000000..f015cf6
--- /dev/null
+++ b/Tests/Fuzzing/cmVersion.dict
@@ -0,0 +1,42 @@
+# Version string dictionary
+
+# Separators
+"."
+"-"
+"+"
+
+# Common versions
+"0"
+"1"
+"2"
+"3"
+"10"
+"99"
+"100"
+"999"
+
+# CMake versions
+"3.28"
+"3.28.0"
+"3.27.0"
+"2.8.12"
+"3.0.0"
+
+# Semantic versioning
+"alpha"
+"beta"
+"rc"
+"rc1"
+"rc2"
+"dev"
+"SNAPSHOT"
+"build"
+"pre"
+"post"
+
+# Edge cases
+"0.0.0"
+"999.999.999"
+"1.0.0-alpha"
+"1.0.0+build"
+"1.0.0-alpha+build"
diff --git a/Tests/Fuzzing/cmVersionFuzzer.cxx b/Tests/Fuzzing/cmVersionFuzzer.cxx
new file mode 100644
index 0000000..c733df1
--- /dev/null
+++ b/Tests/Fuzzing/cmVersionFuzzer.cxx
@@ -0,0 +1,56 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's version comparison
+ *
+ * Tests version string parsing and comparison operations.
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+
+static constexpr size_t kMaxInputSize = 1024;
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  std::string input(reinterpret_cast<char const*>(data), size);
+
+  // Test version comparison with current CMake version
+  (void)cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, input, "3.28.0");
+  (void)cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER, input,
+                                      "3.28.0");
+  (void)cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, input,
+                                      "3.28.0");
+  (void)cmSystemTools::VersionCompare(cmSystemTools::OP_LESS_EQUAL, input,
+                                      "3.28.0");
+  (void)cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, input,
+                                      "3.28.0");
+
+  // Compare against itself
+  (void)cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, input, input);
+
+  // If input is large enough, compare two different versions from input
+  if (size >= 4) {
+    std::string v1(reinterpret_cast<char const*>(data), size / 2);
+    std::string v2(reinterpret_cast<char const*>(data + size / 2),
+                   size - size / 2);
+    (void)cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, v1, v2);
+    (void)cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER, v1, v2);
+    (void)cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, v1, v2);
+  }
+
+  // Version compare with greater/less string format
+  (void)cmSystemTools::VersionCompareGreater(input, "1.0.0");
+  (void)cmSystemTools::VersionCompareGreaterEq(input, "1.0.0");
+
+  return 0;
+}
diff --git a/Tests/Fuzzing/corpus/README.rst b/Tests/Fuzzing/corpus/README.rst
new file mode 100644
index 0000000..05fd348
--- /dev/null
+++ b/Tests/Fuzzing/corpus/README.rst
@@ -0,0 +1,26 @@
+Fuzzing Seed Corpora
+====================
+
+This directory contains seed corpus files for the CMake fuzz targets.
+Each subdirectory corresponds to a specific fuzzer.
+
+Regenerating Binary Corpus Files
+--------------------------------
+
+Some corpus files are binary and include generation scripts for reproducibility:
+
+- ``elf/generate.py`` - Generates minimal ELF headers for cmELFFuzzer
+
+To regenerate::
+
+    cd elf && python3 generate.py
+
+Adding New Corpus Files
+-----------------------
+
+When adding new corpus files:
+
+1. Keep files minimal - smaller seeds lead to faster fuzzing
+2. For binary formats, include a generation script
+3. Cover different code paths and edge cases
+4. Avoid duplicating coverage between files
diff --git a/Tests/Fuzzing/corpus/archive/.gitattributes b/Tests/Fuzzing/corpus/archive/.gitattributes
new file mode 100644
index 0000000..ddfe02a
--- /dev/null
+++ b/Tests/Fuzzing/corpus/archive/.gitattributes
@@ -0,0 +1 @@
+spaces.tar -text -whitespace
diff --git a/Tests/Fuzzing/corpus/archive/simple.tar b/Tests/Fuzzing/corpus/archive/simple.tar
new file mode 100644
index 0000000..b973117
--- /dev/null
+++ b/Tests/Fuzzing/corpus/archive/simple.tar
Binary files differ
diff --git a/Tests/Fuzzing/corpus/archive/simple.tar.gz b/Tests/Fuzzing/corpus/archive/simple.tar.gz
new file mode 100644
index 0000000..443939e
--- /dev/null
+++ b/Tests/Fuzzing/corpus/archive/simple.tar.gz
Binary files differ
diff --git a/Tests/Fuzzing/corpus/archive/simple.zip b/Tests/Fuzzing/corpus/archive/simple.zip
new file mode 100644
index 0000000..72726f7
--- /dev/null
+++ b/Tests/Fuzzing/corpus/archive/simple.zip
Binary files differ
diff --git a/Tests/Fuzzing/corpus/archive/spaces.tar b/Tests/Fuzzing/corpus/archive/spaces.tar
new file mode 100644
index 0000000..991aa1a
--- /dev/null
+++ b/Tests/Fuzzing/corpus/archive/spaces.tar
@@ -0,0 +1 @@
+    
\ No newline at end of file
diff --git a/Tests/Fuzzing/corpus/archive/with_dir.tar b/Tests/Fuzzing/corpus/archive/with_dir.tar
new file mode 100644
index 0000000..8712d6c
--- /dev/null
+++ b/Tests/Fuzzing/corpus/archive/with_dir.tar
Binary files differ
diff --git a/Tests/Fuzzing/corpus/depfile/multiline.d b/Tests/Fuzzing/corpus/depfile/multiline.d
new file mode 100644
index 0000000..9c1556f
--- /dev/null
+++ b/Tests/Fuzzing/corpus/depfile/multiline.d
@@ -0,0 +1,4 @@
+target.o: \
+  source.cpp \
+  header1.h \
+  header2.h
diff --git a/Tests/Fuzzing/corpus/depfile/simple.d b/Tests/Fuzzing/corpus/depfile/simple.d
new file mode 100644
index 0000000..95307cc
--- /dev/null
+++ b/Tests/Fuzzing/corpus/depfile/simple.d
@@ -0,0 +1 @@
+main.o: main.cpp header.h
diff --git a/Tests/Fuzzing/corpus/depfile/spaces.d b/Tests/Fuzzing/corpus/depfile/spaces.d
new file mode 100644
index 0000000..2c1015b
--- /dev/null
+++ b/Tests/Fuzzing/corpus/depfile/spaces.d
@@ -0,0 +1 @@
+"path with spaces.o": "source file.cpp" "my header.h"
diff --git a/Tests/Fuzzing/corpus/elf/generate.py b/Tests/Fuzzing/corpus/elf/generate.py
new file mode 100755
index 0000000..74c8487
--- /dev/null
+++ b/Tests/Fuzzing/corpus/elf/generate.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python3
+"""Generate minimal ELF corpus files for fuzzing.
+
+These are hand-crafted minimal ELF headers that exercise the ELF parser
+without requiring actual compiled binaries. They contain just enough
+structure to be recognized as valid ELF files.
+
+Usage: python3 generate.py
+
+Output files can be verified with: file *.elf
+"""
+
+import os
+import struct
+
+SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
+
+
+def generate_minimal_elf64():
+    """Generate a minimal 64-bit ELF executable header (72 bytes).
+
+    Structure: ELF64 header (64 bytes) with e_type=ET_EXEC, e_machine=EM_X86_64,
+    plus 8 bytes padding for fuzzer mutation headroom.
+    """
+    elf = bytearray()
+
+    # e_ident[16]: ELF identification
+    elf.extend(b'\x7fELF')  # EI_MAG: magic number
+    elf.append(2)           # EI_CLASS: ELFCLASS64
+    elf.append(1)           # EI_DATA: ELFDATA2LSB (little-endian)
+    elf.append(1)           # EI_VERSION: EV_CURRENT
+    elf.append(0)           # EI_OSABI: ELFOSABI_NONE
+    elf.extend(b'\x00' * 8) # EI_PAD: padding
+
+    # ELF header fields
+    elf.extend(struct.pack('<H', 2))      # e_type: ET_EXEC
+    elf.extend(struct.pack('<H', 0x3e))   # e_machine: EM_X86_64
+    elf.extend(struct.pack('<I', 1))      # e_version: EV_CURRENT
+    elf.extend(struct.pack('<Q', 0))      # e_entry: entry point
+    elf.extend(struct.pack('<Q', 0))      # e_phoff: program header offset
+    elf.extend(struct.pack('<Q', 0))      # e_shoff: section header offset
+    elf.extend(struct.pack('<I', 0))      # e_flags
+    elf.extend(struct.pack('<H', 0))      # e_ehsize
+    elf.extend(struct.pack('<H', 0))      # e_phentsize
+    elf.extend(struct.pack('<H', 0))      # e_phnum
+    elf.extend(struct.pack('<H', 0))      # e_shentsize
+    elf.extend(struct.pack('<H', 0))      # e_shnum
+    elf.extend(struct.pack('<H', 0))      # e_shstrndx
+
+    # Padding for fuzzer mutation headroom
+    elf.extend(b'\x00' * 8)
+
+    return bytes(elf)
+
+
+def generate_minimal_elf32():
+    """Generate a minimal 32-bit ELF PIE header (60 bytes).
+
+    Structure: ELF32 header (52 bytes) with e_type=ET_DYN, e_machine=EM_386,
+    plus 8 bytes padding for fuzzer mutation headroom.
+    """
+    elf = bytearray()
+
+    # e_ident[16]: ELF identification
+    elf.extend(b'\x7fELF')  # EI_MAG: magic number
+    elf.append(1)           # EI_CLASS: ELFCLASS32
+    elf.append(1)           # EI_DATA: ELFDATA2LSB (little-endian)
+    elf.append(1)           # EI_VERSION: EV_CURRENT
+    elf.append(0)           # EI_OSABI: ELFOSABI_NONE
+    elf.extend(b'\x00' * 8) # EI_PAD: padding
+
+    # ELF header fields
+    elf.extend(struct.pack('<H', 3))      # e_type: ET_DYN (PIE)
+    elf.extend(struct.pack('<H', 3))      # e_machine: EM_386
+    elf.extend(struct.pack('<I', 1))      # e_version: EV_CURRENT
+    elf.extend(struct.pack('<I', 0))      # e_entry: entry point
+    elf.extend(struct.pack('<I', 0))      # e_phoff: program header offset
+    elf.extend(struct.pack('<I', 0))      # e_shoff: section header offset
+    elf.extend(struct.pack('<I', 0))      # e_flags
+    elf.extend(struct.pack('<H', 0))      # e_ehsize
+    elf.extend(struct.pack('<H', 0))      # e_phentsize
+    elf.extend(struct.pack('<H', 0))      # e_phnum
+    elf.extend(struct.pack('<H', 0))      # e_shentsize
+    elf.extend(struct.pack('<H', 0))      # e_shnum
+    elf.extend(struct.pack('<H', 0))      # e_shstrndx
+
+    # Padding for fuzzer mutation headroom
+    elf.extend(b'\x00' * 8)
+
+    return bytes(elf)
+
+
+def main():
+    os.chdir(SCRIPT_DIR)
+
+    elf64 = generate_minimal_elf64()
+    elf32 = generate_minimal_elf32()
+
+    with open('minimal64.elf', 'wb') as f:
+        f.write(elf64)
+    print(f"Generated minimal64.elf ({len(elf64)} bytes)")
+
+    with open('minimal32.elf', 'wb') as f:
+        f.write(elf32)
+    print(f"Generated minimal32.elf ({len(elf32)} bytes)")
+
+
+if __name__ == '__main__':
+    main()
diff --git a/Tests/Fuzzing/corpus/elf/minimal32.elf b/Tests/Fuzzing/corpus/elf/minimal32.elf
new file mode 100755
index 0000000..fd06616
--- /dev/null
+++ b/Tests/Fuzzing/corpus/elf/minimal32.elf
Binary files differ
diff --git a/Tests/Fuzzing/corpus/elf/minimal64.elf b/Tests/Fuzzing/corpus/elf/minimal64.elf
new file mode 100755
index 0000000..57e3546
--- /dev/null
+++ b/Tests/Fuzzing/corpus/elf/minimal64.elf
Binary files differ
diff --git a/Tests/Fuzzing/corpus/expr/hex.txt b/Tests/Fuzzing/corpus/expr/hex.txt
new file mode 100644
index 0000000..d7960fc
--- /dev/null
+++ b/Tests/Fuzzing/corpus/expr/hex.txt
@@ -0,0 +1 @@
+0xff & 0x0f
diff --git a/Tests/Fuzzing/corpus/expr/not.txt b/Tests/Fuzzing/corpus/expr/not.txt
new file mode 100644
index 0000000..9ca2922
--- /dev/null
+++ b/Tests/Fuzzing/corpus/expr/not.txt
@@ -0,0 +1 @@
+~0
diff --git a/Tests/Fuzzing/corpus/expr/parens.txt b/Tests/Fuzzing/corpus/expr/parens.txt
new file mode 100644
index 0000000..9f745a4
--- /dev/null
+++ b/Tests/Fuzzing/corpus/expr/parens.txt
@@ -0,0 +1 @@
+(1+2)*3
diff --git a/Tests/Fuzzing/corpus/expr/precedence.txt b/Tests/Fuzzing/corpus/expr/precedence.txt
new file mode 100644
index 0000000..fcc49a6
--- /dev/null
+++ b/Tests/Fuzzing/corpus/expr/precedence.txt
@@ -0,0 +1 @@
+1+2*3
diff --git a/Tests/Fuzzing/corpus/expr/shift.txt b/Tests/Fuzzing/corpus/expr/shift.txt
new file mode 100644
index 0000000..98f9c13
--- /dev/null
+++ b/Tests/Fuzzing/corpus/expr/shift.txt
@@ -0,0 +1 @@
+1 << 4
diff --git a/Tests/Fuzzing/corpus/expr/simple.txt b/Tests/Fuzzing/corpus/expr/simple.txt
new file mode 100644
index 0000000..19f5084
--- /dev/null
+++ b/Tests/Fuzzing/corpus/expr/simple.txt
@@ -0,0 +1 @@
+1+2
diff --git a/Tests/Fuzzing/corpus/filelock/custom_name.bin b/Tests/Fuzzing/corpus/filelock/custom_name.bin
new file mode 100644
index 0000000..dc408a3
--- /dev/null
+++ b/Tests/Fuzzing/corpus/filelock/custom_name.bin
Binary files differ
diff --git a/Tests/Fuzzing/corpus/filelock/mode0.bin b/Tests/Fuzzing/corpus/filelock/mode0.bin
new file mode 100644
index 0000000..09f370e
--- /dev/null
+++ b/Tests/Fuzzing/corpus/filelock/mode0.bin
Binary files differ
diff --git a/Tests/Fuzzing/corpus/filelock/mode1.bin b/Tests/Fuzzing/corpus/filelock/mode1.bin
new file mode 100644
index 0000000..35a0387
--- /dev/null
+++ b/Tests/Fuzzing/corpus/filelock/mode1.bin
Binary files differ
diff --git a/Tests/Fuzzing/corpus/filelock/mode2.bin b/Tests/Fuzzing/corpus/filelock/mode2.bin
new file mode 100644
index 0000000..5407bf3
--- /dev/null
+++ b/Tests/Fuzzing/corpus/filelock/mode2.bin
Binary files differ
diff --git a/Tests/Fuzzing/corpus/filelock/mode3.bin b/Tests/Fuzzing/corpus/filelock/mode3.bin
new file mode 100644
index 0000000..15294a5
--- /dev/null
+++ b/Tests/Fuzzing/corpus/filelock/mode3.bin
Binary files differ
diff --git a/Tests/Fuzzing/corpus/filelock/symlink.bin b/Tests/Fuzzing/corpus/filelock/symlink.bin
new file mode 100644
index 0000000..8835708
--- /dev/null
+++ b/Tests/Fuzzing/corpus/filelock/symlink.bin
Binary files differ
diff --git a/Tests/Fuzzing/corpus/filelock/timeout.bin b/Tests/Fuzzing/corpus/filelock/timeout.bin
new file mode 100644
index 0000000..d6db588
--- /dev/null
+++ b/Tests/Fuzzing/corpus/filelock/timeout.bin
Binary files differ
diff --git a/Tests/Fuzzing/corpus/genex/basic.txt b/Tests/Fuzzing/corpus/genex/basic.txt
new file mode 100644
index 0000000..a999ee4
--- /dev/null
+++ b/Tests/Fuzzing/corpus/genex/basic.txt
@@ -0,0 +1 @@
+$<TARGET_FILE:mylib>
diff --git a/Tests/Fuzzing/corpus/genex/complex.txt b/Tests/Fuzzing/corpus/genex/complex.txt
new file mode 100644
index 0000000..6532d98
--- /dev/null
+++ b/Tests/Fuzzing/corpus/genex/complex.txt
@@ -0,0 +1 @@
+$<IF:$<AND:$<BOOL:${BUILD_SHARED},$<NOT:$<PLATFORM_ID:Windows>>>>,shared,static>
diff --git a/Tests/Fuzzing/corpus/genex/interface.txt b/Tests/Fuzzing/corpus/genex/interface.txt
new file mode 100644
index 0000000..f0f4837
--- /dev/null
+++ b/Tests/Fuzzing/corpus/genex/interface.txt
@@ -0,0 +1 @@
+$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>$<INSTALL_INTERFACE:include>
diff --git a/Tests/Fuzzing/corpus/genex/nested.txt b/Tests/Fuzzing/corpus/genex/nested.txt
new file mode 100644
index 0000000..f3d5f23
--- /dev/null
+++ b/Tests/Fuzzing/corpus/genex/nested.txt
@@ -0,0 +1 @@
+$<$<CONFIG:Debug>:DEBUG_MODE>
diff --git a/Tests/Fuzzing/corpus/genex/target.txt b/Tests/Fuzzing/corpus/genex/target.txt
new file mode 100644
index 0000000..fbf5920
--- /dev/null
+++ b/Tests/Fuzzing/corpus/genex/target.txt
@@ -0,0 +1 @@
+$<TARGET_PROPERTY:mylib,INTERFACE_INCLUDE_DIRECTORIES>
diff --git a/Tests/Fuzzing/corpus/json/nested.json b/Tests/Fuzzing/corpus/json/nested.json
new file mode 100644
index 0000000..69a5e08
--- /dev/null
+++ b/Tests/Fuzzing/corpus/json/nested.json
@@ -0,0 +1 @@
+{"a":{"b":{"c":{"d":[1,2,3]}}}}
diff --git a/Tests/Fuzzing/corpus/json/preset.json b/Tests/Fuzzing/corpus/json/preset.json
new file mode 100644
index 0000000..2850fcf
--- /dev/null
+++ b/Tests/Fuzzing/corpus/json/preset.json
@@ -0,0 +1,10 @@
+{
+  "version": 3,
+  "configurePresets": [
+    {
+      "name": "default",
+      "generator": "Ninja",
+      "binaryDir": "${sourceDir}/build"
+    }
+  ]
+}
diff --git a/Tests/Fuzzing/corpus/json/types.json b/Tests/Fuzzing/corpus/json/types.json
new file mode 100644
index 0000000..f3c078b
--- /dev/null
+++ b/Tests/Fuzzing/corpus/json/types.json
@@ -0,0 +1,9 @@
+{
+  "string": "hello",
+  "number": 42,
+  "float": 3.14,
+  "bool": true,
+  "null": null,
+  "array": [1, "two", false],
+  "object": {"nested": "value"}
+}
diff --git a/Tests/Fuzzing/corpus/listfile/basic.txt b/Tests/Fuzzing/corpus/listfile/basic.txt
new file mode 100644
index 0000000..34f60cf
--- /dev/null
+++ b/Tests/Fuzzing/corpus/listfile/basic.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.10)
+project(Test)
+add_executable(main main.cpp)
diff --git a/Tests/Fuzzing/corpus/listfile/bracket.txt b/Tests/Fuzzing/corpus/listfile/bracket.txt
new file mode 100644
index 0000000..8e37caf
--- /dev/null
+++ b/Tests/Fuzzing/corpus/listfile/bracket.txt
@@ -0,0 +1,2 @@
+set(x [=[nested [[brackets]] here]=])
+set(y [==[even more [=[nested]=] brackets]==])
diff --git a/Tests/Fuzzing/corpus/listfile/complex.txt b/Tests/Fuzzing/corpus/listfile/complex.txt
new file mode 100644
index 0000000..89e8e72
--- /dev/null
+++ b/Tests/Fuzzing/corpus/listfile/complex.txt
@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 3.16)
+project(ComplexProject VERSION 1.0.0 LANGUAGES CXX)
+
+set(CMAKE_CXX_STANDARD 17)
+
+option(BUILD_TESTS "Build tests" ON)
+
+if(BUILD_TESTS)
+  enable_testing()
+  add_subdirectory(tests)
+endif()
+
+function(my_function arg1 arg2)
+  message(STATUS "Function called with ${arg1} and ${arg2}")
+endfunction()
+
+# Bracket comment [[
+This is a bracket comment
+]]
+
+set(LONG_STRING [[
+This is a bracket
+argument with multiple
+lines
+]])
+
+foreach(item IN ITEMS a b c)
+  message("Item: ${item}")
+endforeach()
diff --git a/Tests/Fuzzing/corpus/path/dotdot.txt b/Tests/Fuzzing/corpus/path/dotdot.txt
new file mode 100644
index 0000000..b9a8881
--- /dev/null
+++ b/Tests/Fuzzing/corpus/path/dotdot.txt
@@ -0,0 +1 @@
+/home/user/../other/./path
diff --git a/Tests/Fuzzing/corpus/path/relative.txt b/Tests/Fuzzing/corpus/path/relative.txt
new file mode 100644
index 0000000..9e16302
--- /dev/null
+++ b/Tests/Fuzzing/corpus/path/relative.txt
@@ -0,0 +1 @@
+../build/CMakeFiles
diff --git a/Tests/Fuzzing/corpus/path/unix.txt b/Tests/Fuzzing/corpus/path/unix.txt
new file mode 100644
index 0000000..b09d685
--- /dev/null
+++ b/Tests/Fuzzing/corpus/path/unix.txt
@@ -0,0 +1 @@
+/usr/local/lib/cmake
diff --git a/Tests/Fuzzing/corpus/path/windows.txt b/Tests/Fuzzing/corpus/path/windows.txt
new file mode 100644
index 0000000..544f098
--- /dev/null
+++ b/Tests/Fuzzing/corpus/path/windows.txt
@@ -0,0 +1 @@
+C:\Program Files\CMake\bin
diff --git a/Tests/Fuzzing/corpus/pkgconfig/deps.pc b/Tests/Fuzzing/corpus/pkgconfig/deps.pc
new file mode 100644
index 0000000..1977457
--- /dev/null
+++ b/Tests/Fuzzing/corpus/pkgconfig/deps.pc
@@ -0,0 +1,5 @@
+Name: WithDeps
+Version: 2.0
+Requires: dep1 >= 1.0, dep2
+Requires.private: internal
+Libs: -lwithdeps
diff --git a/Tests/Fuzzing/corpus/pkgconfig/simple.pc b/Tests/Fuzzing/corpus/pkgconfig/simple.pc
new file mode 100644
index 0000000..593db97
--- /dev/null
+++ b/Tests/Fuzzing/corpus/pkgconfig/simple.pc
@@ -0,0 +1,9 @@
+prefix=/usr
+libdir=${prefix}/lib
+includedir=${prefix}/include
+
+Name: Example
+Description: An example library
+Version: 1.0.0
+Libs: -L${libdir} -lexample
+Cflags: -I${includedir}
diff --git a/Tests/Fuzzing/corpus/script/cmake_path.cmake b/Tests/Fuzzing/corpus/script/cmake_path.cmake
new file mode 100644
index 0000000..75e9f3c
--- /dev/null
+++ b/Tests/Fuzzing/corpus/script/cmake_path.cmake
@@ -0,0 +1,20 @@
+cmake_path(SET p "/usr/local/lib/cmake/foo.cmake")
+cmake_path(GET p ROOT_NAME root)
+cmake_path(GET p ROOT_DIRECTORY rootdir)
+cmake_path(GET p ROOT_PATH rootpath)
+cmake_path(GET p FILENAME fname)
+cmake_path(GET p EXTENSION ext)
+cmake_path(GET p STEM stem)
+cmake_path(GET p RELATIVE_PART rel)
+cmake_path(GET p PARENT_PATH parent)
+cmake_path(APPEND p "bar" OUTPUT_VARIABLE appended)
+cmake_path(REMOVE_FILENAME p)
+cmake_path(REPLACE_FILENAME p "new.txt")
+cmake_path(REMOVE_EXTENSION p)
+cmake_path(REPLACE_EXTENSION p ".hpp")
+cmake_path(NORMAL_PATH p)
+cmake_path(IS_ABSOLUTE p result)
+cmake_path(IS_RELATIVE p result)
+cmake_path(HAS_ROOT_NAME p result)
+cmake_path(HAS_FILENAME p result)
+cmake_path(COMPARE p EQUAL "/usr/local" equal_result)
diff --git a/Tests/Fuzzing/corpus/script/complex_string.cmake b/Tests/Fuzzing/corpus/script/complex_string.cmake
new file mode 100644
index 0000000..0b7ee56
--- /dev/null
+++ b/Tests/Fuzzing/corpus/script/complex_string.cmake
@@ -0,0 +1,14 @@
+set(input "Hello;World;From;CMake")
+string(REPLACE ";" " " spaced "${input}")
+string(REGEX REPLACE "([A-Z])" "_\\1" snake "${spaced}")
+string(REGEX MATCHALL "[A-Za-z]+" words "${spaced}")
+string(GENEX_STRIP "$<TARGET_FILE:foo>" stripped)
+string(APPEND result "line1\n" "line2\n")
+string(PREPEND result "header\n")
+string(CONCAT full "a" "b" "c" "d")
+string(JOIN ":" joined a b c d)
+string(MAKE_C_IDENTIFIER "my-var.name" c_id)
+string(RANDOM LENGTH 16 ALPHABET "0123456789ABCDEF" random)
+string(TIMESTAMP ts "%Y-%m-%d %H:%M:%S")
+string(UUID uuid NAMESPACE 6ba7b810-9dad-11d1-80b4-00c04fd430c8 NAME test TYPE SHA1)
+string(JSON json_val GET "{\"key\":\"value\"}" "key")
diff --git a/Tests/Fuzzing/corpus/script/configure_file.cmake b/Tests/Fuzzing/corpus/script/configure_file.cmake
new file mode 100644
index 0000000..6c2c949
--- /dev/null
+++ b/Tests/Fuzzing/corpus/script/configure_file.cmake
@@ -0,0 +1,7 @@
+set(VERSION "1.0.0")
+set(AUTHOR "Test Author")
+file(WRITE /tmp/config.h.in "#define VERSION \"@VERSION@\"\n#define AUTHOR \"@AUTHOR@\"\n")
+configure_file(/tmp/config.h.in /tmp/config.h @ONLY)
+file(READ /tmp/config.h config_content)
+message(STATUS "Configured: ${config_content}")
+file(REMOVE /tmp/config.h.in /tmp/config.h)
diff --git a/Tests/Fuzzing/corpus/script/control_flow.cmake b/Tests/Fuzzing/corpus/script/control_flow.cmake
new file mode 100644
index 0000000..8d84d63
--- /dev/null
+++ b/Tests/Fuzzing/corpus/script/control_flow.cmake
@@ -0,0 +1,12 @@
+set(X 5)
+if(X GREATER 3)
+  message("X > 3")
+elseif(X EQUAL 3)
+  message("X == 3")
+else()
+  message("X < 3")
+endif()
+
+foreach(i RANGE 3)
+  message("i = ${i}")
+endforeach()
diff --git a/Tests/Fuzzing/corpus/script/execute_process.cmake b/Tests/Fuzzing/corpus/script/execute_process.cmake
new file mode 100644
index 0000000..96b0fd9
--- /dev/null
+++ b/Tests/Fuzzing/corpus/script/execute_process.cmake
@@ -0,0 +1,10 @@
+execute_process(
+  COMMAND echo "Hello from process"
+  OUTPUT_VARIABLE output
+  ERROR_VARIABLE error
+  RESULT_VARIABLE result
+  TIMEOUT 5
+  WORKING_DIRECTORY /tmp
+)
+message(STATUS "Output: ${output}")
+message(STATUS "Result: ${result}")
diff --git a/Tests/Fuzzing/corpus/script/file_ops.cmake b/Tests/Fuzzing/corpus/script/file_ops.cmake
new file mode 100644
index 0000000..1c5c619
--- /dev/null
+++ b/Tests/Fuzzing/corpus/script/file_ops.cmake
@@ -0,0 +1,4 @@
+file(WRITE "/tmp/cmake_fuzz_test.txt" "test content")
+file(READ "/tmp/cmake_fuzz_test.txt" content)
+file(REMOVE "/tmp/cmake_fuzz_test.txt")
+file(GLOB files "/tmp/*.txt")
diff --git a/Tests/Fuzzing/corpus/script/function.cmake b/Tests/Fuzzing/corpus/script/function.cmake
new file mode 100644
index 0000000..b8cf7b7
--- /dev/null
+++ b/Tests/Fuzzing/corpus/script/function.cmake
@@ -0,0 +1,7 @@
+function(my_func arg1 arg2)
+  message("arg1: ${arg1}, arg2: ${arg2}")
+  set(RESULT "${arg1}_${arg2}" PARENT_SCOPE)
+endfunction()
+
+my_func("hello" "world")
+message("Result: ${RESULT}")
diff --git a/Tests/Fuzzing/corpus/script/list_ops.cmake b/Tests/Fuzzing/corpus/script/list_ops.cmake
new file mode 100644
index 0000000..fef4874
--- /dev/null
+++ b/Tests/Fuzzing/corpus/script/list_ops.cmake
@@ -0,0 +1,17 @@
+set(MYLIST a b c d e f)
+list(LENGTH MYLIST len)
+list(GET MYLIST 0 first)
+list(GET MYLIST -1 last)
+list(APPEND MYLIST g h)
+list(PREPEND MYLIST z)
+list(INSERT MYLIST 2 x y)
+list(FIND MYLIST c idx)
+list(REMOVE_AT MYLIST 0)
+list(REMOVE_ITEM MYLIST e)
+list(REMOVE_DUPLICATES MYLIST)
+list(REVERSE MYLIST)
+list(SORT MYLIST)
+list(SUBLIST MYLIST 1 3 sub)
+list(JOIN MYLIST "," joined)
+list(TRANSFORM MYLIST TOUPPER)
+list(FILTER MYLIST INCLUDE REGEX "[A-Z]")
diff --git a/Tests/Fuzzing/corpus/script/math_ops.cmake b/Tests/Fuzzing/corpus/script/math_ops.cmake
new file mode 100644
index 0000000..78e7853
--- /dev/null
+++ b/Tests/Fuzzing/corpus/script/math_ops.cmake
@@ -0,0 +1,3 @@
+math(EXPR result "1 + 2 * 3")
+math(EXPR hex "0xFF" OUTPUT_FORMAT HEXADECIMAL)
+math(EXPR dec "0x10" OUTPUT_FORMAT DECIMAL)
diff --git a/Tests/Fuzzing/corpus/script/string_ops.cmake b/Tests/Fuzzing/corpus/script/string_ops.cmake
new file mode 100644
index 0000000..08b9a1b
--- /dev/null
+++ b/Tests/Fuzzing/corpus/script/string_ops.cmake
@@ -0,0 +1,6 @@
+set(STR "Hello World")
+string(LENGTH "${STR}" len)
+string(TOUPPER "${STR}" upper)
+string(TOLOWER "${STR}" lower)
+string(REPLACE "World" "CMake" result "${STR}")
+string(REGEX MATCH "[A-Z]+" match "${STR}")
diff --git a/Tests/Fuzzing/corpus/script/variables.cmake b/Tests/Fuzzing/corpus/script/variables.cmake
new file mode 100644
index 0000000..cfd374d
--- /dev/null
+++ b/Tests/Fuzzing/corpus/script/variables.cmake
@@ -0,0 +1,5 @@
+set(MY_VAR "hello")
+set(MY_LIST a b c d)
+message(STATUS "VAR: ${MY_VAR}")
+list(LENGTH MY_LIST len)
+message(STATUS "Length: ${len}")
diff --git a/Tests/Fuzzing/corpus/string/cmake_var.txt b/Tests/Fuzzing/corpus/string/cmake_var.txt
new file mode 100644
index 0000000..3c3974e
--- /dev/null
+++ b/Tests/Fuzzing/corpus/string/cmake_var.txt
@@ -0,0 +1 @@
+${CMAKE_SOURCE_DIR}
diff --git a/Tests/Fuzzing/corpus/string/list.txt b/Tests/Fuzzing/corpus/string/list.txt
new file mode 100644
index 0000000..2bde41b
--- /dev/null
+++ b/Tests/Fuzzing/corpus/string/list.txt
@@ -0,0 +1 @@
+item1;item2;item3;item4
diff --git a/Tests/Fuzzing/corpus/string/quoted.txt b/Tests/Fuzzing/corpus/string/quoted.txt
new file mode 100644
index 0000000..cab0dd8
--- /dev/null
+++ b/Tests/Fuzzing/corpus/string/quoted.txt
@@ -0,0 +1 @@
+"quoted string with spaces"
diff --git a/Tests/Fuzzing/corpus/version/long.txt b/Tests/Fuzzing/corpus/version/long.txt
new file mode 100644
index 0000000..4e783d9
--- /dev/null
+++ b/Tests/Fuzzing/corpus/version/long.txt
@@ -0,0 +1 @@
+3.28.0.20231201
diff --git a/Tests/Fuzzing/corpus/version/semver.txt b/Tests/Fuzzing/corpus/version/semver.txt
new file mode 100644
index 0000000..5f3aef5
--- /dev/null
+++ b/Tests/Fuzzing/corpus/version/semver.txt
@@ -0,0 +1 @@
+1.2.3-alpha+build
diff --git a/Tests/Fuzzing/corpus/version/simple.txt b/Tests/Fuzzing/corpus/version/simple.txt
new file mode 100644
index 0000000..a72fd67
--- /dev/null
+++ b/Tests/Fuzzing/corpus/version/simple.txt
@@ -0,0 +1 @@
+3.28.0
diff --git a/Tests/Fuzzing/corpus/version/tweak.txt b/Tests/Fuzzing/corpus/version/tweak.txt
new file mode 100644
index 0000000..70f7f54
--- /dev/null
+++ b/Tests/Fuzzing/corpus/version/tweak.txt
@@ -0,0 +1 @@
+3.28.0.1
diff --git a/Tests/Fuzzing/xml_parser.dict b/Tests/Fuzzing/xml_parser.dict
new file mode 100644
index 0000000..c50ef6d
--- /dev/null
+++ b/Tests/Fuzzing/xml_parser.dict
@@ -0,0 +1,75 @@
+# XML dictionary for xml_parser_fuzzer
+
+# Processing instruction
+"<?xml"
+"?>"
+"version="
+"encoding="
+"standalone="
+
+# Document structure
+"<!DOCTYPE"
+"<!ELEMENT"
+"<!ATTLIST"
+"<!ENTITY"
+"<!NOTATION"
+"SYSTEM"
+"PUBLIC"
+
+# Tags
+"<"
+">"
+"/>"
+"</"
+
+# Attributes
+"="
+"\x22"
+"\x27"
+
+# CDATA and comments
+"<![CDATA["
+"]]>"
+"<!--"
+"-->"
+
+# Namespaces
+"xmlns"
+"xmlns:"
+
+# Common CMake XML elements
+"<cmake"
+"<project"
+"<target"
+"<file"
+"<dependency"
+"<source"
+"<include"
+"<define"
+"<flag"
+"<option"
+"<property"
+"<configuration"
+"<install"
+"<test"
+"<cache"
+
+# Entity references
+"&lt;"
+"&gt;"
+"&amp;"
+"&quot;"
+"&apos;"
+"&#"
+"&#x"
+
+# Whitespace
+"\x09"
+"\x0a"
+"\x0d"
+"\x20"
+
+# Special patterns
+"]]]]><![CDATA["
+"-->"
+"?>"
diff --git a/Tests/HIP/ArchSpecial/CMakeLists.txt b/Tests/HIP/ArchSpecial/CMakeLists.txt
index 2bc6bd2..de7c7eb 100644
--- a/Tests/HIP/ArchSpecial/CMakeLists.txt
+++ b/Tests/HIP/ArchSpecial/CMakeLists.txt
@@ -57,7 +57,14 @@
   COMPILE_DEFINITIONS ${try_compile_flags}
   OUTPUT_VARIABLE output
   )
-verify_output(native)
+if(native_archs_compiles)
+  verify_output(native)
+elseif("$ENV{CMAKE_CUDA_ARCHITECTURES_NATIVE_CLAMP}"
+    AND CMAKE_HIP_COMPILER_ID STREQUAL "NVIDIA"
+    AND output MATCHES "Unsupported gpu architecture")
+  # nvcc -arch=native is not affected by the clamp
+  set(native_archs_compiles 1)
+endif()
 
 if(all_archs_compiles AND all_major_archs_compiles AND native_archs_compiles)
   set(CMAKE_HIP_ARCHITECTURES all)
diff --git a/Tests/InterfaceLinkLibrariesDirect/testStaticLibWithPluginBad1.c b/Tests/InterfaceLinkLibrariesDirect/testStaticLibWithPluginBad1.c
index b41abc9..2a27333 100644
--- a/Tests/InterfaceLinkLibrariesDirect/testStaticLibWithPluginBad1.c
+++ b/Tests/InterfaceLinkLibrariesDirect/testStaticLibWithPluginBad1.c
@@ -1,4 +1,4 @@
-/* Produce an error if if the object compiled from this source is used.  */
+/* Produce an error if the object compiled from this source is used.  */
 extern int testStaticLibWithPlugin_linked_before_testStaticLibPlugin(void);
 int testStaticLibPlugin(void)
 {
diff --git a/Tests/InterfaceLinkLibrariesDirect/testStaticLibWithPluginBad2.c b/Tests/InterfaceLinkLibrariesDirect/testStaticLibWithPluginBad2.c
index 43337a5..d2e8483 100644
--- a/Tests/InterfaceLinkLibrariesDirect/testStaticLibWithPluginBad2.c
+++ b/Tests/InterfaceLinkLibrariesDirect/testStaticLibWithPluginBad2.c
@@ -1,4 +1,4 @@
-/* Produce an error if if the object compiled from this source is used.  */
+/* Produce an error if the object compiled from this source is used.  */
 extern int testStaticLibWithPlugin_linked_before_testStaticLibPluginExtra(
   void);
 int testStaticLibPluginExtra(void)
diff --git a/Tests/JavaModExportImport/BuildExport/CMakeLists.txt b/Tests/JavaModExportImport/BuildExport/CMakeLists.txt
new file mode 100644
index 0000000..f818f44
--- /dev/null
+++ b/Tests/JavaModExportImport/BuildExport/CMakeLists.txt
@@ -0,0 +1,13 @@
+project(foo Java)
+
+cmake_minimum_required(VERSION 3.10)
+set(CMAKE_VERBOSE_MAKEFILE 1)
+
+find_package(Java COMPONENTS Development)
+include(UseJava)
+
+add_jar(${PROJECT_NAME} Foo.java module-info.java)
+export_jars(
+  TARGETS ${PROJECT_NAME}
+  NAMESPACE foo::
+  FILE JavaBuildExportTestConfig.cmake)
diff --git a/Tests/JavaModExportImport/BuildExport/Foo.java b/Tests/JavaModExportImport/BuildExport/Foo.java
new file mode 100644
index 0000000..c0e2a1a
--- /dev/null
+++ b/Tests/JavaModExportImport/BuildExport/Foo.java
@@ -0,0 +1,13 @@
+package org.foo;
+
+public class Foo
+{
+  public Foo()
+  {
+  }
+
+  public void printName()
+  {
+    System.out.println("Foo");
+  }
+}
diff --git a/Tests/JavaModExportImport/BuildExport/module-info.java b/Tests/JavaModExportImport/BuildExport/module-info.java
new file mode 100644
index 0000000..aeb0e17
--- /dev/null
+++ b/Tests/JavaModExportImport/BuildExport/module-info.java
@@ -0,0 +1,3 @@
+module mod_foo {
+    exports org.foo;
+}
diff --git a/Tests/JavaModExportImport/CMakeLists.txt b/Tests/JavaModExportImport/CMakeLists.txt
new file mode 100644
index 0000000..5326457
--- /dev/null
+++ b/Tests/JavaModExportImport/CMakeLists.txt
@@ -0,0 +1,105 @@
+cmake_minimum_required(VERSION 3.10)
+project(JavaModExportImport)
+if(NOT DEFINED CMake_TEST_NESTED_MAKE_PROGRAM AND NOT CMAKE_GENERATOR MATCHES "Visual Studio")
+  set(CMake_TEST_NESTED_MAKE_PROGRAM "${CMAKE_MAKE_PROGRAM}")
+endif()
+
+find_package(Java COMPONENTS Development)
+
+# Wipe out the install tree to make sure the exporter works.
+add_custom_command(
+  OUTPUT ${JavaModExportImport_BINARY_DIR}/CleanupProject
+  COMMAND ${CMAKE_COMMAND} -E rm -rf ${JavaModExportImport_BINARY_DIR}/Root
+  )
+add_custom_target(CleanupTarget ALL DEPENDS ${JavaModExportImport_BINARY_DIR}/CleanupProject)
+set_property(
+  SOURCE ${JavaModExportImport_BINARY_DIR}/CleanupProject
+  PROPERTY SYMBOLIC 1
+  )
+
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+  set(NESTED_CONFIG_TYPE -C "${CMAKE_CFG_INTDIR}")
+else()
+  if(CMAKE_BUILD_TYPE)
+    set(NESTED_CONFIG_TYPE -C "${CMAKE_BUILD_TYPE}")
+  else()
+    set(NESTED_CONFIG_TYPE)
+  endif()
+endif()
+
+configure_file(${JavaModExportImport_SOURCE_DIR}/InitialCache.cmake.in
+               ${JavaModExportImport_BINARY_DIR}/InitialCache.cmake @ONLY)
+
+# Build the build exporter.
+add_custom_command(
+  OUTPUT ${JavaModExportImport_BINARY_DIR}/BuildExportProject
+  COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+    --build-and-test
+    ${JavaModExportImport_SOURCE_DIR}/BuildExport
+    ${JavaModExportImport_BINARY_DIR}/BuildExport
+    --build-noclean
+    --build-project BuildExport
+    --build-generator ${CMAKE_GENERATOR}
+    --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+    --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+    --build-options -C${JavaModExportImport_BINARY_DIR}/InitialCache.cmake
+  VERBATIM
+  )
+add_custom_target(BuildExportTarget ALL DEPENDS ${JavaModExportImport_BINARY_DIR}/BuildExportProject)
+add_dependencies(BuildExportTarget CleanupTarget)
+set_property(
+  SOURCE ${JavaModExportImport_BINARY_DIR}/BuildExportProject
+  PROPERTY SYMBOLIC 1
+  )
+
+# Build and install the install exporter.
+add_custom_command(
+  OUTPUT ${JavaModExportImport_BINARY_DIR}/InstallExportProject
+  COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+    --build-and-test
+    ${JavaModExportImport_SOURCE_DIR}/InstallExport
+    ${JavaModExportImport_BINARY_DIR}/InstallExport
+    --build-noclean
+    --build-project InstallExport
+    --build-target install
+    --build-generator ${CMAKE_GENERATOR}
+    --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+    --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+    --build-options -C${JavaModExportImport_BINARY_DIR}/InitialCache.cmake
+  VERBATIM
+  )
+add_custom_target(InstallExportTarget ALL DEPENDS ${JavaModExportImport_BINARY_DIR}/InstallExportProject)
+add_dependencies(InstallExportTarget CleanupTarget)
+set_property(
+  SOURCE ${JavaModExportImport_BINARY_DIR}/InstallExportProject
+  PROPERTY SYMBOLIC 1
+  )
+
+# Build and install the importer.
+add_custom_command(
+  OUTPUT ${JavaModExportImport_BINARY_DIR}/ImportProject
+  COMMAND ${CMAKE_CTEST_COMMAND} ${NESTED_CONFIG_TYPE}
+    --build-and-test
+    ${JavaModExportImport_SOURCE_DIR}/Import
+    ${JavaModExportImport_BINARY_DIR}/Import
+    --build-noclean
+    --build-project Import
+    --build-generator ${CMAKE_GENERATOR}
+    --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+    --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+    --build-options
+      -C${JavaModExportImport_BINARY_DIR}/InitialCache.cmake
+      -DJavaBuildExportTest_DIR:PATH=${JavaModExportImport_BINARY_DIR}/BuildExport
+      -DJavaInstallExportTest_DIR:PATH=${JavaModExportImport_BINARY_DIR}/Root/share/cmake
+  VERBATIM
+  )
+add_custom_target(ImportTarget ALL DEPENDS ${JavaModExportImport_BINARY_DIR}/ImportProject)
+add_dependencies(ImportTarget BuildExportTarget InstallExportTarget)
+set_property(
+  SOURCE ${JavaModExportImport_BINARY_DIR}/ImportProject
+  PROPERTY SYMBOLIC 1
+  )
+
+add_executable(JavaModExportImport main.c)
+add_dependencies(JavaModExportImport ImportTarget)
diff --git a/Tests/JavaModExportImport/Import/CMakeLists.txt b/Tests/JavaModExportImport/Import/CMakeLists.txt
new file mode 100644
index 0000000..f8f773a
--- /dev/null
+++ b/Tests/JavaModExportImport/Import/CMakeLists.txt
@@ -0,0 +1,14 @@
+project(import Java)
+
+cmake_minimum_required(VERSION 3.10)
+set(CMAKE_VERBOSE_MAKEFILE 1)
+
+find_package(Java COMPONENTS Development)
+include(UseJava)
+
+find_package(JavaBuildExportTest REQUIRED)
+find_package(JavaInstallExportTest REQUIRED)
+
+add_jar(${PROJECT_NAME}
+  SOURCES Import.java module-info.java
+  INCLUDE_MODULES foo::foo bar::bar)
diff --git a/Tests/JavaModExportImport/Import/Import.java b/Tests/JavaModExportImport/Import/Import.java
new file mode 100644
index 0000000..46b1e9a
--- /dev/null
+++ b/Tests/JavaModExportImport/Import/Import.java
@@ -0,0 +1,13 @@
+import org.foo.Foo;
+import com.bar.Bar;
+
+class Import
+{
+  public static void main(String args[])
+  {
+    Foo foo = new Foo();
+    Bar bar = new Bar();
+    foo.printName();
+    bar.printName();
+  }
+}
diff --git a/Tests/JavaModExportImport/Import/module-info.java b/Tests/JavaModExportImport/Import/module-info.java
new file mode 100644
index 0000000..9d719cd
--- /dev/null
+++ b/Tests/JavaModExportImport/Import/module-info.java
@@ -0,0 +1,4 @@
+module client {
+    requires mod_foo;
+    requires mod_bar;
+}
diff --git a/Tests/JavaModExportImport/InitialCache.cmake.in b/Tests/JavaModExportImport/InitialCache.cmake.in
new file mode 100644
index 0000000..cc7871e
--- /dev/null
+++ b/Tests/JavaModExportImport/InitialCache.cmake.in
@@ -0,0 +1,5 @@
+set(CMAKE_MAKE_PROGRAM "@CMake_TEST_NESTED_MAKE_PROGRAM@" CACHE FILEPATH "Make Program")
+set(Java_JAVA_EXECUTABLE "@Java_JAVA_EXECUTABLE@" CACHE STRING "Java Interpreter")
+set(Java_JAVAC_EXECUTABLE "@Java_JAVAC_EXECUTABLE@" CACHE STRING "Java Compiler")
+set(Java_JAR_EXECUTABLE "@Java_JAR_EXECUTABLE@" CACHE STRING "Java Archive Tool")
+set(CMAKE_INSTALL_PREFIX "@JavaModExportImport_BINARY_DIR@/Root" CACHE STRING "Installation Prefix")
diff --git a/Tests/JavaModExportImport/InstallExport/Bar.java b/Tests/JavaModExportImport/InstallExport/Bar.java
new file mode 100644
index 0000000..dfa941c
--- /dev/null
+++ b/Tests/JavaModExportImport/InstallExport/Bar.java
@@ -0,0 +1,13 @@
+package com.bar;
+
+public class Bar
+{
+  public Bar()
+  {
+  }
+
+  public void printName()
+  {
+    System.out.println("Bar");
+  }
+}
diff --git a/Tests/JavaModExportImport/InstallExport/CMakeLists.txt b/Tests/JavaModExportImport/InstallExport/CMakeLists.txt
new file mode 100644
index 0000000..5997bdc
--- /dev/null
+++ b/Tests/JavaModExportImport/InstallExport/CMakeLists.txt
@@ -0,0 +1,15 @@
+project(bar Java)
+
+cmake_minimum_required(VERSION 3.10)
+set(CMAKE_VERBOSE_MAKEFILE 1)
+
+find_package(Java COMPONENTS Development)
+include(UseJava)
+
+add_jar(${PROJECT_NAME} Bar.java module-info.java)
+install_jar(${PROJECT_NAME} DESTINATION share/java)
+install_jar_exports(
+  TARGETS ${PROJECT_NAME}
+  NAMESPACE bar::
+  FILE JavaInstallExportTestConfig.cmake
+  DESTINATION share/cmake)
diff --git a/Tests/JavaModExportImport/InstallExport/module-info.java b/Tests/JavaModExportImport/InstallExport/module-info.java
new file mode 100644
index 0000000..7c8b62d
--- /dev/null
+++ b/Tests/JavaModExportImport/InstallExport/module-info.java
@@ -0,0 +1,3 @@
+module mod_bar {
+    exports com.bar;
+}
diff --git a/Tests/LinkFlags/LinkFlags.c b/Tests/JavaModExportImport/main.c
similarity index 100%
copy from Tests/LinkFlags/LinkFlags.c
copy to Tests/JavaModExportImport/main.c
diff --git a/Tests/LinkFlags/CMakeLists.txt b/Tests/LinkFlags/CMakeLists.txt
deleted file mode 100644
index d2d4149..0000000
--- a/Tests/LinkFlags/CMakeLists.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-project(LinkFlags C)
-
-string(TOUPPER "${TEST_CONFIG}" TEST_CONFIG_UPPER)
-set(obj "${CMAKE_C_OUTPUT_EXTENSION}")
-if(BORLAND)
-  set(pre -)
-endif()
-
-add_library(LinkFlags_lib STATIC LinkFlagsLib.c)
-set_property(TARGET LinkFlags_lib PROPERTY STATIC_LIBRARY_FLAGS ${pre}BADFLAG${obj})
-
-add_library(LinkFlags_dll SHARED LinkFlagsLib.c)
-set_property(TARGET LinkFlags_dll PROPERTY LINK_FLAGS ${pre}BADFLAG${obj})
-
-add_library(LinkFlags_mod MODULE LinkFlagsLib.c)
-set_property(TARGET LinkFlags_mod PROPERTY LINK_FLAGS ${pre}BADFLAG${obj})
-
-add_executable(LinkFlags_exe LinkFlagsExe.c)
-set_property(TARGET LinkFlags_exe PROPERTY LINK_FLAGS ${pre}BADFLAG${obj})
-
-add_library(LinkFlags_lib_config STATIC LinkFlagsLib.c)
-set_property(TARGET LinkFlags_lib_config PROPERTY STATIC_LIBRARY_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG_${TEST_CONFIG}${obj})
-
-add_library(LinkFlags_dll_config SHARED LinkFlagsLib.c)
-set_property(TARGET LinkFlags_dll_config PROPERTY LINK_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG_${TEST_CONFIG}${obj})
-
-add_library(LinkFlags_mod_config MODULE LinkFlagsLib.c)
-set_property(TARGET LinkFlags_mod_config PROPERTY LINK_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG_${TEST_CONFIG}${obj})
-
-add_executable(LinkFlags_exe_config LinkFlagsExe.c)
-set_property(TARGET LinkFlags_exe_config PROPERTY LINK_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG_${TEST_CONFIG}${obj})
-
-add_executable(LinkFlags LinkFlags.c)
-if("x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC")
-  set_property(TARGET LinkFlags PROPERTY
-    LINK_FLAGS "/NODEFAULTLIB:\"libcdg.lib\" /NODEFAULTLIB:\"libcmtg.lib\" /NODEFAULTLIB:\"foomsvcrt.lib\" /NODEFAULTLIB:\"libbar.lib\" /NODEFAULTLIB:\"libfooba.lib\""
-    )
-endif()
-
-add_subdirectory(LinkerFlags)
-add_subdirectory(LinkerFlagsConfig)
diff --git a/Tests/LinkFlags/LinkFlagsExe.c b/Tests/LinkFlags/LinkFlagsExe.c
deleted file mode 100644
index 202d34d..0000000
--- a/Tests/LinkFlags/LinkFlagsExe.c
+++ /dev/null
@@ -1,9 +0,0 @@
-int main(void)
-{
-  return 0;
-}
-
-/* Intel compiler does not reject bad flags or objects!  */
-#if defined(__INTEL_COMPILER)
-#  error BADFLAG
-#endif
diff --git a/Tests/LinkFlags/LinkFlagsLib.c b/Tests/LinkFlags/LinkFlagsLib.c
deleted file mode 100644
index bd288e9..0000000
--- a/Tests/LinkFlags/LinkFlagsLib.c
+++ /dev/null
@@ -1,9 +0,0 @@
-int flags_lib(void)
-{
-  return 0;
-}
-
-/* Intel compiler does not reject bad flags or objects!  */
-#if defined(__INTEL_COMPILER)
-#  error BADFLAG
-#endif
diff --git a/Tests/LinkFlags/LinkerFlags/CMakeLists.txt b/Tests/LinkFlags/LinkerFlags/CMakeLists.txt
deleted file mode 100644
index 4707f47..0000000
--- a/Tests/LinkFlags/LinkerFlags/CMakeLists.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-set(CMAKE_STATIC_LINKER_FLAGS ${pre}BADFLAG${obj})
-add_library(LinkFlags_lib_flags STATIC ../LinkFlagsLib.c)
-
-set(CMAKE_SHARED_LINKER_FLAGS ${pre}BADFLAG${obj})
-add_library(LinkFlags_dll_flags SHARED ../LinkFlagsLib.c)
-
-set(CMAKE_MODULE_LINKER_FLAGS ${pre}BADFLAG${obj})
-add_library(LinkFlags_mod_flags MODULE ../LinkFlagsLib.c)
-
-set(CMAKE_EXE_LINKER_FLAGS ${pre}BADFLAG${obj})
-add_executable(LinkFlags_exe_flags ../LinkFlagsExe.c)
diff --git a/Tests/LinkFlags/LinkerFlagsConfig/CMakeLists.txt b/Tests/LinkFlags/LinkerFlagsConfig/CMakeLists.txt
deleted file mode 100644
index 2854fe7..0000000
--- a/Tests/LinkFlags/LinkerFlagsConfig/CMakeLists.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-set(CMAKE_STATIC_LINKER_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG${obj})
-add_library(LinkFlags_lib_flags_config STATIC ../LinkFlagsLib.c)
-
-set(CMAKE_SHARED_LINKER_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG${obj})
-add_library(LinkFlags_dll_flags_config SHARED ../LinkFlagsLib.c)
-
-set(CMAKE_MODULE_LINKER_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG${obj})
-add_library(LinkFlags_mod_flags_config MODULE ../LinkFlagsLib.c)
-
-set(CMAKE_EXE_LINKER_FLAGS_${TEST_CONFIG_UPPER} ${pre}BADFLAG${obj})
-add_executable(LinkFlags_exe_flags_config ../LinkFlagsExe.c)
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt b/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt
index 6c23c95..0bfbcce 100644
--- a/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt
+++ b/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt
@@ -18,10 +18,10 @@
 set(MCC "sdc/sdc_autogen/mocs_compilation*.cpp")
 set(MCG "gat_autogen/mocs_compilation*.cpp")
 
-set(DRA "sda/sda_autogen/*qrc_data.cpp")
-set(DRB "sdb/sdb_autogen/*qrc_data.cpp")
-set(DRC "sdc/sdc_autogen/*qrc_data.cpp")
-set(DRG "gat_autogen/*qrc_data.cpp")
+set(DRA "sda/sda_autogen/*qrc_data*.cpp")
+set(DRB "sdb/sdb_autogen/*qrc_data*.cpp")
+set(DRC "sdc/sdc_autogen/*qrc_data*.cpp")
+set(DRG "gat_autogen/*qrc_data*.cpp")
 
 # -- Utility macros
 macro(GAT_FIND_FILES VAR NAME)
diff --git a/Tests/QtAutogen/RccObjectLibrary/CMakeLists.txt b/Tests/QtAutogen/RccObjectLibrary/CMakeLists.txt
new file mode 100644
index 0000000..695b84d
--- /dev/null
+++ b/Tests/QtAutogen/RccObjectLibrary/CMakeLists.txt
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 3.16)
+project(RccObjectLibrary)
+include("../AutogenCoreTest.cmake")
+
+# Test for issue #26977:
+# AUTOGEN_BETTER_GRAPH_MULTI_CONFIG with AUTORCC and OBJECT libraries.
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+
+# OBJECT library with a .qrc file
+add_library(rcc_obj OBJECT
+  rcc_obj.cpp
+  rcc_obj.qrc
+)
+target_link_libraries(rcc_obj PRIVATE ${QT_LIBRARIES})
+
+# Executable that uses the OBJECT library
+add_executable(rccObjectLibrary
+  main.cpp
+  $<TARGET_OBJECTS:rcc_obj>
+)
+target_link_libraries(rccObjectLibrary PRIVATE ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/RccObjectLibrary/main.cpp b/Tests/QtAutogen/RccObjectLibrary/main.cpp
new file mode 100644
index 0000000..0521fd4
--- /dev/null
+++ b/Tests/QtAutogen/RccObjectLibrary/main.cpp
@@ -0,0 +1,38 @@
+
+#include <iostream>
+
+#include <QCoreApplication>
+#include <QFile>
+
+#include "rcc_obj.h"
+
+int main(int argc, char* argv[])
+{
+  QCoreApplication app(argc, argv);
+
+  // Test that the resource from the OBJECT library is accessible
+  QString resourcePath = RccObj::resourceContent();
+  if (!QFile::exists(resourcePath)) {
+    std::cerr << "Resource not found: " << resourcePath.toStdString()
+              << std::endl;
+    return 1;
+  }
+
+  QFile file(resourcePath);
+  if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+    std::cerr << "Failed to open resource: " << resourcePath.toStdString()
+              << std::endl;
+    return 1;
+  }
+
+  QString content = file.readAll();
+  if (content.isEmpty()) {
+    std::cerr << "Resource content is empty" << std::endl;
+    return 1;
+  }
+
+  std::cout << "Resource content: " << content.toStdString() << std::endl;
+  std::cout << "Test passed!" << std::endl;
+
+  return 0;
+}
diff --git a/Tests/QtAutogen/RccObjectLibrary/rcc_obj.cpp b/Tests/QtAutogen/RccObjectLibrary/rcc_obj.cpp
new file mode 100644
index 0000000..577d507
--- /dev/null
+++ b/Tests/QtAutogen/RccObjectLibrary/rcc_obj.cpp
@@ -0,0 +1,11 @@
+
+#include "rcc_obj.h"
+
+RccObj::RccObj()
+{
+}
+
+QString RccObj::resourceContent()
+{
+  return ":/test.txt";
+}
diff --git a/Tests/QtAutogen/RccObjectLibrary/rcc_obj.h b/Tests/QtAutogen/RccObjectLibrary/rcc_obj.h
new file mode 100644
index 0000000..ed5b088
--- /dev/null
+++ b/Tests/QtAutogen/RccObjectLibrary/rcc_obj.h
@@ -0,0 +1,15 @@
+#ifndef RCC_OBJ_H
+#define RCC_OBJ_H
+
+#include <QObject>
+#include <QString>
+
+class RccObj : public QObject
+{
+  Q_OBJECT
+public:
+  RccObj();
+  static QString resourceContent();
+};
+
+#endif
diff --git a/Tests/QtAutogen/RccObjectLibrary/rcc_obj.qrc b/Tests/QtAutogen/RccObjectLibrary/rcc_obj.qrc
new file mode 100644
index 0000000..48c52a3
--- /dev/null
+++ b/Tests/QtAutogen/RccObjectLibrary/rcc_obj.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+  <qresource>
+    <file>test.txt</file>
+  </qresource>
+</RCC>
diff --git a/Tests/QtAutogen/RccObjectLibrary/test.txt b/Tests/QtAutogen/RccObjectLibrary/test.txt
new file mode 100644
index 0000000..4ff326d
--- /dev/null
+++ b/Tests/QtAutogen/RccObjectLibrary/test.txt
@@ -0,0 +1 @@
+Test resource for RccObjectLibrary
diff --git a/Tests/QtAutogen/RerunMocOnAddFile/CMakeLists.txt b/Tests/QtAutogen/RerunMocOnAddFile/CMakeLists.txt
index 3a9244d..1184fb3 100644
--- a/Tests/QtAutogen/RerunMocOnAddFile/CMakeLists.txt
+++ b/Tests/QtAutogen/RerunMocOnAddFile/CMakeLists.txt
@@ -27,6 +27,21 @@
 
 macro(rebuild buildName)
   message(STATUS "Starting build ${buildName}.")
+  # Work around CMake issue #27611: The Xcode build system creates its build
+  # plan at the start of a build and does not pick up project file changes
+  # made by ZERO_CHECK during the build. Explicitly re-run CMake to ensure
+  # the project file includes new sources before the native build tool starts.
+  if(CMAKE_GENERATOR MATCHES "Xcode")
+    execute_process(
+      COMMAND "${CMAKE_COMMAND}" -S "${testProjectSrc}" -B "${testProjectBinDir}"
+      RESULT_VARIABLE result
+      OUTPUT_VARIABLE output
+      ERROR_VARIABLE output
+    )
+    if (result)
+      message(FATAL_ERROR "CMake reconfigure for build ${buildName} failed. Output: ${output}")
+    endif()
+  endif()
   execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${testProjectBinDir}" RESULT_VARIABLE result)
   if (result)
     message(FATAL_ERROR "Build ${buildName} failed.")
diff --git a/Tests/QtAutogen/Tests.cmake b/Tests/QtAutogen/Tests.cmake
index bd0c598..9117765 100644
--- a/Tests/QtAutogen/Tests.cmake
+++ b/Tests/QtAutogen/Tests.cmake
@@ -27,6 +27,7 @@
 ADD_AUTOGEN_TEST(ParallelAUTO parallelAUTO)
 ADD_AUTOGEN_TEST(RccAutogenBuildDir)
 ADD_AUTOGEN_TEST(RccEmpty rccEmpty)
+ADD_AUTOGEN_TEST(RccObjectLibrary rccObjectLibrary)
 ADD_AUTOGEN_TEST(RccOffMocLibrary)
 ADD_AUTOGEN_TEST(RccOnly rccOnly)
 ADD_AUTOGEN_TEST(RccSkipSource)
diff --git a/Tests/README.rst b/Tests/README.rst
index 4bbbce1..ab1438c 100644
--- a/Tests/README.rst
+++ b/Tests/README.rst
@@ -33,4 +33,10 @@
 
   See `RunCMake/README.rst`_.
 
+* ``Fuzzing/``:
+  Fuzz testing targets using libFuzzer, integrated with OSS-Fuzz.
+
+  See `Fuzzing/README.rst`_.
+
 .. _`RunCMake/README.rst`: RunCMake/README.rst
+.. _`Fuzzing/README.rst`: Fuzzing/README.rst
diff --git a/Tests/RunCMake/AddRunCMakeTest.cmake b/Tests/RunCMake/AddRunCMakeTestSuite.cmake
similarity index 100%
rename from Tests/RunCMake/AddRunCMakeTest.cmake
rename to Tests/RunCMake/AddRunCMakeTestSuite.cmake
diff --git a/Tests/RunCMake/Autogen_1/RunCMakeTest.cmake b/Tests/RunCMake/Autogen_1/RunCMakeTest.cmake
index 8e9ded3..14671ec 100644
--- a/Tests/RunCMake/Autogen_1/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Autogen_1/RunCMakeTest.cmake
@@ -102,7 +102,9 @@
 
         block()
           set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0151-old-build)
+          set(RunCMake_TEST_EXPECT_stderr ".") # ignore CMP0151 deprecation warnings
           run_cmake_with_options(CMP0151-old ${RunCMake_TEST_OPTIONS} -DCMAKE_AUTO${autogen_type}=ON -DCMAKE_POLICY_DEFAULT_CMP0151=OLD)
+          unset(RunCMake_TEST_EXPECT_stderr)
           set(RunCMake_TEST_NO_CLEAN 1)
           set(RunCMake_TEST_EXPECT_stdout "${test_expect_stdout}")
           run_cmake_command(CMP0151-old-build ${CMAKE_COMMAND} --build . --config Debug --verbose)
@@ -119,7 +121,9 @@
         if (RunCMake_GENERATOR MATCHES "(Ninja|Makefiles|Visual Studio)")
           block()
             set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0151Short-old-build)
+            set(RunCMake_TEST_EXPECT_stderr ".") # ignore CMP0151 deprecation warnings
             run_cmake_with_options(CMP0151Short-old ${RunCMake_TEST_OPTIONS} -DCMAKE_AUTO${autogen_type}=ON -DCMAKE_POLICY_DEFAULT_CMP0151=OLD)
+            unset(RunCMake_TEST_EXPECT_stderr)
             set(RunCMake_TEST_NO_CLEAN 1)
             set(RunCMake_TEST_EXPECT_stdout "${test_expect_stdout_short}")
             run_cmake_command(CMP0151Short-old-build ${CMAKE_COMMAND} --build . --config Debug --verbose)
diff --git a/Tests/RunCMake/CMP0135/CMP0135-Common.cmake b/Tests/RunCMake/CMP0135/CMP0135-Common.cmake
index ad60b7c..f78c8a5 100644
--- a/Tests/RunCMake/CMP0135/CMP0135-Common.cmake
+++ b/Tests/RunCMake/CMP0135/CMP0135-Common.cmake
@@ -25,7 +25,8 @@
 set(archive_file ${CMAKE_CURRENT_BINARY_DIR}/test_archive.7z)
 file(ARCHIVE_CREATE
   OUTPUT ${archive_file}
-  PATHS ${CMAKE_CURRENT_LIST_DIR}
+  PATHS "${CMAKE_CURRENT_LIST_FILE}"
+  WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}"
   FORMAT 7zip
 )
 include(FetchContent)
diff --git a/Tests/RunCMake/CMP0150/CMP0150-OLD-stderr.txt b/Tests/RunCMake/CMP0150/CMP0150-OLD-stderr.txt
new file mode 100644
index 0000000..41da154
--- /dev/null
+++ b/Tests/RunCMake/CMP0150/CMP0150-OLD-stderr.txt
@@ -0,0 +1,9 @@
+^CMake Deprecation Warning at ([^
+]*/Tests/RunCMake/CMP0150/)?OLD-build/Top/CMakeLists\.txt:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0150 will be removed from a future version
+  of CMake\.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances\.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD\.$
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 8d0c299..6d23fc8 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -310,6 +310,7 @@
       "-DCMAKE_PREFIX_PATH:STRING=${base_dir}"
       -DPSEUDO_TIDY=$<TARGET_FILE:pseudo_tidy>
       -DPSEUDO_IWYU=$<TARGET_FILE:pseudo_iwyu>
+      -DPSEUDO_PVS=$<TARGET_FILE:pseudo_pvs>
       -DPSEUDO_CPPLINT=$<TARGET_FILE:pseudo_cpplint>
       -DPSEUDO_CPPCHECK=$<TARGET_FILE:pseudo_cppcheck>
     )
@@ -406,6 +407,7 @@
 add_RunCMake_test(Configure -DMSVC_IDE=${MSVC_IDE})
 add_RunCMake_test(CpsExportImportBuild)
 add_RunCMake_test(CpsExportImportInstall)
+add_RunCMake_test(CpsMapConfig)
 add_RunCMake_test(DisallowedCommands)
 if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles|Ninja|FASTBuild")
   add_RunCMake_test(ExportCompileCommands)
@@ -427,7 +429,8 @@
                           -DCMAKE_CXX_SIMULATE_ID=${CMAKE_CXX_SIMULATE_ID}
                           -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA})
 if(CMAKE_GENERATOR MATCHES "Make|Ninja|FASTBuild")
-  add_RunCMake_test(Instrumentation)
+  add_RunCMake_test(Instrumentation -DPython_EXECUTABLE=${Python_EXECUTABLE}
+                                    -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA})
 endif()
 add_RunCMake_test(ConfigDir)
 if(CMake_TEST_FindPython2)
@@ -497,6 +500,12 @@
 endif()
 add_RunCMake_test(FindBoost)
 add_RunCMake_test(FindLua)
+if(CMake_TEST_FindRuby)
+  add_RunCMake_test(FindRuby
+    -DCMake_TEST_FindRuby_RBENV=${CMake_TEST_FindRuby_RBENV}
+    -DCMake_TEST_FindRuby_RVM=${CMake_TEST_FindRuby_RVM}
+    )
+endif()
 add_RunCMake_test(FindOpenGL)
 add_RunCMake_test(InitialFlags)
 if(CMake_TEST_FindOpenSSL)
@@ -521,8 +530,13 @@
 add_RunCMake_test(GenEx-TARGET_FILE -DLINKER_SUPPORTS_PDB=${LINKER_SUPPORTS_PDB})
 add_RunCMake_test(GenEx-TARGET_IMPORT_FILE)
 add_RunCMake_test(GenEx-GENEX_EVAL)
+add_RunCMake_test(GenEx-SOURCE_EXISTS)
+add_RunCMake_test(GenEx-SOURCE_PROPERTY)
+add_RunCMake_test(GenEx-FILE_SET_EXISTS)
+add_RunCMake_test(GenEx-FILE_SET_PROPERTY)
 add_RunCMake_test(GenEx-TARGET_PROPERTY)
 add_RunCMake_test(GenEx-TARGET_RUNTIME_DLLS)
+add_RunCMake_test(GenEx-STRING)
 add_RunCMake_test(GenEx-PATH)
 add_RunCMake_test(GenEx-PATH_EQUAL)
 add_RunCMake_test(GenEx-LIST)
@@ -586,6 +600,9 @@
     -DCMAKE_EXECUTABLE_FORMAT=${CMAKE_EXECUTABLE_FORMAT}
     )
 endif()
+if(CMake_TEST_Rust)
+  add_RunCMake_test(Rust)
+endif()
 add_RunCMake_test(ScriptMode)
 add_RunCMake_test(StandardLinkDirectories)
 add_RunCMake_test(Swift -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
@@ -668,6 +685,9 @@
 endif()
 add_RunCMake_test(execute_process)
 add_RunCMake_test(export)
+if(DEFINED CMake_TEST_LOCALE_CHARSET)
+  list(APPEND cmake_host_system_information_ARGS -DCMake_TEST_LOCALE_CHARSET=${CMake_TEST_LOCALE_CHARSET})
+endif()
 if(CMake_TEST_MSYSTEM_PREFIX)
   list(APPEND cmake_host_system_information_ARGS -DCMake_TEST_MSYSTEM_PREFIX=${CMake_TEST_MSYSTEM_PREFIX})
 endif()
@@ -719,6 +739,7 @@
     list(APPEND file-DOWNLOAD_ARGS -D${var}=${${var}})
   endif()
 endforeach()
+add_RunCMake_test(file-CREATE_LINK)
 add_RunCMake_test(file-DOWNLOAD)
 add_RunCMake_test(file-MAKE_DIRECTORY)
 add_RunCMake_test(file-RPATH
@@ -778,6 +799,7 @@
   foreach(
     var
     IN ITEMS
+      CMAKE_C_COMPILER_ID
       CMAKE_SYSTEM_NAME
       CMake_TEST_CUDA
       CMake_TEST_ISPC
@@ -832,11 +854,14 @@
 
 # Add C++ Module tests.
 add_RunCMake_test(CXXModules
+  -DCMake_TEST_CXX_STDLIB_MODULES_JSON=${CMake_TEST_CXX_STDLIB_MODULES_JSON}
+)
+add_RunCMake_test(CXXModulesCompile
   -DCMake_TEST_MODULE_COMPILATION=${CMake_TEST_MODULE_COMPILATION}
   -DCMake_TEST_MODULE_COMPILATION_RULES=${CMake_TEST_MODULE_COMPILATION_RULES}
   -DCMake_TEST_CXX_STDLIB_MODULES_JSON=${CMake_TEST_CXX_STDLIB_MODULES_JSON}
 )
-set_property(TEST RunCMake.CXXModules APPEND
+set_property(TEST RunCMake.CXXModules RunCMake.CXXModulesCompile APPEND
   PROPERTY LABELS "CXXModules")
 
 # ctresalloc links against CMakeLib and CTestLib, which means it can't be built
@@ -973,7 +998,8 @@
 
 add_RunCMake_test(LinkLibrariesProcessing)
 add_RunCMake_test(LinkLibrariesStrategy)
-add_RunCMake_test(File_Archive)
+add_RunCMake_test(LinkFlags -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
+add_RunCMake_test(File_Archive -DPython_EXECUTABLE=${Python_EXECUTABLE})
 add_RunCMake_test(File_Configure)
 add_RunCMake_test(File_Generate)
 add_RunCMake_test(ExportWithoutLanguage)
@@ -1064,8 +1090,13 @@
 add_executable(pseudo_llvm-rc pseudo_llvm-rc.c)
 add_RunCMake_test(CommandLine -DLLVM_RC=$<TARGET_FILE:pseudo_llvm-rc> -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
                   -DCYGWIN=${CYGWIN} -DMSYS=${MSYS} -DPython_EXECUTABLE=${Python_EXECUTABLE}
+                  -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA}
                   -DEXIT_CODE_EXE=$<TARGET_FILE:exit_code>
                   -DPRINT_STDIN_EXE=$<TARGET_FILE:print_stdin>)
+if(CMake_TEST_LibArchive_VERSION)
+  list(APPEND CommandLineTar_ARGS -DCMake_TEST_LibArchive_VERSION=${CMake_TEST_LibArchive_VERSION})
+endif()
+list(APPEND CommandLineTar_ARGS -DPython_EXECUTABLE=${Python_EXECUTABLE})
 add_RunCMake_test(CommandLineTar)
 
 if(CMAKE_PLATFORM_NO_VERSIONED_SONAME OR (NOT CMAKE_SHARED_LIBRARY_SONAME_FLAG AND NOT CMAKE_SHARED_LIBRARY_SONAME_C_FLAG))
@@ -1157,6 +1188,13 @@
 add_executable(pseudo_iwyu pseudo_iwyu.c)
 add_executable(pseudo_cpplint pseudo_cpplint.c)
 add_executable(pseudo_cppcheck pseudo_cppcheck.c)
+add_executable(pseudo_pvs pseudo_pvs.c)
+add_executable(pseudo_plog_converter pseudo_plog_converter.c)
+if (WIN32)
+  set_target_properties(pseudo_plog_converter PROPERTIES OUTPUT_NAME HtmlGenerator)
+else()
+  set_target_properties(pseudo_plog_converter PROPERTIES OUTPUT_NAME plog-converter)
+endif()
 
 if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja|FASTBuild")
   if(UNIX AND NOT CYGWIN)
@@ -1170,11 +1208,13 @@
   endif()
   add_RunCMake_test(ClangTidy -DPSEUDO_TIDY=$<TARGET_FILE:pseudo_tidy>)
   add_RunCMake_test(IncludeWhatYouUse -DPSEUDO_IWYU=$<TARGET_FILE:pseudo_iwyu>)
+  add_RunCMake_test(PVSStudio -DPSEUDO_PVS=$<TARGET_FILE:pseudo_pvs>)
   add_RunCMake_test(Cpplint -DPSEUDO_CPPLINT=$<TARGET_FILE:pseudo_cpplint>)
   add_RunCMake_test(Cppcheck -DPSEUDO_CPPCHECK=$<TARGET_FILE:pseudo_cppcheck>)
   add_RunCMake_test(MultiLint
     -DPSEUDO_TIDY=$<TARGET_FILE:pseudo_tidy>
     -DPSEUDO_IWYU=$<TARGET_FILE:pseudo_iwyu>
+    -DPSEUDO_PVS=$<TARGET_FILE:pseudo_pvs>
     -DPSEUDO_CPPLINT=$<TARGET_FILE:pseudo_cpplint>
     -DPSEUDO_CPPCHECK=$<TARGET_FILE:pseudo_cppcheck>
     )
@@ -1253,12 +1293,26 @@
   RPM.COMPONENT_WITH_SPECIAL_CHARS
 
   7Z
+  7Z_STORE
+  7Z_DEFLATE
+  7Z_BZ2
+  7Z_LZMA
+  7Z_LZMA2
+  7Z_ZSTD
+  7Z_PPMD
   TAR
   TBZ2
   TGZ
   TXZ
   TZ
+  TZST
   ZIP
+  ZIP_STORE
+  ZIP_DEFLATE
+  ZIP_BZ2
+  ZIP_LZMA
+  ZIP_LZMA2
+  ZIP_ZSTD
   STGZ
   External
   )
@@ -1294,10 +1348,24 @@
       RPM.DIST
       RPM.AUTO_SUFFIXES
       7Z
+      7Z_STORE
+      7Z_DEFLATE
+      7Z_BZ2
+      7Z_LZMA
+      7Z_LZMA2
+      7Z_ZSTD
+      7Z_PPMD
       TXZ
+      TZST
       TBZ2
       TGZ
       ZIP
+      ZIP_STORE
+      ZIP_DEFLATE
+      ZIP_BZ2
+      ZIP_LZMA
+      ZIP_LZMA2
+      ZIP_ZSTD
       STGZ
       External
       )
@@ -1305,6 +1373,18 @@
   endif()
 endif()
 
+if(CMake_TEST_LibArchive_VERSION AND CMake_TEST_LibArchive_VERSION VERSION_LESS 3.8.0)
+  # Exclude tests, that require libarchive >= 3.8.0
+  # if the version of libarchive is less than required
+  list(REMOVE_ITEM cpack_tests
+    7Z_ZSTD
+    ZIP_BZ2
+    ZIP_LZMA
+    ZIP_LZMA2
+    ZIP_ZSTD
+  )
+endif()
+
 add_RunCMake_test_group(CPack "${cpack_tests}")
 
 if(CMake_TEST_CPACK_APPIMAGE)
@@ -1313,6 +1393,14 @@
   )
 endif()
 
+if(CMake_TEST_CPACK_DEB)
+  add_RunCMake_test(CPack_DEB)
+endif()
+
+if(CMake_TEST_CPACK_RPM)
+  add_RunCMake_test(CPack_RPM)
+endif()
+
 if(CMake_TEST_CPACK_WIX3 OR CMake_TEST_CPACK_WIX4)
   add_RunCMake_test(CPack_WIX
     -DCMake_TEST_CPACK_WIX3=${CMake_TEST_CPACK_WIX3}
@@ -1333,7 +1421,11 @@
 
 add_RunCMake_test(AndroidMK)
 add_RunCMake_test(ExportPackageInfo)
+add_RunCMake_test(ExportSbom)
+add_RunCMake_test(EnvSbom)
 add_RunCMake_test(InstallPackageInfo)
+add_RunCMake_test(InstallExportsAsPackageInfo)
+add_RunCMake_test(InstallSbom)
 
 if(CMake_TEST_ANDROID_NDK OR CMake_TEST_ANDROID_STANDALONE_TOOLCHAIN)
   if(NOT "${CMAKE_GENERATOR}" MATCHES "Make|Ninja|Visual Studio 1[456]")
@@ -1368,6 +1460,7 @@
 add_RunCMake_test(PrecompileHeaders -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
   -DCMAKE_C_SIMULATE_ID=${CMAKE_C_SIMULATE_ID}
   -DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION})
+add_RunCMake_test(PrecompileHeaders-Reuse -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
 
 # This test can take a long time due to the number of test cases.
 # Provide an option to customize it.
@@ -1454,3 +1547,8 @@
   -DCMake_TEST_CUDA=${CMake_TEST_CUDA}
 )
 set_property(TEST RunCMake.MsvcCharsetDefines APPEND PROPERTY LABELS "CUDA")
+
+add_RunCMake_test(cmake-E-bin2c -DCMake_TEST_BIN2C_LARGE_FILE=${CMake_TEST_BIN2C_LARGE_FILE})
+if(CMake_TEST_BIN2C_LARGE_FILE)
+  set_property(TEST RunCMake.cmake-E-bin2c PROPERTY TIMEOUT ${CMAKE_LONG_TEST_TIMEOUT})
+endif()
diff --git a/Tests/RunCMake/CMakePresets/HighVersion-stderr.txt b/Tests/RunCMake/CMakePresets/HighVersion-stderr.txt
index b02663d..ba962b4 100644
--- a/Tests/RunCMake/CMakePresets/HighVersion-stderr.txt
+++ b/Tests/RunCMake/CMakePresets/HighVersion-stderr.txt
@@ -1,5 +1,5 @@
 ^CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresets/HighVersion:
-CMakePresets\.json:2: Unrecognized "version" 1000: must be >=1 and <=10
+CMakePresets\.json:2: Unrecognized "version" 1000: must be >=1 and <=11
   "version": 1000,
              \^$
diff --git a/Tests/RunCMake/CMakePresets/LowVersion-stderr.txt b/Tests/RunCMake/CMakePresets/LowVersion-stderr.txt
index fa9a985..5ed2857 100644
--- a/Tests/RunCMake/CMakePresets/LowVersion-stderr.txt
+++ b/Tests/RunCMake/CMakePresets/LowVersion-stderr.txt
@@ -1,5 +1,5 @@
 ^CMake Error: Could not read presets from [^
 ]*/Tests/RunCMake/CMakePresets/LowVersion:
-CMakePresets\.json:2: Unrecognized "version" 0: must be >=1 and <=10
+CMakePresets\.json:2: Unrecognized "version" 0: must be >=1 and <=11
   "version": 0,
              \^
diff --git a/Tests/RunCMake/CMakePresets/validate_schema.cmake b/Tests/RunCMake/CMakePresets/validate_schema.cmake
index ed60760..8b4f0b6 100644
--- a/Tests/RunCMake/CMakePresets/validate_schema.cmake
+++ b/Tests/RunCMake/CMakePresets/validate_schema.cmake
@@ -6,13 +6,11 @@
   execute_process(
     COMMAND "${Python_EXECUTABLE}" "${CMakePresets_VALIDATE_SCRIPT_PATH}" "${file}"
     RESULT_VARIABLE _result
-    OUTPUT_VARIABLE _output
     ERROR_VARIABLE _error
     )
   if(NOT _result STREQUAL expected_result)
-    string(REPLACE "\n" "\n  " _output_p "${_output}")
     string(REPLACE "\n" "\n  " _error_p "${_error}")
-    string(APPEND RunCMake_TEST_FAILED "Expected result of validating ${file}: ${expected_result}\nActual result: ${_result}\nOutput:\n  ${_output_p}\nError:\n  ${_error_p}\n")
+    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)
diff --git a/Tests/RunCMake/CMakePresets/validate_schema.py b/Tests/RunCMake/CMakePresets/validate_schema.py
index 836147a..2409095 100644
--- a/Tests/RunCMake/CMakePresets/validate_schema.py
+++ b/Tests/RunCMake/CMakePresets/validate_schema.py
@@ -13,4 +13,8 @@
 with open(schema_file, "r", encoding="utf-8") as f:
     schema = json.load(f)
 
-jsonschema.validate(contents, schema)
+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/ExportPackageInfo/ExperimentalGate-result.txt b/Tests/RunCMake/CMakePresetsBuild/BuildDirectoryOverride-build-override-result.txt
similarity index 100%
copy from Tests/RunCMake/ExportPackageInfo/ExperimentalGate-result.txt
copy to Tests/RunCMake/CMakePresetsBuild/BuildDirectoryOverride-build-override-result.txt
diff --git a/Tests/RunCMake/CMakePresetsBuild/BuildDirectoryOverride-build-override-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/BuildDirectoryOverride-build-override-stderr.txt
new file mode 100644
index 0000000..fbd9416
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/BuildDirectoryOverride-build-override-stderr.txt
@@ -0,0 +1,2 @@
+^Error: [^
+]*/Tests/RunCMake/build2 is not a directory$
diff --git a/Tests/RunCMake/CMakePresetsBuild/BuildDirectoryOverride.json.in b/Tests/RunCMake/CMakePresetsBuild/BuildDirectoryOverride.json.in
new file mode 100644
index 0000000..66e8e42
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/BuildDirectoryOverride.json.in
@@ -0,0 +1,24 @@
+{
+  "version": 2,
+  "cmakeMinimumRequired": {
+    "major": 3,
+    "minor": 20,
+    "patch": 0
+  },
+  "configurePresets": [
+    {
+      "name": "default",
+      "binaryDir": "${sourceDir}/build",
+      "generator": "@RunCMake_GENERATOR@",
+      "cacheVariables": {
+        "CMAKE_BUILD_TYPE": "Debug"
+      }
+    }
+  ],
+  "buildPresets": [
+    {
+      "name": "override",
+      "configurePreset": "default"
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CommandLineTar/7zip-gz-result.txt b/Tests/RunCMake/CMakePresetsBuild/JobsNegative-build-default-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLineTar/7zip-gz-result.txt
copy to Tests/RunCMake/CMakePresetsBuild/JobsNegative-build-default-result.txt
diff --git a/Tests/RunCMake/CMakePresetsBuild/JobsNegative-build-default-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/JobsNegative-build-default-stderr.txt
new file mode 100644
index 0000000..a4ec597
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/JobsNegative-build-default-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsBuild/JobsNegative:
+CMakePresets\.json:14: "jobs" expected an unsigned integer, got: -10
+            "jobs": -10
+                    \^$
diff --git a/Tests/RunCMake/CXXModules/examples/export-build-database/dep_interface_include/anchor b/Tests/RunCMake/CMakePresetsBuild/JobsNegative.cmake
similarity index 100%
copy from Tests/RunCMake/CXXModules/examples/export-build-database/dep_interface_include/anchor
copy to Tests/RunCMake/CMakePresetsBuild/JobsNegative.cmake
diff --git a/Tests/RunCMake/CMakePresetsBuild/JobsNegative.json.in b/Tests/RunCMake/CMakePresetsBuild/JobsNegative.json.in
new file mode 100644
index 0000000..863bad9
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/JobsNegative.json.in
@@ -0,0 +1,17 @@
+{
+    "version": 2,
+    "configurePresets": [
+        {
+            "name": "default",
+            "generator": "@RunCMake_GENERATOR@",
+            "binaryDir": "${sourceDir}/build/${presetName}"
+        }
+    ],
+    "buildPresets": [
+        {
+            "name": "default",
+            "configurePreset": "default",
+            "jobs": -10
+        }
+    ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake
index 1ededc1..63dc4f3 100644
--- a/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake
@@ -5,7 +5,7 @@
   set(RunCMake_GENERATOR "${CMAKE_MATCH_1}")
 endif()
 
-function(run_cmake_build_presets name CMakePresetsBuild_CONFIGURE_PRESETS CMakePresetsBuild_BUILD_PRESETS)
+function(run_cmake_build_presets name CMakePresetsBuild_CONFIGURE_PRESETS CMakePresetsBuild_BUILD_PRESETS CMakePresetsBuild_BUILD_DIR_OVERRIDE)
   set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/${name}")
   set(RunCMake_TEST_BINARY_DIR "${RunCMake_TEST_SOURCE_DIR}/build")
   set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY "${RunCMake_TEST_SOURCE_DIR}")
@@ -50,11 +50,11 @@
 
     if(eq)
       run_cmake_command(${name}-build-${BUILD_PRESET}
-        ${CMAKE_COMMAND} "--build" "--preset=${BUILD_PRESET}" ${ARGN})
+        ${CMAKE_COMMAND} "--build" ${CMakePresetsBuild_BUILD_DIR_OVERRIDE} "--preset=${BUILD_PRESET}" ${ARGN})
       set(eq 0)
     else()
       run_cmake_command(${name}-build-${BUILD_PRESET}
-        ${CMAKE_COMMAND} "--build" "--preset" "${BUILD_PRESET}" ${ARGN})
+        ${CMAKE_COMMAND} "--build" ${CMakePresetsBuild_BUILD_DIR_OVERRIDE} "--preset" "${BUILD_PRESET}" ${ARGN})
       set(eq 1)
     endif()
   endforeach()
@@ -70,19 +70,21 @@
   set(Good_json_jobs [["jobs": 0,]])
 endif()
 
-run_cmake_build_presets(Good "default;other" "build-other;withEnvironment;noEnvironment;macros;vendorObject;singleTarget;initResolve")
-run_cmake_build_presets(InvalidConfigurePreset "default" "badConfigurePreset")
-run_cmake_build_presets(Condition "default" "enabled;disabled")
+run_cmake_build_presets(Good "default;other" "build-other;withEnvironment;noEnvironment;macros;vendorObject;singleTarget;initResolve" "")
+run_cmake_build_presets(InvalidConfigurePreset "default" "badConfigurePreset" "")
+run_cmake_build_presets(Condition "default" "enabled;disabled" "")
 
 set(CMakePresetsBuild_BUILD_ONLY 1)
-run_cmake_build_presets(ListPresets "x" "x" "--list-presets")
-run_cmake_build_presets(NoConfigurePreset "x" "noConfigurePreset")
-run_cmake_build_presets(Invalid "x" "hidden;vendorMacro")
+run_cmake_build_presets(ListPresets "x" "x" "--list-presets" "")
+run_cmake_build_presets(NoConfigurePreset "x" "noConfigurePreset" "")
+run_cmake_build_presets(Invalid "x" "hidden;vendorMacro" "")
+run_cmake_build_presets(BuildDirectoryOverride "" "override" "${RunCMake_BINARY_DIR}/../build2")
 
 set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
-run_cmake_build_presets(PresetsUnsupported "x" "x")
-run_cmake_build_presets(ConditionFuture "x" "conditionFuture")
+run_cmake_build_presets(PresetsUnsupported "x" "x" "")
+run_cmake_build_presets(ConditionFuture "x" "conditionFuture" "")
+run_cmake_build_presets(JobsNegative "" "default" "")
 set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
 
-run_cmake_build_presets(ConfigurePresetUnreachable "x" "x")
+run_cmake_build_presets(ConfigurePresetUnreachable "x" "x" "")
 set(CMakePresetsBuild_BUILD_ONLY 0)
diff --git a/Tests/RunCMake/CMakePresetsTest/Good-test-jobsProc-stdout.txt b/Tests/RunCMake/CMakePresetsTest/Good-test-jobsProc-stdout.txt
new file mode 100644
index 0000000..c59dcd3
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Good-test-jobsProc-stdout.txt
@@ -0,0 +1,4 @@
+Test project [^
+]*/Tests/RunCMake/CMakePresetsTest/Good/build/default
+.*
+100% tests passed, 0 tests failed out of 5
diff --git a/Tests/RunCMake/CMakePresetsTest/Good.json.in b/Tests/RunCMake/CMakePresetsTest/Good.json.in
index a4b875a..b436cc8 100644
--- a/Tests/RunCMake/CMakePresetsTest/Good.json.in
+++ b/Tests/RunCMake/CMakePresetsTest/Good.json.in
@@ -1,5 +1,5 @@
 {
-    "version": 6,
+    "version": 11,
     "configurePresets": [
         {
             "name": "default",
@@ -161,6 +161,13 @@
             }
         },
         {
+            "name": "jobsProc",
+            "inherits": "minimal",
+            "execution": {
+                "jobs": ""
+            }
+        },
+        {
             "name": "showOnly",
             "inherits": "minimal",
             "filter": {
diff --git a/Tests/RunCMake/CommandLineTar/7zip-gz-result.txt b/Tests/RunCMake/CMakePresetsTest/InvalidJobs-test-x-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLineTar/7zip-gz-result.txt
copy to Tests/RunCMake/CMakePresetsTest/InvalidJobs-test-x-result.txt
diff --git a/Tests/RunCMake/CMakePresetsTest/InvalidJobs-test-x-stderr.txt b/Tests/RunCMake/CMakePresetsTest/InvalidJobs-test-x-stderr.txt
new file mode 100644
index 0000000..d47899c
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/InvalidJobs-test-x-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsTest/InvalidJobs:
+CMakePresets\.json:15: Invalid preset
+                "jobs": -10
+                        \^$
diff --git a/Tests/RunCMake/CXXModules/examples/export-build-database/dep_interface_include/anchor b/Tests/RunCMake/CMakePresetsTest/InvalidJobs.cmake
similarity index 100%
copy from Tests/RunCMake/CXXModules/examples/export-build-database/dep_interface_include/anchor
copy to Tests/RunCMake/CMakePresetsTest/InvalidJobs.cmake
diff --git a/Tests/RunCMake/CMakePresetsTest/InvalidJobs.json.in b/Tests/RunCMake/CMakePresetsTest/InvalidJobs.json.in
new file mode 100644
index 0000000..d9f6778
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/InvalidJobs.json.in
@@ -0,0 +1,19 @@
+{
+    "version": 2,
+    "configurePresets": [
+        {
+            "name": "default",
+            "generator": "@RunCMake_GENERATOR@",
+            "binaryDir": "${sourceDir}/build/${presetName}"
+        }
+    ],
+    "testPresets": [
+        {
+            "name": "x",
+            "configurePreset": "default",
+            "execution": {
+                "jobs": -10
+            }
+        }
+    ]
+}
diff --git a/Tests/RunCMake/CommandLineTar/7zip-gz-result.txt b/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported-test-x-result.txt
similarity index 100%
copy from Tests/RunCMake/CommandLineTar/7zip-gz-result.txt
copy to Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported-test-x-result.txt
diff --git a/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported-test-x-stderr.txt b/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported-test-x-stderr.txt
new file mode 100644
index 0000000..0c0ae4a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported-test-x-stderr.txt
@@ -0,0 +1,3 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported:
+File version must be 11 or higher for processor-count-based jobs preset support$
diff --git a/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported.json.in b/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported.json.in
new file mode 100644
index 0000000..8f09b24
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/JobsProcUnsupported.json.in
@@ -0,0 +1,19 @@
+{
+  "version": 10,
+  "configurePresets": [
+    {
+      "name": "default",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build"
+    }
+  ],
+  "testPresets": [
+    {
+      "name": "default",
+      "configurePreset": "default",
+      "execution": {
+        "jobs": ""
+      }
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresetsTest/ListPresets-test-x-stdout.txt b/Tests/RunCMake/CMakePresetsTest/ListPresets-test-x-stdout.txt
index 46ffbcf..737a2a0 100644
--- a/Tests/RunCMake/CMakePresetsTest/ListPresets-test-x-stdout.txt
+++ b/Tests/RunCMake/CMakePresetsTest/ListPresets-test-x-stdout.txt
@@ -9,4 +9,5 @@
   "exclude"
   "index"
   "indexFile"
+  "jobsProc"
   "showOnly"
diff --git a/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake
index 5bd0158..d7fcb48 100644
--- a/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake
@@ -82,7 +82,7 @@
 set(GoodTestPresets
   "minimal;defaults;noEnvironment;withEnvironment"
   "config-debug;config-release"
-  "exclude;index;indexFile;showOnly;outputLog;outputJUnit")
+  "exclude;index;indexFile;jobsProc;showOnly;outputLog;outputJUnit")
 run_cmake_test_presets(Good
                        "default"
                        ""
@@ -111,6 +111,8 @@
 run_cmake_test_presets(ConditionFuture "" "" "x")
 run_cmake_test_presets(TestOutputTruncationUnsupported "" "" "x")
 run_cmake_test_presets(OutputJUnitUnsupported "" "" "x")
+run_cmake_test_presets(InvalidJobs "" "" "x")
+run_cmake_test_presets(JobsProcUnsupported "" "" "x")
 set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
 run_cmake_test_presets(ConfigurePresetUnreachable "" "" "x")
 set(CMakePresetsTest_NO_CONFIGURE 0)
diff --git a/Tests/RunCMake/CPack/7Z_BZ2/Helpers.cmake b/Tests/RunCMake/CPack/7Z_BZ2/Helpers.cmake
new file mode 100644
index 0000000..f256a42
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_BZ2/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "7z")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/7Z_BZ2/Prerequirements.cmake b/Tests/RunCMake/CPack/7Z_BZ2/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_BZ2/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+  file(WRITE "${config_file}" "")
+  set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/7Z_BZ2/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/7Z_BZ2/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..81a5035
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_BZ2/packaging_COMPONENT_default.cmake
@@ -0,0 +1 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
diff --git a/Tests/RunCMake/CPack/7Z_DEFLATE/Helpers.cmake b/Tests/RunCMake/CPack/7Z_DEFLATE/Helpers.cmake
new file mode 100644
index 0000000..f256a42
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_DEFLATE/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "7z")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/7Z_DEFLATE/Prerequirements.cmake b/Tests/RunCMake/CPack/7Z_DEFLATE/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_DEFLATE/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+  file(WRITE "${config_file}" "")
+  set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/7Z_DEFLATE/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/7Z_DEFLATE/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..69e1528
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_DEFLATE/packaging_COMPONENT_default.cmake
@@ -0,0 +1,2 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
+set(CPACK_COMPRESSION_LEVEL 7)
diff --git a/Tests/RunCMake/CPack/7Z_LZMA/Helpers.cmake b/Tests/RunCMake/CPack/7Z_LZMA/Helpers.cmake
new file mode 100644
index 0000000..f256a42
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_LZMA/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "7z")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/7Z_LZMA/Prerequirements.cmake b/Tests/RunCMake/CPack/7Z_LZMA/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_LZMA/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+  file(WRITE "${config_file}" "")
+  set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/7Z_LZMA/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/7Z_LZMA/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..81a5035
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_LZMA/packaging_COMPONENT_default.cmake
@@ -0,0 +1 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
diff --git a/Tests/RunCMake/CPack/7Z_LZMA2/Helpers.cmake b/Tests/RunCMake/CPack/7Z_LZMA2/Helpers.cmake
new file mode 100644
index 0000000..f256a42
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_LZMA2/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "7z")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/7Z_LZMA2/Prerequirements.cmake b/Tests/RunCMake/CPack/7Z_LZMA2/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_LZMA2/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+  file(WRITE "${config_file}" "")
+  set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/7Z_LZMA2/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/7Z_LZMA2/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..c05e9aa
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_LZMA2/packaging_COMPONENT_default.cmake
@@ -0,0 +1,2 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
+set(CPACK_ARCHIVE_COMPRESSION_LEVEL 9)
diff --git a/Tests/RunCMake/CPack/7Z_PPMD/Helpers.cmake b/Tests/RunCMake/CPack/7Z_PPMD/Helpers.cmake
new file mode 100644
index 0000000..f256a42
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_PPMD/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "7z")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/7Z_PPMD/Prerequirements.cmake b/Tests/RunCMake/CPack/7Z_PPMD/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_PPMD/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+  file(WRITE "${config_file}" "")
+  set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/7Z_PPMD/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/7Z_PPMD/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..f28a89c
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_PPMD/packaging_COMPONENT_default.cmake
@@ -0,0 +1,2 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
+set(CPACK_COMPRESSION_LEVEL 2)
diff --git a/Tests/RunCMake/CPack/7Z_STORE/Helpers.cmake b/Tests/RunCMake/CPack/7Z_STORE/Helpers.cmake
new file mode 100644
index 0000000..f256a42
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_STORE/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "7z")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/7Z_STORE/Prerequirements.cmake b/Tests/RunCMake/CPack/7Z_STORE/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_STORE/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+  file(WRITE "${config_file}" "")
+  set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/7Z_STORE/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/7Z_STORE/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..81a5035
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_STORE/packaging_COMPONENT_default.cmake
@@ -0,0 +1 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
diff --git a/Tests/RunCMake/CPack/7Z_ZSTD/Helpers.cmake b/Tests/RunCMake/CPack/7Z_ZSTD/Helpers.cmake
new file mode 100644
index 0000000..f256a42
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_ZSTD/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "7z")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/7Z_ZSTD/Prerequirements.cmake b/Tests/RunCMake/CPack/7Z_ZSTD/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_ZSTD/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+  file(WRITE "${config_file}" "")
+  set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/7Z_ZSTD/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/7Z_ZSTD/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..b2e3a66
--- /dev/null
+++ b/Tests/RunCMake/CPack/7Z_ZSTD/packaging_COMPONENT_default.cmake
@@ -0,0 +1,2 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
+set(CPACK_ARCHIVE_COMPRESSION_LEVEL 19)
diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake
index 83bf136..617d30b 100644
--- a/Tests/RunCMake/CPack/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake
@@ -36,8 +36,8 @@
 endif()
 run_cpack_test(LONG_FILENAMES "DEB.LONG_FILENAMES" false "MONOLITHIC")
 run_cpack_test_subtests(MAIN_COMPONENT "invalid;found" "RPM.MAIN_COMPONENT" false "COMPONENT")
-run_cpack_test(MINIMAL "RPM.MINIMAL;DEB.MINIMAL;7Z;TBZ2;TGZ;TXZ;TZ;ZIP;STGZ;TAR;External" false "MONOLITHIC;COMPONENT")
-run_cpack_test_package_target(MINIMAL "RPM.MINIMAL;DEB.MINIMAL;7Z;TBZ2;TGZ;TXZ;TZ;ZIP;STGZ;TAR;External" false "MONOLITHIC;COMPONENT")
+run_cpack_test(MINIMAL "RPM.MINIMAL;DEB.MINIMAL;7Z;7Z_STORE;7Z_DEFLATE;7Z_BZ2;7Z_LZMA;7Z_LZMA2;7Z_ZSTD;7Z_PPMD;TBZ2;TGZ;TXZ;TZST;TZ;ZIP;ZIP_STORE;ZIP_DEFLATE;ZIP_BZ2;ZIP_LZMA;ZIP_LZMA2;ZIP_ZSTD;STGZ;TAR;External" false "MONOLITHIC;COMPONENT")
+run_cpack_test_package_target(MINIMAL "RPM.MINIMAL;DEB.MINIMAL;7Z;7Z_STORE;7Z_DEFLATE;7Z_BZ2;7Z_LZMA;7Z_LZMA2;7Z_ZSTD;7Z_PPMD;TBZ2;TGZ;TXZ;TZST;TZ;ZIP;ZIP_STORE;ZIP_DEFLATE;ZIP_BZ2;ZIP_LZMA;ZIP_LZMA2;ZIP_ZSTD;STGZ;TAR;External" false "MONOLITHIC;COMPONENT")
 run_cpack_test_package_target(THREADED_ALL "TXZ;DEB" false "MONOLITHIC;COMPONENT")
 run_cpack_test_package_target(THREADED "TXZ;DEB" false "MONOLITHIC;COMPONENT")
 run_cpack_test_subtests(PACKAGE_CHECKSUM "invalid;MD5;SHA1;SHA224;SHA256;SHA384;SHA512" "TGZ" false "MONOLITHIC")
diff --git a/Tests/RunCMake/CPack/TGZ/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/TGZ/packaging_COMPONENT_default.cmake
index 81a5035..b835889 100644
--- a/Tests/RunCMake/CPack/TGZ/packaging_COMPONENT_default.cmake
+++ b/Tests/RunCMake/CPack/TGZ/packaging_COMPONENT_default.cmake
@@ -1 +1,2 @@
 set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
+set(CPACK_COMPRESSION_LEVEL 1)
diff --git a/Tests/RunCMake/CPack/TXZ/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/TXZ/packaging_COMPONENT_default.cmake
index 81a5035..2a57279 100644
--- a/Tests/RunCMake/CPack/TXZ/packaging_COMPONENT_default.cmake
+++ b/Tests/RunCMake/CPack/TXZ/packaging_COMPONENT_default.cmake
@@ -1 +1,2 @@
 set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
+set(CPACK_ARCHIVE_COMPRESSION_LEVEL 4)
diff --git a/Tests/RunCMake/CPack/TZST/Helpers.cmake b/Tests/RunCMake/CPack/TZST/Helpers.cmake
new file mode 100644
index 0000000..3c8fa32
--- /dev/null
+++ b/Tests/RunCMake/CPack/TZST/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "tar.zst")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/TZST/Prerequirements.cmake b/Tests/RunCMake/CPack/TZST/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/TZST/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+  file(WRITE "${config_file}" "")
+  set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/TZST/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/TZST/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..81a5035
--- /dev/null
+++ b/Tests/RunCMake/CPack/TZST/packaging_COMPONENT_default.cmake
@@ -0,0 +1 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
diff --git a/Tests/RunCMake/CPack/ZIP_BZ2/Helpers.cmake b/Tests/RunCMake/CPack/ZIP_BZ2/Helpers.cmake
new file mode 100644
index 0000000..3710bcf
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_BZ2/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "zip")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/ZIP_BZ2/Prerequirements.cmake b/Tests/RunCMake/CPack/ZIP_BZ2/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_BZ2/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+  file(WRITE "${config_file}" "")
+  set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/ZIP_BZ2/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/ZIP_BZ2/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..81a5035
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_BZ2/packaging_COMPONENT_default.cmake
@@ -0,0 +1 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
diff --git a/Tests/RunCMake/CPack/ZIP_DEFLATE/Helpers.cmake b/Tests/RunCMake/CPack/ZIP_DEFLATE/Helpers.cmake
new file mode 100644
index 0000000..3710bcf
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_DEFLATE/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "zip")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/ZIP_DEFLATE/Prerequirements.cmake b/Tests/RunCMake/CPack/ZIP_DEFLATE/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_DEFLATE/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+  file(WRITE "${config_file}" "")
+  set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/ZIP_DEFLATE/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/ZIP_DEFLATE/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..2a57279
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_DEFLATE/packaging_COMPONENT_default.cmake
@@ -0,0 +1,2 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
+set(CPACK_ARCHIVE_COMPRESSION_LEVEL 4)
diff --git a/Tests/RunCMake/CPack/ZIP_LZMA/Helpers.cmake b/Tests/RunCMake/CPack/ZIP_LZMA/Helpers.cmake
new file mode 100644
index 0000000..3710bcf
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_LZMA/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "zip")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/ZIP_LZMA/Prerequirements.cmake b/Tests/RunCMake/CPack/ZIP_LZMA/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_LZMA/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+  file(WRITE "${config_file}" "")
+  set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/ZIP_LZMA/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/ZIP_LZMA/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..81a5035
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_LZMA/packaging_COMPONENT_default.cmake
@@ -0,0 +1 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
diff --git a/Tests/RunCMake/CPack/ZIP_LZMA2/Helpers.cmake b/Tests/RunCMake/CPack/ZIP_LZMA2/Helpers.cmake
new file mode 100644
index 0000000..3710bcf
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_LZMA2/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "zip")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/ZIP_LZMA2/Prerequirements.cmake b/Tests/RunCMake/CPack/ZIP_LZMA2/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_LZMA2/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+  file(WRITE "${config_file}" "")
+  set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/ZIP_LZMA2/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/ZIP_LZMA2/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..f75d0d8
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_LZMA2/packaging_COMPONENT_default.cmake
@@ -0,0 +1,2 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
+set(CPACK_ARCHIVE_COMPRESSION_LEVEL 8)
diff --git a/Tests/RunCMake/CPack/ZIP_STORE/Helpers.cmake b/Tests/RunCMake/CPack/ZIP_STORE/Helpers.cmake
new file mode 100644
index 0000000..3710bcf
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_STORE/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "zip")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/ZIP_STORE/Prerequirements.cmake b/Tests/RunCMake/CPack/ZIP_STORE/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_STORE/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+  file(WRITE "${config_file}" "")
+  set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/ZIP_STORE/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/ZIP_STORE/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..81a5035
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_STORE/packaging_COMPONENT_default.cmake
@@ -0,0 +1 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
diff --git a/Tests/RunCMake/CPack/ZIP_ZSTD/Helpers.cmake b/Tests/RunCMake/CPack/ZIP_ZSTD/Helpers.cmake
new file mode 100644
index 0000000..3710bcf
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_ZSTD/Helpers.cmake
@@ -0,0 +1,3 @@
+set(cpack_archive_extension_ "zip")
+
+include("${CMAKE_CURRENT_LIST_DIR}/../ArchiveCommon/common_helpers.cmake")
diff --git a/Tests/RunCMake/CPack/ZIP_ZSTD/Prerequirements.cmake b/Tests/RunCMake/CPack/ZIP_ZSTD/Prerequirements.cmake
new file mode 100644
index 0000000..dbaf682
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_ZSTD/Prerequirements.cmake
@@ -0,0 +1,4 @@
+function(get_test_prerequirements found_var config_file)
+  file(WRITE "${config_file}" "")
+  set(${found_var} true PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/ZIP_ZSTD/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/ZIP_ZSTD/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..81a5035
--- /dev/null
+++ b/Tests/RunCMake/CPack/ZIP_ZSTD/packaging_COMPONENT_default.cmake
@@ -0,0 +1 @@
+set(CPACK_ARCHIVE_COMPONENT_INSTALL "ON")
diff --git a/Tests/RunCMake/CPackConfig/CMP0206-NEW-check.cmake b/Tests/RunCMake/CPackConfig/CMP0206-NEW-check.cmake
new file mode 100644
index 0000000..5352a14
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/CMP0206-NEW-check.cmake
@@ -0,0 +1,3 @@
+include(${RunCMake_SOURCE_DIR}/check.cmake)
+test_variable(CPACK_ARCHIVE_UID "")
+test_variable(CPACK_ARCHIVE_GID "")
diff --git a/Tests/RunCMake/CPackConfig/CMP0206-NEW.cmake b/Tests/RunCMake/CPackConfig/CMP0206-NEW.cmake
new file mode 100644
index 0000000..8b143e5
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/CMP0206-NEW.cmake
@@ -0,0 +1 @@
+cmake_policy(SET CMP0206 NEW)
diff --git a/Tests/RunCMake/CPackConfig/CMP0206-OLD-check.cmake b/Tests/RunCMake/CPackConfig/CMP0206-OLD-check.cmake
new file mode 100644
index 0000000..86f4e9c
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/CMP0206-OLD-check.cmake
@@ -0,0 +1,3 @@
+include(${RunCMake_SOURCE_DIR}/check.cmake)
+test_variable(CPACK_ARCHIVE_UID "-1")
+test_variable(CPACK_ARCHIVE_GID "-1")
diff --git a/Tests/RunCMake/CPackConfig/CMP0206-OLD.cmake b/Tests/RunCMake/CPackConfig/CMP0206-OLD.cmake
new file mode 100644
index 0000000..aa8597a
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/CMP0206-OLD.cmake
@@ -0,0 +1,2 @@
+set(CMAKE_POLICY_WARNING_CMP0206 1)
+cmake_policy(SET CMP0206 OLD)
diff --git a/Tests/RunCMake/CPackConfig/CMP0206-WARN-check.cmake b/Tests/RunCMake/CPackConfig/CMP0206-WARN-check.cmake
new file mode 100644
index 0000000..86f4e9c
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/CMP0206-WARN-check.cmake
@@ -0,0 +1,3 @@
+include(${RunCMake_SOURCE_DIR}/check.cmake)
+test_variable(CPACK_ARCHIVE_UID "-1")
+test_variable(CPACK_ARCHIVE_GID "-1")
diff --git a/Tests/RunCMake/CPackConfig/CMP0206-WARN-stderr.txt b/Tests/RunCMake/CPackConfig/CMP0206-WARN-stderr.txt
new file mode 100644
index 0000000..ce6f443
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/CMP0206-WARN-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Warning \(dev\) at [^
+]*/Modules/CPack\.cmake:[0-9]+ \(message\):
+  Policy CMP0206 is not set: The CPack Archive Generator defaults to UID 0
+  and GID 0\.  Run "cmake --help-policy CMP0206" for policy details\.  Use the
+  cmake_policy command to set the policy and suppress this warning\.
+
+  For compatibility, CMake will set archive UID/GID to -1/-1\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.$
diff --git a/Tests/RunCMake/CPackConfig/CMP0206-WARN.cmake b/Tests/RunCMake/CPackConfig/CMP0206-WARN.cmake
new file mode 100644
index 0000000..75ee7f3
--- /dev/null
+++ b/Tests/RunCMake/CPackConfig/CMP0206-WARN.cmake
@@ -0,0 +1 @@
+set(CMAKE_POLICY_WARNING_CMP0206 1)
diff --git a/Tests/RunCMake/CPackConfig/RunCMakeTest.cmake b/Tests/RunCMake/CPackConfig/RunCMakeTest.cmake
index 4d61073..70ed68a 100644
--- a/Tests/RunCMake/CPackConfig/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CPackConfig/RunCMakeTest.cmake
@@ -8,6 +8,9 @@
 run_cmake(CMP0172-NEW)
 run_cmake(CMP0172-OLD)
 run_cmake(CMP0172-WARN)
+run_cmake(CMP0206-NEW)
+run_cmake(CMP0206-OLD)
+run_cmake(CMP0206-WARN)
 run_cmake(Simple)
 run_cmake(Default)
 run_cmake(Special)
diff --git a/Tests/RunCMake/CPack_AppImage/RunCMakeTest.cmake b/Tests/RunCMake/CPack_AppImage/RunCMakeTest.cmake
index 2273e9c..18a0451 100644
--- a/Tests/RunCMake/CPack_AppImage/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CPack_AppImage/RunCMakeTest.cmake
@@ -1,4 +1,4 @@
-include(RunCPack)
+include(RunCPack) # Uses sample projects from `../RunCPack/*`
 
 set(RunCPack_GENERATORS AppImage)
 
diff --git a/Tests/RunCMake/CPack_DEB/Basic-cpack-DEB-stdout.txt b/Tests/RunCMake/CPack_DEB/Basic-cpack-DEB-stdout.txt
new file mode 100644
index 0000000..00831bf
--- /dev/null
+++ b/Tests/RunCMake/CPack_DEB/Basic-cpack-DEB-stdout.txt
@@ -0,0 +1,8 @@
+CPack: Create package using DEB
+CPack: Install projects(
+CPack: - Run preinstall target for: Basic)?
+CPack: - Install project: Basic \[Release\]
+CPack: Create package
+-- CPACK_DEBIAN_PACKAGE_DEPENDS not set, the package will have no dependencies\.
+CPack: - package: [^
+]*/Tests/RunCMake/CPack_DEB/Basic-build/Basic-1\.2\.3-[A-Za-z]+\.deb generated\.
diff --git a/Tests/RunCMake/CPack_DEB/Basic-verify-stdout.txt b/Tests/RunCMake/CPack_DEB/Basic-verify-stdout.txt
new file mode 100644
index 0000000..bcb8a4a
--- /dev/null
+++ b/Tests/RunCMake/CPack_DEB/Basic-verify-stdout.txt
@@ -0,0 +1,18 @@
+-- Basic-1\.2\.3-[A-Za-z]+\.deb
+-- dpkg-deb --info(
+ [^
+]+)*
+ Maintainer: somebody@cmake\.org(
+ [^
+]+)*
+-- dpkg-deb --contents
+d[rwx-]+ root/root         0 [0-9-]+ [0-9:]+ \./usr/
+d[rwx-]+ root/root         0 [0-9-]+ [0-9:]+ \./usr/share/
+d[rwx-]+ root/root         0 [0-9-]+ [0-9:]+ \./usr/share/doc/
+d[rwx-]+ root/root         0 [0-9-]+ [0-9:]+ \./usr/share/doc/basic/
+-[rwx-]+ root/root         0 [0-9-]+ [0-9:]+ \./usr/share/doc/basic/basic\.txt
+-- ar t
+debian-binary
+control\.tar\.xz
+data\.tar\.xz
+--
diff --git a/Tests/RunCMake/CPack_DEB/RunCMakeTest.cmake b/Tests/RunCMake/CPack_DEB/RunCMakeTest.cmake
new file mode 100644
index 0000000..143d19b
--- /dev/null
+++ b/Tests/RunCMake/CPack_DEB/RunCMakeTest.cmake
@@ -0,0 +1,7 @@
+include(RunCPack)
+
+set(RunCPack_GENERATORS DEB)
+set(RunCPack_GLOB *.deb)
+set(RunCPack_VERIFY ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/verify.cmake --)
+
+run_cpack(Basic)
diff --git a/Tests/RunCMake/CPack_DEB/verify.cmake b/Tests/RunCMake/CPack_DEB/verify.cmake
new file mode 100644
index 0000000..95f6308
--- /dev/null
+++ b/Tests/RunCMake/CPack_DEB/verify.cmake
@@ -0,0 +1,6 @@
+message(STATUS "dpkg-deb --info")
+execute_process(COMMAND dpkg-deb --info ${CMAKE_ARGV4})
+message(STATUS "dpkg-deb --contents")
+execute_process(COMMAND dpkg-deb --contents ${CMAKE_ARGV4})
+message(STATUS "ar t")
+execute_process(COMMAND ar t ${CMAKE_ARGV4})
diff --git a/Tests/RunCMake/CPack_NuGet/RunCMakeTest.cmake b/Tests/RunCMake/CPack_NuGet/RunCMakeTest.cmake
index 7daa457..a992171 100644
--- a/Tests/RunCMake/CPack_NuGet/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CPack_NuGet/RunCMakeTest.cmake
@@ -1,4 +1,4 @@
-include(RunCPack)
+include(RunCPack) # Uses sample projects from `../RunCPack/*`
 
 set(env_PATH "$ENV{PATH}")
 
diff --git a/Tests/RunCMake/CPack_RPM/Basic-cpack-RPM-stderr.txt b/Tests/RunCMake/CPack_RPM/Basic-cpack-RPM-stderr.txt
new file mode 100644
index 0000000..1219e6d
--- /dev/null
+++ b/Tests/RunCMake/CPack_RPM/Basic-cpack-RPM-stderr.txt
@@ -0,0 +1,2 @@
+CPackRPM: Will use GENERATED spec file: [^
+]*/Tests/RunCMake/CPack_RPM/Basic-build/_CPack_Packages/[A-Za-z]+/RPM/SPECS/basic\.spec
diff --git a/Tests/RunCMake/CPack_RPM/Basic-cpack-RPM-stdout.txt b/Tests/RunCMake/CPack_RPM/Basic-cpack-RPM-stdout.txt
new file mode 100644
index 0000000..5b1fa3e
--- /dev/null
+++ b/Tests/RunCMake/CPack_RPM/Basic-cpack-RPM-stdout.txt
@@ -0,0 +1,7 @@
+CPack: Create package using RPM
+CPack: Install projects(
+CPack: - Run preinstall target for: Basic)?
+CPack: - Install project: Basic \[Release\]
+CPack: Create package
+CPack: - package: [^
+]*/Tests/RunCMake/CPack_RPM/Basic-build/Basic-1\.2\.3-[A-Za-z]+\.rpm generated\.
diff --git a/Tests/RunCMake/CPack_RPM/Basic-verify-stderr.txt b/Tests/RunCMake/CPack_RPM/Basic-verify-stderr.txt
new file mode 100644
index 0000000..059e629
--- /dev/null
+++ b/Tests/RunCMake/CPack_RPM/Basic-verify-stderr.txt
@@ -0,0 +1,2 @@
+^(error: can't create transaction lock[^
+]*)?$
diff --git a/Tests/RunCMake/CPack_RPM/Basic-verify-stdout.txt b/Tests/RunCMake/CPack_RPM/Basic-verify-stdout.txt
new file mode 100644
index 0000000..54066a4
--- /dev/null
+++ b/Tests/RunCMake/CPack_RPM/Basic-verify-stdout.txt
@@ -0,0 +1,4 @@
+-- Basic-1\.2\.3-[A-Za-z]+\.rpm
+/usr/share/doc/basic
+/usr/share/doc/basic/basic\.txt
+--
diff --git a/Tests/RunCMake/CPack_RPM/RunCMakeTest.cmake b/Tests/RunCMake/CPack_RPM/RunCMakeTest.cmake
new file mode 100644
index 0000000..caaf43a
--- /dev/null
+++ b/Tests/RunCMake/CPack_RPM/RunCMakeTest.cmake
@@ -0,0 +1,7 @@
+include(RunCPack)
+
+set(RunCPack_GENERATORS RPM)
+set(RunCPack_GLOB *.rpm)
+set(RunCPack_VERIFY rpm -qlp)
+
+run_cpack(Basic)
diff --git a/Tests/RunCMake/CPack_WIX/3-AppWiX-perUser-cpack-WIX-check.cmake b/Tests/RunCMake/CPack_WIX/3-AppWiX-perUser-cpack-WIX-check.cmake
new file mode 100644
index 0000000..a7a28ae
--- /dev/null
+++ b/Tests/RunCMake/CPack_WIX/3-AppWiX-perUser-cpack-WIX-check.cmake
@@ -0,0 +1 @@
+include(${RunCMake_SOURCE_DIR}/cpack-check-common.cmake)
diff --git a/Tests/RunCMake/CPack_WIX/3-AppWiX-perUser-verify-stdout.txt b/Tests/RunCMake/CPack_WIX/3-AppWiX-perUser-verify-stdout.txt
new file mode 100644
index 0000000..2c625fb
--- /dev/null
+++ b/Tests/RunCMake/CPack_WIX/3-AppWiX-perUser-verify-stdout.txt
@@ -0,0 +1,40 @@
+-- MyLib-1\.0\.0-(win64|windows-arm64)\.msi
+Component: 'INSTALL_ROOT_RemoveFolderComponent' 'INSTALL_ROOT'
+Component: 'CM_DP_applications\.bin_RemoveFolderComponent' 'CM_DP_applications\.bin'
+Component: 'CM_DP_applications2\.bin_RemoveFolderComponent' 'CM_DP_applications2\.bin'
+Component: 'CM_DP_extras\.extras_RemoveFolderComponent' 'CM_DP_extras\.extras'
+Component: 'CM_DP_extras\.extras\.empty_RemoveFolderComponent' 'CM_DP_extras\.extras\.empty'
+Component: 'CM_DP_headers\.include_RemoveFolderComponent' 'CM_DP_headers\.include'
+Component: 'CM_DP_libraries\.lib_RemoveFolderComponent' 'CM_DP_libraries\.lib'
+Component: 'CM_CP_applications\.bin\.my_libapp\.exe' 'CM_DP_applications\.bin'
+Component: 'CM_SHORTCUT_applications' 'PROGRAM_MENU_FOLDER'
+Component: 'CM_SHORTCUT_DESKTOP_applications' 'DesktopFolder'
+Component: 'CM_CP_applications2\.bin\.my_other_app\.exe' 'CM_DP_applications2\.bin'
+Component: 'CM_SHORTCUT_applications2' 'PROGRAM_MENU_FOLDER'
+Component: 'CM_SHORTCUT_DESKTOP_applications2' 'DesktopFolder'
+Component: 'CM_C_EMPTY_CM_DP_extras\.extras\.empty' 'CM_DP_extras\.extras\.empty'
+Component: 'CM_CP_headers\.include\.file_with_spaces\.h' 'CM_DP_headers\.include'
+Component: 'CM_CP_headers\.include\.mylib\.h' 'CM_DP_headers\.include'
+Component: 'CM_CP_libraries\.lib\.mylib\.lib' 'CM_DP_libraries\.lib'
+Directory: 'INSTALL_ROOT' 'LocalAppDataFolder' '[^']*\|CPack Component Example'
+Directory: 'CM_DP_applications\.bin' 'INSTALL_ROOT' 'bin'
+Directory: 'CM_DP_applications2\.bin' 'INSTALL_ROOT' 'bin'
+Directory: 'CM_DP_extras\.extras' 'INSTALL_ROOT' 'extras'
+Directory: 'CM_DP_extras\.extras\.empty' 'CM_DP_extras\.extras' 'empty'
+Directory: 'CM_DP_headers\.include' 'INSTALL_ROOT' 'include'
+Directory: 'CM_DP_libraries\.lib' 'INSTALL_ROOT' 'lib'
+Directory: 'PROGRAM_MENU_FOLDER' 'ProgramMenuFolder' 'MyLib'
+Directory: 'DesktopFolder' 'TARGETDIR' 'Desktop'
+Directory: 'LocalAppDataFolder' 'TARGETDIR' '\.'
+Directory: 'TARGETDIR' '' 'SourceDir'
+Directory: 'ProgramMenuFolder' 'TARGETDIR' '\.'
+File: 'CM_FP_applications\.bin\.my_libapp\.exe' 'CM_CP_applications\.bin\.my_libapp\.exe' '[^']*\|my-libapp\.exe'
+File: 'CM_FP_applications2\.bin\.my_other_app\.exe' 'CM_CP_applications2\.bin\.my_other_app\.exe' '[^']*\|my-other-app\.exe'
+File: 'CM_FP_headers\.include\.file_with_spaces\.h' 'CM_CP_headers\.include\.file_with_spaces\.h' '[^']*\|file with spaces\.h'
+File: 'CM_FP_headers\.include\.mylib\.h' 'CM_CP_headers\.include\.mylib\.h' 'mylib\.h'
+File: 'CM_FP_libraries\.lib\.mylib\.lib' 'CM_CP_libraries\.lib\.mylib\.lib' 'mylib\.lib'
+Shortcut: 'CM_SP_applications\.bin\.my_libapp\.exe' 'PROGRAM_MENU_FOLDER' '[^']*\|CPack WiX Test' 'CM_SHORTCUT_applications'
+Shortcut: 'CM_DSP_applications\.bin\.my_libapp\.exe' 'DesktopFolder' '[^']*\|CPack WiX Test' 'CM_SHORTCUT_DESKTOP_applications'
+Shortcut: 'CM_SP_applications2\.bin\.my_other_app\.exe' 'PROGRAM_MENU_FOLDER' '[^']*\|Second CPack WiX Test' 'CM_SHORTCUT_applications2'
+Shortcut: 'CM_DSP_applications2\.bin\.my_other_app\.exe' 'DesktopFolder' '[^']*\|Second CPack WiX Test' 'CM_SHORTCUT_DESKTOP_applications2'
+--
diff --git a/Tests/RunCMake/CPack_WIX/4-AppWiX-perUser-cpack-WIX-check.cmake b/Tests/RunCMake/CPack_WIX/4-AppWiX-perUser-cpack-WIX-check.cmake
new file mode 100644
index 0000000..a7a28ae
--- /dev/null
+++ b/Tests/RunCMake/CPack_WIX/4-AppWiX-perUser-cpack-WIX-check.cmake
@@ -0,0 +1 @@
+include(${RunCMake_SOURCE_DIR}/cpack-check-common.cmake)
diff --git a/Tests/RunCMake/CPack_WIX/4-AppWiX-perUser-cpack-WIX-stdout.txt b/Tests/RunCMake/CPack_WIX/4-AppWiX-perUser-cpack-WIX-stdout.txt
new file mode 100644
index 0000000..80e0e3a
--- /dev/null
+++ b/Tests/RunCMake/CPack_WIX/4-AppWiX-perUser-cpack-WIX-stdout.txt
@@ -0,0 +1,13 @@
+CPack: Create package using WIX
+CPack: Install projects
+CPack: - Install project: CPackWiXGenerator \[Release\]
+CPack: -   Install component: applications
+CPack: -   Install component: applications2
+CPack: -   Install component: empty1
+CPack: -   Install component: empty2
+CPack: -   Install component: extras
+CPack: -   Install component: headers
+CPack: -   Install component: libraries
+CPack: Create package
+CPack: - package: [^
+]*/Tests/RunCMake/CPack_WIX/4-AppWiX-perUser-build/MyLib-1\.0\.0-(win64|windows-arm64)\.msi generated\.
diff --git a/Tests/RunCMake/CPack_WIX/4-AppWiX-perUser-verify-stdout.txt b/Tests/RunCMake/CPack_WIX/4-AppWiX-perUser-verify-stdout.txt
new file mode 100644
index 0000000..bbd9fbe
--- /dev/null
+++ b/Tests/RunCMake/CPack_WIX/4-AppWiX-perUser-verify-stdout.txt
@@ -0,0 +1,40 @@
+-- MyLib-1\.0\.0-(win64|windows-arm64)\.msi
+Component: 'INSTALL_ROOT_RemoveFolderComponent' 'INSTALL_ROOT'
+Component: 'CM_DP_applications\.bin_RemoveFolderComponent' 'CM_DP_applications\.bin'
+Component: 'CM_CP_applications\.bin\.my_libapp\.exe' 'CM_DP_applications\.bin'
+Component: 'CM_SHORTCUT_applications' 'PROGRAM_MENU_FOLDER'
+Component: 'CM_SHORTCUT_DESKTOP_applications' 'DesktopFolder'
+Component: 'CM_DP_applications2\.bin_RemoveFolderComponent' 'CM_DP_applications2\.bin'
+Component: 'CM_CP_applications2\.bin\.my_other_app\.exe' 'CM_DP_applications2\.bin'
+Component: 'CM_SHORTCUT_applications2' 'PROGRAM_MENU_FOLDER'
+Component: 'CM_SHORTCUT_DESKTOP_applications2' 'DesktopFolder'
+Component: 'CM_DP_extras\.extras_RemoveFolderComponent' 'CM_DP_extras\.extras'
+Component: 'CM_DP_extras\.extras\.empty_RemoveFolderComponent' 'CM_DP_extras\.extras\.empty'
+Component: 'CM_C_EMPTY_CM_DP_extras\.extras\.empty' 'CM_DP_extras\.extras\.empty'
+Component: 'CM_DP_headers\.include_RemoveFolderComponent' 'CM_DP_headers\.include'
+Component: 'CM_CP_headers\.include\.file_with_spaces\.h' 'CM_DP_headers\.include'
+Component: 'CM_CP_headers\.include\.mylib\.h' 'CM_DP_headers\.include'
+Component: 'CM_DP_libraries\.lib_RemoveFolderComponent' 'CM_DP_libraries\.lib'
+Component: 'CM_CP_libraries\.lib\.mylib\.lib' 'CM_DP_libraries\.lib'
+Directory: 'INSTALL_ROOT' 'LocalAppDataFolder' '[^']*\|CPack Component Example'
+Directory: 'CM_DP_applications\.bin' 'INSTALL_ROOT' 'bin'
+Directory: 'CM_DP_applications2\.bin' 'INSTALL_ROOT' 'bin'
+Directory: 'CM_DP_extras\.extras' 'INSTALL_ROOT' 'extras'
+Directory: 'CM_DP_extras\.extras\.empty' 'CM_DP_extras\.extras' 'empty'
+Directory: 'CM_DP_headers\.include' 'INSTALL_ROOT' 'include'
+Directory: 'CM_DP_libraries\.lib' 'INSTALL_ROOT' 'lib'
+Directory: 'PROGRAM_MENU_FOLDER' 'ProgramMenuFolder' 'MyLib'
+Directory: 'DesktopFolder' 'TARGETDIR' 'Desktop'
+Directory: 'LocalAppDataFolder' 'TARGETDIR' 'LocalApp'
+Directory: 'ProgramMenuFolder' 'TARGETDIR' 'PMenu'
+Directory: 'TARGETDIR' '' 'SourceDir'
+File: 'CM_FP_applications\.bin\.my_libapp\.exe' 'CM_CP_applications\.bin\.my_libapp\.exe' '[^']*\|my-libapp\.exe'
+File: 'CM_FP_applications2\.bin\.my_other_app\.exe' 'CM_CP_applications2\.bin\.my_other_app\.exe' '[^']*\|my-other-app\.exe'
+File: 'CM_FP_headers\.include\.file_with_spaces\.h' 'CM_CP_headers\.include\.file_with_spaces\.h' '[^']*\|file with spaces\.h'
+File: 'CM_FP_headers\.include\.mylib\.h' 'CM_CP_headers\.include\.mylib\.h' 'mylib\.h'
+File: 'CM_FP_libraries\.lib\.mylib\.lib' 'CM_CP_libraries\.lib\.mylib\.lib' 'mylib\.lib'
+Shortcut: 'CM_SP_applications\.bin\.my_libapp\.exe' 'PROGRAM_MENU_FOLDER' '[^']*\|CPack WiX Test' 'CM_SHORTCUT_applications'
+Shortcut: 'CM_DSP_applications\.bin\.my_libapp\.exe' 'DesktopFolder' '[^']*\|CPack WiX Test' 'CM_SHORTCUT_DESKTOP_applications'
+Shortcut: 'CM_SP_applications2\.bin\.my_other_app\.exe' 'PROGRAM_MENU_FOLDER' '[^']*\|Second CPack WiX Test' 'CM_SHORTCUT_applications2'
+Shortcut: 'CM_DSP_applications2\.bin\.my_other_app\.exe' 'DesktopFolder' '[^']*\|Second CPack WiX Test' 'CM_SHORTCUT_DESKTOP_applications2'
+--
diff --git a/Tests/RunCMake/CPack_WIX/RunCMakeTest.cmake b/Tests/RunCMake/CPack_WIX/RunCMakeTest.cmake
index 816d949..486271b 100644
--- a/Tests/RunCMake/CPack_WIX/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CPack_WIX/RunCMakeTest.cmake
@@ -1,4 +1,4 @@
-include(RunCPack)
+include(RunCPack) # Uses sample projects from `../RunCPack/*`
 
 set(env_PATH "$ENV{PATH}")
 
@@ -11,14 +11,21 @@
   run_cpack(${v}-AppWiX SAMPLE AppWiX BUILD)
 endfunction()
 
+function(run_cpack_wix_peruser v)
+  set(RunCMake_TEST_OPTIONS -DCPACK_WIX_VERSION=${v} -DCPACK_WIX_INSTALL_SCOPE=perUser)
+  run_cpack(${v}-AppWiX-perUser SAMPLE AppWiX BUILD)
+endfunction()
+
 if(CMake_TEST_CPACK_WIX3)
   set(ENV{PATH} "${CMake_TEST_CPACK_WIX3};${env_PATH}")
   run_cpack_wix(3)
+  run_cpack_wix_peruser(3)
 endif()
 
 if(CMake_TEST_CPACK_WIX4)
   set(ENV{PATH} "${CMake_TEST_CPACK_WIX4};${env_PATH}")
   set(ENV{WIX_EXTENSIONS} "${CMake_TEST_CPACK_WIX4}")
   run_cpack_wix(4)
+  run_cpack_wix_peruser(4)
   unset(ENV{WIX_EXTENSIONS})
 endif()
diff --git a/Tests/RunCMake/CTest/CMP0145-Dart-OLD-stderr.txt b/Tests/RunCMake/CTest/CMP0145-Dart-OLD-stderr.txt
new file mode 100644
index 0000000..3624549
--- /dev/null
+++ b/Tests/RunCMake/CTest/CMP0145-Dart-OLD-stderr.txt
@@ -0,0 +1,23 @@
+^CMake Deprecation Warning at CMP0145-Dart-OLD\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0145 will be removed from a future version
+  of CMake\.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances\.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:5 \(include\)
++
+CMake Deprecation Warning at [^
+]*/Modules/Dart\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0145 will be removed from a future version
+  of CMake\.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances\.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+  CMP0145-Dart-OLD\.cmake:3 \(include\)
+  CMakeLists\.txt:5 \(include\)$
diff --git a/Tests/RunCMake/CTest/CMP0145-Dart-WARN-stderr.txt b/Tests/RunCMake/CTest/CMP0145-Dart-WARN-stderr.txt
index 5a751fc..e8ec493 100644
--- a/Tests/RunCMake/CTest/CMP0145-Dart-WARN-stderr.txt
+++ b/Tests/RunCMake/CTest/CMP0145-Dart-WARN-stderr.txt
@@ -15,4 +15,17 @@
 Call Stack \(most recent call first\):
   CMP0145-Dart-WARN\.cmake:[0-9]+ \(include\)
   CMakeLists\.txt:[0-9]+ \(include\)
-This warning is for project developers\.  Use -Wno-dev to suppress it\.$
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
++
+CMake Deprecation Warning at [^
+]*/Modules/Dart\.cmake:[0-9]+6 \(cmake_policy\):
+  The OLD behavior for policy CMP0145 will be removed from a future version
+  of CMake\.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances\.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+  CMP0145-Dart-WARN\.cmake:[0-9]+ \(include\)
+  CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CTest/CMP0145-FindDart-OLD-stderr.txt b/Tests/RunCMake/CTest/CMP0145-FindDart-OLD-stderr.txt
new file mode 100644
index 0000000..e11ffc6
--- /dev/null
+++ b/Tests/RunCMake/CTest/CMP0145-FindDart-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0145-FindDart-OLD\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0145 will be removed from a future version
+  of CMake\.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances\.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
index 0b8226e..ede949a 100644
--- a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
@@ -104,6 +104,19 @@
 run_repeat_until_fail_tests(--repeat-until-fail 3)
 run_repeat_until_fail_tests(--repeat until-fail:3)
 
+block()
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/rerun)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+  file(WRITE "${RunCMake_TEST_BINARY_DIR}/CTestTestfile.cmake" "
+add_test(works \"${CMAKE_COMMAND}\" -E true)
+add_test(fails \"${CMAKE_COMMAND}\" -E false)
+")
+  run_cmake_command(rerun-init ${CMAKE_CTEST_COMMAND})
+  run_cmake_command(rerun-failed ${CMAKE_CTEST_COMMAND} --rerun-failed)
+endblock()
+
 function(run_BadCTestTestfile)
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/BadCTestTestfile)
   set(RunCMake_TEST_NO_CLEAN 1)
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-no-std-property-build-result.txt b/Tests/RunCMake/CTestCommandLine/rerun-failed-result.txt
similarity index 100%
copy from Tests/RunCMake/CXXModules/examples/import-std-no-std-property-build-result.txt
copy to Tests/RunCMake/CTestCommandLine/rerun-failed-result.txt
diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyHeaderSets-exe_verify_interface_header_sets-Debug-build-stderr.txt b/Tests/RunCMake/CTestCommandLine/rerun-failed-stderr.txt
similarity index 100%
copy from Tests/RunCMake/VerifyHeaderSets/VerifyHeaderSets-exe_verify_interface_header_sets-Debug-build-stderr.txt
copy to Tests/RunCMake/CTestCommandLine/rerun-failed-stderr.txt
diff --git a/Tests/RunCMake/CTestCommandLine/rerun-failed-stdout.txt b/Tests/RunCMake/CTestCommandLine/rerun-failed-stdout.txt
new file mode 100644
index 0000000..b376a7f
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/rerun-failed-stdout.txt
@@ -0,0 +1,11 @@
+^Test project [^
+]*/Tests/RunCMake/CTestCommandLine/rerun
+    Start 2: fails
+1/1 Test #2: fails \.+\*\*\*Failed +[0-9\.]+ sec
++
+0% tests passed, 1 tests failed out of 1
++
+Total Test time \(real\) = +[0-9\.]+ sec
++
+The following tests FAILED:
+[	 ]+2 - fails \(Failed\)$
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-no-std-property-build-result.txt b/Tests/RunCMake/CTestCommandLine/rerun-init-result.txt
similarity index 100%
copy from Tests/RunCMake/CXXModules/examples/import-std-no-std-property-build-result.txt
copy to Tests/RunCMake/CTestCommandLine/rerun-init-result.txt
diff --git a/Tests/RunCMake/VerifyHeaderSets/VerifyHeaderSets-exe_verify_interface_header_sets-Debug-build-stderr.txt b/Tests/RunCMake/CTestCommandLine/rerun-init-stderr.txt
similarity index 100%
copy from Tests/RunCMake/VerifyHeaderSets/VerifyHeaderSets-exe_verify_interface_header_sets-Debug-build-stderr.txt
copy to Tests/RunCMake/CTestCommandLine/rerun-init-stderr.txt
diff --git a/Tests/RunCMake/CTestCommandLine/rerun-init-stdout.txt b/Tests/RunCMake/CTestCommandLine/rerun-init-stdout.txt
new file mode 100644
index 0000000..e1615d2
--- /dev/null
+++ b/Tests/RunCMake/CTestCommandLine/rerun-init-stdout.txt
@@ -0,0 +1,13 @@
+^Test project [^
+]*/Tests/RunCMake/CTestCommandLine/rerun
+    Start 1: works
+1/2 Test #1: works \.+   Passed +[0-9\.]+ sec
+    Start 2: fails
+2/2 Test #2: fails \.+\*\*\*Failed +[0-9\.]+ sec
++
+50% tests passed, 1 tests failed out of 2
++
+Total Test time \(real\) = +[0-9\.]+ sec
++
+The following tests FAILED:
+[	 ]+2 - fails \(Failed\)$
diff --git a/Tests/RunCMake/CXXModules/Inspect.cmake b/Tests/RunCMake/CXXModules/Inspect.cmake
index 2913c87..702e349 100644
--- a/Tests/RunCMake/CXXModules/Inspect.cmake
+++ b/Tests/RunCMake/CXXModules/Inspect.cmake
@@ -37,6 +37,7 @@
 set(CMAKE_MAKE_PROGRAM \"${CMAKE_MAKE_PROGRAM}\")
 set(forced_cxx_standard \"${forced_cxx_standard}\")
 set(have_cxx23_import_std \"${have_cxx23_import_std}\")
+set(have_cxx26_import_std \"${have_cxx26_import_std}\")
 set(CMAKE_CXX_COMPILER_VERSION \"${CMAKE_CXX_COMPILER_VERSION}\")
 set(CMAKE_CXX_OUTPUT_EXTENSION \"${CMAKE_CXX_OUTPUT_EXTENSION}\")
 set(CXXModules_default_build_type \"${CMAKE_BUILD_TYPE}\")
diff --git a/Tests/RunCMake/CXXModules/InstallBMINoGenericArgs-check.cmake b/Tests/RunCMake/CXXModules/InstallBMINoGenericArgs-check.cmake
deleted file mode 100644
index 412e260..0000000
--- a/Tests/RunCMake/CXXModules/InstallBMINoGenericArgs-check.cmake
+++ /dev/null
@@ -1,8 +0,0 @@
-file(READ "${RunCMake_TEST_BINARY_DIR}/cmake_install.cmake" install_script)
-
-if (install_script MATCHES [[include\("[^)]*/CMakeFiles/install-bmi-generic-args\.dir/install-cxx-module-bmi-[^.]*\.cmake" OPTIONAL\)]])
-  list(APPEND RunCMake_TEST_FAILED
-    "Found BMI install script inclusion")
-endif ()
-
-string(REPLACE ";" "; " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")
diff --git a/Tests/RunCMake/CXXModules/NoCXX23TargetRequired-stderr.txt b/Tests/RunCMake/CXXModules/NoCXX23TargetRequired-stderr.txt
index fd09dfa..48a8b94 100644
--- a/Tests/RunCMake/CXXModules/NoCXX23TargetRequired-stderr.txt
+++ b/Tests/RunCMake/CXXModules/NoCXX23TargetRequired-stderr.txt
@@ -1,9 +1,8 @@
 CMake Error in CMakeLists\.txt:
-  The "CXX_MODULE_STD" property on the target "nocxx23target" requires that
-  the "__CMAKE::CXX23" target exist, but it was not provided by the
-  toolchain\.  Reason:
+  The "CXX_MODULE_STD" property on target "nocxx23target" requires toolchain
+  support, but it was not provided.  Reason:
 
-    (Toolchain does not support discovering `import std` support|Experimental `import std` support not enabled when detecting toolchain; it must be set before `CXX` is enabled \(usually a `project\(\)` call\)|Unsupported generator: [^\n]*)
+    (Toolchain does not support discovering module metadata|Experimental `import std` support not enabled when detecting toolchain; it must be set before `CXX` is enabled \(usually a `project\(\)` call\)|Unsupported generator: [^\n]*)
 
 
 CMake Generate step failed\.  Build files cannot be regenerated correctly\.
diff --git a/Tests/RunCMake/CXXModules/NoCXX23TargetUnset.cmake b/Tests/RunCMake/CXXModules/NoCXX23TargetUnset.cmake
index 8f6a656..be9c632 100644
--- a/Tests/RunCMake/CXXModules/NoCXX23TargetUnset.cmake
+++ b/Tests/RunCMake/CXXModules/NoCXX23TargetUnset.cmake
@@ -3,7 +3,7 @@
 
 # TODO(cxxmodules): Add instances of this test which test the policy
 # of the property's unset behavior.
-# set(CMAKE_CXX_MODULE_STD …)
+# set(CMAKE_CXX_MODULE_STD ...)
 
 add_library(nocxx23target)
 target_sources(nocxx23target
diff --git a/Tests/RunCMake/CXXModules/NoCXX26TargetRequired-stderr.txt b/Tests/RunCMake/CXXModules/NoCXX26TargetRequired-stderr.txt
index 836b39b..b45b04e 100644
--- a/Tests/RunCMake/CXXModules/NoCXX26TargetRequired-stderr.txt
+++ b/Tests/RunCMake/CXXModules/NoCXX26TargetRequired-stderr.txt
@@ -1,9 +1,8 @@
 CMake Error in CMakeLists\.txt:
-  The "CXX_MODULE_STD" property on the target "nocxx26target" requires that
-  the "__CMAKE::CXX26" target exist, but it was not provided by the
-  toolchain\.  Reason:
+  The "CXX_MODULE_STD" property on target "nocxx26target" requires toolchain
+  support, but it was not provided.  Reason:
 
-    (Toolchain does not support discovering `import std` support|Experimental `import std` support not enabled when detecting toolchain; it must be set before `CXX` is enabled \(usually a `project\(\)` call\)|Unsupported generator: [^\n]*)
+    (Toolchain does not support discovering module metadata|Experimental `import std` support not enabled when detecting toolchain; it must be set before `CXX` is enabled \(usually a `project\(\)` call\)|Unsupported generator: [^\n]*)
 
 
 CMake Generate step failed\.  Build files cannot be regenerated correctly\.
diff --git a/Tests/RunCMake/CXXModules/NoCXX26TargetUnset.cmake b/Tests/RunCMake/CXXModules/NoCXX26TargetUnset.cmake
index 85108ff..c725490 100644
--- a/Tests/RunCMake/CXXModules/NoCXX26TargetUnset.cmake
+++ b/Tests/RunCMake/CXXModules/NoCXX26TargetUnset.cmake
@@ -3,7 +3,7 @@
 
 # TODO(cxxmodules): Add instances of this test which test the policy
 # of the property's unset behavior.
-# set(CMAKE_CXX_MODULE_STD …)
+# set(CMAKE_CXX_MODULE_STD ...)
 
 add_library(nocxx26target)
 target_sources(nocxx26target
diff --git a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake
index 9a8e698..31c5e3e 100644
--- a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake
@@ -135,330 +135,3 @@
   message(FATAL_ERROR
     "Please add 'DependInfo' tests for the '${RunCMake_GENERATOR}' generator.")
 endif ()
-
-# Actual compilation tests.
-if (NOT CMake_TEST_MODULE_COMPILATION)
-  return ()
-endif ()
-
-function (run_cxx_module_test directory)
-  set(test_name "${directory}")
-  if (NOT ARGN STREQUAL "")
-    list(POP_FRONT ARGN test_name)
-  endif ()
-
-  set(RunCMake_TEST_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/examples/${directory}")
-  set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/examples/${test_name}-build")
-
-  if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
-    set(RunCMake_TEST_OPTIONS -DCMAKE_CONFIGURATION_TYPES=Debug)
-  else ()
-    set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
-  endif ()
-  if (directory MATCHES "import-std")
-    list(APPEND RunCMake_TEST_OPTIONS
-      ${stdlib_custom_json})
-  endif ()
-
-  if (RunCMake_CXXModules_INSTALL)
-    set(prefix "${RunCMake_BINARY_DIR}/examples/${test_name}-install")
-    file(REMOVE_RECURSE "${prefix}")
-    list(APPEND RunCMake_TEST_OPTIONS
-      "-DCMAKE_INSTALL_PREFIX=${prefix}")
-  endif ()
-
-  list(APPEND RunCMake_TEST_OPTIONS
-    "-DCMake_TEST_MODULE_COMPILATION_RULES=${CMake_TEST_MODULE_COMPILATION_RULES}"
-    ${ARGN})
-  run_cmake("examples/${test_name}")
-  set(RunCMake_TEST_NO_CLEAN 1)
-  if (RunCMake_CXXModules_TARGET)
-    run_cmake_command("examples/${test_name}-build" "${CMAKE_COMMAND}" --build . --config Debug --target "${RunCMake_CXXModules_TARGET}")
-  else ()
-    run_cmake_command("examples/${test_name}-build" "${CMAKE_COMMAND}" --build . --config Debug)
-    foreach (RunCMake_CXXModules_TARGET IN LISTS RunCMake_CXXModules_TARGETS)
-      set(RunCMake_CXXModules_CONFIG "Debug")
-      set(RunCMake_CXXModules_NAME_SUFFIX "")
-      if (RunCMake_CXXModules_TARGET MATCHES "(.*)@(.*)")
-        set(RunCMake_CXXModules_TARGET "${CMAKE_MATCH_1}")
-        set(RunCMake_CXXModules_CONFIG "${CMAKE_MATCH_2}")
-        set(RunCMake_CXXModules_NAME_SUFFIX "-${RunCMake_CXXModules_CONFIG}")
-      endif ()
-      run_cmake_command("examples/${test_name}-target-${RunCMake_CXXModules_TARGET}${RunCMake_CXXModules_NAME_SUFFIX}" "${CMAKE_COMMAND}" --build . --target "${RunCMake_CXXModules_TARGET}" --config "${RunCMake_CXXModules_CONFIG}")
-    endforeach ()
-  endif ()
-  if (RunCMake_CXXModules_INSTALL)
-    run_cmake_command("examples/${test_name}-install" "${CMAKE_COMMAND}" --build . --target install --config Debug)
-  endif ()
-  if (NOT RunCMake_CXXModules_NO_TEST)
-    run_cmake_command("examples/${test_name}-test" "${CMAKE_CTEST_COMMAND}" -C Debug --output-on-failure)
-  endif ()
-  if (RunCMake_CXXModules_REBUILD)
-    execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 1.125) # handle 1s resolution
-    include("${RunCMake_TEST_SOURCE_DIR}/pre-rebuild.cmake")
-    execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 1.125) # handle 1s resolution
-    run_cmake_command("examples/${test_name}-rebuild" "${CMAKE_COMMAND}" --build . --config Debug)
-  endif ()
-endfunction ()
-
-function (run_cxx_module_test_target directory target)
-  set(RunCMake_CXXModules_TARGET "${target}")
-  set(RunCMake_CXXModules_NO_TEST 1)
-  run_cxx_module_test("${directory}" ${ARGN})
-endfunction ()
-
-function (run_cxx_module_test_rebuild directory)
-  set(RunCMake_CXXModules_INSTALL 0)
-  set(RunCMake_CXXModules_NO_TEST 1)
-  set(RunCMake_CXXModules_REBUILD 1)
-  run_cxx_module_test("${directory}" ${ARGN})
-endfunction ()
-
-# Module compilation features:
-# Compiler-based:
-# - `named`: basic support for named modules is available
-# - `shared`: shared libraries are supported
-# - `partitions`: module partitions are supported
-# - `internal_partitions`: internal module partitions are supported
-# - `bmionly`: the compiler supports BMI-only builds
-# - `import_std23`: the compiler supports `import std` for C++23
-#
-# Generator-based:
-# - `compile_commands`: the generator supports `compile_commands.json`
-# - `collation`: the generator supports module collation features
-# - `export_bmi`: the generator supports exporting BMIs
-# - `ninja`: a `ninja` binary is available to perform `Ninja`-only testing
-#   (assumed if the generator matches `Ninja`).
-string(REPLACE "," ";" CMake_TEST_MODULE_COMPILATION "${CMake_TEST_MODULE_COMPILATION}")
-if (RunCMake_GENERATOR MATCHES "Ninja")
-  list(APPEND CMake_TEST_MODULE_COMPILATION
-    "ninja")
-endif ()
-
-if (RunCMake_GENERATOR MATCHES "Ninja")
-  if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
-    set(ninja_cmp0154_target "CMakeFiles/ninja_cmp0154.dir/Debug/unrelated.cxx${CMAKE_CXX_OUTPUT_EXTENSION}")
-  else ()
-    set(ninja_cmp0154_target "CMakeFiles/ninja_cmp0154.dir/unrelated.cxx${CMAKE_CXX_OUTPUT_EXTENSION}")
-  endif ()
-  run_cxx_module_test_target(ninja-cmp0154 "${ninja_cmp0154_target}")
-endif ()
-
-run_cxx_module_test(scan-with-pch)
-
-# Tests which use named modules.
-if ("named" IN_LIST CMake_TEST_MODULE_COMPILATION)
-  run_cxx_module_test(simple)
-  run_cxx_module_test(file-sets-with-dot)
-  run_cxx_module_test(vs-without-flags)
-  run_cxx_module_test(library library-static -DBUILD_SHARED_LIBS=OFF)
-  run_cxx_module_test(unity-build)
-  run_cxx_module_test(object-library)
-  run_cxx_module_test(generated)
-  run_cxx_module_test(deep-chain)
-  run_cxx_module_test(non-trivial-collation-order)
-  run_cxx_module_test(non-trivial-collation-order-randomized)
-  run_cxx_module_test(duplicate)
-  set(RunCMake_CXXModules_NO_TEST 1)
-  run_cxx_module_test(import-from-object)
-  run_cxx_module_test(circular)
-  run_cxx_module_test(try-compile)
-  run_cxx_module_test(try-run)
-  unset(RunCMake_CXXModules_NO_TEST)
-  run_cxx_module_test(same-src-name)
-  run_cxx_module_test(scan_properties)
-  run_cxx_module_test(target-objects)
-
-  if ("cxx_std_23" IN_LIST CMAKE_CXX_COMPILE_FEATURES AND
-      "import_std23" IN_LIST CMake_TEST_MODULE_COMPILATION)
-    run_cxx_module_test(import-std)
-    set(RunCMake_CXXModules_NO_TEST 1)
-    run_cxx_module_test(import-std-no-std-property)
-    unset(RunCMake_CXXModules_NO_TEST)
-    run_cxx_module_test(import-std-export-no-std-build)
-    set(RunCMake_CXXModules_INSTALL 1)
-    run_cxx_module_test(import-std-export-no-std-install)
-    unset(RunCMake_CXXModules_INSTALL)
-
-    if ("collation" IN_LIST CMake_TEST_MODULE_COMPILATION)
-      run_cxx_module_test(import-std-not-in-export-build)
-      run_cxx_module_test(import-std-transitive import-std-transitive-not-in-export-build "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/import-std-not-in-export-build-build")
-
-      set(RunCMake_CXXModules_INSTALL 1)
-      run_cxx_module_test(import-std-not-in-export-install)
-      unset(RunCMake_CXXModules_INSTALL)
-      run_cxx_module_test(import-std-transitive import-std-transitive-not-in-export-install "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/import-std-not-in-export-install-install")
-
-      run_cxx_module_test(import-std-transitive import-std-transitive-export-no-std-build "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/import-std-export-no-std-build-build" -DEXPORT_NO_STD=1)
-      run_cxx_module_test(import-std-transitive import-std-transitive-export-no-std-install "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/import-std-export-no-std-install-install" -DEXPORT_NO_STD=1)
-    endif ()
-  endif ()
-endif ()
-
-# Tests which require compile commands support.
-if ("compile_commands" IN_LIST CMake_TEST_MODULE_COMPILATION)
-  run_cxx_module_test(export-compile-commands)
-endif ()
-
-macro (setup_export_build_database_targets)
-  set(RunCMake_CXXModules_TARGETS
-    cmake_build_database-CXX
-    cmake_build_database)
-
-  if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
-    list(INSERT RunCMake_CXXModules_TARGETS 0
-      cmake_build_database-CXX-Debug
-      cmake_build_database-Debug
-      # Other config targets.
-      cmake_build_database-CXX-Release@Release
-      cmake_build_database-Release@Release)
-  endif ()
-endmacro ()
-
-# Tests which require build database support.
-if ("build_database" IN_LIST CMake_TEST_MODULE_COMPILATION)
-  setup_export_build_database_targets()
-  set(RunCMake_CXXModules_NO_TEST 1)
-
-  run_cxx_module_test(export-build-database)
-
-  unset(RunCMake_CXXModules_NO_TEST)
-  unset(RunCMake_CXXModules_TARGETS)
-endif ()
-
-# Tests which require collation work.
-if ("collation" IN_LIST CMake_TEST_MODULE_COMPILATION)
-  run_cxx_module_test(duplicate-sources)
-  run_cxx_module_test(public-req-private)
-  set(RunCMake_CXXModules_NO_TEST 1)
-  run_cxx_module_test(req-private-other-target)
-  unset(RunCMake_CXXModules_NO_TEST)
-  run_cxx_module_test_rebuild(depchain-modmap)
-  run_cxx_module_test_rebuild(depchain-modules-json-file)
-  if (RunCMake_GENERATOR MATCHES "Ninja")
-    run_cxx_module_test_rebuild(depchain-collation-restat)
-  endif ()
-endif ()
-
-# Tests which use named modules in shared libraries.
-if ("shared" IN_LIST CMake_TEST_MODULE_COMPILATION)
-  run_cxx_module_test(library library-shared -DBUILD_SHARED_LIBS=ON)
-endif ()
-
-# Tests which use partitions.
-if ("partitions" IN_LIST CMake_TEST_MODULE_COMPILATION)
-  run_cxx_module_test(partitions)
-endif ()
-
-# Tests which use internal partitions.
-if ("internal_partitions" IN_LIST CMake_TEST_MODULE_COMPILATION)
-  run_cxx_module_test(internal-partitions)
-endif ()
-
-function (run_cxx_module_import_test type name)
-  set(RunCMake_CXXModules_INSTALL 0)
-
-  if ("EXPORT_BUILD_DATABASE" IN_LIST ARGN)
-    list(REMOVE_ITEM ARGN EXPORT_BUILD_DATABASE)
-    list(APPEND ARGN -DCMAKE_EXPORT_BUILD_DATABASE=1)
-  endif ()
-
-  run_cxx_module_test(import-modules "import-modules-${name}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/${name}-${type}" ${ARGN})
-endfunction ()
-
-# Tests which install BMIs
-if ("export_bmi" IN_LIST CMake_TEST_MODULE_COMPILATION)
-  run_cxx_module_test(export-interface-no-properties-build)
-  run_cxx_module_test(export-interface-build)
-  run_cxx_module_test(export-include-directories-build)
-  run_cxx_module_test(export-include-directories-old-cmake-build)
-  run_cxx_module_test(export-usage-build)
-  run_cxx_module_test(export-bmi-and-interface-build)
-  run_cxx_module_test(export-command-sepdir-build)
-  run_cxx_module_test(export-transitive-targets-build)
-  run_cxx_module_test(export-transitive-modules1-build)
-  run_cxx_module_test(export-transitive-modules-build export-transitive-modules-build "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/export-transitive-modules1-build-build" )
-  run_cxx_module_test(export-with-headers-build)
-
-  if ("collation" IN_LIST CMake_TEST_MODULE_COMPILATION AND
-      "bmionly" IN_LIST CMake_TEST_MODULE_COMPILATION)
-    run_cxx_module_import_test(build export-interface-build)
-    run_cxx_module_import_test(build export-interface-no-properties-build -DNO_PROPERTIES=1)
-    run_cxx_module_import_test(build export-include-directories-build -DINCLUDE_PROPERTIES=1)
-    run_cxx_module_import_test(build export-bmi-and-interface-build -DWITH_BMIS=1)
-    run_cxx_module_import_test(build export-command-sepdir-build -DEXPORT_COMMAND_SEPDIR=1)
-    run_cxx_module_import_test(build export-transitive-targets-build -DTRANSITIVE_TARGETS=1)
-    run_cxx_module_import_test(build export-transitive-modules-build -DTRANSITIVE_MODULES=1)
-    run_cxx_module_import_test(build export-with-headers-build -DWITH_HEADERS=1)
-
-    if ("build_database" IN_LIST CMake_TEST_MODULE_COMPILATION)
-      setup_export_build_database_targets()
-
-      run_cxx_module_import_test(build export-build-database -DBUILD_DATABASE=1 EXPORT_BUILD_DATABASE)
-
-      unset(RunCMake_CXXModules_TARGETS)
-    endif ()
-  endif ()
-endif ()
-
-# All of the following tests perform installation.
-set(RunCMake_CXXModules_INSTALL 1)
-
-# Tests which install BMIs
-if ("install_bmi" IN_LIST CMake_TEST_MODULE_COMPILATION)
-  run_cxx_module_test(install-bmi)
-  run_cxx_module_test(install-bmi-and-interfaces)
-
-  if ("export_bmi" IN_LIST CMake_TEST_MODULE_COMPILATION)
-    run_cxx_module_test(export-interface-no-properties-install)
-    run_cxx_module_test(export-interface-install)
-    run_cxx_module_test(export-include-directories-install)
-    run_cxx_module_test(export-include-directories-old-cmake-install)
-    run_cxx_module_test(export-usage-install)
-    run_cxx_module_test(export-bmi-and-interface-install)
-    run_cxx_module_test(export-command-sepdir-install)
-    run_cxx_module_test(export-transitive-targets-install)
-    run_cxx_module_test(export-transitive-modules1-install)
-    run_cxx_module_test(export-transitive-modules-install export-transitive-modules-install "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/export-transitive-modules1-install-install" )
-    run_cxx_module_test(export-with-headers-install)
-
-    if ("collation" IN_LIST CMake_TEST_MODULE_COMPILATION AND
-        "bmionly" IN_LIST CMake_TEST_MODULE_COMPILATION)
-      run_cxx_module_import_test(install export-interface-install)
-      run_cxx_module_import_test(install export-interface-no-properties-install -DNO_PROPERTIES=1)
-      run_cxx_module_import_test(install export-include-directories-install -DINCLUDE_PROPERTIES=1)
-      run_cxx_module_import_test(install export-bmi-and-interface-install -DWITH_BMIS=1)
-      run_cxx_module_import_test(install export-command-sepdir-install -DEXPORT_COMMAND_SEPDIR=1)
-      run_cxx_module_import_test(install export-transitive-targets-install -DTRANSITIVE_TARGETS=1)
-      run_cxx_module_import_test(install export-transitive-modules-install -DTRANSITIVE_MODULES=1)
-      run_cxx_module_import_test(install export-with-headers-install -DWITH_HEADERS=1)
-    endif ()
-  endif ()
-endif ()
-
-# All remaining tests require a working `Ninja` generator to set up a test case
-# for the current generator.
-if (NOT "ninja" IN_LIST CMake_TEST_MODULE_COMPILATION)
-  return ()
-endif ()
-# All remaining tests require `bmionly` in order to consume from the `ninja`
-# build.
-if (NOT "bmionly" IN_LIST CMake_TEST_MODULE_COMPILATION)
-  return ()
-endif ()
-
-function (run_cxx_module_test_ninja directory)
-  set(RunCMake_GENERATOR "Ninja")
-  set(RunCMake_CXXModules_NO_TEST 1)
-  set(RunCMake_CXXModules_INSTALL 1)
-  # `Ninja` is not a multi-config generator.
-  set(RunCMake_GENERATOR_IS_MULTI_CONFIG 0)
-  run_cxx_module_test("${directory}" "${directory}-ninja" ${ARGN})
-endfunction ()
-
-# Installation happens within `run_cxx_module_test_ninja`.
-set(RunCMake_CXXModules_INSTALL 0)
-
-set(test_set modules-from-ninja)
-run_cxx_module_test_ninja("export-${test_set}")
-run_cxx_module_test(import-modules "import-${test_set}" "-DCMAKE_PREFIX_PATH=${RunCMake_BINARY_DIR}/examples/export-${test_set}-ninja-install" -DFROM_NINJA=1)
diff --git a/Tests/RunCMake/CXXModules/examples/build-database-check.cmake b/Tests/RunCMake/CXXModules/examples/build-database-check.cmake
deleted file mode 100644
index 9b440a8..0000000
--- a/Tests/RunCMake/CXXModules/examples/build-database-check.cmake
+++ /dev/null
@@ -1,88 +0,0 @@
-include("${CMAKE_CURRENT_LIST_DIR}/../check-json.cmake")
-
-function (check_build_database expect_basename fname component)
-  if (component STREQUAL "NO_EXIST")
-    if (EXISTS "${RunCMake_TEST_BINARY_DIR}/${fname}")
-      list(APPEND RunCMake_TEST_FAILED
-        "Build database detected before it is expected (${fname}).")
-      set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
-    endif ()
-    return ()
-  endif ()
-
-  if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/${fname}")
-    list(APPEND RunCMake_TEST_FAILED
-      "No build database detected (${fname}).")
-    set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
-    return ()
-  endif ()
-
-  if (component STREQUAL "ALL")
-    set(CXXModules_config "Debug")
-    set(suffix "all")
-  elseif (component STREQUAL "ALL_MULTI")
-    set(CXXModules_config "Debug")
-    set(CXXModules_config_other "Release")
-    set(suffix "all-multi")
-  elseif (component STREQUAL "JUST_CXX")
-    set(CXXModules_config "Debug")
-    set(suffix "cxx")
-  elseif (component STREQUAL "JUST_CXX_MULTI")
-    set(CXXModules_config "Debug")
-    set(CXXModules_config_other "Release")
-    set(suffix "cxx-multi")
-  elseif (component STREQUAL "CXX_AND_DEBUG")
-    set(CXXModules_config "Debug")
-    set(suffix "cxx-config")
-  elseif (component STREQUAL "CXX_AND_RELEASE")
-    set(CXXModules_config "Release")
-    set(suffix "cxx-config")
-  elseif (component STREQUAL "JUST_DEBUG")
-    set(CXXModules_config "Debug")
-    set(suffix "config")
-  elseif (component STREQUAL "JUST_RELEASE")
-    set(CXXModules_config "Release")
-    set(suffix "config")
-  elseif (component STREQUAL "JUST_TARGET_DEBUG")
-    set(CXXModules_config "Debug")
-    set(suffix "target")
-  elseif (component STREQUAL "JUST_TARGET_RELEASE")
-    set(CXXModules_config "Release")
-    set(suffix "target")
-  elseif (component STREQUAL "JUST_TARGET")
-    set(CXXModules_config "Debug")
-    set(suffix "target")
-  else ()
-    list(APPEND RunCMake_TEST_FAILED
-      "Unrecognized test component for ${fname}: ${component}")
-    set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
-    return ()
-  endif ()
-
-  set(expected_file "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/expect/${expect_basename}-${suffix}.json")
-  if (NOT EXISTS "${expected_file}")
-    list(APPEND RunCMake_TEST_FAILED
-      "No expected output JSON file found: ${expected_file}")
-    set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
-    return ()
-  endif ()
-
-  file(READ "${RunCMake_TEST_BINARY_DIR}/${fname}" actual)
-  file(READ "${expected_file}" expect)
-
-  set(RunCMake_TEST_FAILED_before "${RunCMake_TEST_FAILED}")
-  set(RunCMake_TEST_FAILED "")
-
-  check_json("${actual}" "${expect}")
-
-  if (RunCMake_TEST_FAILED)
-    string(PREPEND RunCMake_TEST_FAILED
-      "${RunCMake_TEST_FAILED_before}\n"
-      "actual file: ${RunCMake_TEST_BINARY_DIR}/${fname}\n"
-      "expect file: ${expected_file}\n")
-  else ()
-    set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED_before}")
-  endif ()
-
-  set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
-endfunction ()
diff --git a/Tests/RunCMake/CXXModules/examples/duplicate-sources-stderr.txt b/Tests/RunCMake/CXXModules/examples/duplicate-sources-stderr.txt
deleted file mode 100644
index d3960f6..0000000
--- a/Tests/RunCMake/CXXModules/examples/duplicate-sources-stderr.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-CMake Warning \(dev\) in CMakeLists\.txt:
-  Target "duplicate_sources" has source file
-
-    [^
-]*/Tests/RunCMake/CXXModules/examples/duplicate-sources/duplicate\.cxx
-
-  in a "FILE_SET TYPE CXX_MODULES" multiple times\.
-This warning is for project developers\.  Use -Wno-dev to suppress it\.
diff --git a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-all-multi.json b/Tests/RunCMake/CXXModules/examples/expect/export-build-database-all-multi.json
deleted file mode 100644
index ffb74cb..0000000
--- a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-all-multi.json
+++ /dev/null
@@ -1,312 +0,0 @@
-{
-  "version": 1,
-  "revision": 0,
-  "sets": [
-    {
-      "family-name": "export_build_database",
-      "name": "export_build_database@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
-          "work-directory": "<BINARY_DIR>"
-        },
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
-          "private": false,
-          "provides": {
-            "importable": "PATH:<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable<BMIEXT>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    },
-    {
-      "family-name": "export_build_database",
-      "name": "export_build_database@<CONFIG_OTHER>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/lib.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/lib.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/lib.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
-          "work-directory": "<BINARY_DIR>"
-        },
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/importable.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/importable.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/importable.cxx<OBJEXT>",
-          "private": false,
-          "provides": {
-            "importable": "<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/importable<BMIEXT>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    }
-  ]
-}
diff --git a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-all.json b/Tests/RunCMake/CXXModules/examples/expect/export-build-database-all.json
deleted file mode 100644
index 4412d35..0000000
--- a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-all.json
+++ /dev/null
@@ -1,159 +0,0 @@
-{
-  "version": 1,
-  "revision": 0,
-  "sets": [
-    {
-      "family-name": "export_build_database",
-      "name": "export_build_database@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
-          "work-directory": "<BINARY_DIR>"
-        },
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
-          "private": false,
-          "provides": {
-            "importable": "<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable<BMIEXT>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    }
-  ]
-}
diff --git a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-config.json b/Tests/RunCMake/CXXModules/examples/expect/export-build-database-config.json
deleted file mode 100644
index 3815df5..0000000
--- a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-config.json
+++ /dev/null
@@ -1,159 +0,0 @@
-{
-  "version": 1,
-  "revision": 0,
-  "sets": [
-    {
-      "family-name": "export_build_database",
-      "name": "export_build_database@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
-          "work-directory": "<BINARY_DIR>"
-        },
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
-          "private": false,
-          "provides": {
-            "importable": "PATH:<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable<BMIEXT>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    }
-  ]
-}
diff --git a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-cxx-config.json b/Tests/RunCMake/CXXModules/examples/expect/export-build-database-cxx-config.json
deleted file mode 100644
index 3815df5..0000000
--- a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-cxx-config.json
+++ /dev/null
@@ -1,159 +0,0 @@
-{
-  "version": 1,
-  "revision": 0,
-  "sets": [
-    {
-      "family-name": "export_build_database",
-      "name": "export_build_database@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
-          "work-directory": "<BINARY_DIR>"
-        },
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
-          "private": false,
-          "provides": {
-            "importable": "PATH:<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable<BMIEXT>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    }
-  ]
-}
diff --git a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-cxx-multi.json b/Tests/RunCMake/CXXModules/examples/expect/export-build-database-cxx-multi.json
deleted file mode 100644
index 5d2fa07..0000000
--- a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-cxx-multi.json
+++ /dev/null
@@ -1,312 +0,0 @@
-{
-  "version": 1,
-  "revision": 0,
-  "sets": [
-    {
-      "family-name": "export_build_database",
-      "name": "export_build_database@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
-          "work-directory": "<BINARY_DIR>"
-        },
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
-          "private": false,
-          "provides": {
-            "importable": "PATH:<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable<BMIEXT>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    },
-    {
-      "family-name": "export_build_database",
-      "name": "export_build_database@<CONFIG_OTHER>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/lib.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/lib.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/lib.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
-          "work-directory": "<BINARY_DIR>"
-        },
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/importable.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/importable.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/importable.cxx<OBJEXT>",
-          "private": false,
-          "provides": {
-            "importable": "PATH:<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_OTHER_DIR>/importable<BMIEXT>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    }
-  ]
-}
diff --git a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-cxx.json b/Tests/RunCMake/CXXModules/examples/expect/export-build-database-cxx.json
deleted file mode 100644
index 3815df5..0000000
--- a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-cxx.json
+++ /dev/null
@@ -1,159 +0,0 @@
-{
-  "version": 1,
-  "revision": 0,
-  "sets": [
-    {
-      "family-name": "export_build_database",
-      "name": "export_build_database@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
-          "work-directory": "<BINARY_DIR>"
-        },
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
-          "private": false,
-          "provides": {
-            "importable": "PATH:<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable<BMIEXT>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    }
-  ]
-}
diff --git a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-all-multi.json b/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-all-multi.json
deleted file mode 100644
index de16f8e..0000000
--- a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-all-multi.json
+++ /dev/null
@@ -1,290 +0,0 @@
-{
-  "version": 1,
-  "revision": 0,
-  "sets": [
-    {
-      "family-name": "use_import_interfaces",
-      "name": "use_import_interfaces@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>"]
-    },
-    {
-      "family-name": "use_import_interfaces",
-      "name": "use_import_interfaces@<CONFIG_OTHER>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_OTHER_DIR>/use.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_OTHER_DIR>/use.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_OTHER_DIR>/use.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG_OTHER>"]
-    },
-    {
-      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
-      "name": "REGEX:CXXModules__export_build_database@synth_<HEX>@<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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_interface_option",
-            "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
-            "REGEX:<BMI_ONLY_FLAG>",
-            "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_interface_option"
-          ],
-          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-          "private": false,
-          "provides": {
-            "importable": "<IGNORE>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    },
-    {
-      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
-      "name": "REGEX:CXXModules__export_build_database@synth_<HEX>@<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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/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",
-            "-Ddep_interface_option",
-            "-Dtarget_interface_option",
-            "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_OTHER_DIR>/.d\"",
-            "REGEX:<BMI_ONLY_FLAG>",
-            "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_OTHER_DIR>/",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/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",
-            "-Ddep_interface_option",
-            "-Dtarget_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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/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",
-            "-Ddep_interface_option",
-            "-Dtarget_interface_option"
-          ],
-          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_OTHER_DIR>/use.cxx<OBJEXT>",
-          "private": false,
-          "provides": {
-            "importable": "<IGNORE>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    }
-  ]
-}
diff --git a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-all.json b/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-all.json
deleted file mode 100644
index 0e510b8..0000000
--- a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-all.json
+++ /dev/null
@@ -1,148 +0,0 @@
-{
-  "version": 1,
-  "revision": 0,
-  "sets": [
-    {
-      "family-name": "use_import_interfaces",
-      "name": "use_import_interfaces@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>"]
-    },
-    {
-      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
-      "name": "REGEX:CXXModules__export_build_database@synth_<HEX>@<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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_interface_option",
-            "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
-            "REGEX:<BMI_ONLY_FLAG>",
-            "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_interface_option"
-          ],
-          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-          "private": false,
-          "provides": {
-            "importable": "<IGNORE>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    }
-  ]
-}
diff --git a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-config.json b/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-config.json
deleted file mode 100644
index 0e510b8..0000000
--- a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-config.json
+++ /dev/null
@@ -1,148 +0,0 @@
-{
-  "version": 1,
-  "revision": 0,
-  "sets": [
-    {
-      "family-name": "use_import_interfaces",
-      "name": "use_import_interfaces@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>"]
-    },
-    {
-      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
-      "name": "REGEX:CXXModules__export_build_database@synth_<HEX>@<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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_interface_option",
-            "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
-            "REGEX:<BMI_ONLY_FLAG>",
-            "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_interface_option"
-          ],
-          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-          "private": false,
-          "provides": {
-            "importable": "<IGNORE>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    }
-  ]
-}
diff --git a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-cxx-config.json b/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-cxx-config.json
deleted file mode 100644
index 0e510b8..0000000
--- a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-cxx-config.json
+++ /dev/null
@@ -1,148 +0,0 @@
-{
-  "version": 1,
-  "revision": 0,
-  "sets": [
-    {
-      "family-name": "use_import_interfaces",
-      "name": "use_import_interfaces@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>"]
-    },
-    {
-      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
-      "name": "REGEX:CXXModules__export_build_database@synth_<HEX>@<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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_interface_option",
-            "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
-            "REGEX:<BMI_ONLY_FLAG>",
-            "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_interface_option"
-          ],
-          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-          "private": false,
-          "provides": {
-            "importable": "<IGNORE>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    }
-  ]
-}
diff --git a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-cxx-multi.json b/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-cxx-multi.json
deleted file mode 100644
index de16f8e..0000000
--- a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-cxx-multi.json
+++ /dev/null
@@ -1,290 +0,0 @@
-{
-  "version": 1,
-  "revision": 0,
-  "sets": [
-    {
-      "family-name": "use_import_interfaces",
-      "name": "use_import_interfaces@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>"]
-    },
-    {
-      "family-name": "use_import_interfaces",
-      "name": "use_import_interfaces@<CONFIG_OTHER>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_OTHER_DIR>/use.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_OTHER_DIR>/use.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_OTHER_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_OTHER_DIR>/use.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG_OTHER>"]
-    },
-    {
-      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
-      "name": "REGEX:CXXModules__export_build_database@synth_<HEX>@<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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_interface_option",
-            "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
-            "REGEX:<BMI_ONLY_FLAG>",
-            "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_interface_option"
-          ],
-          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-          "private": false,
-          "provides": {
-            "importable": "<IGNORE>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    },
-    {
-      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
-      "name": "REGEX:CXXModules__export_build_database@synth_<HEX>@<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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/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",
-            "-Ddep_interface_option",
-            "-Dtarget_interface_option",
-            "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_OTHER_DIR>/.d\"",
-            "REGEX:<BMI_ONLY_FLAG>",
-            "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_OTHER_DIR>/",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/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",
-            "-Ddep_interface_option",
-            "-Dtarget_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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/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",
-            "-Ddep_interface_option",
-            "-Dtarget_interface_option"
-          ],
-          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_OTHER_DIR>/use.cxx<OBJEXT>",
-          "private": false,
-          "provides": {
-            "importable": "<IGNORE>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    }
-  ]
-}
diff --git a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-cxx.json b/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-cxx.json
deleted file mode 100644
index 0e510b8..0000000
--- a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-cxx.json
+++ /dev/null
@@ -1,148 +0,0 @@
-{
-  "version": 1,
-  "revision": 0,
-  "sets": [
-    {
-      "family-name": "use_import_interfaces",
-      "name": "use_import_interfaces@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>"]
-    },
-    {
-      "family-name": "REGEX:CXXModules::export_build_database@<HEX>",
-      "name": "REGEX:CXXModules__export_build_database@synth_<HEX>@<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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_interface_option",
-            "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
-            "REGEX:<BMI_ONLY_FLAG>",
-            "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_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>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dtarget_interface_option"
-          ],
-          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-          "private": false,
-          "provides": {
-            "importable": "<IGNORE>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    }
-  ]
-}
diff --git a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-target.json b/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-target.json
deleted file mode 100644
index 1435edc..0000000
--- a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-imported-target.json
+++ /dev/null
@@ -1,62 +0,0 @@
-{
-  "version": 1,
-  "revision": 0,
-  "sets": [
-    {
-      "family-name": "use_import_interfaces",
-      "name": "use_import_interfaces@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option",
-            "PATH:-Ddepflag=\"CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Dtarget_interface_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_interface_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dtarget_interface_option",
-            "-Dtarget_public_option"
-          ],
-          "object": "PATH:CMakeFiles/use_import_interfaces.dir<CONFIG_DIR>/use.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/import-modules/use.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": ["REGEX:CXXModules__export_build_database@synth_<HEX>@<CONFIG>"]
-    }
-  ]
-}
diff --git a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-target.json b/Tests/RunCMake/CXXModules/examples/expect/export-build-database-target.json
deleted file mode 100644
index 4412d35..0000000
--- a/Tests/RunCMake/CXXModules/examples/expect/export-build-database-target.json
+++ /dev/null
@@ -1,159 +0,0 @@
-{
-  "version": 1,
-  "revision": 0,
-  "sets": [
-    {
-      "family-name": "export_build_database",
-      "name": "export_build_database@<CONFIG>",
-      "translation-units": [
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/lib.cxx<OBJEXT>",
-          "private": true,
-          "provides": {},
-          "requires": ["importable"],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/lib.cxx",
-          "work-directory": "<BINARY_DIR>"
-        },
-        {
-          "arguments": [
-            "<IGNORE>",
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option",
-            "PATH:-Ddepflag=\"CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>.d\"",
-            "PATH:<OUTPUT_FLAG>CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
-            "-c",
-            "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx"
-          ],
-          "baseline-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option"
-          ],
-          "local-arguments": [
-            "-D_MBCS",
-            "-Ddep_interface_define",
-            "-Dfrom_compile_definitions",
-            "-Dtarget_private_define",
-            "-Dtarget_public_define",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/from_include_directories",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_private_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/target_public_include",
-            "PATH:-I<SOURCE_DIR>/examples/export-build-database/dep_interface_include",
-            "-Dfrom_cmake_cxx_flags",
-            "-Dfrom_cmake_cxx_<CONFIG_LOWER>_flags",
-            "<CXX20_OPTION>",
-            "-Dfrom_compile_flags",
-            "-Dfrom_compile_options",
-            "-Dtarget_private_option",
-            "-Dtarget_public_option",
-            "-Ddep_interface_option",
-            "-Dfrom_source_flag",
-            "-Dfrom_source_option"
-          ],
-          "object": "PATH:CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable.cxx<OBJEXT>",
-          "private": false,
-          "provides": {
-            "importable": "<BINARY_DIR>/CMakeFiles/export_build_database.dir<CONFIG_DIR>/importable<BMIEXT>"
-          },
-          "requires": [],
-          "source": "PATH:<SOURCE_DIR>/examples/export-build-database/importable.cxx",
-          "work-directory": "<BINARY_DIR>"
-        }
-      ],
-      "visible-sets": []
-    }
-  ]
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/forward.cxx b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/forward.cxx
deleted file mode 100644
index 7f53271..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/forward.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-import priv;
-
-int forwarding()
-{
-  return from_private();
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/importable.cxx
deleted file mode 100644
index 8dfc41b..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/importable.cxx
+++ /dev/null
@@ -1,10 +0,0 @@
-export module importable;
-
-extern "C++" {
-int forwarding();
-}
-
-export int from_import()
-{
-  return forwarding();
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/no_modules.cxx b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/no_modules.cxx
deleted file mode 100644
index eea854f..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/no_modules.cxx
+++ /dev/null
@@ -1,3 +0,0 @@
-void no_modules()
-{
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/private.cxx b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/private.cxx
deleted file mode 100644
index c5b719a..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/private.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-export module priv;
-
-export int from_private()
-{
-  return 0;
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/subdir/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/subdir/importable.cxx
deleted file mode 100644
index 07d6af6..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-build/subdir/importable.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-export module subdir_importable;
-
-export int from_subdir()
-{
-  return 0;
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/forward.cxx b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/forward.cxx
deleted file mode 100644
index 7f53271..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/forward.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-import priv;
-
-int forwarding()
-{
-  return from_private();
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/importable.cxx
deleted file mode 100644
index 8dfc41b..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/importable.cxx
+++ /dev/null
@@ -1,10 +0,0 @@
-export module importable;
-
-extern "C++" {
-int forwarding();
-}
-
-export int from_import()
-{
-  return forwarding();
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/no_modules.cxx b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/no_modules.cxx
deleted file mode 100644
index eea854f..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/no_modules.cxx
+++ /dev/null
@@ -1,3 +0,0 @@
-void no_modules()
-{
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/private.cxx b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/private.cxx
deleted file mode 100644
index c5b719a..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/private.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-export module priv;
-
-export int from_private()
-{
-  return 0;
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/subdir/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/subdir/importable.cxx
deleted file mode 100644
index 07d6af6..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-bmi-and-interface-install/subdir/importable.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-export module subdir_importable;
-
-export int from_subdir()
-{
-  return 0;
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-build-database-build-check.cmake b/Tests/RunCMake/CXXModules/examples/export-build-database-build-check.cmake
deleted file mode 100644
index 131926b..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-build-database-build-check.cmake
+++ /dev/null
@@ -1,19 +0,0 @@
-include("${CMAKE_CURRENT_LIST_DIR}/build-database-check.cmake")
-
-check_build_database("export-build-database" "build_database.json" NO_EXIST)
-check_build_database("export-build-database" "build_database_CXX.json" NO_EXIST)
-
-check_build_database("export-build-database" "build_database_CXX_Debug.json" NO_EXIST)
-check_build_database("export-build-database" "build_database_Debug.json" NO_EXIST)
-
-if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
-  check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
-
-  # check_build_database("export-build-database" "build_database_CXX_Release.json" NO_EXIST)
-  # check_build_database("export-build-database" "build_database_Release.json" NO_EXIST)
-  # check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Release/CXX_build_database.json" NO_EXIST)
-else ()
-  check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/CXX_build_database.json" JUST_TARGET)
-endif ()
-
-string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")
diff --git a/Tests/RunCMake/CXXModules/examples/export-build-database-setup.cmake b/Tests/RunCMake/CXXModules/examples/export-build-database-setup.cmake
deleted file mode 100644
index abe7d3b..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-build-database-setup.cmake
+++ /dev/null
@@ -1,44 +0,0 @@
-set(CMAKE_EXPERIMENTAL_EXPORT_BUILD_DATABASE "73194a1d-c0b5-41b9-9190-a4512925e192")
-
-# _MBCS default append for MSVC ABI workaround: see CMP0204
-# So, force add the default value for all platforms to be consistent.
-cmake_policy(SET CMP0204 NEW)
-add_compile_definitions(_MBCS)
-
-get_property(is_multiconfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
-if (is_multiconfig)
-  set(CMAKE_CONFIGURATION_TYPES "Debug" "Release")
-endif ()
-
-set(CMAKE_EXPORT_BUILD_DATABASE 1)
-
-# Mock up depfile flags to keep things consistent; we don't need accurate
-# dependency tracking for this test case anyways.
-set(CMAKE_CXX_DEPFILE_FORMAT gcc)
-set(CMAKE_DEPFILE_FLAGS_CXX "-Ddepflag=\\\"<DEP_FILE>\\\"")
-unset(CMAKE_CXX_DEPFILE_EXTENSION_REPLACE)
-
-# Disable MSVC flag injection from CMake abstractions.
-set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "")
-set(CMAKE_MSVC_RUNTIME_LIBRARY "")
-
-if (CMAKE_CXX_MODULE_BMI_ONLY_FLAG MATCHES "ifcOutput")
-  # Make a single flag for BMI-only to make the JSON expectations simpler.
-  set(CMAKE_CXX_MODULE_BMI_ONLY_FLAG
-    "-ifcOnly;-ifcOutput<OBJECT>")
-endif ()
-
-# Disable extensions to keep flag selection simpler.
-set(CMAKE_CXX_EXTENSIONS 0)
-
-if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
-  set(output_flag "-Fo")
-else ()
-  set(output_flag "-o")
-endif ()
-set(CMAKE_CXX_COMPILE_OBJECT
-  "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> ${output_flag}<OBJECT> -c <SOURCE>")
-
-set(CMAKE_CXX_FLAGS "-Dfrom_cmake_cxx_flags")
-set(CMAKE_CXX_FLAGS_DEBUG "-Dfrom_cmake_cxx_debug_flags")
-set(CMAKE_CXX_FLAGS_RELEASE "-Dfrom_cmake_cxx_release_flags")
diff --git a/Tests/RunCMake/CXXModules/examples/export-build-database-target-cmake_build_database-check.cmake b/Tests/RunCMake/CXXModules/examples/export-build-database-target-cmake_build_database-check.cmake
deleted file mode 100644
index 79db482..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-build-database-target-cmake_build_database-check.cmake
+++ /dev/null
@@ -1,21 +0,0 @@
-include("${CMAKE_CURRENT_LIST_DIR}/build-database-check.cmake")
-
-if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
-  check_build_database("export-build-database" "build_database.json" ALL_MULTI)
-  check_build_database("export-build-database" "build_database_CXX.json" JUST_CXX_MULTI)
-
-  check_build_database("export-build-database" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
-  check_build_database("export-build-database" "build_database_Debug.json" JUST_DEBUG)
-  check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
-
-  check_build_database("export-build-database" "build_database_CXX_Release.json" CXX_AND_RELEASE)
-  check_build_database("export-build-database" "build_database_Release.json" JUST_RELEASE)
-  check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/Release/CXX_build_database.json" JUST_TARGET_RELEASE)
-else ()
-  check_build_database("export-build-database" "build_database.json" ALL)
-  check_build_database("export-build-database" "build_database_CXX.json" JUST_CXX)
-
-  check_build_database("export-build-database" "CMakeFiles/export_build_database.dir/CXX_build_database.json" JUST_TARGET)
-endif ()
-
-string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")
diff --git a/Tests/RunCMake/CXXModules/examples/export-build-database/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-build-database/importable.cxx
deleted file mode 100644
index 607680a..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-build-database/importable.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-export module importable;
-
-export int from_import()
-{
-  return 0;
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-command-sepdir-build/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-command-sepdir-build/CMakeLists.txt
deleted file mode 100644
index 4f3fcf8..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-command-sepdir-build/CMakeLists.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-cmake_minimum_required(VERSION 3.24...3.28)
-project(cxx_modules_export_sepdir CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-add_subdirectory(subdir)
-
-install(TARGETS export_sepdir
-  EXPORT CXXModules
-  FILE_SET modules DESTINATION "lib/cxx/miu")
-export(EXPORT CXXModules
-  NAMESPACE CXXModules::
-  FILE "${CMAKE_CURRENT_BINARY_DIR}/export_sepdir-targets.cmake")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_sepdir-config.cmake"
-  "include(\"\${CMAKE_CURRENT_LIST_DIR}/export_sepdir-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_sepdir_build
-  COMMAND
-    "${CMAKE_COMMAND}"
-    "-Dexpected_dir=${CMAKE_CURRENT_SOURCE_DIR}"
-    "-Dexport_sepdir_DIR=${CMAKE_CURRENT_BINARY_DIR}"
-    ${generator}
-    -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
-    -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/export-command-sepdir-build/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-command-sepdir-build/test/CMakeLists.txt
deleted file mode 100644
index d393271..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-command-sepdir-build/test/CMakeLists.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-cmake_minimum_required(VERSION 3.24...3.28)
-project(cxx_modules_library NONE)
-
-find_package(export_sepdir REQUIRED)
-
-if (NOT TARGET CXXModules::export_sepdir)
-  message(FATAL_ERROR
-    "Missing imported target")
-endif ()
-
-get_property(modules TARGET CXXModules::export_sepdir
-  PROPERTY "IMPORTED_CXX_MODULES_NOCONFIG")
-if (modules STREQUAL "")
-  message(SEND_ERROR
-    "Expected non-empty property value for IMPORTED_CXX_MODULES_NOCONFIG")
-endif ()
diff --git a/Tests/RunCMake/CXXModules/examples/export-command-sepdir-install/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-command-sepdir-install/CMakeLists.txt
deleted file mode 100644
index de21a2e..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-command-sepdir-install/CMakeLists.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-cmake_minimum_required(VERSION 3.24...3.28)
-project(cxx_modules_export_sepdir CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-add_subdirectory(subdir)
-
-install(TARGETS export_sepdir
-  EXPORT CXXModules
-  FILE_SET modules DESTINATION "lib/cxx/miu")
-install(EXPORT CXXModules
-  NAMESPACE CXXModules::
-  DESTINATION "lib/cmake/export_sepdir"
-  FILE "export_sepdir-targets.cmake")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_sepdir-config.cmake"
-  "include(\"\${CMAKE_CURRENT_LIST_DIR}/export_sepdir-targets.cmake\")
-set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
-")
-install(FILES "${CMAKE_CURRENT_BINARY_DIR}/export_sepdir-config.cmake"
-  DESTINATION "lib/cmake/export_sepdir")
-
-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_sepdir_build
-  COMMAND
-    "${CMAKE_COMMAND}"
-    "-Dexpected_dir=${CMAKE_INSTALL_PREFIX}/lib/cxx/miu"
-    "-Dexport_sepdir_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/export_sepdir"
-    ${generator}
-    -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
-    -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/export-command-sepdir-install/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-command-sepdir-install/test/CMakeLists.txt
deleted file mode 100644
index d393271..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-command-sepdir-install/test/CMakeLists.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-cmake_minimum_required(VERSION 3.24...3.28)
-project(cxx_modules_library NONE)
-
-find_package(export_sepdir REQUIRED)
-
-if (NOT TARGET CXXModules::export_sepdir)
-  message(FATAL_ERROR
-    "Missing imported target")
-endif ()
-
-get_property(modules TARGET CXXModules::export_sepdir
-  PROPERTY "IMPORTED_CXX_MODULES_NOCONFIG")
-if (modules STREQUAL "")
-  message(SEND_ERROR
-    "Expected non-empty property value for IMPORTED_CXX_MODULES_NOCONFIG")
-endif ()
diff --git a/Tests/RunCMake/CXXModules/examples/export-include-directories-build/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-include-directories-build/CMakeLists.txt
deleted file mode 100644
index dd35c1f..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-include-directories-build/CMakeLists.txt
+++ /dev/null
@@ -1,65 +0,0 @@
-cmake_minimum_required(VERSION 3.24...3.28)
-project(cxx_modules_export_include_directories CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-add_library(export_include_directories STATIC
-  include/include.h
-  includes/includes.h)
-target_sources(export_include_directories
-  PRIVATE
-    forward.cxx
-  PRIVATE
-    FILE_SET modules_private TYPE CXX_MODULES
-      BASE_DIRS
-        "${CMAKE_CURRENT_SOURCE_DIR}"
-      FILES
-        private.cxx
-  PUBLIC
-    FILE_SET modules TYPE CXX_MODULES
-      BASE_DIRS
-        "${CMAKE_CURRENT_SOURCE_DIR}"
-      FILES
-        importable.cxx
-        subdir/importable.cxx
-  )
-target_compile_features(export_include_directories PUBLIC cxx_std_20)
-target_include_directories(export_include_directories
-  PRIVATE
-    "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
-    "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/includes>")
-
-add_library(no_modules STATIC no_modules.cxx)
-
-install(TARGETS export_include_directories no_modules
-  EXPORT CXXModules
-  FILE_SET modules DESTINATION "lib/cxx/miu")
-export(EXPORT CXXModules
-  NAMESPACE CXXModules::
-  FILE "${CMAKE_CURRENT_BINARY_DIR}/export_include_directories-targets.cmake"
-  CXX_MODULES_DIRECTORY "export_include_directories-cxx-modules")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_include_directories-config.cmake"
-  "include(\"\${CMAKE_CURRENT_LIST_DIR}/export_include_directories-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_include_directories_build
-  COMMAND
-    "${CMAKE_COMMAND}"
-    "-Dexpected_source_dir=${CMAKE_CURRENT_SOURCE_DIR}"
-    "-Dexpected_binary_dir=${CMAKE_CURRENT_BINARY_DIR}"
-    "-Dexport_include_directories_DIR=${CMAKE_CURRENT_BINARY_DIR}"
-    ${generator}
-    -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
-    -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/export-include-directories-build/forward.cxx b/Tests/RunCMake/CXXModules/examples/export-include-directories-build/forward.cxx
deleted file mode 100644
index 7f53271..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-include-directories-build/forward.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-import priv;
-
-int forwarding()
-{
-  return from_private();
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-include-directories-build/no_modules.cxx b/Tests/RunCMake/CXXModules/examples/export-include-directories-build/no_modules.cxx
deleted file mode 100644
index eea854f..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-include-directories-build/no_modules.cxx
+++ /dev/null
@@ -1,3 +0,0 @@
-void no_modules()
-{
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-include-directories-build/private.cxx b/Tests/RunCMake/CXXModules/examples/export-include-directories-build/private.cxx
deleted file mode 100644
index c5b719a..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-include-directories-build/private.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-export module priv;
-
-export int from_private()
-{
-  return 0;
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-include-directories-build/subdir/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-include-directories-build/subdir/importable.cxx
deleted file mode 100644
index 07d6af6..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-include-directories-build/subdir/importable.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-export module subdir_importable;
-
-export int from_subdir()
-{
-  return 0;
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-include-directories-build/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-include-directories-build/test/CMakeLists.txt
deleted file mode 100644
index 6931176..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-include-directories-build/test/CMakeLists.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-cmake_minimum_required(VERSION 3.24)
-project(cxx_modules_library NONE)
-
-find_package(export_include_directories REQUIRED)
-
-if (NOT TARGET CXXModules::export_include_directories)
-  message(FATAL_ERROR
-    "Missing imported target")
-endif ()
-
-get_property(include_directories TARGET CXXModules::export_include_directories
-  PROPERTY IMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES)
-foreach (include_directory IN LISTS include_directories)
-  if (NOT EXISTS "${include_directory}")
-    message(FATAL_ERROR
-      "Missing include directory in C++ module interface CXXModules::export_include_directories:\n  ${include_directory}")
-  endif ()
-endforeach ()
diff --git a/Tests/RunCMake/CXXModules/examples/export-include-directories-install/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-include-directories-install/CMakeLists.txt
deleted file mode 100644
index 3e447f5..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-include-directories-install/CMakeLists.txt
+++ /dev/null
@@ -1,74 +0,0 @@
-cmake_minimum_required(VERSION 3.24...3.28)
-project(cxx_modules_export_include_directories CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-add_library(export_include_directories STATIC
-  include/include.h
-  includes/includes.h)
-target_sources(export_include_directories
-  PRIVATE
-    forward.cxx
-  PRIVATE
-    FILE_SET modules_private TYPE CXX_MODULES
-      BASE_DIRS
-        "${CMAKE_CURRENT_SOURCE_DIR}"
-      FILES
-        private.cxx
-  PUBLIC
-    FILE_SET modules TYPE CXX_MODULES
-      BASE_DIRS
-        "${CMAKE_CURRENT_SOURCE_DIR}"
-      FILES
-        importable.cxx
-        subdir/importable.cxx
-  )
-target_compile_features(export_include_directories PUBLIC cxx_std_20)
-target_include_directories(export_include_directories
-  PRIVATE
-    "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
-    "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/includes>"
-    "$<INSTALL_INTERFACE:include>")
-
-add_library(no_modules STATIC no_modules.cxx)
-
-install(TARGETS export_include_directories no_modules
-  EXPORT CXXModules
-  FILE_SET modules DESTINATION "lib/cxx/miu"
-  INCLUDES DESTINATION "elsewhere")
-install(DIRECTORY include
-  DESTINATION "include")
-install(DIRECTORY includes
-  DESTINATION "elsewhere")
-install(EXPORT CXXModules
-  NAMESPACE CXXModules::
-  DESTINATION "lib/cmake/export_include_directories"
-  FILE "export_include_directories-targets.cmake"
-  CXX_MODULES_DIRECTORY "export_include_directories-cxx-modules")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_include_directories-config.cmake"
-  "include(\"\${CMAKE_CURRENT_LIST_DIR}/export_include_directories-targets.cmake\")
-set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
-")
-install(FILES "${CMAKE_CURRENT_BINARY_DIR}/export_include_directories-config.cmake"
-  DESTINATION "lib/cmake/export_include_directories")
-
-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_include_directories_build
-  COMMAND
-    "${CMAKE_COMMAND}"
-    "-Dexpected_source_dir=${CMAKE_INSTALL_PREFIX}/lib/cxx/miu"
-    "-Dexpected_binary_dir=${CMAKE_INSTALL_PREFIX}/lib/cxx/bmi"
-    "-Dexport_include_directories_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/export_include_directories"
-    ${generator}
-    -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
-    -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/export-include-directories-install/forward.cxx b/Tests/RunCMake/CXXModules/examples/export-include-directories-install/forward.cxx
deleted file mode 100644
index 7f53271..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-include-directories-install/forward.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-import priv;
-
-int forwarding()
-{
-  return from_private();
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-include-directories-install/includes/includes.h b/Tests/RunCMake/CXXModules/examples/export-include-directories-install/includes/includes.h
deleted file mode 100644
index 96bf33b..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-include-directories-install/includes/includes.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-#define includes_h_included
diff --git a/Tests/RunCMake/CXXModules/examples/export-include-directories-install/no_modules.cxx b/Tests/RunCMake/CXXModules/examples/export-include-directories-install/no_modules.cxx
deleted file mode 100644
index eea854f..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-include-directories-install/no_modules.cxx
+++ /dev/null
@@ -1,3 +0,0 @@
-void no_modules()
-{
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-include-directories-install/private.cxx b/Tests/RunCMake/CXXModules/examples/export-include-directories-install/private.cxx
deleted file mode 100644
index c5b719a..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-include-directories-install/private.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-export module priv;
-
-export int from_private()
-{
-  return 0;
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-include-directories-install/subdir/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-include-directories-install/subdir/importable.cxx
deleted file mode 100644
index 07d6af6..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-include-directories-install/subdir/importable.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-export module subdir_importable;
-
-export int from_subdir()
-{
-  return 0;
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-include-directories-install/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-include-directories-install/test/CMakeLists.txt
deleted file mode 100644
index 4bc2b4b..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-include-directories-install/test/CMakeLists.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-cmake_minimum_required(VERSION 3.24...3.28)
-project(cxx_modules_library NONE)
-
-find_package(export_include_directories REQUIRED)
-
-if (NOT TARGET CXXModules::export_include_directories)
-  message(FATAL_ERROR
-    "Missing imported target")
-endif ()
-
-get_property(file_sets TARGET CXXModules::export_include_directories
-  PROPERTY INTERFACE_CXX_MODULE_SETS)
-if (NOT file_sets STREQUAL "modules")
-  message(FATAL_ERROR
-    "Incorrect exported file sets in CXXModules::export_include_directories:\n  ${file_sets}")
-endif ()
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-build/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-interface-build/CMakeLists.txt
deleted file mode 100644
index df471af..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-interface-build/CMakeLists.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-cmake_minimum_required(VERSION 3.24...3.28)
-project(cxx_modules_export_interfaces CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-add_library(export_interfaces STATIC)
-target_sources(export_interfaces
-  PRIVATE
-    forward.cxx
-  PRIVATE
-    FILE_SET modules_private TYPE CXX_MODULES
-      BASE_DIRS
-        "${CMAKE_CURRENT_SOURCE_DIR}"
-      FILES
-        private.cxx
-  PUBLIC
-    FILE_SET modules TYPE CXX_MODULES
-      BASE_DIRS
-        "${CMAKE_CURRENT_SOURCE_DIR}"
-      FILES
-        importable.cxx
-        subdir/importable.cxx
-  )
-target_compile_features(export_interfaces PUBLIC cxx_std_20)
-
-add_library(no_modules STATIC no_modules.cxx)
-
-install(TARGETS export_interfaces no_modules
-  EXPORT CXXModules
-  FILE_SET modules DESTINATION "lib/cxx/miu")
-export(EXPORT CXXModules
-  NAMESPACE CXXModules::
-  FILE "${CMAKE_CURRENT_BINARY_DIR}/export_interfaces-targets.cmake"
-  CXX_MODULES_DIRECTORY "export_interfaces-cxx-modules")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_interfaces-config.cmake"
-  "include(\"\${CMAKE_CURRENT_LIST_DIR}/export_interfaces-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_interfaces_build
-  COMMAND
-    "${CMAKE_COMMAND}"
-    "-Dexpected_source_dir=${CMAKE_CURRENT_SOURCE_DIR}"
-    "-Dexpected_binary_dir=${CMAKE_CURRENT_BINARY_DIR}"
-    "-Dexport_interfaces_DIR=${CMAKE_CURRENT_BINARY_DIR}"
-    ${generator}
-    -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
-    -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-build/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-interface-build/test/CMakeLists.txt
deleted file mode 100644
index 95fb6e8..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-interface-build/test/CMakeLists.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-cmake_minimum_required(VERSION 3.24...3.28)
-project(cxx_modules_library NONE)
-
-find_package(export_interfaces REQUIRED)
-
-if (NOT TARGET CXXModules::export_interfaces)
-  message(FATAL_ERROR
-    "Missing imported target")
-endif ()
-
-get_property(file_sets TARGET CXXModules::export_interfaces
-  PROPERTY INTERFACE_CXX_MODULE_SETS)
-if (NOT file_sets STREQUAL "modules")
-  message(FATAL_ERROR
-    "Incorrect exported file sets in CXXModules::export_interfaces:\n  ${file_sets}")
-endif ()
-
-get_property(file_set_files TARGET CXXModules::export_interfaces
-  PROPERTY CXX_MODULE_SET_modules)
-set(expected_file_set_files
-  "${expected_source_dir}/importable.cxx"
-  "${expected_source_dir}/subdir/importable.cxx"
-  )
-if (NOT file_set_files STREQUAL "${expected_file_set_files}")
-  message(FATAL_ERROR
-    "Incorrect exported file set paths in CXXModules::export_interfaces:\n  ${file_set_files}")
-endif ()
-
-get_property(imported_modules TARGET CXXModules::export_interfaces
-  PROPERTY IMPORTED_CXX_MODULES_DEBUG)
-set(expected_imported_modules
-  "importable=${expected_source_dir}/importable.cxx,${expected_binary_dir}/CMakeFiles/export_interfaces.dir(/Debug)?/importable.(gcm|pcm|ifc)"
-  "subdir_importable=${expected_source_dir}/subdir/importable.cxx,${expected_binary_dir}/CMakeFiles/export_interfaces.dir(/Debug)?/subdir_importable.(gcm|pcm|ifc)"
-  )
-if (NOT imported_modules MATCHES "^${expected_imported_modules}$")
-  message(FATAL_ERROR
-    "Incorrect exported modules in CXXModules::export_interfaces:\n"
-    "  ${imported_modules}\n"
-    "does not match:\n"
-    "  ${expected_imported_modules}"
-  )
-endif ()
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-install/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-interface-install/CMakeLists.txt
deleted file mode 100644
index 019ae4a..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-interface-install/CMakeLists.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-cmake_minimum_required(VERSION 3.24...3.28)
-project(cxx_modules_export_interfaces CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-add_library(export_interfaces STATIC)
-target_sources(export_interfaces
-  PRIVATE
-    forward.cxx
-  PRIVATE
-    FILE_SET modules_private TYPE CXX_MODULES
-      BASE_DIRS
-        "${CMAKE_CURRENT_SOURCE_DIR}"
-      FILES
-        private.cxx
-  PUBLIC
-    FILE_SET modules TYPE CXX_MODULES
-      BASE_DIRS
-        "${CMAKE_CURRENT_SOURCE_DIR}"
-      FILES
-        importable.cxx
-        subdir/importable.cxx
-  )
-target_compile_features(export_interfaces PUBLIC cxx_std_20)
-
-add_library(no_modules STATIC no_modules.cxx)
-
-install(TARGETS export_interfaces no_modules
-  EXPORT CXXModules
-  FILE_SET modules DESTINATION "lib/cxx/miu")
-install(EXPORT CXXModules
-  NAMESPACE CXXModules::
-  DESTINATION "lib/cmake/export_interfaces"
-  FILE "export_interfaces-targets.cmake"
-  CXX_MODULES_DIRECTORY "export_interfaces-cxx-modules")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_interfaces-config.cmake"
-  "include(\"\${CMAKE_CURRENT_LIST_DIR}/export_interfaces-targets.cmake\")
-set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
-")
-install(FILES "${CMAKE_CURRENT_BINARY_DIR}/export_interfaces-config.cmake"
-  DESTINATION "lib/cmake/export_interfaces")
-
-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_interfaces_build
-  COMMAND
-    "${CMAKE_COMMAND}"
-    "-Dexpected_source_dir=${CMAKE_INSTALL_PREFIX}/lib/cxx/miu"
-    "-Dexpected_binary_dir=${CMAKE_INSTALL_PREFIX}/lib/cxx/bmi"
-    "-Dexport_interfaces_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/export_interfaces"
-    ${generator}
-    -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
-    -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-install/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-interface-install/test/CMakeLists.txt
deleted file mode 100644
index 725090e..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-interface-install/test/CMakeLists.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-cmake_minimum_required(VERSION 3.24...3.28)
-project(cxx_modules_library NONE)
-
-find_package(export_interfaces REQUIRED)
-
-if (NOT TARGET CXXModules::export_interfaces)
-  message(FATAL_ERROR
-    "Missing imported target")
-endif ()
-
-get_property(file_sets TARGET CXXModules::export_interfaces
-  PROPERTY INTERFACE_CXX_MODULE_SETS)
-if (NOT file_sets STREQUAL "modules")
-  message(FATAL_ERROR
-    "Incorrect exported file sets in CXXModules::export_interfaces:\n  ${file_sets}")
-endif ()
-
-get_property(file_set_files TARGET CXXModules::export_interfaces
-  PROPERTY CXX_MODULE_SET_modules)
-set(expected_file_set_files
-  "${expected_source_dir}/importable.cxx"
-  "${expected_source_dir}/subdir/importable.cxx"
-  )
-if (NOT file_set_files STREQUAL "${expected_file_set_files}")
-  message(FATAL_ERROR
-    "Incorrect exported file set paths in CXXModules::export_interfaces:\n  ${file_set_files}")
-endif ()
-
-get_property(imported_modules TARGET CXXModules::export_interfaces
-  PROPERTY IMPORTED_CXX_MODULES_DEBUG)
-set(expected_imported_modules
-  "importable=${expected_source_dir}/importable.cxx"
-  "subdir_importable=${expected_source_dir}/subdir/importable.cxx"
-  )
-if (NOT imported_modules STREQUAL "${expected_imported_modules}")
-  message(FATAL_ERROR
-    "Incorrect exported modules in CXXModules::export_interfaces:\n"
-    "  ${imported_modules}\n"
-    "does not match:\n"
-    "  ${expected_imported_modules}"
-  )
-endif ()
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/forward.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/forward.cxx
deleted file mode 100644
index 7f53271..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/forward.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-import priv;
-
-int forwarding()
-{
-  return from_private();
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/importable.cxx
deleted file mode 100644
index 8dfc41b..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/importable.cxx
+++ /dev/null
@@ -1,10 +0,0 @@
-export module importable;
-
-extern "C++" {
-int forwarding();
-}
-
-export int from_import()
-{
-  return forwarding();
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/no_modules.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/no_modules.cxx
deleted file mode 100644
index eea854f..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/no_modules.cxx
+++ /dev/null
@@ -1,3 +0,0 @@
-void no_modules()
-{
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/private.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/private.cxx
deleted file mode 100644
index c5b719a..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/private.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-export module priv;
-
-export int from_private()
-{
-  return 0;
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/subdir/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/subdir/importable.cxx
deleted file mode 100644
index 07d6af6..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-build/subdir/importable.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-export module subdir_importable;
-
-export int from_subdir()
-{
-  return 0;
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/forward.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/forward.cxx
deleted file mode 100644
index 7f53271..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/forward.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-import priv;
-
-int forwarding()
-{
-  return from_private();
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/importable.cxx
deleted file mode 100644
index 8dfc41b..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/importable.cxx
+++ /dev/null
@@ -1,10 +0,0 @@
-export module importable;
-
-extern "C++" {
-int forwarding();
-}
-
-export int from_import()
-{
-  return forwarding();
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/no_modules.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/no_modules.cxx
deleted file mode 100644
index eea854f..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/no_modules.cxx
+++ /dev/null
@@ -1,3 +0,0 @@
-void no_modules()
-{
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/private.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/private.cxx
deleted file mode 100644
index c5b719a..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/private.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-export module priv;
-
-export int from_private()
-{
-  return 0;
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/subdir/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/subdir/importable.cxx
deleted file mode 100644
index 07d6af6..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-interface-no-properties-install/subdir/importable.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-export module subdir_importable;
-
-export int from_subdir()
-{
-  return 0;
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-transitive-modules-build/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-transitive-modules-build/CMakeLists.txt
deleted file mode 100644
index 3610d93..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-transitive-modules-build/CMakeLists.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-cmake_minimum_required(VERSION 3.24...3.28)
-project(cxx_modules_export_transitive_modules CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-find_package(export_transitive_modules1 REQUIRED)
-
-add_library(export_transitive_modules STATIC)
-target_sources(export_transitive_modules
-  PUBLIC
-    FILE_SET modules TYPE CXX_MODULES
-      BASE_DIRS
-        "${CMAKE_CURRENT_SOURCE_DIR}"
-      FILES
-        importable.cxx
-  )
-target_compile_features(export_transitive_modules PUBLIC cxx_std_20)
-target_link_libraries(export_transitive_modules PRIVATE CXXModules::export_transitive_modules1)
-
-install(TARGETS export_transitive_modules
-  EXPORT CXXModules
-  FILE_SET modules DESTINATION "lib/cxx/miu")
-export(EXPORT CXXModules
-  NAMESPACE CXXModules::
-  FILE "${CMAKE_CURRENT_BINARY_DIR}/export_transitive_modules-targets.cmake"
-  CXX_MODULES_DIRECTORY "export_transitive_modules-cxx-modules")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_transitive_modules-config.cmake"
-  "include(CMakeFindDependencyMacro)
-set(export_transitive_modules1_DIR \"${export_transitive_modules1_DIR}\")
-find_dependency(export_transitive_modules1)
-include(\"\${CMAKE_CURRENT_LIST_DIR}/export_transitive_modules-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_transitive_modules_build
-  COMMAND
-    "${CMAKE_COMMAND}"
-    "-Dexpected_source_dir=${CMAKE_CURRENT_SOURCE_DIR}"
-    "-Dexpected_binary_dir=${CMAKE_CURRENT_BINARY_DIR}"
-    "-Dexport_transitive_modules_DIR=${CMAKE_CURRENT_BINARY_DIR}"
-    ${generator}
-    -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
-    -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/export-transitive-modules-build/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-transitive-modules-build/test/CMakeLists.txt
deleted file mode 100644
index c8ee9f0..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-transitive-modules-build/test/CMakeLists.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-cmake_minimum_required(VERSION 3.28)
-project(cxx_modules_library NONE)
-
-find_package(export_transitive_modules REQUIRED)
-
-if (NOT TARGET CXXModules::export_transitive_modules1)
-  message(FATAL_ERROR
-    "Missing transitive imported target")
-endif ()
-
-if (NOT TARGET CXXModules::export_transitive_modules)
-  message(FATAL_ERROR
-    "Missing imported target")
-endif ()
diff --git a/Tests/RunCMake/CXXModules/examples/export-transitive-modules-install/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-transitive-modules-install/CMakeLists.txt
deleted file mode 100644
index 3076ffc..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-transitive-modules-install/CMakeLists.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-cmake_minimum_required(VERSION 3.24...3.28)
-project(cxx_modules_export_transitive_modules CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-find_package(export_transitive_modules1 REQUIRED)
-
-add_library(export_transitive_modules STATIC)
-target_sources(export_transitive_modules
-  PUBLIC
-    FILE_SET modules TYPE CXX_MODULES
-      BASE_DIRS
-        "${CMAKE_CURRENT_SOURCE_DIR}"
-      FILES
-        importable.cxx
-  )
-target_compile_features(export_transitive_modules PUBLIC cxx_std_20)
-target_link_libraries(export_transitive_modules PRIVATE CXXModules::export_transitive_modules1)
-
-install(TARGETS export_transitive_modules
-  EXPORT CXXModules
-  FILE_SET modules DESTINATION "lib/cxx/miu")
-install(EXPORT CXXModules
-  NAMESPACE CXXModules::
-  DESTINATION "lib/cmake/export_transitive_modules"
-  FILE "export_transitive_modules-targets.cmake"
-  CXX_MODULES_DIRECTORY "export_transitive_modules-cxx-modules")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_transitive_modules-config.cmake"
-  "include(CMakeFindDependencyMacro)
-set(export_transitive_modules1_DIR \"${export_transitive_modules1_DIR}\")
-find_dependency(export_transitive_modules1)
-include(\"\${CMAKE_CURRENT_LIST_DIR}/export_transitive_modules-targets.cmake\")
-set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
-")
-install(FILES "${CMAKE_CURRENT_BINARY_DIR}/export_transitive_modules-config.cmake"
-  DESTINATION "lib/cmake/export_transitive_modules")
-
-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_transitive_modules_build
-  COMMAND
-    "${CMAKE_COMMAND}"
-    "-Dexpected_source_dir=${CMAKE_INSTALL_PREFIX}/lib/cxx/miu"
-    "-Dexpected_binary_dir=${CMAKE_INSTALL_PREFIX}/lib/cxx/bmi"
-    "-Dexport_transitive_modules_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/export_transitive_modules"
-    ${generator}
-    -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
-    -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/export-transitive-modules-install/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-transitive-modules-install/test/CMakeLists.txt
deleted file mode 100644
index c8ee9f0..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-transitive-modules-install/test/CMakeLists.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-cmake_minimum_required(VERSION 3.28)
-project(cxx_modules_library NONE)
-
-find_package(export_transitive_modules REQUIRED)
-
-if (NOT TARGET CXXModules::export_transitive_modules1)
-  message(FATAL_ERROR
-    "Missing transitive imported target")
-endif ()
-
-if (NOT TARGET CXXModules::export_transitive_modules)
-  message(FATAL_ERROR
-    "Missing imported target")
-endif ()
diff --git a/Tests/RunCMake/CXXModules/examples/export-transitive-modules1-build/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-transitive-modules1-build/CMakeLists.txt
deleted file mode 100644
index 0a70abd..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-transitive-modules1-build/CMakeLists.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-cmake_minimum_required(VERSION 3.24...3.28)
-project(cxx_modules_export_transitive_modules1 CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-add_library(export_transitive_modules1 STATIC)
-target_sources(export_transitive_modules1
-  PUBLIC
-    FILE_SET modules TYPE CXX_MODULES
-      BASE_DIRS
-        "${CMAKE_CURRENT_SOURCE_DIR}"
-      FILES
-        importable.cxx
-  )
-target_compile_features(export_transitive_modules1 PUBLIC cxx_std_20)
-
-install(TARGETS export_transitive_modules1
-  EXPORT CXXModules
-  FILE_SET modules DESTINATION "lib/cxx/miu")
-export(EXPORT CXXModules
-  NAMESPACE CXXModules::
-  FILE "${CMAKE_CURRENT_BINARY_DIR}/export_transitive_modules1-targets.cmake"
-  CXX_MODULES_DIRECTORY "export_transitive_modules1-cxx-modules")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_transitive_modules1-config.cmake"
-  "include(\"\${CMAKE_CURRENT_LIST_DIR}/export_transitive_modules1-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_transitive_modules1_build
-  COMMAND
-    "${CMAKE_COMMAND}"
-    "-Dexpected_source_dir=${CMAKE_CURRENT_SOURCE_DIR}"
-    "-Dexpected_binary_dir=${CMAKE_CURRENT_BINARY_DIR}"
-    "-Dexport_transitive_modules1_DIR=${CMAKE_CURRENT_BINARY_DIR}"
-    ${generator}
-    -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
-    -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/export-transitive-modules1-build/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-transitive-modules1-build/test/CMakeLists.txt
deleted file mode 100644
index 35d8a68..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-transitive-modules1-build/test/CMakeLists.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-cmake_minimum_required(VERSION 3.28)
-project(cxx_modules_library NONE)
-
-find_package(export_transitive_modules1 REQUIRED)
-
-if (NOT TARGET CXXModules::export_transitive_modules1)
-  message(FATAL_ERROR
-    "Missing imported target")
-endif ()
diff --git a/Tests/RunCMake/CXXModules/examples/export-transitive-modules1-install/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-transitive-modules1-install/CMakeLists.txt
deleted file mode 100644
index d6f9bbf..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-transitive-modules1-install/CMakeLists.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-cmake_minimum_required(VERSION 3.24...3.28)
-project(cxx_modules_export_transitive_modules1 CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-add_library(export_transitive_modules1 STATIC)
-target_sources(export_transitive_modules1
-  PUBLIC
-    FILE_SET modules TYPE CXX_MODULES
-      BASE_DIRS
-        "${CMAKE_CURRENT_SOURCE_DIR}"
-      FILES
-        importable.cxx
-  )
-target_compile_features(export_transitive_modules1 PUBLIC cxx_std_20)
-
-install(TARGETS export_transitive_modules1
-  EXPORT CXXModules
-  FILE_SET modules DESTINATION "lib/cxx/miu")
-install(EXPORT CXXModules
-  NAMESPACE CXXModules::
-  DESTINATION "lib/cmake/export_transitive_modules1"
-  FILE "export_transitive_modules1-targets.cmake"
-  CXX_MODULES_DIRECTORY "export_transitive_modules1-cxx-modules")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_transitive_modules1-config.cmake"
-  "include(\"\${CMAKE_CURRENT_LIST_DIR}/export_transitive_modules1-targets.cmake\")
-set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
-")
-install(FILES "${CMAKE_CURRENT_BINARY_DIR}/export_transitive_modules1-config.cmake"
-  DESTINATION "lib/cmake/export_transitive_modules1")
-
-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_transitive_modules1_build
-  COMMAND
-    "${CMAKE_COMMAND}"
-    "-Dexpected_source_dir=${CMAKE_INSTALL_PREFIX}/lib/cxx/miu"
-    "-Dexpected_binary_dir=${CMAKE_INSTALL_PREFIX}/lib/cxx/bmi"
-    "-Dexport_transitive_modules1_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/export_transitive_modules1"
-    ${generator}
-    -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
-    -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/export-transitive-modules1-install/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-transitive-modules1-install/test/CMakeLists.txt
deleted file mode 100644
index 35d8a68..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-transitive-modules1-install/test/CMakeLists.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-cmake_minimum_required(VERSION 3.28)
-project(cxx_modules_library NONE)
-
-find_package(export_transitive_modules1 REQUIRED)
-
-if (NOT TARGET CXXModules::export_transitive_modules1)
-  message(FATAL_ERROR
-    "Missing imported target")
-endif ()
diff --git a/Tests/RunCMake/CXXModules/examples/export-transitive-targets-install/subdir/importable.cxx b/Tests/RunCMake/CXXModules/examples/export-transitive-targets-install/subdir/importable.cxx
deleted file mode 100644
index 07d6af6..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-transitive-targets-install/subdir/importable.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-export module subdir_importable;
-
-export int from_subdir()
-{
-  return 0;
-}
diff --git a/Tests/RunCMake/CXXModules/examples/export-with-headers-build/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-with-headers-build/CMakeLists.txt
deleted file mode 100644
index e329189..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-with-headers-build/CMakeLists.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-cmake_minimum_required(VERSION 3.28)
-project(export_with_headers CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-add_library(export_with_headers)
-target_sources(export_with_headers
-  PUBLIC
-    FILE_SET headers TYPE HEADERS
-    BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include"
-    FILES
-      "${CMAKE_CURRENT_SOURCE_DIR}/include/subdir/header.h"
-  PUBLIC
-    FILE_SET modules TYPE CXX_MODULES
-    FILES
-      importable.cxx)
-target_compile_features(export_with_headers PUBLIC cxx_std_20)
-
-install(TARGETS export_with_headers
-  EXPORT CXXModules
-  FILE_SET headers
-  FILE_SET modules DESTINATION ${CMAKE_INSTALL_LIBDIR}/miu)
-export(EXPORT CXXModules
-  NAMESPACE CXXModules::
-  FILE "${CMAKE_CURRENT_BINARY_DIR}/export_with_headers-targets.cmake"
-  CXX_MODULES_DIRECTORY "export_with_headers-cxx-modules")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_with_headers-config.cmake"
-  "include(\"\${CMAKE_CURRENT_LIST_DIR}/export_with_headers-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_with_headers_build
-  COMMAND
-    "${CMAKE_COMMAND}"
-    "-Dexport_with_headers_DIR=${CMAKE_CURRENT_BINARY_DIR}"
-    ${generator}
-    -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
-    -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/export-with-headers-build/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-with-headers-build/test/CMakeLists.txt
deleted file mode 100644
index 11b0dae..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-with-headers-build/test/CMakeLists.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-cmake_minimum_required(VERSION 3.28)
-project(cxx_modules_library NONE)
-
-find_package(export_with_headers REQUIRED)
-
-if (NOT TARGET CXXModules::export_with_headers)
-  message(FATAL_ERROR
-    "Missing imported target")
-endif ()
-
-get_property(iface_includes TARGET CXXModules::export_with_headers
-  PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
-set(include_dir "${CMAKE_CURRENT_SOURCE_DIR}")
-cmake_path(GET include_dir PARENT_PATH include_dir)
-string(APPEND include_dir "/include")
-if (NOT iface_includes STREQUAL "${include_dir};$<BUILD_INTERFACE:${include_dir}>")
-  message(FATAL_ERROR
-    "Incorrect include interface for CXXModules::export_with_headers:\n  ${iface_includes}")
-endif ()
diff --git a/Tests/RunCMake/CXXModules/examples/export-with-headers-install/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-with-headers-install/CMakeLists.txt
deleted file mode 100644
index f6aefaf..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-with-headers-install/CMakeLists.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-cmake_minimum_required(VERSION 3.28)
-project(export_with_headers CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-add_library(export_with_headers)
-target_sources(export_with_headers
-  PUBLIC
-    FILE_SET headers TYPE HEADERS
-    BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include"
-    FILES
-      "${CMAKE_CURRENT_SOURCE_DIR}/include/subdir/header.h"
-  PUBLIC
-    FILE_SET modules TYPE CXX_MODULES
-    FILES
-      importable.cxx)
-target_compile_features(export_with_headers PUBLIC cxx_std_20)
-
-install(TARGETS export_with_headers
-  EXPORT CXXModules
-  FILE_SET headers
-  FILE_SET modules DESTINATION lib/miu)
-install(EXPORT CXXModules
-  NAMESPACE CXXModules::
-  DESTINATION "lib/cmake/export_with_headers"
-  FILE "export_with_headers-targets.cmake")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/export_with_headers-config.cmake"
-  "include(\"\${CMAKE_CURRENT_LIST_DIR}/export_with_headers-targets.cmake\")
-set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
-")
-install(FILES "${CMAKE_CURRENT_BINARY_DIR}/export_with_headers-config.cmake"
-  DESTINATION "lib/cmake/export_with_headers")
-
-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_with_headers_build
-  COMMAND
-    "${CMAKE_COMMAND}"
-    "-Dexport_with_headers_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/export_with_headers"
-    ${generator}
-    -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
-    -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/export-with-headers-install/test/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/export-with-headers-install/test/CMakeLists.txt
deleted file mode 100644
index 40d66cb..0000000
--- a/Tests/RunCMake/CXXModules/examples/export-with-headers-install/test/CMakeLists.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-cmake_minimum_required(VERSION 3.28)
-project(cxx_modules_library NONE)
-
-find_package(export_with_headers REQUIRED)
-
-if (NOT TARGET CXXModules::export_with_headers)
-  message(FATAL_ERROR
-    "Missing imported target")
-endif ()
-
-get_property(iface_includes TARGET CXXModules::export_with_headers
-  PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
-set(include_dir "${export_with_headers_DIR}")
-cmake_path(GET include_dir PARENT_PATH include_dir)
-cmake_path(GET include_dir PARENT_PATH include_dir)
-cmake_path(GET include_dir PARENT_PATH include_dir)
-string(APPEND include_dir "/include")
-if (NOT iface_includes STREQUAL "$<BUILD_INTERFACE:${include_dir}>")
-  message(FATAL_ERROR
-    "Incorrect include interface for CXXModules::export_with_headers:\n  ${iface_includes}")
-endif ()
diff --git a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-build-check.cmake b/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-build-check.cmake
deleted file mode 100644
index 21a29b6..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-build-check.cmake
+++ /dev/null
@@ -1,18 +0,0 @@
-include("${CMAKE_CURRENT_LIST_DIR}/build-database-check.cmake")
-set(item_filter "-ifcOnly")
-
-check_build_database("export-build-database-imported" "build_database.json" NO_EXIST)
-check_build_database("export-build-database-imported" "build_database_CXX.json" NO_EXIST)
-if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
-  check_build_database("export-build-database-imported" "build_database_CXX_Debug.json" NO_EXIST)
-  check_build_database("export-build-database-imported" "build_database_Debug.json" NO_EXIST)
-  check_build_database("export-build-database-imported" "CMakeFiles/export-module-commands.dir/Debug/CXX_build_database.json" NO_EXIST)
-
-  check_build_database("export-build-database-imported" "build_database_CXX_Release.json" NO_EXIST)
-  check_build_database("export-build-database-imported" "build_database_Release.json" NO_EXIST)
-  check_build_database("export-build-database-imported" "CMakeFiles/export-module-commands.dir/Release/CXX_build_database.json" NO_EXIST)
-else ()
-  check_build_database("export-build-database-imported" "CMakeFiles/export-module-commands.dir/CXX_build_database.json" NO_EXIST)
-endif ()
-
-string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")
diff --git a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-check.cmake b/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-check.cmake
deleted file mode 100644
index 21a29b6..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-check.cmake
+++ /dev/null
@@ -1,18 +0,0 @@
-include("${CMAKE_CURRENT_LIST_DIR}/build-database-check.cmake")
-set(item_filter "-ifcOnly")
-
-check_build_database("export-build-database-imported" "build_database.json" NO_EXIST)
-check_build_database("export-build-database-imported" "build_database_CXX.json" NO_EXIST)
-if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
-  check_build_database("export-build-database-imported" "build_database_CXX_Debug.json" NO_EXIST)
-  check_build_database("export-build-database-imported" "build_database_Debug.json" NO_EXIST)
-  check_build_database("export-build-database-imported" "CMakeFiles/export-module-commands.dir/Debug/CXX_build_database.json" NO_EXIST)
-
-  check_build_database("export-build-database-imported" "build_database_CXX_Release.json" NO_EXIST)
-  check_build_database("export-build-database-imported" "build_database_Release.json" NO_EXIST)
-  check_build_database("export-build-database-imported" "CMakeFiles/export-module-commands.dir/Release/CXX_build_database.json" NO_EXIST)
-else ()
-  check_build_database("export-build-database-imported" "CMakeFiles/export-module-commands.dir/CXX_build_database.json" NO_EXIST)
-endif ()
-
-string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")
diff --git a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-stderr.txt b/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-stderr.txt
deleted file mode 100644
index a001af7..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-stderr.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-CMake Warning \(dev\) in CMakeLists\.txt:
-  CMake's support for exporting build databases is experimental\.  It is meant
-  only for experimentation and feedback to CMake developers\.
-This warning is for project developers\.  Use -Wno-dev to suppress it\.
diff --git a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database-check.cmake b/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database-check.cmake
deleted file mode 100644
index cfa3a3c..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database-check.cmake
+++ /dev/null
@@ -1,22 +0,0 @@
-include("${CMAKE_CURRENT_LIST_DIR}/build-database-check.cmake")
-set(item_filter "-ifcOnly")
-
-if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
-  check_build_database("export-build-database-imported" "build_database.json" ALL_MULTI)
-  check_build_database("export-build-database-imported" "build_database_CXX.json" JUST_CXX_MULTI)
-
-  check_build_database("export-build-database-imported" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
-  check_build_database("export-build-database-imported" "build_database_Debug.json" JUST_DEBUG)
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
-
-  check_build_database("export-build-database-imported" "build_database_CXX_Release.json" CXX_AND_RELEASE)
-  check_build_database("export-build-database-imported" "build_database_Release.json" JUST_RELEASE)
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Release/CXX_build_database.json" JUST_TARGET_RELEASE)
-else ()
-  check_build_database("export-build-database-imported" "build_database.json" ALL)
-  check_build_database("export-build-database-imported" "build_database_CXX.json" JUST_CXX)
-
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/CXX_build_database.json" JUST_TARGET)
-endif ()
-
-string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")
diff --git a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/CXX-check.cmake b/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/CXX-check.cmake
deleted file mode 100644
index 39203d9..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/CXX-check.cmake
+++ /dev/null
@@ -1,22 +0,0 @@
-include("${CMAKE_CURRENT_LIST_DIR}/../build-database-check.cmake")
-set(item_filter "-ifcOnly")
-
-check_build_database("export-build-database-imported" "build_database.json" NO_EXIST)
-
-if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
-  check_build_database("export-build-database-imported" "build_database_CXX.json" JUST_CXX_MULTI)
-
-  check_build_database("export-build-database-imported" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
-  check_build_database("export-build-database-imported" "build_database_Debug.json" JUST_DEBUG)
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
-
-  check_build_database("export-build-database-imported" "build_database_CXX_Release.json" CXX_AND_RELEASE)
-  check_build_database("export-build-database-imported" "build_database_Release.json" JUST_RELEASE)
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Release/CXX_build_database.json" JUST_TARGET_RELEASE)
-else ()
-  check_build_database("export-build-database-imported" "build_database_CXX.json" JUST_CXX)
-
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/CXX_build_database.json" JUST_TARGET)
-endif ()
-
-string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")
diff --git a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/CXX/Debug-check.cmake b/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/CXX/Debug-check.cmake
deleted file mode 100644
index cf01237..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/CXX/Debug-check.cmake
+++ /dev/null
@@ -1,19 +0,0 @@
-include("${CMAKE_CURRENT_LIST_DIR}/../../build-database-check.cmake")
-set(item_filter "-ifcOnly")
-
-check_build_database("export-build-database-imported" "build_database.json" NO_EXIST)
-check_build_database("export-build-database-imported" "build_database_CXX.json" NO_EXIST)
-
-if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
-  check_build_database("export-build-database-imported" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
-  check_build_database("export-build-database-imported" "build_database_Debug.json" NO_EXIST)
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
-
-  check_build_database("export-build-database-imported" "build_database_CXX_Release.json" NO_EXIST)
-  check_build_database("export-build-database-imported" "build_database_Release.json" NO_EXIST)
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Release/CXX_build_database.json" NO_EXIST)
-else ()
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/CXX_build_database.json" JUST_TARGET)
-endif ()
-
-string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")
diff --git a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/CXX/Release-Release-check.cmake b/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/CXX/Release-Release-check.cmake
deleted file mode 100644
index 7e231ea..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/CXX/Release-Release-check.cmake
+++ /dev/null
@@ -1,19 +0,0 @@
-include("${CMAKE_CURRENT_LIST_DIR}/../../build-database-check.cmake")
-set(item_filter "-ifcOnly")
-
-check_build_database("export-build-database-imported" "build_database.json" NO_EXIST)
-check_build_database("export-build-database-imported" "build_database_CXX.json" NO_EXIST)
-
-if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
-  check_build_database("export-build-database-imported" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
-  check_build_database("export-build-database-imported" "build_database_Debug.json" JUST_DEBUG)
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
-
-  check_build_database("export-build-database-imported" "build_database_CXX_Release.json" CXX_AND_RELEASE)
-  check_build_database("export-build-database-imported" "build_database_Release.json" NO_EXIST)
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Release/CXX_build_database.json" JUST_TARGET_RELEASE)
-else ()
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/CXX_build_database.json" JUST_TARGET)
-endif ()
-
-string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")
diff --git a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/Debug-check.cmake b/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/Debug-check.cmake
deleted file mode 100644
index 876888c..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/Debug-check.cmake
+++ /dev/null
@@ -1,19 +0,0 @@
-include("${CMAKE_CURRENT_LIST_DIR}/../build-database-check.cmake")
-set(item_filter "-ifcOnly")
-
-check_build_database("export-build-database-imported" "build_database.json" NO_EXIST)
-check_build_database("export-build-database-imported" "build_database_CXX.json" NO_EXIST)
-
-if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
-  check_build_database("export-build-database-imported" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
-  check_build_database("export-build-database-imported" "build_database_Debug.json" JUST_DEBUG)
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
-
-  check_build_database("export-build-database-imported" "build_database_CXX_Release.json" NO_EXIST)
-  check_build_database("export-build-database-imported" "build_database_Release.json" NO_EXIST)
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Release/CXX_build_database.json" NO_EXIST)
-else ()
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/CXX_build_database.json" JUST_TARGET)
-endif ()
-
-string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")
diff --git a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/Release-check.cmake b/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/Release-check.cmake
deleted file mode 100644
index 94edc3b..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-modules-export-build-database-target-cmake_build_database/Release-check.cmake
+++ /dev/null
@@ -1,19 +0,0 @@
-include("${CMAKE_CURRENT_LIST_DIR}/../build-database-check.cmake")
-set(item_filter "-ifcOnly")
-
-check_build_database("export-build-database-imported" "build_database.json" NO_EXIST)
-check_build_database("export-build-database-imported" "build_database_CXX.json" JUST_CXX)
-
-if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
-  check_build_database("export-build-database-imported" "build_database_CXX_Debug.json" CXX_AND_DEBUG)
-  check_build_database("export-build-database-imported" "build_database_Debug.json" JUST_DEBUG)
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Debug/CXX_build_database.json" JUST_TARGET_DEBUG)
-
-  check_build_database("export-build-database-imported" "build_database_CXX_Release.json" CXX_AND_RELEASE)
-  check_build_database("export-build-database-imported" "build_database_Release.json" JUST_RELEASE)
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/Release/CXX_build_database.json" JUST_TARGET_RELEASE)
-else ()
-  check_build_database("export-build-database-imported" "CMakeFiles/use_import_interfaces.dir/CXX_build_database.json" JUST_TARGET)
-endif ()
-
-string(REPLACE ";" "\n  " RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}")
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-export-no-std-build-stderr.txt b/Tests/RunCMake/CXXModules/examples/import-std-export-no-std-build-stderr.txt
deleted file mode 100644
index 583556f..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-std-export-no-std-build-stderr.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-CMake Warning \(dev\) at .*/Modules/Compiler/CMakeCommonCompilerMacros\.cmake:[0-9]* \(cmake_language\):
-  CMake's support for `import std;` in C\+\+23 and newer is experimental\.  It
-  is meant only for experimentation and feedback to CMake developers\.
-Call Stack \(most recent call first\):
-  .*/Modules/CMakeDetermineCompilerSupport\.cmake:[0-9]* \(cmake_create_cxx_import_std\)
-  .*/Modules/CMakeTestCXXCompiler\.cmake:[0-9]* \(CMAKE_DETERMINE_COMPILER_SUPPORT\)
-  CMakeLists\.txt:[0-9]* \(project\)
-This warning is for project developers\.  Use -Wno-dev to suppress it\.
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-export-no-std-build/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/import-std-export-no-std-build/CMakeLists.txt
deleted file mode 100644
index 3dfc927..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-std-export-no-std-build/CMakeLists.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
-  "d0edc3af-4c50-42ea-a356-e2862fe7a444")
-
-cmake_minimum_required(VERSION 3.29)
-project(cxx_modules_import_std_export_no_std CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-set(CMAKE_NO_STD 1)
-
-add_library(import_std_export_no_std)
-target_sources(import_std_export_no_std
-  PRIVATE
-    uses-std.cxx
-  PUBLIC
-    FILE_SET use_std TYPE CXX_MODULES FILES
-      impl-uses-std.cxx)
-target_compile_features(import_std_export_no_std PUBLIC cxx_std_23)
-set_property(TARGET import_std_export_no_std
-  PROPERTY
-    CXX_MODULE_STD "$<BOOL:$<BUILD_LOCAL_INTERFACE:1>>")
-
-add_executable(main
-  main.cxx)
-target_link_libraries(main PRIVATE import_std_export_no_std)
-
-install(TARGETS import_std_export_no_std
-  EXPORT export
-  ARCHIVE DESTINATION "lib"
-  FILE_SET use_std DESTINATION "lib/cxx/miu")
-export(EXPORT export
-  NAMESPACE CXXModules::
-  FILE "${CMAKE_CURRENT_BINARY_DIR}/import_std_export_no_std-targets.cmake")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/import_std_export_no_std-config.cmake"
-  "include(\"\${CMAKE_CURRENT_LIST_DIR}/import_std_export_no_std-targets.cmake\")
-set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
-")
-
-add_test(NAME main COMMAND main)
-
-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 import_std_export_no_std_build
-  COMMAND
-    "${CMAKE_COMMAND}"
-    "-Dexpected_dir=${CMAKE_CURRENT_SOURCE_DIR}"
-    "-Dimport_std_export_no_std_DIR=${CMAKE_CURRENT_BINARY_DIR}"
-    ${generator}
-    -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
-    -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-export-no-std-install-stderr.txt b/Tests/RunCMake/CXXModules/examples/import-std-export-no-std-install-stderr.txt
deleted file mode 100644
index 583556f..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-std-export-no-std-install-stderr.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-CMake Warning \(dev\) at .*/Modules/Compiler/CMakeCommonCompilerMacros\.cmake:[0-9]* \(cmake_language\):
-  CMake's support for `import std;` in C\+\+23 and newer is experimental\.  It
-  is meant only for experimentation and feedback to CMake developers\.
-Call Stack \(most recent call first\):
-  .*/Modules/CMakeDetermineCompilerSupport\.cmake:[0-9]* \(cmake_create_cxx_import_std\)
-  .*/Modules/CMakeTestCXXCompiler\.cmake:[0-9]* \(CMAKE_DETERMINE_COMPILER_SUPPORT\)
-  CMakeLists\.txt:[0-9]* \(project\)
-This warning is for project developers\.  Use -Wno-dev to suppress it\.
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-export-no-std-install/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/import-std-export-no-std-install/CMakeLists.txt
deleted file mode 100644
index 9b25973..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-std-export-no-std-install/CMakeLists.txt
+++ /dev/null
@@ -1,61 +0,0 @@
-set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
-  "d0edc3af-4c50-42ea-a356-e2862fe7a444")
-
-cmake_minimum_required(VERSION 3.29)
-project(cxx_modules_import_std_export_no_std CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-add_library(import_std_export_no_std)
-target_sources(import_std_export_no_std
-  PRIVATE
-    uses-std.cxx
-  PUBLIC
-    FILE_SET use_std TYPE CXX_MODULES FILES
-      impl-uses-std.cxx)
-target_compile_features(import_std_export_no_std PUBLIC cxx_std_23)
-set_property(TARGET import_std_export_no_std
-  PROPERTY
-    CXX_MODULE_STD "$<BOOL:$<BUILD_LOCAL_INTERFACE:1>>")
-
-add_executable(main
-  main.cxx)
-target_link_libraries(main PRIVATE import_std_export_no_std)
-
-install(TARGETS import_std_export_no_std
-  EXPORT export
-  ARCHIVE DESTINATION "lib"
-  FILE_SET use_std DESTINATION "lib/cxx/miu")
-install(
-  EXPORT export
-  NAMESPACE CXXModules::
-  DESTINATION "lib/cmake/import_std_export_no_std"
-  FILE "import_std_export_no_std-targets.cmake")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/import_std_export_no_std-config.cmake"
-  "include(\"\${CMAKE_CURRENT_LIST_DIR}/import_std_export_no_std-targets.cmake\")
-set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
-")
-install(FILES "${CMAKE_CURRENT_BINARY_DIR}/import_std_export_no_std-config.cmake"
-  DESTINATION "lib/cmake/import_std_export_no_std")
-
-add_test(NAME main COMMAND main)
-
-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 import_std_export_no_std_build
-  COMMAND
-    "${CMAKE_COMMAND}"
-    "-Dexpected_dir=${CMAKE_INSTALL_PREFIX}/lib/cxx/miu"
-    "-Dimport_std_export_no_std_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/import_std_export_no_std"
-    ${generator}
-    -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
-    -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-no-std-property-stderr.txt b/Tests/RunCMake/CXXModules/examples/import-std-no-std-property-stderr.txt
deleted file mode 100644
index 583556f..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-std-no-std-property-stderr.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-CMake Warning \(dev\) at .*/Modules/Compiler/CMakeCommonCompilerMacros\.cmake:[0-9]* \(cmake_language\):
-  CMake's support for `import std;` in C\+\+23 and newer is experimental\.  It
-  is meant only for experimentation and feedback to CMake developers\.
-Call Stack \(most recent call first\):
-  .*/Modules/CMakeDetermineCompilerSupport\.cmake:[0-9]* \(cmake_create_cxx_import_std\)
-  .*/Modules/CMakeTestCXXCompiler\.cmake:[0-9]* \(CMAKE_DETERMINE_COMPILER_SUPPORT\)
-  CMakeLists\.txt:[0-9]* \(project\)
-This warning is for project developers\.  Use -Wno-dev to suppress it\.
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-no-std-property/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/import-std-no-std-property/CMakeLists.txt
deleted file mode 100644
index 52d76f0..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-std-no-std-property/CMakeLists.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
-  "d0edc3af-4c50-42ea-a356-e2862fe7a444")
-
-cmake_minimum_required(VERSION 3.29)
-project(cxx_modules_import_std_no_std_property CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-set(CMAKE_CXX_MODULE_STD 0)
-
-add_executable(main
-  main.cxx)
-target_compile_features(main PRIVATE cxx_std_23)
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-build-stderr.txt b/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-build-stderr.txt
deleted file mode 100644
index 583556f..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-build-stderr.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-CMake Warning \(dev\) at .*/Modules/Compiler/CMakeCommonCompilerMacros\.cmake:[0-9]* \(cmake_language\):
-  CMake's support for `import std;` in C\+\+23 and newer is experimental\.  It
-  is meant only for experimentation and feedback to CMake developers\.
-Call Stack \(most recent call first\):
-  .*/Modules/CMakeDetermineCompilerSupport\.cmake:[0-9]* \(cmake_create_cxx_import_std\)
-  .*/Modules/CMakeTestCXXCompiler\.cmake:[0-9]* \(CMAKE_DETERMINE_COMPILER_SUPPORT\)
-  CMakeLists\.txt:[0-9]* \(project\)
-This warning is for project developers\.  Use -Wno-dev to suppress it\.
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-build/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-build/CMakeLists.txt
deleted file mode 100644
index 204a9db..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-build/CMakeLists.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
-  "d0edc3af-4c50-42ea-a356-e2862fe7a444")
-
-cmake_minimum_required(VERSION 3.29)
-project(cxx_modules_import_std_not_in_export CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-set(CMAKE_CXX_MODULE_STD 1)
-
-add_library(import_std_not_in_export)
-target_sources(import_std_not_in_export
-  PUBLIC
-    FILE_SET use_std TYPE CXX_MODULES FILES
-      uses-std.cxx)
-target_compile_features(import_std_not_in_export PUBLIC cxx_std_23)
-
-add_executable(main
-  main.cxx)
-target_link_libraries(main PRIVATE import_std_not_in_export)
-
-install(TARGETS import_std_not_in_export
-  EXPORT export
-  ARCHIVE DESTINATION "lib"
-  FILE_SET use_std DESTINATION "lib/cxx/miu")
-export(EXPORT export
-  NAMESPACE CXXModules::
-  FILE "${CMAKE_CURRENT_BINARY_DIR}/import_std_not_in_export-targets.cmake")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/import_std_not_in_export-config.cmake"
-  "include(\"\${CMAKE_CURRENT_LIST_DIR}/import_std_not_in_export-targets.cmake\")
-set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
-")
-
-add_test(NAME main COMMAND main)
-
-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 import_std_not_in_export_build
-  COMMAND
-    "${CMAKE_COMMAND}"
-    "-Dexpected_dir=${CMAKE_CURRENT_SOURCE_DIR}"
-    "-Dimport_std_not_in_export_DIR=${CMAKE_CURRENT_BINARY_DIR}"
-    ${generator}
-    -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
-    -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-build/main.cxx b/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-build/main.cxx
deleted file mode 100644
index a6dd8d8..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-build/main.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-import uses_std;
-
-int main(int argc, char* argv[])
-{
-  return f();
-}
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-install-stderr.txt b/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-install-stderr.txt
deleted file mode 100644
index 583556f..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-install-stderr.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-CMake Warning \(dev\) at .*/Modules/Compiler/CMakeCommonCompilerMacros\.cmake:[0-9]* \(cmake_language\):
-  CMake's support for `import std;` in C\+\+23 and newer is experimental\.  It
-  is meant only for experimentation and feedback to CMake developers\.
-Call Stack \(most recent call first\):
-  .*/Modules/CMakeDetermineCompilerSupport\.cmake:[0-9]* \(cmake_create_cxx_import_std\)
-  .*/Modules/CMakeTestCXXCompiler\.cmake:[0-9]* \(CMAKE_DETERMINE_COMPILER_SUPPORT\)
-  CMakeLists\.txt:[0-9]* \(project\)
-This warning is for project developers\.  Use -Wno-dev to suppress it\.
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-install/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-install/CMakeLists.txt
deleted file mode 100644
index 83fc385..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-install/CMakeLists.txt
+++ /dev/null
@@ -1,58 +0,0 @@
-set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
-  "d0edc3af-4c50-42ea-a356-e2862fe7a444")
-
-cmake_minimum_required(VERSION 3.29)
-project(cxx_modules_import_std_not_in_export CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-set(CMAKE_CXX_MODULE_STD 1)
-
-add_library(import_std_not_in_export)
-target_sources(import_std_not_in_export
-  PUBLIC
-    FILE_SET use_std TYPE CXX_MODULES FILES
-      uses-std.cxx)
-target_compile_features(import_std_not_in_export PUBLIC cxx_std_23)
-
-add_executable(main
-  main.cxx)
-target_link_libraries(main PRIVATE import_std_not_in_export)
-
-install(TARGETS import_std_not_in_export
-  EXPORT export
-  ARCHIVE DESTINATION "lib"
-  FILE_SET use_std DESTINATION "lib/cxx/miu")
-install(
-  EXPORT export
-  NAMESPACE CXXModules::
-  DESTINATION "lib/cmake/import_std_not_in_export"
-  FILE "import_std_not_in_export-targets.cmake")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/import_std_not_in_export-config.cmake"
-  "include(\"\${CMAKE_CURRENT_LIST_DIR}/import_std_not_in_export-targets.cmake\")
-set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND 1)
-")
-install(FILES "${CMAKE_CURRENT_BINARY_DIR}/import_std_not_in_export-config.cmake"
-  DESTINATION "lib/cmake/import_std_not_in_export")
-
-add_test(NAME main COMMAND main)
-
-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 import_std_not_in_export_build
-  COMMAND
-    "${CMAKE_COMMAND}"
-    "-Dexpected_dir=${CMAKE_INSTALL_PREFIX}/lib/cxx/miu"
-    "-Dimport_std_not_in_export_DIR=${CMAKE_INSTALL_PREFIX}/lib/cmake/import_std_not_in_export"
-    ${generator}
-    -S "${CMAKE_CURRENT_SOURCE_DIR}/test"
-    -B "${CMAKE_CURRENT_BINARY_DIR}/test")
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-install/main.cxx b/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-install/main.cxx
deleted file mode 100644
index a6dd8d8..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-std-not-in-export-install/main.cxx
+++ /dev/null
@@ -1,6 +0,0 @@
-import uses_std;
-
-int main(int argc, char* argv[])
-{
-  return f();
-}
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-stderr.txt b/Tests/RunCMake/CXXModules/examples/import-std-stderr.txt
deleted file mode 100644
index 583556f..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-std-stderr.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-CMake Warning \(dev\) at .*/Modules/Compiler/CMakeCommonCompilerMacros\.cmake:[0-9]* \(cmake_language\):
-  CMake's support for `import std;` in C\+\+23 and newer is experimental\.  It
-  is meant only for experimentation and feedback to CMake developers\.
-Call Stack \(most recent call first\):
-  .*/Modules/CMakeDetermineCompilerSupport\.cmake:[0-9]* \(cmake_create_cxx_import_std\)
-  .*/Modules/CMakeTestCXXCompiler\.cmake:[0-9]* \(CMAKE_DETERMINE_COMPILER_SUPPORT\)
-  CMakeLists\.txt:[0-9]* \(project\)
-This warning is for project developers\.  Use -Wno-dev to suppress it\.
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-transitive-not-in-export-build-stderr.txt b/Tests/RunCMake/CXXModules/examples/import-std-transitive-not-in-export-build-stderr.txt
deleted file mode 100644
index 583556f..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-std-transitive-not-in-export-build-stderr.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-CMake Warning \(dev\) at .*/Modules/Compiler/CMakeCommonCompilerMacros\.cmake:[0-9]* \(cmake_language\):
-  CMake's support for `import std;` in C\+\+23 and newer is experimental\.  It
-  is meant only for experimentation and feedback to CMake developers\.
-Call Stack \(most recent call first\):
-  .*/Modules/CMakeDetermineCompilerSupport\.cmake:[0-9]* \(cmake_create_cxx_import_std\)
-  .*/Modules/CMakeTestCXXCompiler\.cmake:[0-9]* \(CMAKE_DETERMINE_COMPILER_SUPPORT\)
-  CMakeLists\.txt:[0-9]* \(project\)
-This warning is for project developers\.  Use -Wno-dev to suppress it\.
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-transitive-not-in-export-install-stderr.txt b/Tests/RunCMake/CXXModules/examples/import-std-transitive-not-in-export-install-stderr.txt
deleted file mode 100644
index 583556f..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-std-transitive-not-in-export-install-stderr.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-CMake Warning \(dev\) at .*/Modules/Compiler/CMakeCommonCompilerMacros\.cmake:[0-9]* \(cmake_language\):
-  CMake's support for `import std;` in C\+\+23 and newer is experimental\.  It
-  is meant only for experimentation and feedback to CMake developers\.
-Call Stack \(most recent call first\):
-  .*/Modules/CMakeDetermineCompilerSupport\.cmake:[0-9]* \(cmake_create_cxx_import_std\)
-  .*/Modules/CMakeTestCXXCompiler\.cmake:[0-9]* \(CMAKE_DETERMINE_COMPILER_SUPPORT\)
-  CMakeLists\.txt:[0-9]* \(project\)
-This warning is for project developers\.  Use -Wno-dev to suppress it\.
diff --git a/Tests/RunCMake/CXXModules/examples/import-std-transitive/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/import-std-transitive/CMakeLists.txt
deleted file mode 100644
index 943bf8f..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-std-transitive/CMakeLists.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
-  "d0edc3af-4c50-42ea-a356-e2862fe7a444")
-
-cmake_minimum_required(VERSION 3.29)
-
-if (EXPORT_NO_STD)
-  # Block making C++ `import std` targets.
-  add_library(__CMAKE::CXX23 IMPORTED INTERFACE)
-  add_library(__CMAKE::CXX26 IMPORTED INTERFACE)
-endif ()
-
-project(cxx_modules_import_std_transitive CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-if (EXPORT_NO_STD)
-  set(package "import_std_export_no_std")
-else ()
-  set(package "import_std_not_in_export")
-endif ()
-find_package("${package}" REQUIRED)
-
-set(CMAKE_CXX_MODULE_STD 0)
-
-add_executable(main
-  main.cxx)
-target_link_libraries(main PRIVATE "CXXModules::${package}")
-
-add_test(NAME main COMMAND main)
diff --git a/Tests/RunCMake/CXXModules/examples/import-std/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/import-std/CMakeLists.txt
deleted file mode 100644
index fd15455..0000000
--- a/Tests/RunCMake/CXXModules/examples/import-std/CMakeLists.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD
-  "d0edc3af-4c50-42ea-a356-e2862fe7a444")
-
-cmake_minimum_required(VERSION 3.29)
-project(cxx_modules_import_std CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-set(CMAKE_CXX_MODULE_STD 1)
-
-add_executable(main
-  main.cxx)
-target_compile_features(main PRIVATE cxx_std_23)
-
-add_test(NAME main COMMAND main)
diff --git a/Tests/RunCMake/CXXModules/examples/library/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/library/CMakeLists.txt
deleted file mode 100644
index 97d2325..0000000
--- a/Tests/RunCMake/CXXModules/examples/library/CMakeLists.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-cmake_minimum_required(VERSION 3.24...3.28)
-project(cxx_modules_library CXX)
-
-include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
-
-include(GenerateExportHeader)
-
-add_library(library)
-generate_export_header(library)
-target_sources(library
-  PUBLIC
-    FILE_SET HEADERS
-      BASE_DIRS
-        "${CMAKE_CURRENT_BINARY_DIR}"
-      FILES
-        "${CMAKE_CURRENT_BINARY_DIR}/library_export.h"
-    FILE_SET CXX_MODULES
-      BASE_DIRS
-        "${CMAKE_CURRENT_SOURCE_DIR}"
-      FILES
-        importable.cxx)
-target_compile_features(library PUBLIC cxx_std_20)
-
-add_executable(exe)
-target_link_libraries(exe PRIVATE library)
-target_sources(exe
-  PRIVATE
-    main.cxx)
-
-add_test(NAME exe COMMAND exe)
diff --git a/Tests/RunCMake/CXXModules/examples/library/importable.cxx b/Tests/RunCMake/CXXModules/examples/library/importable.cxx
deleted file mode 100644
index 72ed0df..0000000
--- a/Tests/RunCMake/CXXModules/examples/library/importable.cxx
+++ /dev/null
@@ -1,8 +0,0 @@
-export module importable;
-
-#include "library_export.h"
-
-export LIBRARY_EXPORT int from_import()
-{
-  return 0;
-}
diff --git a/Tests/RunCMake/CXXModules/examples/public-req-private-build-result.txt b/Tests/RunCMake/CXXModules/examples/public-req-private-build-result.txt
deleted file mode 100644
index d00491f..0000000
--- a/Tests/RunCMake/CXXModules/examples/public-req-private-build-result.txt
+++ /dev/null
@@ -1 +0,0 @@
-1
diff --git a/Tests/RunCMake/CXXModules/examples/public-req-private-build-stdout.txt b/Tests/RunCMake/CXXModules/examples/public-req-private-build-stdout.txt
deleted file mode 100644
index def33fa..0000000
--- a/Tests/RunCMake/CXXModules/examples/public-req-private-build-stdout.txt
+++ /dev/null
@@ -1 +0,0 @@
-CMake Error: Public C\+\+ module source `.*/Tests/RunCMake/CXXModules/examples/public-req-private/pub\.cxx` requires the `priv` C\+\+ module which is provided by a private source
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-private.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-private.json
index dfca73e..79c0b0d 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-private.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-private.json
@@ -12,7 +12,11 @@
   "cxx-modules": {
     "CMakeFiles/ninja-bmi-install-private.dir<CONFIG_DIR>/sources/module-internal-part.cxx<OBJEXT>": {
       "bmi-only": false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
       "destination": null,
+      "include-directories" : [],
       "name": "internal_partitions",
       "relative-directory": "sources",
       "source": "<SOURCE_DIR>/sources/module-internal-part.cxx",
@@ -21,7 +25,11 @@
     },
     "CMakeFiles/ninja-bmi-install-private.dir<CONFIG_DIR>/sources/module-part.cxx<OBJEXT>": {
       "bmi-only": false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
       "destination": null,
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module-part.cxx",
@@ -30,7 +38,11 @@
     },
     "CMakeFiles/ninja-bmi-install-private.dir<CONFIG_DIR>/sources/module.cxx<OBJEXT>": {
       "bmi-only": false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
       "destination": null,
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module.cxx",
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-public.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-public.json
index 20f164a..3643e45 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-public.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-public.json
@@ -12,7 +12,11 @@
   "cxx-modules": {
     "CMakeFiles/ninja-bmi-install-public.dir<CONFIG_DIR>/sources/module-internal-part.cxx<OBJEXT>": {
       "bmi-only": false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
       "destination": "lib/cxx/internals",
+      "include-directories" : [],
       "name": "internal_partitions",
       "relative-directory": "sources",
       "source": "<SOURCE_DIR>/sources/module-internal-part.cxx",
@@ -21,7 +25,11 @@
     },
     "CMakeFiles/ninja-bmi-install-public.dir<CONFIG_DIR>/sources/module-part.cxx<OBJEXT>": {
       "bmi-only": false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
       "destination": "lib/cxx",
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module-part.cxx",
@@ -30,7 +38,11 @@
     },
     "CMakeFiles/ninja-bmi-install-public.dir<CONFIG_DIR>/sources/module.cxx<OBJEXT>": {
       "bmi-only": false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
       "destination": "lib/cxx",
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module.cxx",
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoCompileDatabase-private.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoCompileDatabase-private.json
index a4131606..6c68333 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoCompileDatabase-private.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoCompileDatabase-private.json
@@ -6,8 +6,12 @@
   "config": "<CONFIG>",
   "cxx-modules": {
     "CMakeFiles/ninja-compiledb-private.dir<CONFIG_DIR>/sources/module-internal-part.cxx<OBJEXT>": {
-      "bmi-only": false,
-      "destination": null,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
+      "destination" : null,
+      "include-directories" : [],
       "name": "internal_partitions",
       "relative-directory": "sources",
       "source": "<SOURCE_DIR>/sources/module-internal-part.cxx",
@@ -15,8 +19,12 @@
       "visibility": "PRIVATE"
     },
     "CMakeFiles/ninja-compiledb-private.dir<CONFIG_DIR>/sources/module-part.cxx<OBJEXT>": {
-      "bmi-only": false,
-      "destination": null,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
+      "destination" : null,
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module-part.cxx",
@@ -24,8 +32,12 @@
       "visibility": "PRIVATE"
     },
     "CMakeFiles/ninja-compiledb-private.dir<CONFIG_DIR>/sources/module.cxx<OBJEXT>": {
-      "bmi-only": false,
-      "destination": null,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
+      "destination" : null,
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module.cxx",
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoCompileDatabase-public.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoCompileDatabase-public.json
index 632d56b..5bff5e5 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoCompileDatabase-public.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoCompileDatabase-public.json
@@ -6,8 +6,12 @@
   "config": "<CONFIG>",
   "cxx-modules": {
     "CMakeFiles/ninja-compiledb-public.dir<CONFIG_DIR>/sources/module-internal-part.cxx<OBJEXT>": {
-      "bmi-only": false,
-      "destination": null,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
+      "destination" : null,
+      "include-directories" : [],
       "name": "internal_partitions",
       "relative-directory": "sources",
       "source": "<SOURCE_DIR>/sources/module-internal-part.cxx",
@@ -15,8 +19,12 @@
       "visibility": "PUBLIC"
     },
     "CMakeFiles/ninja-compiledb-public.dir<CONFIG_DIR>/sources/module-part.cxx<OBJEXT>": {
-      "bmi-only": false,
-      "destination": null,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
+      "destination" : null,
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module-part.cxx",
@@ -24,8 +32,12 @@
       "visibility": "PUBLIC"
     },
     "CMakeFiles/ninja-compiledb-public.dir<CONFIG_DIR>/sources/module.cxx<OBJEXT>": {
-      "bmi-only": false,
-      "destination": null,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
+      "destination" : null,
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module.cxx",
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-private.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-private.json
index 235e17d..ac422f9 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-private.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-private.json
@@ -6,8 +6,12 @@
   "config": "<CONFIG>",
   "cxx-modules": {
     "CMakeFiles/ninja-exports-private.dir<CONFIG_DIR>/sources/module-internal-part.cxx<OBJEXT>": {
-      "bmi-only": false,
-      "destination": null,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
+      "destination" : null,
+      "include-directories" : [],
       "name": "internal_partitions",
       "relative-directory": "sources",
       "source": "<SOURCE_DIR>/sources/module-internal-part.cxx",
@@ -15,8 +19,12 @@
       "visibility": "PRIVATE"
     },
     "CMakeFiles/ninja-exports-private.dir<CONFIG_DIR>/sources/module-part.cxx<OBJEXT>": {
-      "bmi-only": false,
-      "destination": null,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
+      "destination" : null,
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module-part.cxx",
@@ -24,8 +32,12 @@
       "visibility": "PRIVATE"
     },
     "CMakeFiles/ninja-exports-private.dir<CONFIG_DIR>/sources/module.cxx<OBJEXT>": {
-      "bmi-only": false,
-      "destination": null,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
+      "destination" : null,
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module.cxx",
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-public.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-public.json
index ed19dd8..bc51c66 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-public.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-public.json
@@ -6,8 +6,12 @@
   "config": "<CONFIG>",
   "cxx-modules": {
     "CMakeFiles/ninja-exports-public.dir<CONFIG_DIR>/sources/module-internal-part.cxx<OBJEXT>": {
-      "bmi-only": false,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
       "destination": "lib/cxx/internals",
+      "include-directories" : [],
       "name": "internal_partitions",
       "relative-directory": "sources",
       "source": "<SOURCE_DIR>/sources/module-internal-part.cxx",
@@ -15,8 +19,12 @@
       "visibility": "PUBLIC"
     },
     "CMakeFiles/ninja-exports-public.dir<CONFIG_DIR>/sources/module-part.cxx<OBJEXT>": {
-      "bmi-only": false,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
       "destination": "lib/cxx",
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module-part.cxx",
@@ -24,8 +32,12 @@
       "visibility": "PUBLIC"
     },
     "CMakeFiles/ninja-exports-public.dir<CONFIG_DIR>/sources/module.cxx<OBJEXT>": {
-      "bmi-only": false,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
       "destination": "lib/cxx",
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module.cxx",
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-private.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-private.json
index 22005a2..f21c433 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-private.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-private.json
@@ -6,8 +6,12 @@
   "config": "<CONFIG>",
   "cxx-modules": {
     "CMakeFiles/ninja-exports-private.dir<CONFIG_DIR>/sources/module-internal-part.cxx<OBJEXT>": {
-      "bmi-only": false,
-      "destination": null,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
+      "destination" : null,
+      "include-directories" : [],
       "name": "internal_partitions",
       "relative-directory": "sources",
       "source": "<SOURCE_DIR>/sources/module-internal-part.cxx",
@@ -15,8 +19,12 @@
       "visibility": "PRIVATE"
     },
     "CMakeFiles/ninja-exports-private.dir<CONFIG_DIR>/sources/module-part.cxx<OBJEXT>": {
-      "bmi-only": false,
-      "destination": null,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
+      "destination" : null,
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module-part.cxx",
@@ -24,8 +32,12 @@
       "visibility": "PRIVATE"
     },
     "CMakeFiles/ninja-exports-private.dir<CONFIG_DIR>/sources/module.cxx<OBJEXT>": {
-      "bmi-only": false,
-      "destination": null,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
+      "destination" : null,
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module.cxx",
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-public.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-public.json
index e9d4852..3f5b7f3 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-public.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExportFilesystemSafe-public.json
@@ -6,8 +6,12 @@
   "config": "<CONFIG>",
   "cxx-modules": {
     "CMakeFiles/ninja-exports-public.dir<CONFIG_DIR>/sources/module-internal-part.cxx<OBJEXT>": {
-      "bmi-only": false,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
       "destination": "lib/cxx/internals",
+      "include-directories" : [],
       "name": "internal_partitions",
       "relative-directory": "sources",
       "source": "<SOURCE_DIR>/sources/module-internal-part.cxx",
@@ -15,8 +19,12 @@
       "visibility": "PUBLIC"
     },
     "CMakeFiles/ninja-exports-public.dir<CONFIG_DIR>/sources/module-part.cxx<OBJEXT>": {
-      "bmi-only": false,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
       "destination": "lib/cxx",
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module-part.cxx",
@@ -24,8 +32,12 @@
       "visibility": "PUBLIC"
     },
     "CMakeFiles/ninja-exports-public.dir<CONFIG_DIR>/sources/module.cxx<OBJEXT>": {
-      "bmi-only": false,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
       "destination": "lib/cxx",
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module.cxx",
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json
index 571998f..110c351 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json
@@ -6,8 +6,12 @@
   "config": "<CONFIG>",
   "cxx-modules": {
     "CMakeFiles/ninja-file-sets-private.dir<CONFIG_DIR>/sources/module-internal-part.cxx<OBJEXT>": {
-      "bmi-only": false,
-      "destination": null,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
+      "destination" : null,
+      "include-directories" : [],
       "name": "internal_partitions",
       "relative-directory": "sources",
       "source": "<SOURCE_DIR>/sources/module-internal-part.cxx",
@@ -15,8 +19,12 @@
       "visibility": "PRIVATE"
     },
     "CMakeFiles/ninja-file-sets-private.dir<CONFIG_DIR>/sources/module-part.cxx<OBJEXT>": {
-      "bmi-only": false,
-      "destination": null,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
+      "destination" : null,
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module-part.cxx",
@@ -24,8 +32,12 @@
       "visibility": "PRIVATE"
     },
     "CMakeFiles/ninja-file-sets-private.dir<CONFIG_DIR>/sources/module.cxx<OBJEXT>": {
-      "bmi-only": false,
-      "destination": null,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
+      "destination" : null,
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module.cxx",
diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json
index 781b988..d71fffe 100644
--- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json
+++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json
@@ -6,8 +6,12 @@
   "config": "<CONFIG>",
   "cxx-modules": {
     "CMakeFiles/ninja-file-sets-public.dir<CONFIG_DIR>/sources/module-internal-part.cxx<OBJEXT>": {
-      "bmi-only": false,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
       "destination": "lib/cxx/internals",
+      "include-directories" : [],
       "name": "internal_partitions",
       "relative-directory": "sources",
       "source": "<SOURCE_DIR>/sources/module-internal-part.cxx",
@@ -15,8 +19,12 @@
       "visibility": "PUBLIC"
     },
     "CMakeFiles/ninja-file-sets-public.dir<CONFIG_DIR>/sources/module-part.cxx<OBJEXT>": {
-      "bmi-only": false,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
       "destination": "lib/cxx",
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module-part.cxx",
@@ -24,8 +32,12 @@
       "visibility": "PUBLIC"
     },
     "CMakeFiles/ninja-file-sets-public.dir<CONFIG_DIR>/sources/module.cxx<OBJEXT>": {
-      "bmi-only": false,
+      "bmi-only" : false,
+      "compile-features" : ["cxx_std_20"],
+      "compile-options" : [],
+      "definitions" : [],
       "destination": "lib/cxx",
+      "include-directories" : [],
       "name": "modules",
       "relative-directory": "",
       "source": "<SOURCE_DIR>/sources/module.cxx",
diff --git a/Tests/RunCMake/CXXModulesCompile/CMakeLists.txt b/Tests/RunCMake/CXXModulesCompile/CMakeLists.txt
new file mode 100644
index 0000000..913371f
--- /dev/null
+++ b/Tests/RunCMake/CXXModulesCompile/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.23)
+project(${RunCMake_TEST} NONE)
+
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CXXModulesCompile/Inspect.cmake b/Tests/RunCMake/CXXModulesCompile/Inspect.cmake
new file mode 100644
index 0000000..39cd6da
--- /dev/null
+++ b/Tests/RunCMake/CXXModulesCompile/Inspect.cmake
@@ -0,0 +1,24 @@
+enable_language(CXX)
+
+set(info "")
+
+# See `Modules/Compiler/MSVC-CXX.cmake` for this. If there is explicitly no
+# default, the feature list is populated to be everything.
+if (DEFINED CMAKE_CXX_STANDARD_DEFAULT AND
+    CMAKE_CXX_STANDARD_DEFAULT STREQUAL "")
+  set(CMAKE_CXX_COMPILE_FEATURES "")
+endif ()
+
+# Forward information about the C++ compile features.
+string(APPEND info "\
+set(CMAKE_CXX_COMPILE_FEATURES \"${CMAKE_CXX_COMPILE_FEATURES}\")
+set(CMAKE_MAKE_PROGRAM \"${CMAKE_MAKE_PROGRAM}\")
+set(CMAKE_CXX_COMPILER_ID \"${CMAKE_CXX_COMPILER_ID}\")
+set(CMAKE_CXX_COMPILER_VERSION \"${CMAKE_CXX_COMPILER_VERSION}\")
+set(CMAKE_CXX_OUTPUT_EXTENSION \"${CMAKE_CXX_OUTPUT_EXTENSION}\")
+set(CMAKE_CXX20_STANDARD_COMPILE_OPTION \"${CMAKE_CXX20_STANDARD_COMPILE_OPTION}\")
+set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT \"${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}\")
+set(CMAK