Merge topic 'revert-FindHDF5-library'

b5bc72574e FindHDF5: Revert "Add explicit library location instead of guessed ..."

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !7416
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8f26508..f321d33 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -275,6 +275,26 @@
     variables:
         CMAKE_CI_NO_MR: "true"
 
+t:linux-gcc-cxx-modules-ninja:
+    extends:
+        - .gcc_cxx_modules_ninja
+        - .cmake_test_linux_release
+        - .linux_builder_tags
+        - .run_dependent
+        - .needs_centos6_x86_64
+    variables:
+        CMAKE_CI_JOB_NIGHTLY: "true"
+
+t:linux-gcc-cxx-modules-ninja-multi:
+    extends:
+        - .gcc_cxx_modules_ninja_multi
+        - .cmake_test_linux_release
+        - .linux_builder_tags
+        - .run_dependent
+        - .needs_centos6_x86_64
+    variables:
+        CMAKE_CI_JOB_NIGHTLY: "true"
+
 b:fedora36-ninja:
     extends:
         - .fedora36_ninja
diff --git a/.gitlab/ci/configure_debian10_aarch64_ninja.cmake b/.gitlab/ci/configure_debian10_aarch64_ninja.cmake
index bbccbcf..08c1a1a 100644
--- a/.gitlab/ci/configure_debian10_aarch64_ninja.cmake
+++ b/.gitlab/ci/configure_debian10_aarch64_ninja.cmake
@@ -44,6 +44,7 @@
 set(CMake_TEST_FindMPI "ON" CACHE BOOL "")
 set(CMake_TEST_FindODBC "ON" CACHE BOOL "")
 set(CMake_TEST_FindOpenACC "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenAL "ON" CACHE BOOL "")
 set(CMake_TEST_FindOpenGL "ON" CACHE BOOL "")
 set(CMake_TEST_FindOpenMP_C "ON" CACHE BOOL "")
 set(CMake_TEST_FindOpenMP_CXX "ON" CACHE BOOL "")
diff --git a/.gitlab/ci/configure_debian10_ninja.cmake b/.gitlab/ci/configure_debian10_ninja.cmake
index 2fcff7a..12564fa 100644
--- a/.gitlab/ci/configure_debian10_ninja.cmake
+++ b/.gitlab/ci/configure_debian10_ninja.cmake
@@ -48,6 +48,7 @@
 set(CMake_TEST_FindMPI "ON" CACHE BOOL "")
 set(CMake_TEST_FindODBC "ON" CACHE BOOL "")
 set(CMake_TEST_FindOpenACC "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenAL "ON" CACHE BOOL "")
 set(CMake_TEST_FindOpenGL "ON" CACHE BOOL "")
 set(CMake_TEST_FindOpenMP_C "ON" CACHE BOOL "")
 set(CMake_TEST_FindOpenMP_CXX "ON" CACHE BOOL "")
diff --git a/.gitlab/ci/configure_fedora36_makefiles.cmake b/.gitlab/ci/configure_fedora36_makefiles.cmake
index c5b5190..7abc269 100644
--- a/.gitlab/ci/configure_fedora36_makefiles.cmake
+++ b/.gitlab/ci/configure_fedora36_makefiles.cmake
@@ -47,6 +47,7 @@
 set(CMake_TEST_FindMPI "ON" CACHE BOOL "")
 set(CMake_TEST_FindODBC "ON" CACHE BOOL "")
 set(CMake_TEST_FindOpenACC "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenAL "ON" CACHE BOOL "")
 set(CMake_TEST_FindOpenGL "ON" CACHE BOOL "")
 set(CMake_TEST_FindOpenMP_C "ON" CACHE BOOL "")
 set(CMake_TEST_FindOpenMP_CXX "ON" CACHE BOOL "")
diff --git a/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja.cmake b/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja.cmake
new file mode 100644
index 0000000..bf990c8
--- /dev/null
+++ b/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja.cmake
@@ -0,0 +1,4 @@
+set(CMake_TEST_MODULE_COMPILATION "named,partitions,internal_partitions" CACHE STRING "")
+set(CMake_TEST_MODULE_COMPILATION_RULES "${CMAKE_CURRENT_LIST_DIR}/cxx_modules_rules_gcc.cmake" CACHE STRING "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja_multi.cmake b/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja_multi.cmake
new file mode 100644
index 0000000..bf990c8
--- /dev/null
+++ b/.gitlab/ci/configure_linux_gcc_cxx_modules_ninja_multi.cmake
@@ -0,0 +1,4 @@
+set(CMake_TEST_MODULE_COMPILATION "named,partitions,internal_partitions" CACHE STRING "")
+set(CMake_TEST_MODULE_COMPILATION_RULES "${CMAKE_CURRENT_LIST_DIR}/cxx_modules_rules_gcc.cmake" CACHE STRING "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/cxx_modules_rules_gcc.cmake b/.gitlab/ci/cxx_modules_rules_gcc.cmake
new file mode 100644
index 0000000..d800099
--- /dev/null
+++ b/.gitlab/ci/cxx_modules_rules_gcc.cmake
@@ -0,0 +1,10 @@
+set(CMake_TEST_CXXModules_UUID "a246741c-d067-4019-a8fb-3d16b0c9d1d3")
+
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)
+string(CONCAT CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE
+  "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E -x c++ <SOURCE>"
+  " -MT <DYNDEP_FILE> -MD -MF <DEP_FILE>"
+  " -fmodules-ts -fdep-file=<DYNDEP_FILE> -fdep-output=<OBJECT> -fdep-format=trtbd"
+  " -o <PREPROCESSED_SOURCE>")
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT "gcc")
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG "-fmodules-ts -fmodule-mapper=<MODULE_MAP_FILE> -fdep-format=trtbd -x c++")
diff --git a/.gitlab/ci/docker/gcc_cxx_modules/Dockerfile b/.gitlab/ci/docker/gcc_cxx_modules/Dockerfile
new file mode 100644
index 0000000..e0af0b9
--- /dev/null
+++ b/.gitlab/ci/docker/gcc_cxx_modules/Dockerfile
@@ -0,0 +1,9 @@
+FROM fedora:36
+MAINTAINER Ben Boeckel <ben.boeckel@kitware.com>
+
+# Install build dependencies for packages.
+COPY install_deps.sh /root/install_deps.sh
+RUN sh /root/install_deps.sh
+
+COPY install_gcc.sh /root/install_gcc.sh
+RUN sh /root/install_gcc.sh
diff --git a/.gitlab/ci/docker/gcc_cxx_modules/install_deps.sh b/.gitlab/ci/docker/gcc_cxx_modules/install_deps.sh
new file mode 100755
index 0000000..b8b706b
--- /dev/null
+++ b/.gitlab/ci/docker/gcc_cxx_modules/install_deps.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+set -e
+
+dnf install -y --setopt=install_weak_deps=False \
+    gcc-c++ mpfr-devel libmpc-devel isl-devel flex bison file findutils diffutils git-core
+dnf clean all
diff --git a/.gitlab/ci/docker/gcc_cxx_modules/install_gcc.sh b/.gitlab/ci/docker/gcc_cxx_modules/install_gcc.sh
new file mode 100755
index 0000000..20ea35f
--- /dev/null
+++ b/.gitlab/ci/docker/gcc_cxx_modules/install_gcc.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+set -e
+
+readonly revision="p1689r5-cmake-ci-20220614" # 3075e510e3d29583f8886b95aff044c0474c84a5
+readonly tarball="https://github.com/mathstuf/gcc/archive/$revision.tar.gz"
+
+readonly workdir="$HOME/gcc"
+readonly srcdir="$workdir/gcc"
+readonly builddir="$workdir/build"
+readonly njobs="$( nproc )"
+
+mkdir -p "$workdir"
+cd "$workdir"
+curl -L "$tarball" > "gcc-$revision.tar.gz"
+tar xf "gcc-$revision.tar.gz"
+mv "gcc-$revision" "$srcdir"
+mkdir -p "$builddir"
+cd "$builddir"
+"$srcdir/configure" \
+    --disable-multilib \
+    --enable-languages=c,c++ \
+    --prefix="/opt/gcc-p1689"
+make "-j$njobs"
+make "-j$njobs" install-strip
+rm -rf "$workdir"
diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml
index 12fbc1e..25d5365 100644
--- a/.gitlab/os-linux.yml
+++ b/.gitlab/os-linux.yml
@@ -299,6 +299,30 @@
         CMAKE_CONFIGURATION: hip4.2_radeon
         CMAKE_GENERATOR: "Ninja Multi-Config"
 
+### C++ modules
+
+.gcc_cxx_modules_x86_64:
+    image: "kitware/cmake:ci-gcc_cxx_modules-x86_64-2022-06-21"
+
+    variables:
+        GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
+        CMAKE_ARCH: x86_64
+        CC: "/opt/gcc-p1689/bin/gcc"
+        CXX: "/opt/gcc-p1689/bin/g++"
+
+.gcc_cxx_modules_ninja:
+    extends: .gcc_cxx_modules_x86_64
+
+    variables:
+        CMAKE_CONFIGURATION: linux_gcc_cxx_modules_ninja
+
+.gcc_cxx_modules_ninja_multi:
+    extends: .gcc_cxx_modules_x86_64
+
+    variables:
+        CMAKE_CONFIGURATION: linux_gcc_cxx_modules_ninja_multi
+        CMAKE_GENERATOR: "Ninja Multi-Config"
+
 ## Tags
 
 .linux_builder_tags:
diff --git a/Auxiliary/cmake-mode.el b/Auxiliary/cmake-mode.el
index 8224d9e..2de9b98 100644
--- a/Auxiliary/cmake-mode.el
+++ b/Auxiliary/cmake-mode.el
@@ -288,6 +288,39 @@
 
 ;------------------------------------------------------------------------------
 
+(defun cmake--syntax-propertize-until-bracket-close (syntax)
+  ;; This function assumes that a previous search has matched the
+  ;; beginning of a bracket_comment or bracket_argument and that the
+  ;; second capture group has matched the equal signs between the two
+  ;; opening brackets
+  (let* ((mb (match-beginning 2))
+         (me (match-end 2))
+         (cb (format "]%s]" (buffer-substring mb me))))
+    (save-match-data
+      (if (search-forward cb end 'move)
+          (progn
+            (setq me (match-end 0))
+            (put-text-property
+             (1- me)
+             me
+             'syntax-table
+             (string-to-syntax syntax)))
+        (setq me end)))
+    (put-text-property
+     (match-beginning 1)
+     me
+     'syntax-multiline
+     t)))
+
+(defconst cmake--syntax-propertize-function
+  (syntax-propertize-rules
+   ("\\(#\\)\\[\\(=*\\)\\["
+    (1
+     (prog1 "!" (cmake--syntax-propertize-until-bracket-close "!"))))
+   ("\\(\\[\\)\\(=*\\)\\["
+    (1
+     (prog1 "|" (cmake--syntax-propertize-until-bracket-close "|"))))))
+
 ;; Syntax table for this mode.
 (defvar cmake-mode-syntax-table nil
   "Syntax table for CMake mode.")
@@ -318,7 +351,10 @@
   ; Setup indentation function.
   (set (make-local-variable 'indent-line-function) 'cmake-indent)
   ; Setup comment syntax.
-  (set (make-local-variable 'comment-start) "#"))
+  (set (make-local-variable 'comment-start) "#")
+  ;; Setup syntax propertization
+  (set (make-local-variable 'syntax-propertize-function) cmake--syntax-propertize-function)
+  (add-hook 'syntax-propertize-extend-region-functions #'syntax-propertize-multiline nil t))
 
 ;; Default cmake-mode key bindings
 (define-key cmake-mode-map "\e\C-a" #'cmake-beginning-of-defun)
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim
index e1a2885..1273c00 100644
--- a/Auxiliary/vim/syntax/cmake.vim
+++ b/Auxiliary/vim/syntax/cmake.vim
@@ -436,6 +436,7 @@
             \ XCODE_SCHEME_ENVIRONMENT
             \ XCODE_SCHEME_EXECUTABLE
             \ XCODE_SCHEME_GUARD_MALLOC
+            \ XCODE_SCHEME_LAUNCH_MODE
             \ XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP
             \ XCODE_SCHEME_MALLOC_GUARD_EDGES
             \ XCODE_SCHEME_MALLOC_SCRIBBLE
@@ -1537,6 +1538,7 @@
             \ CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE
             \ CMAKE_XCODE_SCHEME_ENVIRONMENT
             \ CMAKE_XCODE_SCHEME_GUARD_MALLOC
+            \ CMAKE_XCODE_SCHEME_LAUNCH_MODE
             \ CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP
             \ CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES
             \ CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9de5338..4d9d3ca 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,7 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-cmake_minimum_required(VERSION 3.13...3.22 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.13...3.23 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)
 
diff --git a/Help/command/FIND_XXX.txt b/Help/command/FIND_XXX.txt
index 6683edb..e5e7496 100644
--- a/Help/command/FIND_XXX.txt
+++ b/Help/command/FIND_XXX.txt
@@ -15,6 +15,7 @@
              [PATHS [path | ENV var]... ]
              [REGISTRY_VIEW (64|32|64_32|32_64|HOST|TARGET|BOTH)]
              [PATH_SUFFIXES suffix1 [suffix2 ...]]
+             [VALIDATOR function]
              [DOC "cache documentation string"]
              [NO_CACHE]
              [REQUIRED]
@@ -66,6 +67,26 @@
   Specify additional subdirectories to check below each directory
   location otherwise considered.
 
+``VALIDATOR``
+  .. versionadded:: 3.25
+
+  Specify a :command:`function` (a :command:`macro` is not an acceptable
+  choice) which will be called for each found item. The search ends when
+  the validation function returns a successful status.
+
+  The validation function expects two arguments: output variable name and item
+  value. By default, the output variable name already holds a ``TRUE`` value.
+
+  .. parsed-literal::
+
+     function (MY_CHECK output_status item)
+       if (NOT item MATCHES ...)
+         set(${output_status} FALSE PARENT_SCOPE)
+       endif()
+     endfunction()
+
+     |FIND_XXX| (result NAMES ... VALIDATOR my_check)
+
 ``DOC``
   Specify the documentation string for the ``<VAR>`` cache entry.
 
diff --git a/Help/command/target_sources.rst b/Help/command/target_sources.rst
index 1ad6c37..0c4323c 100644
--- a/Help/command/target_sources.rst
+++ b/Help/command/target_sources.rst
@@ -75,9 +75,33 @@
 Adds a file set to a target, or adds files to an existing file set. Targets
 have zero or more named file sets. Each file set has a name, a type, a scope of
 ``INTERFACE``, ``PUBLIC``, or ``PRIVATE``, one or more base directories, and
-files within those directories. The only acceptable type is ``HEADERS``. The
-optional default file sets are named after their type. The target may not be a
-custom target or :prop_tgt:`FRAMEWORK` target.
+files within those directories. The acceptable types include:
+
+``HEADERS``
+
+  Sources intended to be used via a language's ``#include`` mechanism.
+
+``CXX_MODULES``
+
+.. note ::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
+
+  Sources which contain C++ interface module or partition units (i.e., those
+  using the ``export`` keyword). This file set type may not have an
+  ``INTERFACE`` scope.
+
+``CXX_MODULE_HEADER_UNITS``
+
+.. note ::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
+
+  C++ header sources which may be imported by other C++ source code. This file
+  set type may not have an ``INTERFACE`` scope.
+
+The optional default file sets are named after their type. The target may not
+be a custom target or :prop_tgt:`FRAMEWORK` target.
 
 Files in a ``PRIVATE`` or ``PUBLIC`` file set are marked as source files for
 the purposes of IDE integration. Additionally, files in ``HEADERS`` file sets
@@ -93,16 +117,17 @@
 
   The name of the file set to create or add to. It must contain only letters,
   numbers and underscores. Names starting with a capital letter are reserved
-  for built-in file sets predefined by CMake. The only predefined set name is
-  ``HEADERS``. All other set names must not start with a capital letter or
+  for built-in file sets predefined by CMake. The only predefined set names
+  are those matching the acceptable types. All other set names must not start
+  with a capital letter or
   underscore.
 
 ``TYPE <type>``
 
-  Every file set is associated with a particular type of file. ``HEADERS``
-  is currently the only defined type and it is an error to specify anything
-  else. As a special case, if the name of the file set is ``HEADERS``, the
-  type does not need to be specified and the ``TYPE <type>`` arguments can be
+  Every file set is associated with a particular type of file. Only types
+  specified above may be used and it is an error to specify anything else. As
+  a special case, if the name of the file set is one of the types, the type
+  does not need to be specified and the ``TYPE <type>`` arguments can be
   omitted. For all other file set names, ``TYPE`` is required.
 
 ``BASE_DIRS <dirs>...``
@@ -134,6 +159,8 @@
 The following target properties are set by ``target_sources(FILE_SET)``,
 but they should not generally be manipulated directly:
 
+For file sets of type ``HEADERS``:
+
 * :prop_tgt:`HEADER_SETS`
 * :prop_tgt:`INTERFACE_HEADER_SETS`
 * :prop_tgt:`HEADER_SET`
@@ -141,17 +168,37 @@
 * :prop_tgt:`HEADER_DIRS`
 * :prop_tgt:`HEADER_DIRS_<NAME>`
 
+For file sets of type ``CXX_MODULES``:
+
+* :prop_tgt:`CXX_MODULE_SETS`
+* :prop_tgt:`INTERFACE_CXX_MODULE_SETS`
+* :prop_tgt:`CXX_MODULE_SET`
+* :prop_tgt:`CXX_MODULE_SET_<NAME>`
+* :prop_tgt:`CXX_MODULE_DIRS`
+* :prop_tgt:`CXX_MODULE_DIRS_<NAME>`
+
+For file sets of type ``CXX_MODULE_HEADER_UNITS``:
+
+* :prop_tgt:`CXX_MODULE_HEADER_UNIT_SETS`
+* :prop_tgt:`INTERFACE_CXX_MODULE_HEADER_UNIT_SETS`
+* :prop_tgt:`CXX_MODULE_HEADER_UNIT_SET`
+* :prop_tgt:`CXX_MODULE_HEADER_UNIT_SET_<NAME>`
+* :prop_tgt:`CXX_MODULE_HEADER_UNIT_DIRS`
+* :prop_tgt:`CXX_MODULE_HEADER_UNIT_DIRS_<NAME>`
+
 Target properties related to include directories are also modified by
 ``target_sources(FILE_SET)`` as follows:
 
 :prop_tgt:`INCLUDE_DIRECTORIES`
 
-  If the ``TYPE`` is ``HEADERS``, and the scope of the file set is ``PRIVATE``
-  or ``PUBLIC``, all of the ``BASE_DIRS`` of the file set are wrapped in
-  :genex:`$<BUILD_INTERFACE>` and appended to this property.
+  If the ``TYPE`` is ``HEADERS`` or ``CXX_MODULE_HEADER_UNITS``, and the scope
+  of the file set is ``PRIVATE`` or ``PUBLIC``, all of the ``BASE_DIRS`` of
+  the file set are wrapped in :genex:`$<BUILD_INTERFACE>` and appended to this
+  property.
 
 :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`
 
-  If the ``TYPE`` is ``HEADERS``, and the scope of the file set is
-  ``INTERFACE`` or ``PUBLIC``, all of the ``BASE_DIRS`` of the file set are
-  wrapped in :genex:`$<BUILD_INTERFACE>` and appended to this property.
+  If the ``TYPE`` is ``HEADERS`` or ``CXX_MODULE_HEADER_UNITS``, and the scope
+  of the file set is ``INTERFACE`` or ``PUBLIC``, all of the ``BASE_DIRS`` of
+  the file set are wrapped in :genex:`$<BUILD_INTERFACE>` and appended to this
+  property.
diff --git a/Help/dev/experimental.rst b/Help/dev/experimental.rst
index 7638d22..14e6075 100644
--- a/Help/dev/experimental.rst
+++ b/Help/dev/experimental.rst
@@ -7,6 +7,23 @@
 
 .. _`CMake Development`: README.rst
 
+Features are gated behind ``CMAKE_EXPERIMENTAL_`` variables which must be set
+to specific values in order to enable their gated behaviors. Note that the
+specific values will change over time to reinforce their experimental nature.
+When used, a warning will be generated to indicate that an experimental
+feature is in use and that the affected behavior in the project is not part of
+CMake's stability guarantees.
+
+C++20 Module APIs
+=================
+
+Variable: ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
+Value: ``17be90bd-a850-44e0-be50-448de847d652``
+
+In order to support C++20 modules, there are a number of behaviors that have
+CMake APIs to provide the required features to build and export them from a
+project.
+
 C++20 Module Dependencies
 =========================
 
@@ -40,11 +57,6 @@
 ``CMAKE_EXPERIMENTAL_CXX_SCANDEP_DEPFILE_FORMAT`` file may be set to ``msvc``
 for scandep rules which use ``msvc``-style dependency reporting.
 
-For tools which need to know the file set the source belongs to, the
-``CMAKE_EXPERIMENTAL_CXX_MODULE_SOURCE_TYPE_FLAG_<FILE_SET_TYPE>`` flag may
-be provided so that different source types can be distinguished prior to
-scanning.
-
 The module dependencies should be written in the format described
 by the `P1689r4`_ paper.
 
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index d88322c..9fb46be 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -184,6 +184,16 @@
    /prop_tgt/CUDA_STANDARD
    /prop_tgt/CUDA_STANDARD_REQUIRED
    /prop_tgt/CXX_EXTENSIONS
+   /prop_tgt/CXX_MODULE_DIRS
+   /prop_tgt/CXX_MODULE_DIRS_NAME
+   /prop_tgt/CXX_MODULE_SET
+   /prop_tgt/CXX_MODULE_SET_NAME
+   /prop_tgt/CXX_MODULE_SETS
+   /prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS
+   /prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS_NAME
+   /prop_tgt/CXX_MODULE_HEADER_UNIT_SET
+   /prop_tgt/CXX_MODULE_HEADER_UNIT_SET_NAME
+   /prop_tgt/CXX_MODULE_HEADER_UNIT_SETS
    /prop_tgt/CXX_STANDARD
    /prop_tgt/CXX_STANDARD_REQUIRED
    /prop_tgt/DEBUG_POSTFIX
@@ -202,6 +212,7 @@
    /prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD_CONFIG
    /prop_tgt/EXPORT_COMPILE_COMMANDS
    /prop_tgt/EXPORT_NAME
+   /prop_tgt/EXPORT_NO_SYSTEM
    /prop_tgt/EXPORT_PROPERTIES
    /prop_tgt/FOLDER
    /prop_tgt/Fortran_BUILDING_INSTRINSIC_MODULES
@@ -262,6 +273,8 @@
    /prop_tgt/INTERFACE_COMPILE_DEFINITIONS
    /prop_tgt/INTERFACE_COMPILE_FEATURES
    /prop_tgt/INTERFACE_COMPILE_OPTIONS
+   /prop_tgt/INTERFACE_CXX_MODULE_SETS
+   /prop_tgt/INTERFACE_CXX_MODULE_HEADER_UNIT_SETS
    /prop_tgt/INTERFACE_HEADER_SETS
    /prop_tgt/INTERFACE_HEADER_SETS_TO_VERIFY
    /prop_tgt/INTERFACE_INCLUDE_DIRECTORIES
@@ -375,6 +388,7 @@
    /prop_tgt/Swift_LANGUAGE_VERSION
    /prop_tgt/Swift_MODULE_DIRECTORY
    /prop_tgt/Swift_MODULE_NAME
+   /prop_tgt/SYSTEM
    /prop_tgt/TYPE
    /prop_tgt/UNITY_BUILD
    /prop_tgt/UNITY_BUILD_BATCH_SIZE
@@ -451,6 +465,7 @@
    /prop_tgt/XCODE_SCHEME_ENVIRONMENT
    /prop_tgt/XCODE_SCHEME_EXECUTABLE
    /prop_tgt/XCODE_SCHEME_GUARD_MALLOC
+   /prop_tgt/XCODE_SCHEME_LAUNCH_MODE
    /prop_tgt/XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP
    /prop_tgt/XCODE_SCHEME_MALLOC_GUARD_EDGES
    /prop_tgt/XCODE_SCHEME_MALLOC_SCRIBBLE
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 7c8a7fa..ce65aee 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -278,6 +278,7 @@
    /variable/CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE
    /variable/CMAKE_XCODE_SCHEME_ENVIRONMENT
    /variable/CMAKE_XCODE_SCHEME_GUARD_MALLOC
+   /variable/CMAKE_XCODE_SCHEME_LAUNCH_MODE
    /variable/CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP
    /variable/CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES
    /variable/CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE
diff --git a/Help/prop_tgt/CXX_MODULE_DIRS.rst b/Help/prop_tgt/CXX_MODULE_DIRS.rst
new file mode 100644
index 0000000..fdf3831
--- /dev/null
+++ b/Help/prop_tgt/CXX_MODULE_DIRS.rst
@@ -0,0 +1,17 @@
+CXX_MODULE_DIRS
+---------------
+
+.. note ::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
+
+Semicolon-separated list of base directories of the target's default
+C++ module set (i.e. the file set with name and type ``CXX_MODULES``). The
+property supports
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+This property is normally only set by :command:`target_sources(FILE_SET)`
+rather than being manipulated directly.
+
+See :prop_tgt:`CXX_MODULE_DIRS_<NAME>` for the list of base directories in
+other C++ module sets.
diff --git a/Help/prop_tgt/CXX_MODULE_DIRS_NAME.rst b/Help/prop_tgt/CXX_MODULE_DIRS_NAME.rst
new file mode 100644
index 0000000..8c27d45
--- /dev/null
+++ b/Help/prop_tgt/CXX_MODULE_DIRS_NAME.rst
@@ -0,0 +1,17 @@
+CXX_MODULE_DIRS_<NAME>
+----------------------
+
+.. note ::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
+
+Semicolon-separated list of base directories of the target's ``<NAME>`` C++
+module set, which has the set type ``CXX_MODULES``. The property supports
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+This property is normally only set by :command:`target_sources(FILE_SET)`
+rather than being manipulated directly.
+
+See :prop_tgt:`CXX_MODULE_DIRS` for the list of base directories in the
+default C++ module set. See :prop_tgt:`CXX_MODULE_SETS` for the file set names
+of all C++ module sets.
diff --git a/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS.rst b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS.rst
new file mode 100644
index 0000000..17e5cf0
--- /dev/null
+++ b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS.rst
@@ -0,0 +1,17 @@
+CXX_MODULE_HEADER_UNIT_DIRS
+---------------------------
+
+.. note ::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
+
+Semicolon-separated list of base directories of the target's default C++
+module header set (i.e. the file set with name and type
+``CXX_MODULE_HEADER_UNITS``). The property supports
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+This property is normally only set by :command:`target_sources(FILE_SET)`
+rather than being manipulated directly.
+
+See :prop_tgt:`CXX_MODULE_HEADER_UNIT_DIRS_<NAME>` for the list of base directories
+in other C++ module header sets.
diff --git a/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS_NAME.rst b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS_NAME.rst
new file mode 100644
index 0000000..ca30f23
--- /dev/null
+++ b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_DIRS_NAME.rst
@@ -0,0 +1,19 @@
+CXX_MODULE_HEADER_UNIT_DIRS_<NAME>
+----------------------------------
+
+.. note ::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
+
+Semicolon-separated list of base directories of the target's ``<NAME>`` C++
+module header set, which has the set type ``CXX_MODULE_HEADER_UNITS``. The
+property supports
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+This property is normally only set by :command:`target_sources(FILE_SET)`
+rather than being manipulated directly.
+
+See :prop_tgt:`CXX_MODULE_HEADER_UNIT_DIRS` for the list of base directories
+in the default C++ module header set. See
+:prop_tgt:`CXX_MODULE_HEADER_UNIT_SETS` for the file set names of all C++
+module header sets.
diff --git a/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SET.rst b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SET.rst
new file mode 100644
index 0000000..f67a848
--- /dev/null
+++ b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SET.rst
@@ -0,0 +1,18 @@
+CXX_MODULE_HEADER_UNIT_SET
+--------------------------
+
+.. note ::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
+
+Semicolon-separated list of files in the target's default C++ module header
+set, (i.e. the file set with name and type ``CXX_MODULE_HEADER_UNITS``). If
+any of the paths are relative, they are computed relative to the target's
+source directory. The property supports
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+This property is normally only set by :command:`target_sources(FILE_SET)`
+rather than being manipulated directly.
+
+See :prop_tgt:`CXX_MODULE_HEADER_UNIT_SET_<NAME>` for the list of files in
+other C++ module header sets.
diff --git a/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SETS.rst b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SETS.rst
new file mode 100644
index 0000000..7b4bd3f
--- /dev/null
+++ b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SETS.rst
@@ -0,0 +1,18 @@
+CXX_MODULE_HEADER_UNIT_SETS
+---------------------------
+
+.. note ::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
+
+Read-only list of the target's ``PRIVATE`` and ``PUBLIC`` C++ module header
+sets (i.e. all file sets with the type ``CXX_MODULE_HEADER_UNITS``). Files
+listed in these file sets are treated as source files for the purpose of IDE
+integration.
+
+C++ module header sets may be defined using the :command:`target_sources`
+command ``FILE_SET`` option with type ``CXX_MODULE_HEADER_UNITS``.
+
+See also :prop_tgt:`CXX_MODULE_HEADER_UNIT_SET_<NAME>`,
+:prop_tgt:`CXX_MODULE_HEADER_UNIT_SET` and
+:prop_tgt:`INTERFACE_CXX_MODULE_HEADER_UNIT_SETS`.
diff --git a/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SET_NAME.rst b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SET_NAME.rst
new file mode 100644
index 0000000..d328950
--- /dev/null
+++ b/Help/prop_tgt/CXX_MODULE_HEADER_UNIT_SET_NAME.rst
@@ -0,0 +1,19 @@
+CXX_MODULE_HEADER_UNIT_SET_<NAME>
+---------------------------------
+
+.. note ::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
+
+Semicolon-separated list of files in the target's ``<NAME>`` C++ module header
+set, which has the set type ``CXX_MODULE_HEADER_UNITS``. If any of the paths
+are relative, they are computed relative to the target's source directory. The
+property supports
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+This property is normally only set by :command:`target_sources(FILE_SET)`
+rather than being manipulated directly.
+
+See :prop_tgt:`CXX_MODULE_HEADER_UNIT_SET` for the list of files in the
+default C++ module header set. See :prop_tgt:`CXX_MODULE_HEADER_UNIT_SETS` for
+the file set names of all C++ module header sets.
diff --git a/Help/prop_tgt/CXX_MODULE_SET.rst b/Help/prop_tgt/CXX_MODULE_SET.rst
new file mode 100644
index 0000000..ae9000e
--- /dev/null
+++ b/Help/prop_tgt/CXX_MODULE_SET.rst
@@ -0,0 +1,18 @@
+CXX_MODULE_SET
+--------------
+
+.. note ::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
+
+Semicolon-separated list of files in the target's default C++ module set,
+(i.e. the file set with name and type ``CXX_MODULES``). If any of the paths
+are relative, they are computed relative to the target's source directory. The
+property supports
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+This property is normally only set by :command:`target_sources(FILE_SET)`
+rather than being manipulated directly.
+
+See :prop_tgt:`CXX_MODULE_SET_<NAME>` for the list of files in other C++
+module sets.
diff --git a/Help/prop_tgt/CXX_MODULE_SETS.rst b/Help/prop_tgt/CXX_MODULE_SETS.rst
new file mode 100644
index 0000000..c03df39
--- /dev/null
+++ b/Help/prop_tgt/CXX_MODULE_SETS.rst
@@ -0,0 +1,16 @@
+CXX_MODULE_SETS
+---------------
+
+.. note ::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
+
+Read-only list of the target's ``PRIVATE`` and ``PUBLIC`` C++ module sets (i.e.
+all file sets with the type ``CXX_MODULES``). Files listed in these file sets are
+treated as source files for the purpose of IDE integration.
+
+C++ module sets may be defined using the :command:`target_sources` command
+``FILE_SET`` option with type ``CXX_MODULES``.
+
+See also :prop_tgt:`CXX_MODULE_SET_<NAME>`, :prop_tgt:`CXX_MODULE_SET` and
+:prop_tgt:`INTERFACE_CXX_MODULE_SETS`.
diff --git a/Help/prop_tgt/CXX_MODULE_SET_NAME.rst b/Help/prop_tgt/CXX_MODULE_SET_NAME.rst
new file mode 100644
index 0000000..27c88f3
--- /dev/null
+++ b/Help/prop_tgt/CXX_MODULE_SET_NAME.rst
@@ -0,0 +1,18 @@
+CXX_MODULE_SET_<NAME>
+---------------------
+
+.. note ::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
+
+Semicolon-separated list of files in the target's ``<NAME>`` C++ module set,
+which has the set type ``CXX_MODULES``. If any of the paths are relative, they
+are computed relative to the target's source directory. The property supports
+:manual:`generator expressions <cmake-generator-expressions(7)>`.
+
+This property is normally only set by :command:`target_sources(FILE_SET)`
+rather than being manipulated directly.
+
+See :prop_tgt:`CXX_MODULE_SET` for the list of files in the default C++ module
+set. See :prop_tgt:`CXX_MODULE_SETS` for the file set names of all C++ module
+sets.
diff --git a/Help/prop_tgt/EXPORT_NO_SYSTEM.rst b/Help/prop_tgt/EXPORT_NO_SYSTEM.rst
new file mode 100644
index 0000000..c93d1a5
--- /dev/null
+++ b/Help/prop_tgt/EXPORT_NO_SYSTEM.rst
@@ -0,0 +1,11 @@
+EXPORT_NO_SYSTEM
+----------------
+
+.. versionadded:: 3.25
+
+Specifies that :command:`install(EXPORT)` and :command:`export` commands will
+generate a imported target with :prop_tgt:`SYSTEM` property `OFF`.
+
+See the :prop_tgt:`NO_SYSTEM_FROM_IMPORTED` target property to set this
+behavior on the target consuming the include directories rather than
+providing them.
diff --git a/Help/prop_tgt/IMPORTED_NO_SYSTEM.rst b/Help/prop_tgt/IMPORTED_NO_SYSTEM.rst
index ee22d6f..913d9f2 100644
--- a/Help/prop_tgt/IMPORTED_NO_SYSTEM.rst
+++ b/Help/prop_tgt/IMPORTED_NO_SYSTEM.rst
@@ -3,11 +3,21 @@
 
 .. versionadded:: 3.23
 
+.. deprecated:: 3.25
+
+  ``IMPORTED_NO_SYSTEM`` is deprecated. Set :prop_tgt:`SYSTEM` to `OFF`
+  instead if you don't want target's include directories to be ``SYSTEM``
+  when compiling consumers. Set :prop_tgt:`EXPORT_NO_SYSTEM` to `ON` instead
+  if you don't want the include directories of the imported target generated
+  by :command:`install(EXPORT)` and :command:`export` commands to be
+  ``SYSTEM`` when compiling consumers.
+
 Specifies that an :ref:`Imported Target <Imported Targets>` is not
 a ``SYSTEM`` library.  This has the following effects:
 
 * Entries of :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` are not treated
-  as ``SYSTEM`` include directories when compiling consumers, as they
+  as ``SYSTEM`` include directories when compiling consumers (regardless of
+  the value of the consumed target's :prop_tgt:`SYSTEM` property), as they
   would be by default.   Entries of
   :prop_tgt:`INTERFACE_SYSTEM_INCLUDE_DIRECTORIES` are not affected,
   and will always be treated as ``SYSTEM`` include directories.
diff --git a/Help/prop_tgt/INTERFACE_CXX_MODULE_HEADER_UNIT_SETS.rst b/Help/prop_tgt/INTERFACE_CXX_MODULE_HEADER_UNIT_SETS.rst
new file mode 100644
index 0000000..eb3a9ff
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_CXX_MODULE_HEADER_UNIT_SETS.rst
@@ -0,0 +1,16 @@
+INTERFACE_CXX_MODULE_HEADER_UNIT_SETS
+-------------------------------------
+
+.. note ::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
+
+Read-only list of the target's ``PUBLIC`` C++ module header sets (i.e. all
+file sets with the type ``CXX_MODULE_HEADER_UNITS``). Files listed in these
+C++ module header sets can be installed with :command:`install(TARGETS)` and
+exported with :command:`install(EXPORT)` and :command:`export`.
+
+C++ module header sets may be defined using the :command:`target_sources`
+command ``FILE_SET`` option with type ``CXX_MODULE_HEADER_UNITS``.
+
+See also :prop_tgt:`CXX_MODULE_HEADER_UNIT_SETS`.
diff --git a/Help/prop_tgt/INTERFACE_CXX_MODULE_SETS.rst b/Help/prop_tgt/INTERFACE_CXX_MODULE_SETS.rst
new file mode 100644
index 0000000..cc30386
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_CXX_MODULE_SETS.rst
@@ -0,0 +1,16 @@
+INTERFACE_CXX_MODULE_SETS
+-------------------------
+
+.. note ::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API``
+
+Read-only list of the target's ``PUBLIC`` C++ module sets (i.e. all file sets
+with the type ``CXX_MODULES``). Files listed in these C++ module sets can be
+installed with :command:`install(TARGETS)` and exported with
+:command:`install(EXPORT)` and :command:`export`.
+
+C++ module sets may be defined using the :command:`target_sources` command
+``FILE_SET`` option with type ``CXX_MODULES``.
+
+See also :prop_tgt:`CXX_MODULE_SETS`.
diff --git a/Help/prop_tgt/SYSTEM.rst b/Help/prop_tgt/SYSTEM.rst
new file mode 100644
index 0000000..2db6aed
--- /dev/null
+++ b/Help/prop_tgt/SYSTEM.rst
@@ -0,0 +1,16 @@
+SYSTEM
+------
+
+.. versionadded:: 3.25
+
+Specifies that a target is a ``SYSTEM`` library.  This has the following effects:
+
+* Entries of :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` are treated as ``SYSTEM``
+  include directories when compiling consumers.
+  Entries of :prop_tgt:`INTERFACE_SYSTEM_INCLUDE_DIRECTORIES` are not affected,
+  and will always be treated as ``SYSTEM`` include directories.
+
+For imported targets, this property has a default value `ON`, which means that their
+`INTERFACE_INCLUDE_DIRECTORIES` are treated as ``SYSTEM`` by default. If their
+`SYSTEM` property is `OFF`, then their `INTERFACE_INCLUDE_DIRECTORIES` will not be
+treated as ``SYSTEM``, regardless of the value of `IMPORTED_NO_SYSTEM` property.
diff --git a/Help/prop_tgt/XCODE_GENERATE_SCHEME.rst b/Help/prop_tgt/XCODE_GENERATE_SCHEME.rst
index 8f46d2f..eceddc1 100644
--- a/Help/prop_tgt/XCODE_GENERATE_SCHEME.rst
+++ b/Help/prop_tgt/XCODE_GENERATE_SCHEME.rst
@@ -41,4 +41,5 @@
 - :prop_tgt:`XCODE_SCHEME_ENABLE_GPU_FRAME_CAPTURE_MODE`
 - :prop_tgt:`XCODE_SCHEME_ENVIRONMENT`
 - :prop_tgt:`XCODE_SCHEME_EXECUTABLE`
+- :prop_tgt:`XCODE_SCHEME_LAUNCH_MODE`
 - :prop_tgt:`XCODE_SCHEME_WORKING_DIRECTORY`
diff --git a/Help/prop_tgt/XCODE_SCHEME_LAUNCH_MODE.rst b/Help/prop_tgt/XCODE_SCHEME_LAUNCH_MODE.rst
new file mode 100644
index 0000000..df5ae07
--- /dev/null
+++ b/Help/prop_tgt/XCODE_SCHEME_LAUNCH_MODE.rst
@@ -0,0 +1,22 @@
+XCODE_SCHEME_LAUNCH_MODE
+------------------------
+
+.. versionadded:: 3.25
+
+Property value for ``Launch`` in the Info section of the generated Xcode
+scheme.
+
+Possible values are:
+
+``AUTO``
+  Launch automatically. This is the default.
+
+``WAIT``
+  Wait for the executable to be launched.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_XCODE_SCHEME_LAUNCH_MODE` if it is set when a target is
+created.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Help/release/dev/0-sample-topic.rst b/Help/release/dev/0-sample-topic.rst
new file mode 100644
index 0000000..e4cc01e
--- /dev/null
+++ b/Help/release/dev/0-sample-topic.rst
@@ -0,0 +1,7 @@
+0-sample-topic
+--------------
+
+* This is a sample release note for the change in a topic.
+  Developers should add similar notes for each topic branch
+  making a noteworthy change.  Each document should be named
+  and titled to match the topic name to avoid merge conflicts.
diff --git a/Help/release/dev/find_item-VALIDATOR.rst b/Help/release/dev/find_item-VALIDATOR.rst
new file mode 100644
index 0000000..2cda421
--- /dev/null
+++ b/Help/release/dev/find_item-VALIDATOR.rst
@@ -0,0 +1,6 @@
+find_item-VALIDATOR
+-------------------
+
+* :command:`find_file`, :command:`find_path`, :command:`find_library`, and
+  :command:`find_program` commands gain the capability to specify a function
+  which will be called for each found item to validate it.
diff --git a/Help/release/dev/findopenal-add-import-library.rst b/Help/release/dev/findopenal-add-import-library.rst
new file mode 100644
index 0000000..6c9c93f
--- /dev/null
+++ b/Help/release/dev/findopenal-add-import-library.rst
@@ -0,0 +1,4 @@
+findopenal-add-import-library
+-----------------------------
+
+* The :module:`FindOpenAL` module now provides an imported target.
diff --git a/Help/release/dev/findvulkan-volk.rst b/Help/release/dev/findvulkan-volk.rst
new file mode 100644
index 0000000..cb77078
--- /dev/null
+++ b/Help/release/dev/findvulkan-volk.rst
@@ -0,0 +1,5 @@
+findvulkan-volk
+---------------
+
+* The :module:`FindVulkan` module now includes a ``volk`` component
+  for the Volk open source vulkan meta-loader.
diff --git a/Help/release/dev/system.rst b/Help/release/dev/system.rst
new file mode 100644
index 0000000..7cc841e
--- /dev/null
+++ b/Help/release/dev/system.rst
@@ -0,0 +1,15 @@
+system
+------
+
+* The :prop_tgt:`SYSTEM` target property was added to specify
+  that a target should be treated as a system library (i.e.
+  its include directories are automatically ``SYSTEM`` when
+  compiling consumers).
+
+* The :prop_tgt:`EXPORT_NO_SYSTEM` target property was added to
+  specify that :command:`install(EXPORT)` and :command:`export`
+  commands will generate a imported target with
+  :prop_tgt:`SYSTEM` property `OFF`.
+
+* The :prop_tgt:`IMPORTED_NO_SYSTEM` target property was deprecated
+  in favor of :prop_tgt:`SYSTEM` and :prop_tgt:`EXPORT_NO_SYSTEM`.
diff --git a/Help/release/dev/xcode-launch-mode.rst b/Help/release/dev/xcode-launch-mode.rst
new file mode 100644
index 0000000..32b9ee6
--- /dev/null
+++ b/Help/release/dev/xcode-launch-mode.rst
@@ -0,0 +1,7 @@
+xcode-launch-mode
+-----------------
+
+* The :variable:`CMAKE_XCODE_SCHEME_LAUNCH_MODE` variable and corresponding
+  :prop_tgt:`XCODE_SCHEME_LAUNCH_MODE` target property were added to tell
+  the :generator:`Xcode` generator what to put in the scheme's "Launch"
+  mode setting.
diff --git a/Help/release/index.rst b/Help/release/index.rst
index 4dfac8a..11d5a11 100644
--- a/Help/release/index.rst
+++ b/Help/release/index.rst
@@ -7,6 +7,8 @@
   This file should include the adjacent "dev.txt" file
   in development versions but not in release versions.
 
+.. include:: dev.txt
+
 Releases
 ========
 
diff --git a/Help/variable/CMAKE_OSX_VARIABLE.txt b/Help/variable/CMAKE_OSX_VARIABLE.txt
index 16f3c1a..5670980 100644
--- a/Help/variable/CMAKE_OSX_VARIABLE.txt
+++ b/Help/variable/CMAKE_OSX_VARIABLE.txt
@@ -3,7 +3,8 @@
 because it may influence configuration of the toolchain and flags.
 It is intended to be set locally by the user creating a build tree.
 This variable should be set as a ``CACHE`` entry (or else CMake may
-remove it while initializing a cache entry of the same name).
+remove it while initializing a cache entry of the same name) unless
+policy :policy:`CMP0126` is set to ``NEW``.
 
 Despite the ``OSX`` part in the variable name(s) they apply also to
 other SDKs than macOS like iOS, tvOS, or watchOS.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_LAUNCH_MODE.rst b/Help/variable/CMAKE_XCODE_SCHEME_LAUNCH_MODE.rst
new file mode 100644
index 0000000..c15b1ea
--- /dev/null
+++ b/Help/variable/CMAKE_XCODE_SCHEME_LAUNCH_MODE.rst
@@ -0,0 +1,13 @@
+CMAKE_XCODE_SCHEME_LAUNCH_MODE
+------------------------------
+
+.. versionadded:: 3.25
+
+Property value for ``Launch`` in the Info section of the generated Xcode
+scheme.
+
+This variable initializes the :prop_tgt:`XCODE_SCHEME_LAUNCH_MODE` property on
+all targets.
+
+Please refer to the :prop_tgt:`XCODE_GENERATE_SCHEME` target property
+documentation to see all Xcode schema related properties.
diff --git a/Modules/Compiler/NVIDIA-CUDA.cmake b/Modules/Compiler/NVIDIA-CUDA.cmake
index 2f12b43..892df90 100644
--- a/Modules/Compiler/NVIDIA-CUDA.cmake
+++ b/Modules/Compiler/NVIDIA-CUDA.cmake
@@ -127,15 +127,19 @@
 
 endif()
 
-# FIXME: investigate use of --options-file.
-# Tell Makefile generator that nvcc does not support @<rspfile> syntax.
-set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_INCLUDES 0)
-set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LIBRARIES 0)
-set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_OBJECTS 0)
-
 if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "9.0")
   set(CMAKE_CUDA_RESPONSE_FILE_DEVICE_LINK_FLAG "--options-file ")
   set(CMAKE_CUDA_RESPONSE_FILE_FLAG "--options-file ")
 endif()
 
+if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "11.0")
+  set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_INCLUDES 1)
+  set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LIBRARIES 1)
+  set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_OBJECTS 1)
+else()
+  set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_INCLUDES 0)
+  set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LIBRARIES 0)
+  set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_OBJECTS 0)
+endif()
+
 __compiler_check_default_language_standard(CUDA 6.0 03)
diff --git a/Modules/FindBLAS.cmake b/Modules/FindBLAS.cmake
index 7a381af..d02c589 100644
--- a/Modules/FindBLAS.cmake
+++ b/Modules/FindBLAS.cmake
@@ -35,6 +35,12 @@
   if set ``pkg-config`` will be used to search for a BLAS library first
   and if one is found that is preferred
 
+``BLA_PKGCONFIG_BLAS``
+  .. versionadded:: 3.25
+
+  If set, the ``pkg-config`` method will look for this module name instead of
+  just ``blas``.
+
 ``BLA_SIZEOF_INTEGER``
   .. versionadded:: 3.22
 
@@ -273,8 +279,11 @@
 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 
 if(BLA_PREFER_PKGCONFIG)
+  if(NOT BLA_PKGCONFIG_BLAS)
+    set(BLA_PKGCONFIG_BLAS "blas")
+  endif()
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PKGC_BLAS QUIET blas)
+  pkg_check_modules(PKGC_BLAS QUIET ${BLA_PKGCONFIG_BLAS})
   if(PKGC_BLAS_FOUND)
     set(BLAS_FOUND ${PKGC_BLAS_FOUND})
     set(BLAS_LIBRARIES "${PKGC_BLAS_LINK_LIBRARIES}")
diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake
index af5f798..470111f 100644
--- a/Modules/FindCUDA.cmake
+++ b/Modules/FindCUDA.cmake
@@ -799,7 +799,9 @@
   unset(CUDA_VERSION CACHE)
 endif()
 
-if(NOT "${CUDA_TOOLKIT_TARGET_DIR}" STREQUAL "${CUDA_TOOLKIT_TARGET_DIR_INTERNAL}")
+# If CUDA_TOOLKIT_TARGET_DIR exists, check if it has changed.
+if(DEFINED CUDA_TOOLKIT_TARGET_DIR
+    AND NOT "${CUDA_TOOLKIT_TARGET_DIR}" STREQUAL "${CUDA_TOOLKIT_TARGET_DIR_INTERNAL}")
   cuda_unset_include_and_libraries()
 endif()
 
diff --git a/Modules/FindGLEW.cmake b/Modules/FindGLEW.cmake
index b9ebe08..a0fda1f 100644
--- a/Modules/FindGLEW.cmake
+++ b/Modules/FindGLEW.cmake
@@ -68,6 +68,30 @@
 
 if(GLEW_FOUND)
   find_package_handle_standard_args(GLEW DEFAULT_MSG GLEW_CONFIG)
+  get_target_property(GLEW_INCLUDE_DIRS GLEW::GLEW INTERFACE_INCLUDE_DIRECTORIES)
+  set(GLEW_INCLUDE_DIR ${GLEW_INCLUDE_DIRS})
+  get_target_property(_GLEW_DEFS GLEW::GLEW INTERFACE_COMPILE_DEFINITIONS)
+  if("${_GLEW_DEFS}" MATCHES "GLEW_STATIC")
+    get_target_property(GLEW_LIBRARY_DEBUG GLEW::GLEW IMPORTED_LOCATION_DEBUG)
+    get_target_property(GLEW_LIBRARY_RELEASE GLEW::GLEW IMPORTED_LOCATION_RELEASE)
+  else()
+    get_target_property(GLEW_LIBRARY_DEBUG GLEW::GLEW IMPORTED_IMPLIB_DEBUG)
+    get_target_property(GLEW_LIBRARY_RELEASE GLEW::GLEW IMPORTED_IMPLIB_RELEASE)
+  endif()
+  get_target_property(_GLEW_LINK_INTERFACE GLEW::GLEW IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE) # same for debug and release
+  list(APPEND GLEW_LIBRARIES ${_GLEW_LINK_INTERFACE})
+  list(APPEND GLEW_LIBRARY ${_GLEW_LINK_INTERFACE})
+  select_library_configurations(GLEW)
+  if("${_GLEW_DEFS}" MATCHES "GLEW_STATIC")
+    set(GLEW_STATIC_LIBRARIES ${GLEW_LIBRARIES})
+  else()
+    set(GLEW_SHARED_LIBRARIES ${GLEW_LIBRARIES})
+  endif()
+  unset(_GLEW_DEFS)
+  unset(_GLEW_LINK_INTERFACE)
+  unset(GLEW_LIBRARY)
+  unset(GLEW_LIBRARY_DEBUG)
+  unset(GLEW_LIBRARY_RELEASE)
   return()
 endif()
 
diff --git a/Modules/FindLAPACK.cmake b/Modules/FindLAPACK.cmake
index 50d4ebd..699ab7e 100644
--- a/Modules/FindLAPACK.cmake
+++ b/Modules/FindLAPACK.cmake
@@ -35,6 +35,13 @@
   if set ``pkg-config`` will be used to search for a LAPACK library first
   and if one is found that is preferred
 
+``BLA_PKGCONFIG_LAPACK``
+  .. versionadded:: 3.25
+
+  If set, the ``pkg-config`` method will look for this module name instead of
+  just ``lapack``.
+
+
 ``BLA_SIZEOF_INTEGER``
   .. versionadded:: 3.22
 
@@ -278,8 +285,11 @@
 
 # Search with pkg-config if specified
 if(BLA_PREFER_PKGCONFIG)
+  if(NOT BLA_PKGCONFIG_LAPACK)
+    set(BLA_PKGCONFIG_LAPACK "lapack")
+  endif()
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PKGC_LAPACK QUIET lapack)
+  pkg_check_modules(PKGC_LAPACK QUIET ${BLA_PKGCONFIG_LAPACK})
   if(PKGC_LAPACK_FOUND)
     set(LAPACK_FOUND TRUE)
     set(LAPACK_LIBRARIES "${PKGC_LAPACK_LINK_LIBRARIES}")
diff --git a/Modules/FindOpenAL.cmake b/Modules/FindOpenAL.cmake
index b5b92c5..53aafdc 100644
--- a/Modules/FindOpenAL.cmake
+++ b/Modules/FindOpenAL.cmake
@@ -29,6 +29,16 @@
 5. Manually compiled framework: ``/Library/Frameworks``.
 6. Add-on package: ``/opt``.
 
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.25
+
+This module defines the :prop_tgt:`IMPORTED` target:
+
+``OpenAL::OpenAL``
+  The OpenAL library, if found.
+
 Result Variables
 ^^^^^^^^^^^^^^^^
 
@@ -94,3 +104,19 @@
   )
 
 mark_as_advanced(OPENAL_LIBRARY OPENAL_INCLUDE_DIR)
+
+if(OPENAL_INCLUDE_DIR AND OPENAL_LIBRARY)
+  if(NOT TARGET OpenAL::OpenAL)
+    if(EXISTS "${OPENAL_LIBRARY}")
+      add_library(OpenAL::OpenAL UNKNOWN IMPORTED)
+      set_target_properties(OpenAL::OpenAL PROPERTIES
+        IMPORTED_LOCATION "${OPENAL_LIBRARY}")
+    else()
+      add_library(OpenAL::OpenAL INTERFACE IMPORTED)
+      set_target_properties(OpenAL::OpenAL PROPERTIES
+        IMPORTED_LIBNAME "${OPENAL_LIBRARY}")
+    endif()
+    set_target_properties(OpenAL::OpenAL PROPERTIES
+      INTERFACE_INCLUDE_DIRECTORIES "${OPENAL_INCLUDE_DIR}")
+  endif()
+endif()
diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake
index 8e98500..a8accae 100644
--- a/Modules/FindPython/Support.cmake
+++ b/Modules/FindPython/Support.cmake
@@ -14,6 +14,8 @@
 cmake_policy (SET CMP0012 NEW)
 # IN_LIST operator
 cmake_policy (SET CMP0057 NEW)
+# registry view behavior
+cmake_policy (SET CMP0134 NEW)
 
 if (NOT DEFINED _PYTHON_PREFIX)
   message (FATAL_ERROR "FindPython: INTERNAL ERROR")
@@ -175,30 +177,31 @@
       foreach (version IN LISTS _PGR_VERSION)
         string (REPLACE "." "" version_no_dots ${version})
         list (APPEND registries
-                     [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${version}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
-                     [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${version}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath])
+                     [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}-${_${_PYTHON_PREFIX}_ARCH}/InstallPath]
+                     [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}-${_${_PYTHON_PREFIX}_ARCH2}/InstallPath])
         if (version VERSION_GREATER_EQUAL "3.5")
+          # cmake_host_system_information is not usable in bootstrap
           get_filename_component (arch "[HKEY_CURRENT_USER\\Software\\Python\\PythonCore\\${version};SysArchitecture]" NAME)
           if (arch MATCHES "(${_${_PYTHON_PREFIX}_ARCH}|${_${_PYTHON_PREFIX}_ARCH2})bit")
             list (APPEND registries
-                         [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${version}\\InstallPath])
+                         [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}/InstallPath])
           endif()
         else()
           list (APPEND registries
-                       [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${version}\\InstallPath])
+                       [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}/InstallPath])
         endif()
         list (APPEND registries
-                     [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
-                     [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
-                     [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${version}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
-                     [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${version}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
-                     [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${version}\\InstallPath]
-                     [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
-                     [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath])
+                     [HKEY_CURRENT_USER/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH}/InstallPath]
+                     [HKEY_CURRENT_USER/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH2}/InstallPath]
+                     [HKEY_LOCAL_MACHINE/SOFTWARE/Python/PythonCore/${version}-${_${_PYTHON_PREFIX}_ARCH}/InstallPath]
+                     [HKEY_LOCAL_MACHINE/SOFTWARE/Python/PythonCore/${version}-${_${_PYTHON_PREFIX}_ARCH2}/InstallPath]
+                     [HKEY_LOCAL_MACHINE/SOFTWARE/Python/PythonCore/${version}/InstallPath]
+                     [HKEY_LOCAL_MACHINE/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH}/InstallPath]
+                     [HKEY_LOCAL_MACHINE/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH2}/InstallPath])
       endforeach()
     elseif (implementation STREQUAL "IronPython")
       foreach (version  IN LISTS _PGR_VERSION)
-        list (APPEND registries [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${version}\\InstallPath])
+        list (APPEND registries [HKEY_LOCAL_MACHINE/SOFTWARE/IronPython/${version}/InstallPath])
       endforeach()
     endif()
   endforeach()
@@ -711,7 +714,7 @@
 
   if (_PVI_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_EXECUTABLE}")
     # interpreter does not exist anymore
-    set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot find the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+    set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Cannot find the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
     set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
     return()
   endif()
@@ -732,7 +735,7 @@
     endif()
     if (NOT abi IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
       # incompatible ABI
-      set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong ABI for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+      set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Wrong ABI for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
       set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
       return()
     endif()
@@ -748,7 +751,7 @@
                      OUTPUT_STRIP_TRAILING_WHITESPACE)
     if (result)
       # interpreter is not usable
-      set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+      set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
       set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
       return()
     endif()
@@ -773,7 +776,7 @@
 
       if (_PVI_EXACT AND NOT version VERSION_EQUAL _PVI_VERSION)
         # interpreter has wrong version
-        set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+        set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
         set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
         return()
       else()
@@ -782,7 +785,7 @@
         string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" expected_major_version "${_PVI_VERSION}")
         if (NOT major_version VERSION_EQUAL expected_major_version
             OR NOT version VERSION_GREATER_EQUAL _PVI_VERSION)
-          set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+          set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
           set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
           return()
         endif()
@@ -794,7 +797,7 @@
       find_package_check_version ("${version}" in_range HANDLE_VERSION_RANGE)
       if (NOT in_range)
         # interpreter has invalid version
-        set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+        set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
         set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
         return()
       endif()
@@ -813,9 +816,9 @@
       if (result OR NOT version EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
         # interpreter not usable or has wrong major version
         if (result)
-          set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+          set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
         else()
-          set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong major version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+          set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Wrong major version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
         endif()
         set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
         return()
@@ -836,9 +839,9 @@
     if (result OR NOT size EQUAL CMAKE_SIZEOF_VOID_P)
       # interpreter not usable or has wrong architecture
       if (result)
-        set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+        set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
       else()
-        set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong architecture for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE)
+        set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Wrong architecture for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
       endif()
       set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
       return()
@@ -846,6 +849,14 @@
   endif()
 endfunction()
 
+function(_python_validate_find_interpreter status interpreter)
+  set(_${_PYTHON_PREFIX}_EXECUTABLE "${interpreter}" CACHE FILEPATH "" FORCE)
+  _python_validate_interpreter (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+  if (NOT _${_PYTHON_PREFIX}_EXECUTABLE)
+    set (${status} FALSE PARENT_SCOPE)
+  endif()
+endfunction()
+
 
 function (_PYTHON_VALIDATE_COMPILER)
   if (NOT _${_PYTHON_PREFIX}_COMPILER)
@@ -856,7 +867,7 @@
 
   if (_PVC_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_COMPILER}")
     # Compiler does not exist anymore
-    set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Cannot find the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE)
+    set_property (CACHE _${_PYTHON_PREFIX}_Compiler_REASON_FAILURE PROPERTY VALUE "Cannot find the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
     set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
     return()
   endif()
@@ -883,7 +894,7 @@
   file (REMOVE_RECURSE "${working_dir}")
   if (result)
     # compiler is not usable
-    set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Cannot use the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE)
+    set_property (CACHE _${_PYTHON_PREFIX}_Compiler_REASON_FAILURE PROPERTY VALUE "Cannot use the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
     set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
     return()
   endif()
@@ -909,7 +920,7 @@
 
       if (_PVC_EXACT AND NOT version VERSION_EQUAL _PVC_VERSION)
         # interpreter has wrong version
-        set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE)
+        set_property (CACHE _${_PYTHON_PREFIX}_Compiler_REASON_FAILURE PROPERTY VALUE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
         set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
         return()
       else()
@@ -918,7 +929,7 @@
         string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" expected_major_version "${_PVC_VERSION}")
         if (NOT major_version VERSION_EQUAL expected_major_version
             OR NOT version VERSION_GREATER_EQUAL _PVC_VERSION)
-          set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE)
+          set_property (CACHE _${_PYTHON_PREFIX}_Compiler_REASON_FAILURE PROPERTY VALUE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
           set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
           return()
         endif()
@@ -930,7 +941,7 @@
       find_package_check_version ("${version}" in_range HANDLE_VERSION_RANGE)
       if (NOT in_range)
         # interpreter has invalid version
-        set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE)
+        set_property (CACHE _${_PYTHON_PREFIX}_Compiler_REASON_FAILURE PROPERTY VALUE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
         set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
         return()
       endif()
@@ -939,13 +950,21 @@
     string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" major_version "${version}")
     if (NOT major_version EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
       # Compiler has wrong major version
-      set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong major version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE)
+      set_property (CACHE _${_PYTHON_PREFIX}_Compiler_REASON_FAILURE PROPERTY VALUE "Wrong major version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
       set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
       return()
     endif()
   endif()
 endfunction()
 
+function(_python_validate_find_compiler status compiler)
+  set(_${_PYTHON_PREFIX}_COMPILER "${compiler}" CACHE FILEPATH "" FORCE)
+  _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+  if (NOT _${_PYTHON_PREFIX}_COMPILER)
+    set (${status} FALSE PARENT_SCOPE)
+  endif()
+endfunction()
+
 
 function (_PYTHON_VALIDATE_LIBRARY)
   if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
@@ -957,7 +976,7 @@
 
   if (_PVL_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
     # library does not exist anymore
-    set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE)
+    set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
     set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
     if (WIN32)
       set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_DEBUG PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_DEBUG-NOTFOUND")
@@ -971,7 +990,7 @@
 
   if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT lib_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
     # incompatible ABI
-    set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong ABI for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE)
+    set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Wrong ABI for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
     set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
   else()
     if (_PVL_VERSION OR _PVL_IN_RANGE)
@@ -980,7 +999,7 @@
         string (REGEX MATCH "[0-9](\\.[0-9]+)?" version "${_PVL_VERSION}")
         if ((_PVL_EXACT AND NOT lib_VERSION VERSION_EQUAL version) OR (lib_VERSION VERSION_LESS version))
           # library has wrong version
-          set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE)
+          set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
           set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
         endif()
       endif()
@@ -990,14 +1009,14 @@
         find_package_check_version ("${lib_VERSION}" in_range HANDLE_VERSION_RANGE)
         if (NOT in_range)
           # library has wrong version
-          set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE)
+          set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
           set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
         endif()
       endif()
     else()
       if (NOT lib_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
         # library has wrong major version
-        set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong major version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE)
+        set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Wrong major version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
         set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
       endif()
     endif()
@@ -1023,7 +1042,7 @@
 
   if (_PVID_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}")
     # include file does not exist anymore
-    set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE)
+    set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
     set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
     return()
   endif()
@@ -1033,14 +1052,14 @@
 
   if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT inc_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
     # incompatible ABI
-    set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong ABI for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE)
+    set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Wrong ABI for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
     set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
   else()
     if (_PVID_VERSION OR _PVID_IN_RANGE)
       if (_PVID_VERSION)
         if ((_PVID_EXACT AND NOT inc_VERSION VERSION_EQUAL expected_version) OR (inc_VERSION VERSION_LESS expected_version))
           # include dir has wrong version
-          set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE)
+          set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
           set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
         endif()
       endif()
@@ -1050,14 +1069,14 @@
         find_package_check_version ("${inc_VERSION}" in_range HANDLE_VERSION_RANGE)
         if (NOT in_range)
           # include dir has wrong version
-          set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE)
+          set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
           set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
         endif()
       endif()
     else()
       if (NOT inc_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
         # include dir has wrong major version
-        set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong major version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE)
+        set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Wrong major version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
         set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
       endif()
     endif()
@@ -1247,12 +1266,14 @@
 endif()
 
 # Python and Anaconda distributions: define which architectures can be used
+unset (_${_PYTHON_PREFIX}_REGISTRY_VIEW)
 if (CMAKE_SIZEOF_VOID_P)
   math (EXPR _${_PYTHON_PREFIX}_ARCH "${CMAKE_SIZEOF_VOID_P} * 8")
   if ("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
       OR "Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
     # In this case, search only for 64bit or 32bit
     set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH})
+    set (_${_PYTHON_PREFIX}_REGISTRY_VIEW REGISTRY_VIEW ${_${_PYTHON_PREFIX}_ARCH})
   else()
     if (_${_PYTHON_PREFIX}_ARCH EQUAL "32")
       set (_${_PYTHON_PREFIX}_ARCH2 64)
@@ -1506,9 +1527,13 @@
 unset (_${_PYTHON_PREFIX}_REQUIRED_VARS)
 unset (_${_PYTHON_PREFIX}_CACHED_VARS)
 unset (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE)
+set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE CACHE INTERNAL "Interpreter reason failure")
 unset (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE)
+set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE CACHE INTERNAL "Compiler reason failure")
 unset (_${_PYTHON_PREFIX}_Development_REASON_FAILURE)
+set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE CACHE INTERNAL "Development reason failure")
 unset (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE)
+set (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE CACHE INTERNAL "NumPy reason failure")
 
 
 # preamble
@@ -1590,9 +1615,8 @@
                         NO_CMAKE_PATH
                         NO_CMAKE_ENVIRONMENT_PATH
                         NO_SYSTEM_ENVIRONMENT_PATH
-                        NO_CMAKE_SYSTEM_PATH)
-
-          _python_validate_interpreter (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_interpreter)
           if (_${_PYTHON_PREFIX}_EXECUTABLE)
             break()
           endif()
@@ -1612,8 +1636,8 @@
                         NO_CMAKE_PATH
                         NO_CMAKE_ENVIRONMENT_PATH
                         NO_SYSTEM_ENVIRONMENT_PATH
-                        NO_CMAKE_SYSTEM_PATH)
-          _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_interpreter)
           if (_${_PYTHON_PREFIX}_EXECUTABLE)
             break()
           endif()
@@ -1626,9 +1650,10 @@
                         HINTS ${_${_PYTHON_PREFIX}_HINTS}
                         PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
                         PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        ${_${_PYTHON_PREFIX}_REGISTRY_VIEW}
                         NO_SYSTEM_ENVIRONMENT_PATH
-                        NO_CMAKE_SYSTEM_PATH)
-          _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_interpreter)
           if (_${_PYTHON_PREFIX}_EXECUTABLE)
             break()
           endif()
@@ -1641,8 +1666,8 @@
                       HINTS ${_${_PYTHON_PREFIX}_HINTS}
                       PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
                       NO_SYSTEM_ENVIRONMENT_PATH
-                      NO_CMAKE_SYSTEM_PATH)
-        _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                      NO_CMAKE_SYSTEM_PATH
+                      VALIDATOR _python_validate_find_interpreter)
         if (_${_PYTHON_PREFIX}_EXECUTABLE)
           break()
         endif()
@@ -1650,8 +1675,8 @@
         find_program (_${_PYTHON_PREFIX}_EXECUTABLE
                       NAMES ${_${_PYTHON_PREFIX}_NAMES}
                       NAMES_PER_DIR
-                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
-        _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                      VALIDATOR _python_validate_find_interpreter)
         if (_${_PYTHON_PREFIX}_EXECUTABLE)
           break()
         endif()
@@ -1663,8 +1688,8 @@
                         NAMES_PER_DIR
                         PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
                         PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
-                        NO_DEFAULT_PATH)
-          _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                        NO_DEFAULT_PATH
+                        VALIDATOR _python_validate_find_interpreter)
           if (_${_PYTHON_PREFIX}_EXECUTABLE)
             break()
           endif()
@@ -1676,8 +1701,9 @@
                         NAMES_PER_DIR
                         PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
                         PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
-                        NO_DEFAULT_PATH)
-          _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                        ${_${_PYTHON_PREFIX}_REGISTRY_VIEW}
+                        NO_DEFAULT_PATH
+                        VALIDATOR _python_validate_find_interpreter)
           if (_${_PYTHON_PREFIX}_EXECUTABLE)
             break()
           endif()
@@ -1687,9 +1713,9 @@
       endwhile()
     else()
       # look-up for various versions and locations
-      set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS EXACT)
+      set (_${_PYTHON_PREFIX}_COMMON_VALIDATE_OPTIONS EXACT)
       if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
-        list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE)
+        list (APPEND _${_PYTHON_PREFIX}_COMMON_VALIDATE_OPTIONS IN_RANGE)
       endif()
 
       foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
@@ -1698,6 +1724,7 @@
 
         _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})
         _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})
+        set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_COMMON_VALIDATE_OPTIONS})
 
         # Virtual environments handling
         if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
@@ -1710,8 +1737,8 @@
                         NO_CMAKE_PATH
                         NO_CMAKE_ENVIRONMENT_PATH
                         NO_SYSTEM_ENVIRONMENT_PATH
-                        NO_CMAKE_SYSTEM_PATH)
-          _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_interpreter)
           if (_${_PYTHON_PREFIX}_EXECUTABLE)
             break()
           endif()
@@ -1731,7 +1758,8 @@
                         NO_CMAKE_PATH
                         NO_CMAKE_ENVIRONMENT_PATH
                         NO_SYSTEM_ENVIRONMENT_PATH
-                        NO_CMAKE_SYSTEM_PATH)
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_interpreter)
         endif()
 
         # Windows registry
@@ -1742,11 +1770,12 @@
                         HINTS ${_${_PYTHON_PREFIX}_HINTS}
                         PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
                         PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        ${_${_PYTHON_PREFIX}_REGISTRY_VIEW}
                         NO_SYSTEM_ENVIRONMENT_PATH
-                        NO_CMAKE_SYSTEM_PATH)
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_interpreter)
         endif()
 
-        _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
         if (_${_PYTHON_PREFIX}_EXECUTABLE)
           break()
         endif()
@@ -1758,21 +1787,18 @@
                       HINTS ${_${_PYTHON_PREFIX}_HINTS}
                       PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
                       NO_SYSTEM_ENVIRONMENT_PATH
-                      NO_CMAKE_SYSTEM_PATH)
-        _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                      NO_CMAKE_SYSTEM_PATH
+                      VALIDATOR _python_validate_find_interpreter)
         if (_${_PYTHON_PREFIX}_EXECUTABLE)
           break()
         endif()
+
         # try using standard paths.
-        # NAMES_PER_DIR is not defined on purpose to have a chance to find
-        # expected version.
-        # For example, typical systems have 'python' for version 2.* and 'python3'
-        # for version 3.*. So looking for names per dir will find, potentially,
-        # systematically 'python' (i.e. version 2) even if version 3 is searched.
         find_program (_${_PYTHON_PREFIX}_EXECUTABLE
                       NAMES ${_${_PYTHON_PREFIX}_NAMES}
-                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
-        _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                      NAMES_PER_DIR
+                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                      VALIDATOR _python_validate_find_interpreter)
         if (_${_PYTHON_PREFIX}_EXECUTABLE)
           break()
         endif()
@@ -1784,7 +1810,8 @@
                         NAMES_PER_DIR
                         PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
                         PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
-                        NO_DEFAULT_PATH)
+                        NO_DEFAULT_PATH
+                        VALIDATOR _python_validate_find_interpreter)
         endif()
 
         # Windows registry
@@ -1794,10 +1821,11 @@
                         NAMES_PER_DIR
                         PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
                         PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
-                        NO_DEFAULT_PATH)
+                        ${_${_PYTHON_PREFIX}_REGISTRY_VIEW}
+                        NO_DEFAULT_PATH
+                        VALIDATOR _python_validate_find_interpreter)
         endif()
 
-        _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
         if (_${_PYTHON_PREFIX}_EXECUTABLE)
           break()
         endif()
@@ -1806,15 +1834,12 @@
       if (NOT _${_PYTHON_PREFIX}_EXECUTABLE AND
           NOT _${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY")
         # No specific version found. Retry with generic names and standard paths.
-        # NAMES_PER_DIR is not defined on purpose to have a chance to find
-        # expected version.
-        # For example, typical systems have 'python' for version 2.* and 'python3'
-        # for version 3.*. So looking for names per dir will find, potentially,
-        # systematically 'python' (i.e. version 2) even if version 3 is searched.
         _python_get_names (_${_PYTHON_PREFIX}_NAMES POSIX INTERPRETER)
+        unset (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS)
         find_program (_${_PYTHON_PREFIX}_EXECUTABLE
-                      NAMES ${_${_PYTHON_PREFIX}_NAMES})
-        _python_validate_interpreter ()
+                      NAMES ${_${_PYTHON_PREFIX}_NAMES}
+                      NAMES_PER_DIR
+                      VALIDATOR _python_validate_find_interpreter)
       endif()
     endif()
   endif()
@@ -1836,7 +1861,7 @@
       # Interpreter is not usable
       set (_${_PYTHON_PREFIX}_EXECUTABLE_USABLE FALSE)
       unset (${_PYTHON_PREFIX}_VERSION)
-      set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot run the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+      set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Cannot run the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
     endif()
   endif()
 
@@ -1884,7 +1909,7 @@
       endif()
 
       if (${_PYTHON_PREFIX}_Interpreter_FOUND)
-        unset (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE)
+        unset (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE CACHE)
 
         # compute and save interpreter signature
         string (MD5 __${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_EXECUTABLE}")
@@ -2058,8 +2083,8 @@
                         NO_CMAKE_PATH
                         NO_CMAKE_ENVIRONMENT_PATH
                         NO_SYSTEM_ENVIRONMENT_PATH
-                        NO_CMAKE_SYSTEM_PATH)
-          _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_compiler)
           if (_${_PYTHON_PREFIX}_COMPILER)
             break()
           endif()
@@ -2072,9 +2097,10 @@
                         HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
                         PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
                         PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        ${_${_PYTHON_PREFIX}_REGISTRY_VIEW}
                         NO_SYSTEM_ENVIRONMENT_PATH
-                        NO_CMAKE_SYSTEM_PATH)
-          _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_compiler)
           if (_${_PYTHON_PREFIX}_COMPILER)
             break()
           endif()
@@ -2087,8 +2113,8 @@
                       HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
                       PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
                       NO_SYSTEM_ENVIRONMENT_PATH
-                      NO_CMAKE_SYSTEM_PATH)
-        _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                      NO_CMAKE_SYSTEM_PATH
+                      VALIDATOR _python_validate_find_compiler)
         if (_${_PYTHON_PREFIX}_COMPILER)
           break()
         endif()
@@ -2097,8 +2123,8 @@
         find_program (_${_PYTHON_PREFIX}_COMPILER
                       NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
                       NAMES_PER_DIR
-                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
-        _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                      VALIDATOR _python_validate_find_compiler)
         if (_${_PYTHON_PREFIX}_COMPILER)
           break()
         endif()
@@ -2110,12 +2136,13 @@
                         NAMES_PER_DIR
                         PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
                         PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
-                        NO_DEFAULT_PATH)
-          _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                        NO_DEFAULT_PATH
+                        VALIDATOR _python_validate_find_compiler)
           if (_${_PYTHON_PREFIX}_COMPILER)
             break()
           endif()
         endif()
+
         # Windows registry
         if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
           find_program (_${_PYTHON_PREFIX}_COMPILER
@@ -2123,8 +2150,9 @@
                         NAMES_PER_DIR
                         PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
                         PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
-                        NO_DEFAULT_PATH)
-          _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                        ${_${_PYTHON_PREFIX}_REGISTRY_VIEW}
+                        NO_DEFAULT_PATH
+                        VALIDATOR _python_validate_find_compiler)
           if (_${_PYTHON_PREFIX}_COMPILER)
             break()
           endif()
@@ -2134,9 +2162,9 @@
       endwhile()
     else()
       # try using root dir and registry
-      set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS EXACT)
+      set (_${_PYTHON_PREFIX}_COMMON_VALIDATE_OPTIONS EXACT)
       if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
-        list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE)
+        list (APPEND _${_PYTHON_PREFIX}_COMMON_VALIDATE_OPTIONS IN_RANGE)
       endif()
 
       foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
@@ -2157,6 +2185,8 @@
                                 IMPLEMENTATIONS IronPython
                                 VERSION ${_${_PYTHON_PREFIX}_VERSION})
 
+        set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_COMMON_VALIDATE_OPTIONS})
+
         # Apple frameworks handling
         if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
           find_program (_${_PYTHON_PREFIX}_COMPILER
@@ -2168,8 +2198,8 @@
                         NO_CMAKE_PATH
                         NO_CMAKE_ENVIRONMENT_PATH
                         NO_SYSTEM_ENVIRONMENT_PATH
-                        NO_CMAKE_SYSTEM_PATH)
-          _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_compiler)
           if (_${_PYTHON_PREFIX}_COMPILER)
             break()
           endif()
@@ -2182,9 +2212,10 @@
                         HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
                         PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
                         PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        ${_${_PYTHON_PREFIX}_REGISTRY_VIEW}
                         NO_SYSTEM_ENVIRONMENT_PATH
-                        NO_CMAKE_SYSTEM_PATH)
-          _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_compiler)
           if (_${_PYTHON_PREFIX}_COMPILER)
             break()
           endif()
@@ -2197,8 +2228,8 @@
                       HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
                       PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
                       NO_SYSTEM_ENVIRONMENT_PATH
-                      NO_CMAKE_SYSTEM_PATH)
-        _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                      NO_CMAKE_SYSTEM_PATH
+                      VALIDATOR _python_validate_find_compiler)
         if (_${_PYTHON_PREFIX}_COMPILER)
           break()
         endif()
@@ -2210,8 +2241,8 @@
                         NAMES_PER_DIR
                         PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
                         PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
-                        NO_DEFAULT_PATH)
-          _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                        NO_DEFAULT_PATH
+                        VALIDATOR _python_validate_find_compiler)
           if (_${_PYTHON_PREFIX}_COMPILER)
             break()
           endif()
@@ -2223,8 +2254,9 @@
                         NAMES_PER_DIR
                         PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
                         PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
-                        NO_DEFAULT_PATH)
-          _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+                        ${_${_PYTHON_PREFIX}_REGISTRY_VIEW}
+                        NO_DEFAULT_PATH
+                        VALIDATOR _python_validate_find_compiler)
           if (_${_PYTHON_PREFIX}_COMPILER)
             break()
           endif()
@@ -2240,11 +2272,13 @@
                                  IMPLEMENTATIONS IronPython
                                  VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}
                                  COMPILER)
+      unset (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS)
       find_program (_${_PYTHON_PREFIX}_COMPILER
                     NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+                    NAMES_PER_DIR
                     HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
-                    PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
-      _python_validate_compiler ()
+                    PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                    VALIDATOR _python_validate_find_compiler)
     endif()
   endif()
 
@@ -2285,7 +2319,7 @@
     else()
       # compiler not usable
       set (_${_PYTHON_PREFIX}_COMPILER_USABLE FALSE)
-      set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Cannot run the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
+      set_property (CACHE _${_PYTHON_PREFIX}_Compiler_REASON_FAILURE PROPERTY VALUE "Cannot run the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
     endif()
     file (REMOVE_RECURSE "${_${_PYTHON_PREFIX}_VERSION_DIR}")
   endif()
@@ -2304,7 +2338,7 @@
   endif()
 
   if (${_PYTHON_PREFIX}_Compiler_FOUND)
-    unset (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE)
+    unset (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE CACHE)
 
     # compute and save compiler signature
     string (MD5 __${_PYTHON_PREFIX}_COMPILER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_COMPILER}")
@@ -2786,7 +2820,7 @@
     set (${_PYTHON_PREFIX}_LIBRARY_RELEASE "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
 
     if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE AND NOT EXISTS "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
-      set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
+      set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
       set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
     endif()
 
@@ -2938,7 +2972,7 @@
     set (${_PYTHON_PREFIX}_INCLUDE_DIRS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}")
 
     if (_${_PYTHON_PREFIX}_INCLUDE_DIR AND NOT EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}")
-      set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
+      set_property (CACHE _${_PYTHON_PREFIX}_Development_REASON_FAILURE PROPERTY VALUE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
       set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
     endif()
 
@@ -3031,7 +3065,7 @@
         AND ${_PYTHON_PREFIX}_Development.Embed_FOUND)
       OR (NOT "Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
         AND ${_PYTHON_PREFIX}_Development.Module_FOUND))
-    unset (_${_PYTHON_PREFIX}_Development_REASON_FAILURE)
+    unset (_${_PYTHON_PREFIX}_Development_REASON_FAILURE CACHE)
   endif()
 
   if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
@@ -3142,7 +3176,7 @@
   set (${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}")
 
   if(_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR AND NOT EXISTS "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}")
-    set (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE "Cannot find the directory \"${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}\"")
+    set_property (CACHE _${_PYTHON_PREFIX}_NumPy_REASON_FAILURE PROPERTY VALUE "Cannot find the directory \"${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}\"")
     set_property (CACHE _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR-NOTFOUND")
   endif()
 
@@ -3164,7 +3198,7 @@
   endif()
 
   if (${_PYTHON_PREFIX}_NumPy_FOUND)
-    unset (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE)
+    unset (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE CACHE)
 
     # compute and save numpy signature
     string (MD5 __${_PYTHON_PREFIX}_NUMPY_SIGNATURE "${_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}:${_${_PYTHON_PREFIX}_DEVELOPMENT_MODULE_SIGNATURE}:${${_PYTHON_PREFIX}_NumPyINCLUDE_DIR}")
@@ -3194,7 +3228,7 @@
 foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Interpreter Compiler Development NumPy)
   if (_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE)
     string (APPEND _${_PYTHON_PREFIX}_REASON_FAILURE "\n        ${_${_PYTHON_PREFIX}_COMPONENT}: ${_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE}")
-    unset (_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE)
+    unset (_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE CACHE)
   endif()
 endforeach()
 
diff --git a/Modules/FindVulkan.cmake b/Modules/FindVulkan.cmake
index 8b322ed..78b07c4 100644
--- a/Modules/FindVulkan.cmake
+++ b/Modules/FindVulkan.cmake
@@ -70,6 +70,11 @@
   Defined if SDK has the Khronos library which implement a subset of Vulkan API
   over Apple Metal graphics framework. (MoltenVK).
 
+``Vulkan::volk``
+  .. versionadded:: 3.25
+
+  Defined if SDK has the Vulkan meta-loader (volk).
+
 Result Variables
 ^^^^^^^^^^^^^^^^
 
@@ -109,6 +114,10 @@
   .. versionadded:: 3.24
 
   True, if the SDK has the MoltenVK library.
+``Vulkan_volk_FOUND``
+  .. versionadded:: 3.25
+
+  True, if the SDK has the volk library.
 
 The module will also defines these cache variables:
 
@@ -137,6 +146,11 @@
 
   Path to the MoltenVK library.
 
+``Vulkan_volk_LIBRARY``
+  .. versionadded:: 3.25
+
+  Path to the volk library.
+
 Hints
 ^^^^^
 
@@ -374,6 +388,13 @@
     )
   mark_as_advanced(Vulkan_MoltenVK_INCLUDE_DIR)
 endif()
+if(volk IN_LIST Vulkan_FIND_COMPONENTS)
+  find_library(Vulkan_volk_LIBRARY
+          NAMES volk
+          HINTS
+            ${_Vulkan_hint_library_search_paths})
+  mark_as_advanced(Vulkan_Volk_LIBRARY)
+endif()
 
 if(Vulkan_GLSLC_EXECUTABLE)
   set(Vulkan_glslc_FOUND TRUE)
@@ -437,6 +458,7 @@
     glslang-genericcodegen)
 _Vulkan_set_library_component_found(shaderc_combined)
 _Vulkan_set_library_component_found(SPIRV-Tools)
+_Vulkan_set_library_component_found(volk)
 
 if(Vulkan_MoltenVK_INCLUDE_DIR AND Vulkan_MoltenVK_LIBRARY)
   set(Vulkan_MoltenVK_FOUND TRUE)
@@ -723,6 +745,25 @@
           IMPORTED_LOCATION_DEBUG "${Vulkan_SPIRV-Tools_DEBUG_LIBRARY}")
     endif()
   endif()
+
+  if(Vulkan_volk_LIBRARY AND NOT TARGET Vulkan::volk)
+    add_library(Vulkan::volk STATIC IMPORTED)
+    set_property(TARGET Vulkan::volk
+            PROPERTY
+              INTERFACE_INCLUDE_DIRECTORIES "${Vulkan_INCLUDE_DIRS}")
+    set_property(TARGET Vulkan::volk APPEND
+            PROPERTY
+              IMPORTED_CONFIGURATIONS Release)
+    set_property(TARGET Vulkan::volk APPEND
+            PROPERTY
+              IMPORTED_LOCATION_RELEASE "${Vulkan_volk_LIBRARY}")
+
+    if (NOT WIN32)
+      set_property(TARGET Vulkan::volk APPEND
+              PROPERTY
+                IMPORTED_LINK_INTERFACE_LIBRARIES dl)
+    endif()
+  endif()
 endif()
 
 if(Vulkan_MoltenVK_FOUND)
diff --git a/Modules/FindwxWidgets.cmake b/Modules/FindwxWidgets.cmake
index f7996ba..9e7937e 100644
--- a/Modules/FindwxWidgets.cmake
+++ b/Modules/FindwxWidgets.cmake
@@ -29,9 +29,9 @@
 ::
 
   wxWidgets_ROOT_DIR      - Base wxWidgets directory
-                            (e.g., C:/wxWidgets-2.6.3).
+                            (e.g., C:/wxWidgets-3.2.0).
   wxWidgets_LIB_DIR       - Path to wxWidgets libraries
-                            (e.g., C:/wxWidgets-2.6.3/lib/vc_lib).
+                            (e.g., C:/wxWidgets-3.2.0/lib/vc_x64_lib).
   wxWidgets_CONFIGURATION - Configuration to use
                             (e.g., msw, mswd, mswu, mswunivud, etc.)
   wxWidgets_EXCLUDE_COMMON_LIBRARIES
@@ -215,6 +215,32 @@
   set(wxWidgets_USE_FILE UsewxWidgets)
 endif()
 
+# Known wxWidgets versions.
+set(wx_versions 3.3 3.2 3.1 3.0 2.9 2.8 2.7 2.6 2.5)
+
+macro(wx_extract_version)
+  unset(_wx_filename)
+  find_file(_wx_filename wx/version.h PATHS ${wxWidgets_INCLUDE_DIRS} NO_DEFAULT_PATH)
+  dbg_msg("_wx_filename:  ${_wx_filename}")
+
+  if(NOT _wx_filename)
+    message(FATAL_ERROR "wxWidgets wx/version.h file not found in ${wxWidgets_INCLUDE_DIRS}.")
+  endif()
+
+  file(READ "${_wx_filename}" _wx_version_h)
+  unset(_wx_filename CACHE)
+
+  string(REGEX REPLACE "^(.*\n)?#define +wxMAJOR_VERSION +([0-9]+).*"
+    "\\2" wxWidgets_VERSION_MAJOR "${_wx_version_h}" )
+  string(REGEX REPLACE "^(.*\n)?#define +wxMINOR_VERSION +([0-9]+).*"
+    "\\2" wxWidgets_VERSION_MINOR "${_wx_version_h}" )
+  string(REGEX REPLACE "^(.*\n)?#define +wxRELEASE_NUMBER +([0-9]+).*"
+    "\\2" wxWidgets_VERSION_PATCH "${_wx_version_h}" )
+  set(wxWidgets_VERSION_STRING
+    "${wxWidgets_VERSION_MAJOR}.${wxWidgets_VERSION_MINOR}.${wxWidgets_VERSION_PATCH}" )
+  dbg_msg("wxWidgets_VERSION_STRING:    ${wxWidgets_VERSION_STRING}")
+endmacro()
+
 #=====================================================================
 # Determine whether unix or win32 paths should be used
 #=====================================================================
@@ -269,10 +295,11 @@
   #
   # Find libraries associated to a configuration.
   #
-  macro(WX_FIND_LIBS _PF _UNV _UCD _DBG)
+  macro(WX_FIND_LIBS _PF _UNV _UCD _DBG _VER)
     DBG_MSG_V("m_unv = ${_UNV}")
     DBG_MSG_V("m_ucd = ${_UCD}")
     DBG_MSG_V("m_dbg = ${_DBG}")
+    DBG_MSG_V("m_ver = ${_VER}")
 
     # FIXME: What if both regex libs are available. regex should be
     # found outside the loop and only wx${LIB}${_UCD}${_DBG}.
@@ -290,28 +317,14 @@
 
     # Find wxWidgets multilib base libraries.
     find_library(WX_base${_DBG}
-      NAMES
-      wxbase31${_UCD}${_DBG}
-      wxbase30${_UCD}${_DBG}
-      wxbase29${_UCD}${_DBG}
-      wxbase28${_UCD}${_DBG}
-      wxbase27${_UCD}${_DBG}
-      wxbase26${_UCD}${_DBG}
-      wxbase25${_UCD}${_DBG}
+      NAMES wxbase${_VER}${_UCD}${_DBG}
       PATHS ${WX_LIB_DIR}
       NO_DEFAULT_PATH
       )
     mark_as_advanced(WX_base${_DBG})
     foreach(LIB net odbc xml)
       find_library(WX_${LIB}${_DBG}
-        NAMES
-        wxbase31${_UCD}${_DBG}_${LIB}
-        wxbase30${_UCD}${_DBG}_${LIB}
-        wxbase29${_UCD}${_DBG}_${LIB}
-        wxbase28${_UCD}${_DBG}_${LIB}
-        wxbase27${_UCD}${_DBG}_${LIB}
-        wxbase26${_UCD}${_DBG}_${LIB}
-        wxbase25${_UCD}${_DBG}_${LIB}
+        NAMES wxbase${_VER}${_UCD}${_DBG}_${LIB}
         PATHS ${WX_LIB_DIR}
         NO_DEFAULT_PATH
         )
@@ -320,14 +333,7 @@
 
     # Find wxWidgets monolithic library.
     find_library(WX_mono${_DBG}
-      NAMES
-      wx${_PF}${_UNV}31${_UCD}${_DBG}
-      wx${_PF}${_UNV}30${_UCD}${_DBG}
-      wx${_PF}${_UNV}29${_UCD}${_DBG}
-      wx${_PF}${_UNV}28${_UCD}${_DBG}
-      wx${_PF}${_UNV}27${_UCD}${_DBG}
-      wx${_PF}${_UNV}26${_UCD}${_DBG}
-      wx${_PF}${_UNV}25${_UCD}${_DBG}
+      NAMES wx${_PF}${_UNV}${_VER}${_UCD}${_DBG}
       PATHS ${WX_LIB_DIR}
       NO_DEFAULT_PATH
       )
@@ -337,14 +343,7 @@
     foreach(LIB core adv aui html media xrc dbgrid gl qa richtext
                 stc ribbon propgrid webview)
       find_library(WX_${LIB}${_DBG}
-        NAMES
-        wx${_PF}${_UNV}31${_UCD}${_DBG}_${LIB}
-        wx${_PF}${_UNV}30${_UCD}${_DBG}_${LIB}
-        wx${_PF}${_UNV}29${_UCD}${_DBG}_${LIB}
-        wx${_PF}${_UNV}28${_UCD}${_DBG}_${LIB}
-        wx${_PF}${_UNV}27${_UCD}${_DBG}_${LIB}
-        wx${_PF}${_UNV}26${_UCD}${_DBG}_${LIB}
-        wx${_PF}${_UNV}25${_UCD}${_DBG}_${LIB}
+        NAMES wx${_PF}${_UNV}${_VER}${_UCD}${_DBG}_${LIB}
         PATHS ${WX_LIB_DIR}
         NO_DEFAULT_PATH
         )
@@ -447,6 +446,13 @@
   # WIN32: Start actual work.
   #-------------------------------------------------------------------
 
+  set(wx_paths "wxWidgets")
+  foreach(version ${wx_versions})
+    foreach(patch RANGE 15 0 -1)
+      list(APPEND wx_paths "wxWidgets-${version}.${patch}")
+    endforeach()
+  endforeach()
+
   # Look for an installation tree.
   find_path(wxWidgets_ROOT_DIR
     NAMES include/wx/wx.h
@@ -458,41 +464,7 @@
       D:/
       ENV ProgramFiles
     PATH_SUFFIXES
-      wxWidgets-3.1.0
-      wxWidgets-3.0.2
-      wxWidgets-3.0.1
-      wxWidgets-3.0.0
-      wxWidgets-2.9.5
-      wxWidgets-2.9.4
-      wxWidgets-2.9.3
-      wxWidgets-2.9.2
-      wxWidgets-2.9.1
-      wxWidgets-2.9.0
-      wxWidgets-2.8.9
-      wxWidgets-2.8.8
-      wxWidgets-2.8.7
-      wxWidgets-2.8.6
-      wxWidgets-2.8.5
-      wxWidgets-2.8.4
-      wxWidgets-2.8.3
-      wxWidgets-2.8.2
-      wxWidgets-2.8.1
-      wxWidgets-2.8.0
-      wxWidgets-2.7.4
-      wxWidgets-2.7.3
-      wxWidgets-2.7.2
-      wxWidgets-2.7.1
-      wxWidgets-2.7.0
-      wxWidgets-2.7.0-1
-      wxWidgets-2.6.4
-      wxWidgets-2.6.3
-      wxWidgets-2.6.2
-      wxWidgets-2.6.1
-      wxWidgets-2.5.4
-      wxWidgets-2.5.3
-      wxWidgets-2.5.2
-      wxWidgets-2.5.1
-      wxWidgets
+      ${wx_paths}
     DOC "wxWidgets base/installation directory"
     )
 
@@ -655,10 +627,14 @@
           set(wxWidgets_FOUND FALSE)
         endif()
 
+        # Get version number.
+        wx_extract_version()
+        set(VER "${wxWidgets_VERSION_MAJOR}${wxWidgets_VERSION_MINOR}")
+
         # Find wxWidgets libraries.
-        WX_FIND_LIBS("${PF}" "${UNV}" "${UCD}" "${DBG}")
+        WX_FIND_LIBS("${PF}" "${UNV}" "${UCD}" "${DBG}" "${VER}")
         if(WX_USE_REL_AND_DBG)
-          WX_FIND_LIBS("${PF}" "${UNV}" "${UCD}" "d")
+          WX_FIND_LIBS("${PF}" "${UNV}" "${UCD}" "d" "${VER}")
         endif()
 
         # Settings for requested libs (i.e., include dir, libraries, etc.).
@@ -773,12 +749,14 @@
     # Look for wx-config -- this can be set in the environment,
     # or try versioned and toolchain-versioned variants of the -config
     # executable as well.
+    set(wx_config_names "wx-config")
+    foreach(version ${wx_versions})
+      list(APPEND wx_config_names "wx-config-${version}" "wxgtk3u-${version}-config" "wxgtk2u-${version}-config")
+    endforeach()
     find_program(wxWidgets_CONFIG_EXECUTABLE
       NAMES
         $ENV{WX_CONFIG}
-        wx-config
-        wx-config-3.1 wx-config-3.0 wx-config-2.9 wx-config-2.8
-        wxgtk3u-3.1-config wxgtk3u-3.0-config wxgtk2u-2.8-config
+        ${wx_config_names}
       DOC "Location of wxWidgets library configuration provider binary (wx-config)."
       ONLY_CMAKE_FIND_ROOT_PATH
       )
@@ -981,26 +959,7 @@
 
 # Check if a specific version was requested by find_package().
 if(wxWidgets_FOUND)
-  unset(_wx_filename)
-  find_file(_wx_filename wx/version.h PATHS ${wxWidgets_INCLUDE_DIRS} NO_DEFAULT_PATH)
-  dbg_msg("_wx_filename:  ${_wx_filename}")
-
-  if(NOT _wx_filename)
-    message(FATAL_ERROR "wxWidgets wx/version.h file not found in ${wxWidgets_INCLUDE_DIRS}.")
-  endif()
-
-  file(READ "${_wx_filename}" _wx_version_h)
-  unset(_wx_filename CACHE)
-
-  string(REGEX REPLACE "^(.*\n)?#define +wxMAJOR_VERSION +([0-9]+).*"
-    "\\2" wxWidgets_VERSION_MAJOR "${_wx_version_h}" )
-  string(REGEX REPLACE "^(.*\n)?#define +wxMINOR_VERSION +([0-9]+).*"
-    "\\2" wxWidgets_VERSION_MINOR "${_wx_version_h}" )
-  string(REGEX REPLACE "^(.*\n)?#define +wxRELEASE_NUMBER +([0-9]+).*"
-    "\\2" wxWidgets_VERSION_PATCH "${_wx_version_h}" )
-  set(wxWidgets_VERSION_STRING
-    "${wxWidgets_VERSION_MAJOR}.${wxWidgets_VERSION_MINOR}.${wxWidgets_VERSION_PATCH}" )
-  dbg_msg("wxWidgets_VERSION_STRING:    ${wxWidgets_VERSION_STRING}")
+  wx_extract_version()
 endif()
 
 # Debug output:
diff --git a/Modules/Platform/Linux-LCC-Fortran.cmake b/Modules/Platform/Linux-LCC-Fortran.cmake
index d3a4cf4..bf2a1c2 100644
--- a/Modules/Platform/Linux-LCC-Fortran.cmake
+++ b/Modules/Platform/Linux-LCC-Fortran.cmake
@@ -1,3 +1,7 @@
 include(Platform/Linux-LCC)
 __linux_compiler_lcc(Fortran)
-set(CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS "-llfortran")
+if (CMAKE_Fortran_COMPILER_VERSION VERSION_LESS "1.26.03")
+  set(CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS "-llfortran")
+else()
+  set(CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS "-lgfortran")
+endif()
diff --git a/Modules/Platform/SerenityOS-Clang-ASM.cmake b/Modules/Platform/SerenityOS-Clang-ASM.cmake
new file mode 100644
index 0000000..ba1e18c
--- /dev/null
+++ b/Modules/Platform/SerenityOS-Clang-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/SerenityOS-GNU)
+__serenity_compiler_gnu(ASM)
diff --git a/Modules/Platform/SerenityOS-Clang-C.cmake b/Modules/Platform/SerenityOS-Clang-C.cmake
new file mode 100644
index 0000000..791a197
--- /dev/null
+++ b/Modules/Platform/SerenityOS-Clang-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/SerenityOS-GNU)
+__serenity_compiler_gnu(C)
diff --git a/Modules/Platform/SerenityOS-Clang-CXX.cmake b/Modules/Platform/SerenityOS-Clang-CXX.cmake
new file mode 100644
index 0000000..084e319
--- /dev/null
+++ b/Modules/Platform/SerenityOS-Clang-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/SerenityOS-GNU)
+__serenity_compiler_gnu(CXX)
diff --git a/Modules/Platform/SerenityOS-GNU-ASM.cmake b/Modules/Platform/SerenityOS-GNU-ASM.cmake
new file mode 100644
index 0000000..ba1e18c
--- /dev/null
+++ b/Modules/Platform/SerenityOS-GNU-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/SerenityOS-GNU)
+__serenity_compiler_gnu(ASM)
diff --git a/Modules/Platform/SerenityOS-GNU-C.cmake b/Modules/Platform/SerenityOS-GNU-C.cmake
new file mode 100644
index 0000000..791a197
--- /dev/null
+++ b/Modules/Platform/SerenityOS-GNU-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/SerenityOS-GNU)
+__serenity_compiler_gnu(C)
diff --git a/Modules/Platform/SerenityOS-GNU-CXX.cmake b/Modules/Platform/SerenityOS-GNU-CXX.cmake
new file mode 100644
index 0000000..084e319
--- /dev/null
+++ b/Modules/Platform/SerenityOS-GNU-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/SerenityOS-GNU)
+__serenity_compiler_gnu(CXX)
diff --git a/Modules/Platform/SerenityOS-GNU.cmake b/Modules/Platform/SerenityOS-GNU.cmake
new file mode 100644
index 0000000..ed39477
--- /dev/null
+++ b/Modules/Platform/SerenityOS-GNU.cmake
@@ -0,0 +1,24 @@
+# This module is shared by multiple languages; use include blocker.
+include_guard()
+
+set(CMAKE_EXE_LINKER_FLAGS_INIT "-Wl,--hash-style=gnu,-z,relro,-z,now,-z,noexecstack,-z,separate-code,-z,max-page-size=0x1000")
+
+macro(__serenity_compiler_gnu lang)
+  set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG "-Wl,-rpath,")
+  set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG_SEP ":")
+  set(CMAKE_SHARED_LIBRARY_RPATH_LINK_${lang}_FLAG "-Wl,-rpath-link,")
+  set(CMAKE_SHARED_LIBRARY_SONAME_${lang}_FLAG "-Wl,-soname,")
+  set(CMAKE_EXE_EXPORTS_${lang}_FLAG "-Wl,--export-dynamic")
+
+  set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared -Wl,--hash-style=gnu,-z,relro,-z,now,-z,noexecstack,-z,separate-code")
+
+  # Initialize link type selection flags.  These flags are used when
+  # building a shared library, shared module, or executable that links
+  # to other libraries to select whether to use the static or shared
+  # versions of the libraries.
+  foreach(type SHARED_LIBRARY SHARED_MODULE EXE)
+    set(CMAKE_${type}_LINK_STATIC_${lang}_FLAGS "-Wl,-Bstatic")
+    set(CMAKE_${type}_LINK_DYNAMIC_${lang}_FLAGS "-Wl,-Bdynamic")
+  endforeach()
+
+endmacro()
diff --git a/Modules/Platform/SerenityOS.cmake b/Modules/Platform/SerenityOS.cmake
new file mode 100644
index 0000000..541620c
--- /dev/null
+++ b/Modules/Platform/SerenityOS.cmake
@@ -0,0 +1,12 @@
+
+set(SERENITYOS 1)
+
+set(CMAKE_DL_LIBS "-ldl")
+set(CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN "\$ORIGIN")
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
+
+# Shared libraries with no builtin soname may not be linked safely by
+# specifying the file path.
+set(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
+
+include(Platform/UnixPaths)
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 95b07cb..6312e93 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -197,6 +197,8 @@
   cmCustomCommandLines.cxx
   cmCustomCommandLines.h
   cmCustomCommandTypes.h
+  cmCxxModuleMapper.cxx
+  cmCxxModuleMapper.h
   cmDefinitions.cxx
   cmDefinitions.h
   cmDependencyProvider.h
@@ -543,6 +545,8 @@
   cmExecuteProcessCommand.h
   cmExpandedCommandArgument.cxx
   cmExpandedCommandArgument.h
+  cmExperimental.cxx
+  cmExperimental.h
   cmExportCommand.cxx
   cmExportCommand.h
   cmExportLibraryDependenciesCommand.cxx
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 03b4e27..026b303 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,8 +1,8 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 24)
-set(CMake_VERSION_PATCH 0)
-set(CMake_VERSION_RC 2)
+set(CMake_VERSION_PATCH 20220628)
+#set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
 # Start with the full version number used in tags.  It has no dev info.
diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx
index 8a7bb86..73e3f3c 100644
--- a/Source/CursesDialog/cmCursesLongMessageForm.cxx
+++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx
@@ -84,7 +84,7 @@
   for (size_t i = 0; i < sideSpace; i++) {
     version[i] = ' ';
   }
-  sprintf(version + sideSpace, "%s", vertmp);
+  snprintf(version + sideSpace, sizeof(version) - sideSpace, "%s", vertmp);
   version[width] = '\0';
 
   char fmt_s[] = "%s";
diff --git a/Source/CursesDialog/form/.gitattributes b/Source/CursesDialog/form/.gitattributes
index 12ede74..6dfa627 100644
--- a/Source/CursesDialog/form/.gitattributes
+++ b/Source/CursesDialog/form/.gitattributes
@@ -1 +1,2 @@
+* -whitespace
 * -format.clang-format-6.0
diff --git a/Source/CursesDialog/form/fty_int.c b/Source/CursesDialog/form/fty_int.c
index 7107fcc..7aeb4b8 100644
--- a/Source/CursesDialog/form/fty_int.c
+++ b/Source/CursesDialog/form/fty_int.c
@@ -117,7 +117,7 @@
 	    {
 	      if (val<low || val>high) return FALSE;
 	    }
-	  sprintf(buf,"%.*ld",(prec>0?prec:0),val);
+	  snprintf(buf,sizeof(buf),"%.*ld",(prec>0?prec:0),val);
 	  set_field_buffer(field,0,buf);
 	  return TRUE;
 	}
diff --git a/Source/CursesDialog/form/fty_num.c b/Source/CursesDialog/form/fty_num.c
index 7809599..4109b6f 100644
--- a/Source/CursesDialog/form/fty_num.c
+++ b/Source/CursesDialog/form/fty_num.c
@@ -140,7 +140,7 @@
 	    {
 	      if (val<low || val>high) return FALSE;
 	    }
-	  sprintf(buf,"%.*f",(prec>0?prec:0),val);
+	  snprintf(buf,sizeof(buf),"%.*f",(prec>0?prec:0),val);
 	  set_field_buffer(field,0,buf);
 	  return TRUE;
 	}
diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx
index ba95168..5fe6756 100644
--- a/Source/cmCommonTargetGenerator.cxx
+++ b/Source/cmCommonTargetGenerator.cxx
@@ -9,6 +9,7 @@
 #include "cmComputeLinkInformation.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalCommonGenerator.h"
+#include "cmGlobalGenerator.h"
 #include "cmLocalCommonGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
@@ -175,6 +176,9 @@
         cmLocalGenerator* lg = linkee->GetLocalGenerator();
         std::string di = cmStrCat(lg->GetCurrentBinaryDirectory(), '/',
                                   lg->GetTargetDirectory(linkee));
+        if (lg->GetGlobalGenerator()->IsMultiConfig()) {
+          di = cmStrCat(di, '/', config);
+        }
         dirs.push_back(std::move(di));
       }
     }
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index 5418e7c..45afdd1 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -605,6 +605,15 @@
       // does not include any system headers anyway.
       fprintf(fout,
               "set_property(DIRECTORY PROPERTY INCLUDE_DIRECTORIES \"\")\n");
+
+      // The link and compile lines for ABI detection step need to not use
+      // response files so we can extract implicit includes given to
+      // the underlying host compiler
+      if (testLangs.find("CUDA") != testLangs.end()) {
+        fprintf(fout, "set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_INCLUDES OFF)\n");
+        fprintf(fout, "set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_LIBRARIES OFF)\n");
+        fprintf(fout, "set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_OBJECTS OFF)\n");
+      }
     }
     fprintf(fout, "set(CMAKE_VERBOSE_MAKEFILE 1)\n");
     for (std::string const& li : testLangs) {
@@ -1117,7 +1126,8 @@
     searchDirs.emplace_back(std::move(tmp));
   }
   searchDirs.emplace_back("/Debug");
-#if defined(__APPLE__)
+
+  // handle app-bundles (for targeting apple-platforms)
   std::string app = "/" + targetName + ".app";
   if (cmNonempty(config)) {
     std::string tmp = cmStrCat('/', *config, app);
@@ -1126,7 +1136,7 @@
   std::string tmp = "/Debug" + app;
   searchDirs.emplace_back(std::move(tmp));
   searchDirs.emplace_back(std::move(app));
-#endif
+
   searchDirs.emplace_back("/Development");
 
   for (std::string const& sdir : searchDirs) {
diff --git a/Source/cmCxxModuleMapper.cxx b/Source/cmCxxModuleMapper.cxx
new file mode 100644
index 0000000..94ad721
--- /dev/null
+++ b/Source/cmCxxModuleMapper.cxx
@@ -0,0 +1,76 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmCxxModuleMapper.h"
+
+#include <cassert>
+#include <sstream>
+#include <vector>
+
+#include "cmScanDepFormat.h"
+
+cm::optional<std::string> CxxModuleLocations::BmiGeneratorPathForModule(
+  std::string const& logical_name) const
+{
+  if (auto l = this->BmiLocationForModule(logical_name)) {
+    return this->PathForGenerator(*l);
+  }
+  return {};
+}
+
+namespace {
+
+std::string CxxModuleMapContentGcc(CxxModuleLocations const& loc,
+                                   cmScanDepInfo const& obj)
+{
+  std::stringstream mm;
+
+  // Documented in GCC's documentation. The format is a series of
+  // lines with a module name and the associated filename separated
+  // by spaces. The first line may use `$root` as the module name
+  // to specify a "repository root". That is used to anchor any
+  // relative paths present in the file (CMake should never
+  // generate any).
+
+  // Write the root directory to use for module paths.
+  mm << "$root " << loc.RootDirectory << "\n";
+
+  for (auto const& p : obj.Provides) {
+    if (auto bmi_loc = loc.BmiGeneratorPathForModule(p.LogicalName)) {
+      mm << p.LogicalName << ' ' << *bmi_loc << '\n';
+    }
+  }
+  for (auto const& r : obj.Requires) {
+    if (auto bmi_loc = loc.BmiGeneratorPathForModule(r.LogicalName)) {
+      mm << r.LogicalName << ' ' << *bmi_loc << '\n';
+    }
+  }
+
+  return mm.str();
+}
+}
+
+cm::static_string_view CxxModuleMapExtension(
+  cm::optional<CxxModuleMapFormat> format)
+{
+  if (format) {
+    switch (*format) {
+      case CxxModuleMapFormat::Gcc:
+        return ".gcm"_s;
+    }
+  }
+
+  return ".bmi"_s;
+}
+
+std::string CxxModuleMapContent(CxxModuleMapFormat format,
+                                CxxModuleLocations const& loc,
+                                cmScanDepInfo const& obj)
+{
+  switch (format) {
+    case CxxModuleMapFormat::Gcc:
+      return CxxModuleMapContentGcc(loc, obj);
+  }
+
+  assert(false);
+  return {};
+}
diff --git a/Source/cmCxxModuleMapper.h b/Source/cmCxxModuleMapper.h
new file mode 100644
index 0000000..99384c9
--- /dev/null
+++ b/Source/cmCxxModuleMapper.h
@@ -0,0 +1,48 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <functional>
+#include <string>
+
+#include <cm/optional>
+#include <cmext/string_view>
+
+struct cmScanDepInfo;
+
+enum class CxxModuleMapFormat
+{
+  Gcc,
+};
+
+struct CxxModuleLocations
+{
+  // The path from which all relative paths should be computed. If
+  // this is relative, it is relative to the compiler's working
+  // directory.
+  std::string RootDirectory;
+
+  // A function to convert a full path to a path for the generator.
+  std::function<std::string(std::string const&)> PathForGenerator;
+
+  // Lookup the BMI location of a logical module name.
+  std::function<cm::optional<std::string>(std::string const&)>
+    BmiLocationForModule;
+
+  // Returns the generator path (if known) for the BMI given a
+  // logical module name.
+  cm::optional<std::string> BmiGeneratorPathForModule(
+    std::string const& logical_name) const;
+};
+
+// Return the extension to use for a given modulemap format.
+cm::static_string_view CxxModuleMapExtension(
+  cm::optional<CxxModuleMapFormat> format);
+
+// Return the contents of the module map in the given format for the
+// object file.
+std::string CxxModuleMapContent(CxxModuleMapFormat format,
+                                CxxModuleLocations const& loc,
+                                cmScanDepInfo const& obj);
diff --git a/Source/cmExperimental.cxx b/Source/cmExperimental.cxx
new file mode 100644
index 0000000..e815d0e
--- /dev/null
+++ b/Source/cmExperimental.cxx
@@ -0,0 +1,63 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#include "cmExperimental.h"
+
+#include <cassert>
+#include <cstddef>
+#include <string>
+
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmValue.h"
+
+namespace {
+
+/*
+ * The `Uuid` fields of these objects should change periodically.
+ * Search for other instances to keep the documentation and test suite
+ * up-to-date.
+ */
+
+struct FeatureData
+{
+  std::string const Uuid;
+  std::string const Variable;
+  std::string const Description;
+  bool Warned;
+} LookupTable[] = {
+  // CxxModuleCMakeApi
+  { "17be90bd-a850-44e0-be50-448de847d652",
+    "CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API",
+    "CMake's C++ module support is experimental. It is meant only for "
+    "experimentation and feedback to CMake developers.",
+    false },
+};
+static_assert(sizeof(LookupTable) / sizeof(LookupTable[0]) ==
+                static_cast<size_t>(cmExperimental::Feature::Sentinel),
+              "Experimental feature lookup table mismatch");
+
+FeatureData& DataForFeature(cmExperimental::Feature f)
+{
+  assert(f != cmExperimental::Feature::Sentinel);
+  return LookupTable[static_cast<size_t>(f)];
+}
+}
+
+bool cmExperimental::HasSupportEnabled(cmMakefile const& mf, Feature f)
+{
+  bool enabled = false;
+  auto& data = DataForFeature(f);
+
+  auto value = mf.GetDefinition(data.Variable);
+  if (value == data.Uuid) {
+    enabled = true;
+  }
+
+  if (enabled && !data.Warned) {
+    mf.IssueMessage(MessageType::AUTHOR_WARNING, data.Description);
+    data.Warned = true;
+  }
+
+  return enabled;
+}
diff --git a/Source/cmExperimental.h b/Source/cmExperimental.h
new file mode 100644
index 0000000..26e0d17
--- /dev/null
+++ b/Source/cmExperimental.h
@@ -0,0 +1,21 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+class cmMakefile;
+
+class cmExperimental
+{
+public:
+  enum class Feature
+  {
+    CxxModuleCMakeApi,
+
+    Sentinel,
+  };
+
+  static bool HasSupportEnabled(cmMakefile const& mf, Feature f);
+};
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index 6ce0c98..af33ada 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -9,7 +9,9 @@
 #include <sstream>
 #include <utility>
 
+#include <cm/string_view>
 #include <cmext/algorithm>
+#include <cmext/string_view>
 
 #include "cmExportSet.h"
 #include "cmFileSet.h"
@@ -382,6 +384,21 @@
       std::any_of(directoryEntries.begin(), directoryEntries.end(),
                   EntryIsContextSensitive);
 
+    auto const& type = fileSet->GetType();
+    // C++ modules do not support interface file sets which are dependent upon
+    // the configuration.
+    if (contextSensitive &&
+        (type == "CXX_MODULES"_s || type == "CXX_MODULE_HEADER_UNITS"_s)) {
+      auto* mf = this->LG->GetMakefile();
+      std::ostringstream e;
+      e << "The \"" << gte->GetName() << "\" target's interface file set \""
+        << fileSet->GetName() << "\" of type \"" << type
+        << "\" contains context-sensitive base directory entries which is not "
+           "supported.";
+      mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+      return std::string{};
+    }
+
     for (auto const& directory : directories) {
       auto dest = cmOutputConverter::EscapeForCMake(
         directory, cmOutputConverter::WrapQuotes::NoWrap);
@@ -427,6 +444,21 @@
       std::any_of(fileEntries.begin(), fileEntries.end(),
                   EntryIsContextSensitive);
 
+    auto const& type = fileSet->GetType();
+    // C++ modules do not support interface file sets which are dependent upon
+    // the configuration.
+    if (contextSensitive &&
+        (type == "CXX_MODULES"_s || type == "CXX_MODULE_HEADER_UNITS"_s)) {
+      auto* mf = this->LG->GetMakefile();
+      std::ostringstream e;
+      e << "The \"" << gte->GetName() << "\" target's interface file set \""
+        << fileSet->GetName() << "\" of type \"" << type
+        << "\" contains context-sensitive file entries which is not "
+           "supported.";
+      mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+      return std::string{};
+    }
+
     for (auto const& it : files) {
       for (auto const& filename : it.second) {
         auto escapedFile = cmOutputConverter::EscapeForCMake(
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 452eb99..9837269 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -932,13 +932,13 @@
 
   // Isolate the file policy level.
   // Support CMake versions as far back as 2.6 but also support using NEW
-  // policy settings for up to CMake 3.22 (this upper limit may be reviewed
+  // policy settings for up to CMake 3.23 (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.
   /* clang-format off */
   os << "cmake_policy(PUSH)\n"
-     << "cmake_policy(VERSION 2.8.3...3.22)\n";
+     << "cmake_policy(VERSION 2.8.3...3.23)\n";
   /* clang-format on */
 }
 
@@ -1088,6 +1088,10 @@
        << " PROPERTY IMPORTED_NO_SYSTEM 1)\n";
   }
 
+  if (target->GetPropertyAsBool("EXPORT_NO_SYSTEM")) {
+    os << "set_property(TARGET " << targetName << " PROPERTY SYSTEM 0)\n";
+  }
+
   os << "\n";
 }
 
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index adccdfe..3a06769 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -7,6 +7,9 @@
 #include <sstream>
 #include <utility>
 
+#include <cm/string_view>
+#include <cmext/string_view>
+
 #include "cmExportSet.h"
 #include "cmFileSet.h"
 #include "cmGeneratedFileStream.h"
@@ -18,6 +21,7 @@
 #include "cmInstallTargetGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
+#include "cmMessageType.h"
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
 #include "cmStateTypes.h"
@@ -562,6 +566,21 @@
                            cge->Evaluate(gte->LocalGenerator, config, gte),
                            cmOutputConverter::WrapQuotes::NoWrap));
 
+    auto const& type = fileSet->GetType();
+    // C++ modules do not support interface file sets which are dependent upon
+    // the configuration.
+    if (cge->GetHadContextSensitiveCondition() &&
+        (type == "CXX_MODULES"_s || type == "CXX_MODULE_HEADER_UNITS"_s)) {
+      auto* mf = this->IEGen->GetLocalGenerator()->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 std::string{};
+    }
+
     if (cge->GetHadContextSensitiveCondition() && configs.size() != 1) {
       resultVector.push_back(
         cmStrCat("\"$<$<CONFIG:", config, ">:", dest, ">\""));
@@ -610,6 +629,21 @@
       std::any_of(fileEntries.begin(), fileEntries.end(),
                   EntryIsContextSensitive);
 
+    auto const& type = fileSet->GetType();
+    // C++ modules do not support interface file sets which are dependent upon
+    // the configuration.
+    if (contextSensitive &&
+        (type == "CXX_MODULES"_s || type == "CXX_MODULE_HEADER_UNITS"_s)) {
+      auto* mf = this->IEGen->GetLocalGenerator()->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 std::string{};
+    }
+
     for (auto const& it : files) {
       auto prefix = it.first.empty() ? "" : cmStrCat(it.first, '/');
       for (auto const& filename : it.second) {
diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx
index 4dfbef9..91efc66 100644
--- a/Source/cmFindBase.cxx
+++ b/Source/cmFindBase.cxx
@@ -2,15 +2,20 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmFindBase.h"
 
+#include <algorithm>
 #include <cstddef>
 #include <deque>
+#include <functional>
 #include <map>
 #include <utility>
 
 #include <cm/optional>
 #include <cmext/algorithm>
+#include <cmext/string_view>
 
 #include "cmCMakePath.h"
+#include "cmExecutionStatus.h"
+#include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
@@ -24,8 +29,6 @@
 #include "cmWindowsRegistry.h"
 #include "cmake.h"
 
-class cmExecutionStatus;
-
 cmFindBase::cmFindBase(std::string findCommandName, cmExecutionStatus& status)
   : cmFindCommon(status)
   , FindCommandName(std::move(findCommandName))
@@ -138,6 +141,31 @@
           cmStrCat("given invalid value for \"REGISTRY_VIEW\": ", args[j]));
         return false;
       }
+    } else if (args[j] == "VALIDATOR") {
+      if (++j == args.size()) {
+        this->SetError("missing required argument for \"VALIDATOR\"");
+        return false;
+      }
+      auto command = this->Makefile->GetState()->GetCommand(args[j]);
+      if (command == nullptr) {
+        this->SetError(cmStrCat(
+          "command specified for \"VALIDATOR\" is undefined: ", args[j], '.'));
+        return false;
+      }
+      // ensure a macro is not specified as validator
+      const auto& validatorName = args[j];
+      auto macros = cmExpandedList(this->Makefile->GetProperty("MACROS"));
+      if (std::find_if(macros.begin(), macros.end(),
+                       [&validatorName](const std::string& item) {
+                         return cmSystemTools::Strucmp(validatorName.c_str(),
+                                                       item.c_str()) == 0;
+                       }) != macros.end()) {
+        this->SetError(cmStrCat(
+          "command specified for \"VALIDATOR\" is not a function: ", args[j],
+          '.'));
+        return false;
+      }
+      this->ValidatorName = args[j];
     } else if (this->CheckCommonArgument(args[j])) {
       doing = DoingNone;
     } else {
@@ -188,6 +216,36 @@
   return true;
 }
 
+bool cmFindBase::Validate(const std::string& path) const
+{
+  if (this->ValidatorName.empty()) {
+    return true;
+  }
+
+  // The validator command will be executed in an isolated scope.
+  cmMakefile::ScopePushPop varScope(this->Makefile);
+  cmMakefile::PolicyPushPop polScope(this->Makefile);
+  static_cast<void>(varScope);
+  static_cast<void>(polScope);
+
+  auto resultName =
+    cmStrCat("CMAKE_"_s, cmSystemTools::UpperCase(this->FindCommandName),
+             "_VALIDATOR_STATUS"_s);
+
+  this->Makefile->AddDefinitionBool(resultName, true);
+
+  cmListFileFunction validator(
+    this->ValidatorName, 0, 0,
+    { cmListFileArgument(resultName, cmListFileArgument::Unquoted, 0),
+      cmListFileArgument(path, cmListFileArgument::Quoted, 0) });
+  cmExecutionStatus status(*this->Makefile);
+
+  if (this->Makefile->ExecuteCommand(validator, status)) {
+    return this->Makefile->GetDefinition(resultName).IsOn();
+  }
+  return false;
+}
+
 void cmFindBase::ExpandPaths()
 {
   if (!this->NoDefaultPath) {
diff --git a/Source/cmFindBase.h b/Source/cmFindBase.h
index d197424..75d9a6d 100644
--- a/Source/cmFindBase.h
+++ b/Source/cmFindBase.h
@@ -31,6 +31,11 @@
    */
   virtual bool ParseArguments(std::vector<std::string> const& args);
 
+  /**
+   * To check validity of a found path using user's validator, if any
+   */
+  bool Validate(const std::string& path) const;
+
 protected:
   friend class cmFindBaseDebugState;
   void ExpandPaths();
@@ -63,6 +68,8 @@
 
   bool Required = false;
 
+  std::string ValidatorName;
+
 private:
   // Add pieces of the search.
   void FillPackageRootPath();
diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx
index 1c4039b..6296a60 100644
--- a/Source/cmFindLibraryCommand.cxx
+++ b/Source/cmFindLibraryCommand.cxx
@@ -192,6 +192,7 @@
 
   // Context information.
   cmMakefile* Makefile;
+  cmFindBase const* FindBase;
   cmGlobalGenerator* GG;
 
   // List of valid prefixes and suffixes.
@@ -239,6 +240,11 @@
   bool CheckDirectory(std::string const& path);
   bool CheckDirectoryForName(std::string const& path, Name& name);
 
+  bool Validate(const std::string& path) const
+  {
+    return this->FindBase->Validate(path);
+  }
+
   cmFindBaseDebugState DebugSearches;
 
   void DebugLibraryFailed(std::string const& name, std::string const& path)
@@ -291,6 +297,7 @@
 cmFindLibraryHelper::cmFindLibraryHelper(std::string debugName, cmMakefile* mf,
                                          cmFindBase const* base)
   : Makefile(mf)
+  , FindBase(base)
   , DebugMode(base->DebugModeEnabled())
   , DebugSearches(std::move(debugName), base)
 {
@@ -416,10 +423,13 @@
     if (!exists) {
       this->DebugLibraryFailed(name.Raw, path);
     } else {
-      this->DebugLibraryFound(name.Raw, path);
-      this->BestPath = cmSystemTools::CollapseFullPath(this->TestPath);
-      cmSystemTools::ConvertToUnixSlashes(this->BestPath);
-      return true;
+      auto testPath = cmSystemTools::CollapseFullPath(this->TestPath);
+      if (this->Validate(testPath)) {
+        this->DebugLibraryFound(name.Raw, path);
+        this->BestPath = testPath;
+        return true;
+      }
+      this->DebugLibraryFailed(name.Raw, path);
     }
   }
 
@@ -443,8 +453,11 @@
       this->TestPath = cmStrCat(path, origName);
       // Make sure the path is readable and is not a directory.
       if (cmSystemTools::FileExists(this->TestPath, true)) {
-        this->DebugLibraryFound(name.Raw, dir);
+        if (!this->Validate(cmSystemTools::CollapseFullPath(this->TestPath))) {
+          continue;
+        }
 
+        this->DebugLibraryFound(name.Raw, dir);
         // This is a matching file.  Check if it is better than the
         // best name found so far.  Earlier prefixes are preferred,
         // followed by earlier suffixes.  For OpenBSD, shared library
@@ -541,7 +554,10 @@
     for (std::string const& n : this->Names) {
       fwPath = cmStrCat(d, n, ".framework");
       if (cmSystemTools::FileIsDirectory(fwPath)) {
-        return cmSystemTools::CollapseFullPath(fwPath);
+        auto finalPath = cmSystemTools::CollapseFullPath(fwPath);
+        if (this->Validate(finalPath)) {
+          return finalPath;
+        }
       }
     }
   }
@@ -558,7 +574,10 @@
     for (std::string const& d : this->SearchPaths) {
       fwPath = cmStrCat(d, n, ".framework");
       if (cmSystemTools::FileIsDirectory(fwPath)) {
-        return cmSystemTools::CollapseFullPath(fwPath);
+        auto finalPath = cmSystemTools::CollapseFullPath(fwPath);
+        if (this->Validate(finalPath)) {
+          return finalPath;
+        }
       }
     }
   }
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index 8c6a0aa..4ad9124 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -822,13 +822,13 @@
   char buf[64];
   snprintf(buf, sizeof(buf), "%u", major);
   addDefinition(prefix + "_MAJOR", buf);
-  sprintf(buf, "%u", minor);
+  snprintf(buf, sizeof(buf), "%u", minor);
   addDefinition(prefix + "_MINOR", buf);
-  sprintf(buf, "%u", patch);
+  snprintf(buf, sizeof(buf), "%u", patch);
   addDefinition(prefix + "_PATCH", buf);
-  sprintf(buf, "%u", tweak);
+  snprintf(buf, sizeof(buf), "%u", tweak);
   addDefinition(prefix + "_TWEAK", buf);
-  sprintf(buf, "%u", count);
+  snprintf(buf, sizeof(buf), "%u", count);
   addDefinition(prefix + "_COUNT", buf);
 }
 
diff --git a/Source/cmFindPathCommand.cxx b/Source/cmFindPathCommand.cxx
index 27074ff..74a69d8 100644
--- a/Source/cmFindPathCommand.cxx
+++ b/Source/cmFindPathCommand.cxx
@@ -88,7 +88,8 @@
     if (!frameWorkName.empty()) {
       std::string fpath = cmStrCat(dir, frameWorkName, ".framework");
       std::string intPath = cmStrCat(fpath, "/Headers/", fileName);
-      if (cmSystemTools::FileExists(intPath)) {
+      if (cmSystemTools::FileExists(intPath) &&
+          this->Validate(this->IncludeFileInPath ? intPath : fpath)) {
         debug.FoundAt(intPath);
         if (this->IncludeFileInPath) {
           return intPath;
@@ -124,7 +125,8 @@
   for (std::string const& n : this->Names) {
     for (std::string const& sp : this->SearchPaths) {
       tryPath = cmStrCat(sp, n);
-      if (cmSystemTools::FileExists(tryPath)) {
+      if (cmSystemTools::FileExists(tryPath) &&
+          this->Validate(this->IncludeFileInPath ? tryPath : sp)) {
         debug.FoundAt(tryPath);
         if (this->IncludeFileInPath) {
           return tryPath;
diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx
index a64e0e4..8a2a69e 100644
--- a/Source/cmFindProgramCommand.cxx
+++ b/Source/cmFindProgramCommand.cxx
@@ -27,6 +27,7 @@
                       cmFindBase const* base)
     : DebugSearches(std::move(debugName), base)
     , Makefile(makefile)
+    , FindBase(base)
     , PolicyCMP0109(makefile->GetPolicyStatus(cmPolicies::CMP0109))
   {
 #if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
@@ -56,6 +57,7 @@
   // Debug state
   cmFindBaseDebugState DebugSearches;
   cmMakefile* Makefile;
+  cmFindBase const* FindBase;
 
   cmPolicies::PolicyStatus PolicyCMP0109;
 
@@ -94,7 +96,7 @@
                          this->TestNameExt = cmStrCat(name, ext);
                          this->TestPath = cmSystemTools::CollapseFullPath(
                            this->TestNameExt, path);
-                         bool exists = this->FileIsExecutable(this->TestPath);
+                         bool exists = this->FileIsValid(this->TestPath);
                          exists ? this->DebugSearches.FoundAt(this->TestPath)
                                 : this->DebugSearches.FailedAt(this->TestPath);
                          if (exists) {
@@ -104,12 +106,12 @@
                          return false;
                        });
   }
-  bool FileIsExecutable(std::string const& file) const
+  bool FileIsValid(std::string const& file) const
   {
-#ifdef _WIN32
     if (!this->FileIsExecutableCMP0109(file)) {
       return false;
     }
+#ifdef _WIN32
     // Pretend the Windows "python" app installer alias does not exist.
     if (cmSystemTools::LowerCase(file).find("/windowsapps/python") !=
         std::string::npos) {
@@ -119,10 +121,8 @@
         return false;
       }
     }
-    return true;
-#else
-    return this->FileIsExecutableCMP0109(file);
 #endif
+    return this->FindBase->Validate(file);
   }
   bool FileIsExecutableCMP0109(std::string const& file) const
   {
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 8a7215b..433c1d5 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -807,11 +807,16 @@
                                                  dagChecker, depTgt, language),
                  result);
   }
-  if (!depTgt->IsImported() || excludeImported) {
+  if (!depTgt->GetPropertyAsBool("SYSTEM")) {
     return;
   }
-  if (depTgt->GetPropertyAsBool("IMPORTED_NO_SYSTEM")) {
-    return;
+  if (depTgt->IsImported()) {
+    if (excludeImported) {
+      return;
+    }
+    if (depTgt->GetPropertyAsBool("IMPORTED_NO_SYSTEM")) {
+      return;
+    }
   }
 
   if (cmValue dirs = depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) {
@@ -1707,7 +1712,8 @@
         }
       }
       if (!found) {
-        if (fileSet->GetType() == "HEADERS"_s) {
+        if (fileSet->GetType() == "HEADERS"_s ||
+            fileSet->GetType() == "CXX_MODULE_HEADER_UNITS"_s) {
           headTarget->Makefile->GetOrCreateSourceGroup("Header Files")
             ->AddGroupFile(path);
         }
@@ -1728,6 +1734,20 @@
       addFileSetEntry(headTarget, config, dagChecker, headerSet, entries);
     }
   }
+  for (auto const& entry : headTarget->Target->GetCxxModuleSetsEntries()) {
+    for (auto const& name : cmExpandedList(entry.Value)) {
+      auto const* cxxModuleSet = headTarget->Target->GetFileSet(name);
+      addFileSetEntry(headTarget, config, dagChecker, cxxModuleSet, entries);
+    }
+  }
+  for (auto const& entry :
+       headTarget->Target->GetCxxModuleHeaderSetsEntries()) {
+    for (auto const& name : cmExpandedList(entry.Value)) {
+      auto const* cxxModuleHeaderSet = headTarget->Target->GetFileSet(name);
+      addFileSetEntry(headTarget, config, dagChecker, cxxModuleHeaderSet,
+                      entries);
+    }
+  }
 }
 
 bool processSources(cmGeneratorTarget const* tgt,
@@ -8700,3 +8720,76 @@
 
   return filename;
 }
+
+bool cmGeneratorTarget::HaveCxx20ModuleSources() const
+{
+  auto const& fs_names = this->Target->GetAllFileSetNames();
+  return std::any_of(fs_names.begin(), fs_names.end(),
+                     [this](std::string const& name) -> bool {
+                       auto const* file_set = this->Target->GetFileSet(name);
+                       if (!file_set) {
+                         this->Makefile->IssueMessage(
+                           MessageType::INTERNAL_ERROR,
+                           cmStrCat("Target \"", this->Target->GetName(),
+                                    "\" is tracked to have file set \"", name,
+                                    "\", but it was not found."));
+                         return false;
+                       }
+
+                       auto const& fs_type = file_set->GetType();
+                       return fs_type == "CXX_MODULES"_s ||
+                         fs_type == "CXX_MODULE_HEADER_UNITS"_s;
+                     });
+}
+
+cmGeneratorTarget::Cxx20SupportLevel cmGeneratorTarget::HaveCxxModuleSupport(
+  std::string const& config) const
+{
+  auto const* state = this->Makefile->GetState();
+  if (!state->GetLanguageEnabled("CXX")) {
+    return Cxx20SupportLevel::MissingCxx;
+  }
+  cmStandardLevelResolver standardResolver(this->Makefile);
+  if (!standardResolver.HaveStandardAvailable(this, "CXX", config,
+                                              "cxx_std_20")) {
+    return Cxx20SupportLevel::NoCxx20;
+  }
+  if (!this->Makefile->IsOn("CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP")) {
+    return Cxx20SupportLevel::MissingExperimentalFlag;
+  }
+  return Cxx20SupportLevel::Supported;
+}
+
+void cmGeneratorTarget::CheckCxxModuleStatus(std::string const& config) const
+{
+  // Check for `CXX_MODULE*` file sets and a lack of support.
+  if (this->HaveCxx20ModuleSources()) {
+    switch (this->HaveCxxModuleSupport(config)) {
+      case cmGeneratorTarget::Cxx20SupportLevel::MissingCxx:
+        this->Makefile->IssueMessage(
+          MessageType::FATAL_ERROR,
+          cmStrCat("The \"", this->GetName(),
+                   "\" target has C++ module sources but the \"CXX\" language "
+                   "has not been enabled"));
+        break;
+      case cmGeneratorTarget::Cxx20SupportLevel::MissingExperimentalFlag:
+        this->Makefile->IssueMessage(
+          MessageType::FATAL_ERROR,
+          cmStrCat("The \"", this->GetName(),
+                   "\" target has C++ module sources but its experimental "
+                   "support has not been requested"));
+        break;
+      case cmGeneratorTarget::Cxx20SupportLevel::NoCxx20:
+        this->Makefile->IssueMessage(
+          MessageType::FATAL_ERROR,
+          cmStrCat(
+            "The \"", this->GetName(),
+            "\" target has C++ module sources but is not using at least "
+            "\"cxx_std_20\""));
+        break;
+      case cmGeneratorTarget::Cxx20SupportLevel::Supported:
+        // All is well.
+        break;
+    }
+  }
+}
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 6bce7d2..349afa7 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -1196,4 +1196,34 @@
     bool operator()(cmGeneratorTarget const* t1,
                     cmGeneratorTarget const* t2) const;
   };
+
+  // C++20 module support queries.
+
+  /**
+   * Query whether the target expects C++20 module support.
+   *
+   * This will inspect the target itself to see if C++20 module
+   * support is expected to work based on its sources.
+   */
+  bool HaveCxx20ModuleSources() const;
+
+  enum class Cxx20SupportLevel
+  {
+    // C++ is not available.
+    MissingCxx,
+    // The experimental feature is not available.
+    MissingExperimentalFlag,
+    // The target does not require at least C++20.
+    NoCxx20,
+    // C++20 modules are available and working.
+    Supported,
+  };
+  /**
+   * Query whether the target has C++20 module support available (regardless of
+   * whether it is required or not).
+   */
+  Cxx20SupportLevel HaveCxxModuleSupport(std::string const& config) const;
+
+  // Check C++ module status for the target.
+  void CheckCxxModuleStatus(std::string const& config) const;
 };
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index acaed36..7cbe80a 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -5,6 +5,7 @@
 #include <algorithm>
 #include <cctype>
 #include <cstdio>
+#include <functional>
 #include <sstream>
 #include <utility>
 
@@ -21,6 +22,7 @@
 
 #include "cmsys/FStream.hxx"
 
+#include "cmCxxModuleMapper.h"
 #include "cmDocumentationEntry.h"
 #include "cmFortranParser.h"
 #include "cmGeneratedFileStream.h"
@@ -2517,7 +2519,7 @@
   // Populate the module map with those provided by linked targets first.
   for (std::string const& linked_target_dir : linked_target_dirs) {
     std::string const ltmn =
-      cmStrCat(linked_target_dir, "/", arg_lang, "Modules.json");
+      cmStrCat(linked_target_dir, '/', arg_lang, "Modules.json");
     Json::Value ltm;
     cmsys::ifstream ltmf(ltmn.c_str(), std::ios::in | std::ios::binary);
     Json::Reader reader;
@@ -2534,11 +2536,20 @@
     }
   }
 
-  const char* module_ext = "";
-  if (arg_modmapfmt == "gcc") {
-    module_ext = ".gcm";
+  cm::optional<CxxModuleMapFormat> modmap_fmt;
+  if (arg_modmapfmt.empty()) {
+    // nothing to do.
+  } else if (arg_modmapfmt == "gcc") {
+    modmap_fmt = CxxModuleMapFormat::Gcc;
+  } else {
+    cmSystemTools::Error(
+      cmStrCat("-E cmake_ninja_dyndep does not understand the ", arg_modmapfmt,
+               " module map format"));
+    return false;
   }
 
+  auto module_ext = CxxModuleMapExtension(modmap_fmt);
+
   // Extend the module map with those provided by this target.
   // We do this after loading the modules provided by linked targets
   // in case we have one of the same name that must be preferred.
@@ -2555,7 +2566,8 @@
         }
       } else {
         // Assume the module file path matches the logical module name.
-        std::string safe_logical_name = p.LogicalName;
+        std::string safe_logical_name =
+          p.LogicalName; // TODO: needs fixing for header units
         cmSystemTools::ReplaceString(safe_logical_name, ":", "-");
         mod = cmStrCat(module_dir, safe_logical_name, module_ext);
       }
@@ -2568,6 +2580,20 @@
   ddf << "ninja_dyndep_version = 1.0\n";
 
   {
+    CxxModuleLocations locs;
+    locs.RootDirectory = ".";
+    locs.PathForGenerator = [this](std::string const& path) -> std::string {
+      return this->ConvertToNinjaPath(path);
+    };
+    locs.BmiLocationForModule =
+      [&mod_files](std::string const& logical) -> cm::optional<std::string> {
+      auto m = mod_files.find(logical);
+      if (m != mod_files.end()) {
+        return m->second;
+      }
+      return {};
+    };
+
     cmNinjaBuild build("dyndep");
     build.Outputs.emplace_back("");
     for (cmScanDepInfo const& object : objects) {
@@ -2589,46 +2615,14 @@
         build.Variables.emplace("restat", "1");
       }
 
-      if (arg_modmapfmt.empty()) {
-        // nothing to do.
-      } else {
-        std::stringstream mm;
-        if (arg_modmapfmt == "gcc") {
-          // Documented in GCC's documentation. The format is a series of lines
-          // with a module name and the associated filename separated by
-          // spaces. The first line may use `$root` as the module name to
-          // specify a "repository root". That is used to anchor any relative
-          // paths present in the file (CMake should never generate any).
-
-          // Write the root directory to use for module paths.
-          mm << "$root .\n";
-
-          for (auto const& l : object.Provides) {
-            auto m = mod_files.find(l.LogicalName);
-            if (m != mod_files.end()) {
-              mm << l.LogicalName << " " << this->ConvertToNinjaPath(m->second)
-                 << "\n";
-            }
-          }
-          for (auto const& r : object.Requires) {
-            auto m = mod_files.find(r.LogicalName);
-            if (m != mod_files.end()) {
-              mm << r.LogicalName << " " << this->ConvertToNinjaPath(m->second)
-                 << "\n";
-            }
-          }
-        } else {
-          cmSystemTools::Error(
-            cmStrCat("-E cmake_ninja_dyndep does not understand the ",
-                     arg_modmapfmt, " module map format"));
-          return false;
-        }
+      if (modmap_fmt) {
+        auto mm = CxxModuleMapContent(*modmap_fmt, locs, object);
 
         // XXX(modmap): If changing this path construction, change
         // `cmNinjaTargetGenerator::WriteObjectBuildStatements` to generate the
         // corresponding file path.
         cmGeneratedFileStream mmf(cmStrCat(object.PrimaryOutput, ".modmap"));
-        mmf << mm.str();
+        mmf << mm;
       }
 
       this->WriteBuild(ddf, build);
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index f7f7317..e53ae8e 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -395,12 +395,27 @@
 {
   VisualStudioFolders.clear();
 
+  std::vector<std::string> configs =
+    root->GetMakefile()->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
+
   for (cmGeneratorTarget const* target : projectTargets) {
     if (!this->IsInSolution(target)) {
       continue;
     }
     bool written = false;
 
+    for (auto const& c : configs) {
+      target->CheckCxxModuleStatus(c);
+    }
+
+    if (target->HaveCxx20ModuleSources() && !this->SupportsCxxModuleDyndep()) {
+      root->GetMakefile()->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat("The \"", target->GetName(),
+                 "\" target contains C++ module sources which are not "
+                 "supported by the generator"));
+    }
+
     // handle external vc project files
     cmValue expath = target->GetProperty("EXTERNAL_MSPROJECT");
     if (expath) {
diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h
index a55cf45..288069c 100644
--- a/Source/cmGlobalVisualStudio7Generator.h
+++ b/Source/cmGlobalVisualStudio7Generator.h
@@ -157,6 +157,8 @@
     cmValue typeGuid,
     const std::set<BT<std::pair<std::string, bool>>>& dependencies) = 0;
 
+  virtual bool SupportsCxxModuleDyndep() const { return false; }
+
   std::string ConvertToSolutionPath(const std::string& path);
 
   std::set<std::string> IsPartOfDefaultBuild(
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index d5783ef..5738799 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -468,6 +468,10 @@
     }
     CFRelease(cfStr);
   }
+#else
+  (void)bindir;
+  (void)projectName;
+  (void)dryRun;
 #endif
 
   return ret;
@@ -1372,6 +1376,18 @@
     return true;
   }
 
+  for (std::string const& configName : this->CurrentConfigurationTypes) {
+    gtgt->CheckCxxModuleStatus(configName);
+  }
+
+  if (gtgt->HaveCxx20ModuleSources()) {
+    gtgt->Makefile->IssueMessage(
+      MessageType::FATAL_ERROR,
+      cmStrCat("The \"", gtgt->GetName(),
+               "\" target contains C++ module sources which are not "
+               "supported by the generator"));
+  }
+
   auto& gtgt_visited = this->CommandsVisited[gtgt];
   auto& deps = this->GetTargetDirectDepends(gtgt);
   for (auto& d : deps) {
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 628eb1d..97a3db9 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -4431,7 +4431,7 @@
   }
 
   // Deprecate old policies.
-  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0097 &&
+  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0102 &&
       !(this->GetCMakeInstance()->GetIsInTryCompile() &&
         (
           // Policies set by cmCoreTryCompile::TryCompileCode.
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index 3849c6f..74574f7 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -182,14 +182,16 @@
 
     // Collect up flags to link in needed libraries.
     std::string linkLibs;
-    this->CreateLinkLibs(linkLineComputer.get(), linkLibs,
-                         useResponseFileForLibs, depends);
+    this->CreateLinkLibs(
+      linkLineComputer.get(), linkLibs, useResponseFileForLibs, depends,
+      cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink);
 
     // Construct object file lists that may be needed to expand the
     // rule.
     std::string buildObjs;
-    this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects,
-                            buildObjs, depends, false);
+    this->CreateObjectLists(
+      useLinkScript, false, useResponseFileForObjects, buildObjs, depends,
+      false, cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink);
 
     cmRulePlaceholderExpander::RuleVariables vars;
     std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index f30ec27..3f7d87d 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -322,15 +322,17 @@
     linkLineComputer->SetForResponse(useResponseFileForLibs);
     linkLineComputer->SetRelink(relink);
 
-    this->CreateLinkLibs(linkLineComputer.get(), linkLibs,
-                         useResponseFileForLibs, depends);
+    this->CreateLinkLibs(
+      linkLineComputer.get(), linkLibs, useResponseFileForLibs, depends,
+      cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink);
 
     // Construct object file lists that may be needed to expand the
     // rule.
     std::string buildObjs;
-    this->CreateObjectLists(useLinkScript, false, // useArchiveRules
-                            useResponseFileForObjects, buildObjs, depends,
-                            false);
+    this->CreateObjectLists(
+      useLinkScript, false, // useArchiveRules
+      useResponseFileForObjects, buildObjs, depends, false,
+      cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink);
 
     std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
     objectDir = this->LocalGenerator->ConvertToOutputFormat(
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index aec6577..1e1df79 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -21,6 +21,7 @@
 #include "cmComputeLinkInformation.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandGenerator.h"
+#include "cmFileSet.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
@@ -46,6 +47,7 @@
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmTarget.h"
 #include "cmValue.h"
 #include "cmake.h"
 
@@ -107,7 +109,7 @@
   return result;
 }
 
-std::string cmMakefileTargetGenerator::GetConfigName()
+std::string cmMakefileTargetGenerator::GetConfigName() const
 {
   auto const& configNames = this->LocalGenerator->GetConfigNames();
   assert(configNames.size() == 1);
@@ -190,6 +192,16 @@
 
 void cmMakefileTargetGenerator::WriteTargetBuildRules()
 {
+  this->GeneratorTarget->CheckCxxModuleStatus(this->GetConfigName());
+
+  if (this->GeneratorTarget->HaveCxx20ModuleSources()) {
+    this->Makefile->IssueMessage(
+      MessageType::FATAL_ERROR,
+      cmStrCat("The \"", this->GeneratorTarget->GetName(),
+               "\" target contains C++ module sources which are not supported "
+               "by the generator"));
+  }
+
   // -- Write the custom commands for this target
 
   // Evaluates generator expressions and expands prop_value
@@ -302,6 +314,40 @@
     }
   }
 
+  std::map<std::string, std::string> file_set_map;
+
+  auto const* tgt = this->GeneratorTarget->Target;
+  for (auto const& name : tgt->GetAllFileSetNames()) {
+    auto const* file_set = tgt->GetFileSet(name);
+    if (!file_set) {
+      this->Makefile->IssueMessage(
+        MessageType::INTERNAL_ERROR,
+        cmStrCat("Target \"", tgt->GetName(),
+                 "\" is tracked to have file set \"", name,
+                 "\", but it was not found."));
+      continue;
+    }
+
+    auto fileEntries = file_set->CompileFileEntries();
+    auto directoryEntries = file_set->CompileDirectoryEntries();
+    auto directories = file_set->EvaluateDirectoryEntries(
+      directoryEntries, this->LocalGenerator, this->GetConfigName(),
+      this->GeneratorTarget);
+
+    std::map<std::string, std::vector<std::string>> files;
+    for (auto const& entry : fileEntries) {
+      file_set->EvaluateFileEntry(directories, files, entry,
+                                  this->LocalGenerator, this->GetConfigName(),
+                                  this->GeneratorTarget);
+    }
+
+    for (auto const& it : files) {
+      for (auto const& filename : it.second) {
+        file_set_map[filename] = file_set->GetType();
+      }
+    }
+  }
+
   std::vector<cmSourceFile const*> objectSources;
   this->GeneratorTarget->GetObjectSources(objectSources,
                                           this->GetConfigName());
@@ -314,6 +360,25 @@
       this->WriteObjectRuleFiles(*sf);
     }
   }
+
+  for (cmSourceFile const* sf : objectSources) {
+    auto const& path = sf->GetFullPath();
+    auto const it = file_set_map.find(path);
+    if (it != file_set_map.end()) {
+      auto const& file_set_type = it->second;
+      if (file_set_type == "CXX_MODULES"_s ||
+          file_set_type == "CXX_MODULE_HEADER_UNITS"_s) {
+        if (sf->GetLanguage() != "CXX"_s) {
+          this->Makefile->IssueMessage(
+            MessageType::FATAL_ERROR,
+            cmStrCat(
+              "Target \"", tgt->GetName(), "\" contains the source\n  ", path,
+              "\nin a file set of type \"", file_set_type,
+              R"(" but the source is not classified as a "CXX" source.)"));
+        }
+      }
+    }
+  }
 }
 
 void cmMakefileTargetGenerator::WriteCommonCodeRules()
@@ -2080,7 +2145,7 @@
 }
 
 std::string cmMakefileTargetGenerator::CreateResponseFile(
-  const char* name, std::string const& options,
+  const std::string& name, std::string const& options,
   std::vector<std::string>& makefile_depends)
 {
   // FIXME: Find a better way to determine the response file encoding,
@@ -2126,7 +2191,8 @@
 
 void cmMakefileTargetGenerator::CreateLinkLibs(
   cmLinkLineComputer* linkLineComputer, std::string& linkLibs,
-  bool useResponseFile, std::vector<std::string>& makefile_depends)
+  bool useResponseFile, std::vector<std::string>& makefile_depends,
+  ResponseFlagFor responseMode)
 {
   std::string frameworkPath;
   std::string linkPath;
@@ -2139,20 +2205,13 @@
   if (useResponseFile &&
       linkLibs.find_first_not_of(' ') != std::string::npos) {
     // Lookup the response file reference flag.
-    std::string responseFlagVar =
-      cmStrCat("CMAKE_",
-               this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()),
-               "_RESPONSE_FILE_LINK_FLAG");
-    std::string responseFlag;
-    if (cmValue p = this->Makefile->GetDefinition(responseFlagVar)) {
-      responseFlag = *p;
-    } else {
-      responseFlag = "@";
-    }
+    std::string responseFlag = this->GetResponseFlag(responseMode);
 
     // Create this response file.
+    std::string responseFileName =
+      (responseMode == Link) ? "linkLibs.rsp" : "deviceLinkLibs.rsp";
     std::string link_rsp =
-      this->CreateResponseFile("linklibs.rsp", linkLibs, makefile_depends);
+      this->CreateResponseFile(responseFileName, linkLibs, makefile_depends);
 
     // Reference the response file.
     linkLibs = cmStrCat(responseFlag,
@@ -2164,7 +2223,7 @@
 void cmMakefileTargetGenerator::CreateObjectLists(
   bool useLinkScript, bool useArchiveRules, bool useResponseFile,
   std::string& buildObjs, std::vector<std::string>& makefile_depends,
-  bool useWatcomQuote)
+  bool useWatcomQuote, ResponseFlagFor responseMode)
 {
   std::string variableName;
   std::string variableNameExternal;
@@ -2179,27 +2238,19 @@
     this->WriteObjectsStrings(object_strings, responseFileLimit);
 
     // Lookup the response file reference flag.
-    std::string responseFlagVar =
-      cmStrCat("CMAKE_",
-               this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()),
-               "_RESPONSE_FILE_LINK_FLAG");
-    std::string responseFlag;
-    if (cmValue p = this->Makefile->GetDefinition(responseFlagVar)) {
-      responseFlag = *p;
-    } else {
-      responseFlag = "@";
-    }
+    std::string responseFlag = this->GetResponseFlag(responseMode);
 
     // Write a response file for each string.
     const char* sep = "";
     for (unsigned int i = 0; i < object_strings.size(); ++i) {
       // Number the response files.
-      char rsp[32];
-      snprintf(rsp, sizeof(rsp), "objects%u.rsp", i + 1);
+      std::string responseFileName =
+        (responseMode == Link) ? "objects" : "deviceObjects";
+      responseFileName += std::to_string(i + 1);
 
       // Create this response file.
-      std::string objects_rsp =
-        this->CreateResponseFile(rsp, object_strings[i], makefile_depends);
+      std::string objects_rsp = this->CreateResponseFile(
+        responseFileName, object_strings[i], makefile_depends);
 
       // Separate from previous response file references.
       buildObjs += sep;
@@ -2251,7 +2302,7 @@
     }
     std::string name = cmStrCat("includes_", lang, ".rsp");
     std::string arg = std::move(responseFlag) +
-      this->CreateResponseFile(name.c_str(), includeFlags,
+      this->CreateResponseFile(name, includeFlags,
                                this->FlagFileDepends[lang]);
     this->LocalGenerator->AppendFlags(flags, arg);
   } else {
@@ -2304,3 +2355,22 @@
     fout << src->GetFullPath() << "\n";
   }
 }
+
+std::string cmMakefileTargetGenerator::GetResponseFlag(
+  ResponseFlagFor mode) const
+{
+  std::string responseFlag = "@";
+  std::string responseFlagVar;
+
+  auto lang = this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName());
+  if (mode == cmMakefileTargetGenerator::ResponseFlagFor::Link) {
+    responseFlagVar = cmStrCat("CMAKE_", lang, "_RESPONSE_FILE_LINK_FLAG");
+  } else if (mode == cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink) {
+    responseFlagVar = "CMAKE_CUDA_RESPONSE_FILE_DEVICE_LINK_FLAG";
+  }
+
+  if (cmValue p = this->Makefile->GetDefinition(responseFlagVar)) {
+    responseFlag = *p;
+  }
+  return responseFlag;
+}
diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h
index cb804e0..dafa650 100644
--- a/Source/cmMakefileTargetGenerator.h
+++ b/Source/cmMakefileTargetGenerator.h
@@ -56,7 +56,7 @@
 
   cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; }
 
-  std::string GetConfigName();
+  std::string GetConfigName() const;
 
 protected:
   void GetDeviceLinkFlags(std::string& linkFlags,
@@ -157,22 +157,31 @@
   /** Create a response file with the given set of options.  Returns
       the relative path from the target build working directory to the
       response file name.  */
-  std::string CreateResponseFile(const char* name, std::string const& options,
+  std::string CreateResponseFile(const std::string& name,
+                                 std::string const& options,
                                  std::vector<std::string>& makefile_depends);
 
   bool CheckUseResponseFileForObjects(std::string const& l) const;
   bool CheckUseResponseFileForLibraries(std::string const& l) const;
 
+  enum ResponseFlagFor
+  {
+    Link,
+    DeviceLink
+  };
+
   /** Create list of flags for link libraries. */
   void CreateLinkLibs(cmLinkLineComputer* linkLineComputer,
                       std::string& linkLibs, bool useResponseFile,
-                      std::vector<std::string>& makefile_depends);
+                      std::vector<std::string>& makefile_depends,
+                      ResponseFlagFor responseMode = ResponseFlagFor::Link);
 
   /** Create lists of object files for linking and cleaning.  */
   void CreateObjectLists(bool useLinkScript, bool useArchiveRules,
                          bool useResponseFile, std::string& buildObjs,
                          std::vector<std::string>& makefile_depends,
-                         bool useWatcomQuote);
+                         bool useWatcomQuote,
+                         ResponseFlagFor responseMode = ResponseFlagFor::Link);
 
   /** Add commands for generate def files */
   void GenDefFile(std::vector<std::string>& real_link_commands);
@@ -180,6 +189,9 @@
   void AddIncludeFlags(std::string& flags, const std::string& lang,
                        const std::string& config) override;
 
+  /** Return the response flag for the given configuration */
+  std::string GetResponseFlag(ResponseFlagFor mode) const;
+
   virtual void CloseFileStreams();
   cmLocalUnixMakefileGenerator3* LocalGenerator;
   cmGlobalUnixMakefileGenerator3* GlobalGenerator;
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 3fac7f5..ee065c4 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -36,7 +36,6 @@
 #include "cmRange.h"
 #include "cmRulePlaceholderExpander.h"
 #include "cmSourceFile.h"
-#include "cmStandardLevelResolver.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
@@ -153,17 +152,12 @@
 bool cmNinjaTargetGenerator::NeedCxxModuleSupport(
   std::string const& lang, std::string const& config) const
 {
-  if (lang != "CXX") {
+  if (lang != "CXX"_s) {
     return false;
   }
-  if (!this->Makefile->IsOn("CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP")) {
-    return false;
-  }
-  cmGeneratorTarget const* tgt = this->GetGeneratorTarget();
-  cmStandardLevelResolver standardResolver(this->Makefile);
-  bool const uses_cxx20 =
-    standardResolver.HaveStandardAvailable(tgt, "CXX", config, "cxx_std_20");
-  return uses_cxx20 && this->GetGlobalGenerator()->CheckCxxModuleSupport();
+  return this->GetGeneratorTarget()->HaveCxxModuleSupport(config) ==
+    cmGeneratorTarget::Cxx20SupportLevel::Supported &&
+    this->GetGlobalGenerator()->CheckCxxModuleSupport();
 }
 
 bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang,
@@ -255,52 +249,54 @@
       flags, genexInterpreter.Evaluate(pchOptions, COMPILE_OPTIONS));
   }
 
-  if (this->NeedCxxModuleSupport(language, config)) {
-    auto const& path = source->GetFullPath();
-    auto const* tgt = this->GeneratorTarget->Target;
+  auto const& path = source->GetFullPath();
+  auto const* tgt = this->GeneratorTarget->Target;
 
-    std::string file_set_type;
+  std::string file_set_type;
 
-    for (auto const& name : tgt->GetAllFileSetNames()) {
-      auto const* file_set = tgt->GetFileSet(name);
-      if (!file_set) {
+  for (auto const& name : tgt->GetAllFileSetNames()) {
+    auto const* file_set = tgt->GetFileSet(name);
+    if (!file_set) {
+      this->GetMakefile()->IssueMessage(
+        MessageType::INTERNAL_ERROR,
+        cmStrCat("Target \"", tgt->GetName(),
+                 "\" is tracked to have file set \"", name,
+                 "\", but it was not found."));
+      continue;
+    }
+
+    auto fileEntries = file_set->CompileFileEntries();
+    auto directoryEntries = file_set->CompileDirectoryEntries();
+    auto directories = file_set->EvaluateDirectoryEntries(
+      directoryEntries, this->LocalGenerator, config, this->GeneratorTarget);
+
+    std::map<std::string, std::vector<std::string>> files;
+    for (auto const& entry : fileEntries) {
+      file_set->EvaluateFileEntry(directories, files, entry,
+                                  this->LocalGenerator, config,
+                                  this->GeneratorTarget);
+    }
+
+    for (auto const& it : files) {
+      for (auto const& filename : it.second) {
+        if (filename == path) {
+          file_set_type = file_set->GetType();
+          break;
+        }
+      }
+    }
+
+    if (file_set_type == "CXX_MODULES"_s ||
+        file_set_type == "CXX_MODULE_HEADER_UNITS"_s) {
+      if (source->GetLanguage() != "CXX"_s) {
         this->GetMakefile()->IssueMessage(
-          MessageType::INTERNAL_ERROR,
-          cmStrCat("Target `", tgt->GetName(),
-                   "` is tracked to have file set `", name,
-                   "`, but it was not found."));
+          MessageType::FATAL_ERROR,
+          cmStrCat(
+            "Target \"", tgt->GetName(), "\" contains the source\n  ", path,
+            "\nin a file set of type \"", file_set_type,
+            R"(" but the source is not classified as a "CXX" source.)"));
         continue;
       }
-
-      auto fileEntries = file_set->CompileFileEntries();
-      auto directoryEntries = file_set->CompileDirectoryEntries();
-      auto directories = file_set->EvaluateDirectoryEntries(
-        directoryEntries, this->LocalGenerator, config, this->GeneratorTarget);
-
-      std::map<std::string, std::vector<std::string>> files;
-      for (auto const& entry : fileEntries) {
-        file_set->EvaluateFileEntry(directories, files, entry,
-                                    this->LocalGenerator, config,
-                                    this->GeneratorTarget);
-      }
-
-      for (auto const& it : files) {
-        for (auto const& filename : it.second) {
-          if (filename == path) {
-            file_set_type = file_set->GetType();
-            break;
-          }
-        }
-      }
-
-      if (!file_set_type.empty()) {
-        std::string source_type_var = cmStrCat(
-          "CMAKE_EXPERIMENTAL_CXX_MODULE_SOURCE_TYPE_FLAG_", file_set_type);
-        cmMakefile* mf = this->GetMakefile();
-        if (cmValue source_type_flag = mf->GetDefinition(source_type_var)) {
-          this->LocalGenerator->AppendFlags(flags, *source_type_flag);
-        }
-      }
     }
   }
 
@@ -1038,6 +1034,8 @@
   const std::string& config, const std::string& fileConfig,
   bool firstForConfig)
 {
+  this->GeneratorTarget->CheckCxxModuleStatus(config);
+
   // Write comments.
   cmGlobalNinjaGenerator::WriteDivider(this->GetImplFileStream(fileConfig));
   this->GetImplFileStream(fileConfig)
@@ -1616,8 +1614,9 @@
     mod_dir = this->GeneratorTarget->GetFortranModuleDirectory(
       this->Makefile->GetHomeOutputDirectory());
   } else if (lang == "CXX") {
-    mod_dir =
-      cmSystemTools::CollapseFullPath(this->GeneratorTarget->ObjectDirectory);
+    mod_dir = this->GetGlobalGenerator()->ExpandCFGIntDir(
+      cmSystemTools::CollapseFullPath(this->GeneratorTarget->ObjectDirectory),
+      config);
   }
   if (mod_dir.empty()) {
     mod_dir = this->Makefile->GetCurrentBinaryDirectory();
diff --git a/Source/cmScriptGenerator.cxx b/Source/cmScriptGenerator.cxx
index 166ee56..32f9bec 100644
--- a/Source/cmScriptGenerator.cxx
+++ b/Source/cmScriptGenerator.cxx
@@ -133,7 +133,7 @@
     std::string config_test = this->CreateConfigTest(this->Configurations);
     os << indent << "if(" << config_test << ")\n";
     this->GenerateScriptActions(os, indent.Next());
-    os << indent << "endif(" << config_test << ")\n";
+    os << indent << "endif()\n";
   }
 }
 
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index c3ee695..fe311d1 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -143,7 +143,8 @@
 
   std::string::size_type hexIndex = 0;
   for (auto const& c : instr) {
-    sprintf(&output[hexIndex], "%.2x", static_cast<unsigned char>(c) & 0xFF);
+    snprintf(&output[hexIndex], 3, "%.2x",
+             static_cast<unsigned char>(c) & 0xFF);
     hexIndex += 2;
   }
 
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 351386a..55b0df8 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -1218,7 +1218,7 @@
                       certContext, CERT_HASH_PROP_ID, hashData, &hashLength)) {
                   for (DWORD i = 0; i < hashLength; i++) {
                     // Convert each byte to hexadecimal
-                    sprintf(pHashPrint, "%02X", hashData[i]);
+                    snprintf(pHashPrint, 3, "%02X", hashData[i]);
                     pHashPrint += 2;
                   }
                   *pHashPrint = '\0';
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index a8cd619..c76e2cb 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -272,6 +272,8 @@
   cmListFileBacktrace Backtrace;
 
   FileSetType HeadersFileSets;
+  FileSetType CxxModulesFileSets;
+  FileSetType CxxModuleHeadersFileSets;
 
   cmTargetInternals();
 
@@ -301,6 +303,19 @@
                     "The default header set"_s, "Header set"_s,
                     FileSetEntries("HEADER_SETS"_s),
                     FileSetEntries("INTERFACE_HEADER_SETS"_s))
+  , CxxModulesFileSets("CXX_MODULES"_s, "CXX_MODULE_DIRS"_s,
+                       "CXX_MODULE_SET"_s, "CXX_MODULE_DIRS_"_s,
+                       "CXX_MODULE_SET_"_s, "C++ module"_s,
+                       "The default C++ module set"_s, "C++ module set"_s,
+                       FileSetEntries("CXX_MODULE_SETS"_s),
+                       FileSetEntries("INTERFACE_CXX_MODULE_SETS"_s))
+  , CxxModuleHeadersFileSets(
+      "CXX_MODULE_HEADER_UNITS"_s, "CXX_MODULE_HEADER_UNIT_DIRS"_s,
+      "CXX_MODULE_HEADER_UNIT_SET"_s, "CXX_MODULE_HEADER_UNIT_DIRS_"_s,
+      "CXX_MODULE_HEADER_UNIT_SET_"_s, "C++ module header"_s,
+      "The default C++ module header set"_s, "C++ module header set"_s,
+      FileSetEntries("CXX_MODULE_HEADER_UNIT_SETS"_s),
+      FileSetEntries("INTERFACE_CXX_MODULE_HEADER_UNIT_SETS"_s))
 {
 }
 
@@ -611,6 +626,7 @@
       initProp("XCODE_SCHEME_MALLOC_SCRIBBLE");
       initProp("XCODE_SCHEME_MALLOC_GUARD_EDGES");
       initProp("XCODE_SCHEME_GUARD_MALLOC");
+      initProp("XCODE_SCHEME_LAUNCH_MODE");
       initProp("XCODE_SCHEME_ZOMBIE_OBJECTS");
       initProp("XCODE_SCHEME_MALLOC_STACK");
       initProp("XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE");
@@ -760,6 +776,10 @@
     }
   }
 
+  if (this->IsImported()) {
+    this->SetProperty("SYSTEM", "ON");
+  }
+
   for (auto const& prop : mf->GetState()->GetPropertyDefinitions().GetMap()) {
     if (prop.first.second == cmProperty::TARGET &&
         !prop.second.GetInitializeFromVariable().empty()) {
@@ -1367,11 +1387,32 @@
   return cmMakeRange(this->impl->HeadersFileSets.SelfEntries.Entries);
 }
 
+cmBTStringRange cmTarget::GetCxxModuleSetsEntries() const
+{
+  return cmMakeRange(this->impl->CxxModulesFileSets.SelfEntries.Entries);
+}
+
+cmBTStringRange cmTarget::GetCxxModuleHeaderSetsEntries() const
+{
+  return cmMakeRange(this->impl->CxxModuleHeadersFileSets.SelfEntries.Entries);
+}
+
 cmBTStringRange cmTarget::GetInterfaceHeaderSetsEntries() const
 {
   return cmMakeRange(this->impl->HeadersFileSets.InterfaceEntries.Entries);
 }
 
+cmBTStringRange cmTarget::GetInterfaceCxxModuleSetsEntries() const
+{
+  return cmMakeRange(this->impl->CxxModulesFileSets.InterfaceEntries.Entries);
+}
+
+cmBTStringRange cmTarget::GetInterfaceCxxModuleHeaderSetsEntries() const
+{
+  return cmMakeRange(
+    this->impl->CxxModuleHeadersFileSets.InterfaceEntries.Entries);
+}
+
 namespace {
 #define MAKE_PROP(PROP) const std::string prop##PROP = #PROP
 MAKE_PROP(C_STANDARD);
@@ -1631,6 +1672,12 @@
   } else if (this->impl->HeadersFileSets.WriteProperties(
                this, this->impl.get(), prop, value, true)) {
     /* Handled in the `if` condition. */
+  } else if (this->impl->CxxModulesFileSets.WriteProperties(
+               this, this->impl.get(), prop, value, true)) {
+    /* Handled in the `if` condition. */
+  } else if (this->impl->CxxModuleHeadersFileSets.WriteProperties(
+               this, this->impl.get(), prop, value, true)) {
+    /* Handled in the `if` condition. */
   } else {
     this->impl->Properties.SetProperty(prop, value);
   }
@@ -1742,6 +1789,13 @@
     this->impl->Makefile->IssueMessage(
       MessageType::FATAL_ERROR, prop + " property may not be appended.");
   } else if (this->impl->HeadersFileSets.WriteProperties(
+               this, this->impl.get(), prop, value,
+               false)) { // NOLINT(bugprone-branch-clone)
+    /* Handled in the `if` condition. */
+  } else if (this->impl->CxxModulesFileSets.WriteProperties(
+               this, this->impl.get(), prop, value, false)) {
+    /* Handled in the `if` condition. */
+  } else if (this->impl->CxxModuleHeadersFileSets.WriteProperties(
                this, this->impl.get(), prop, value, false)) {
     /* Handled in the `if` condition. */
   } else {
@@ -2250,6 +2304,17 @@
     if (headers.first) {
       return headers.second;
     }
+    auto cxx_modules = this->impl->CxxModulesFileSets.ReadProperties(
+      this, this->impl.get(), prop);
+    if (cxx_modules.first) {
+      return cxx_modules.second;
+    }
+    auto cxx_module_headers =
+      this->impl->CxxModuleHeadersFileSets.ReadProperties(
+        this, this->impl.get(), prop);
+    if (cxx_module_headers.first) {
+      return cxx_module_headers.second;
+    }
   }
 
   cmValue retVal = this->impl->Properties.GetPropertyValue(prop);
@@ -2527,6 +2592,11 @@
     auto bt = this->impl->Makefile->GetBacktrace();
     if (type == this->impl->HeadersFileSets.TypeName) {
       this->impl->HeadersFileSets.AddFileSet(name, vis, std::move(bt));
+    } else if (type == this->impl->CxxModulesFileSets.TypeName) {
+      this->impl->CxxModulesFileSets.AddFileSet(name, vis, std::move(bt));
+    } else if (type == this->impl->CxxModuleHeadersFileSets.TypeName) {
+      this->impl->CxxModuleHeadersFileSets.AddFileSet(name, vis,
+                                                      std::move(bt));
     }
   }
   return std::make_pair(&result.first->second, result.second);
@@ -2537,6 +2607,12 @@
   if (type == "HEADERS") {
     return "HEADER_SETS";
   }
+  if (type == "CXX_MODULES") {
+    return "CXX_MODULE_SETS";
+  }
+  if (type == "CXX_MODULE_HEADER_UNITS") {
+    return "CXX_MODULE_HEADER_UNIT_SETS";
+  }
   return "";
 }
 
@@ -2545,6 +2621,12 @@
   if (type == "HEADERS") {
     return "INTERFACE_HEADER_SETS";
   }
+  if (type == "CXX_MODULES") {
+    return "INTERFACE_CXX_MODULE_SETS";
+  }
+  if (type == "CXX_MODULE_HEADER_UNITS") {
+    return "INTERFACE_CXX_MODULE_HEADER_UNIT_SETS";
+  }
   return "";
 }
 
@@ -2572,6 +2654,8 @@
   };
 
   appendEntries(this->impl->HeadersFileSets.InterfaceEntries.Entries);
+  appendEntries(this->impl->CxxModulesFileSets.InterfaceEntries.Entries);
+  appendEntries(this->impl->CxxModuleHeadersFileSets.InterfaceEntries.Entries);
 
   return result;
 }
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 5ed018e..94d6688 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -275,8 +275,12 @@
   cmBTStringRange GetLinkInterfaceDirectExcludeEntries() const;
 
   cmBTStringRange GetHeaderSetsEntries() const;
+  cmBTStringRange GetCxxModuleSetsEntries() const;
+  cmBTStringRange GetCxxModuleHeaderSetsEntries() const;
 
   cmBTStringRange GetInterfaceHeaderSetsEntries() const;
+  cmBTStringRange GetInterfaceCxxModuleSetsEntries() const;
+  cmBTStringRange GetInterfaceCxxModuleHeaderSetsEntries() const;
 
   std::string ImportedGetFullPath(const std::string& config,
                                   cmStateEnums::ArtifactType artifact) const;
diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx
index b1367e1..e4244a6 100644
--- a/Source/cmTargetSourcesCommand.cxx
+++ b/Source/cmTargetSourcesCommand.cxx
@@ -9,6 +9,7 @@
 #include <cmext/string_view>
 
 #include "cmArgumentParser.h"
+#include "cmExperimental.h"
 #include "cmFileSet.h"
 #include "cmGeneratorExpression.h"
 #include "cmListFileCache.h"
@@ -256,9 +257,30 @@
       this->SetError("Must specify a TYPE when creating file set");
       return false;
     }
-    if (type != "HEADERS"_s) {
-      this->SetError("File set TYPE may only be \"HEADERS\"");
-      return false;
+    bool const supportCxx20FileSetTypes = cmExperimental::HasSupportEnabled(
+      *this->Makefile, cmExperimental::Feature::CxxModuleCMakeApi);
+
+    if (supportCxx20FileSetTypes) {
+      if (type != "HEADERS"_s && type != "CXX_MODULES"_s &&
+          type != "CXX_MODULE_HEADER_UNITS"_s) {
+        this->SetError(
+          R"(File set TYPE may only be "HEADERS", "CXX_MODULES", or "CXX_MODULE_HEADER_UNITS")");
+        return false;
+      }
+
+      if (cmFileSetVisibilityIsForInterface(visibility) &&
+          !cmFileSetVisibilityIsForSelf(visibility)) {
+        if (type == "CXX_MODULES"_s || type == "CXX_MODULE_HEADER_UNITS"_s) {
+          this->SetError(
+            R"(File set TYPEs "CXX_MODULES" and "CXX_MODULE_HEADER_UNITS" may not have "INTERFACE" visibility)");
+          return false;
+        }
+      }
+    } else {
+      if (type != "HEADERS"_s) {
+        this->SetError("File set TYPE may only be \"HEADERS\"");
+        return false;
+      }
     }
 
     if (args.BaseDirs.empty()) {
@@ -294,7 +316,7 @@
   if (!baseDirectories.empty()) {
     fileSet.first->AddDirectoryEntry(
       BT<std::string>(baseDirectories, this->Makefile->GetBacktrace()));
-    if (type == "HEADERS"_s) {
+    if (type == "HEADERS"_s || type == "CXX_MODULE_HEADER_UNITS"_s) {
       for (auto const& dir : cmExpandedList(baseDirectories)) {
         auto interfaceDirectoriesGenex =
           cmStrCat("$<BUILD_INTERFACE:", dir, ">");
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index c79331c..a7460e8 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -347,6 +347,18 @@
 
 void cmVisualStudio10TargetGenerator::Generate()
 {
+  for (std::string const& config : this->Configurations) {
+    this->GeneratorTarget->CheckCxxModuleStatus(config);
+  }
+
+  if (this->GeneratorTarget->HaveCxx20ModuleSources()) {
+    this->Makefile->IssueMessage(
+      MessageType::FATAL_ERROR,
+      cmStrCat("The \"", this->GeneratorTarget->GetName(),
+               "\" target contains C++ module sources which are not supported "
+               "by the generator"));
+  }
+
   this->ProjectType = this->ComputeProjectType(this->GeneratorTarget);
   this->Managed = this->ProjectType == VsProjectType::csproj;
   const std::string ProjectFileExtension =
@@ -952,6 +964,10 @@
     std::string outDir = this->GeneratorTarget->GetDirectory(config) + "/";
     ConvertToWindowsSlash(outDir);
     e1.Element("OutputPath", outDir);
+
+    Options& o = *(this->ClOptions[config]);
+    OptionsHelper oh(o, e1);
+    oh.OutputFlagMap();
   }
 
   this->WriteDotNetDocumentationFile(e0);
@@ -3852,21 +3868,28 @@
   this->GeneratorTarget->GetLinkOptions(linkOpts, configName, "CUDA");
   // LINK_OPTIONS are escaped.
   this->LocalGenerator->AppendCompileOptions(linkFlags, linkOpts);
+
+  cmComputeLinkInformation* pcli =
+    this->GeneratorTarget->GetLinkInformation(configName);
+  if (doDeviceLinking && pcli) {
+
+    cmLinkLineDeviceComputer computer(
+      this->LocalGenerator,
+      this->LocalGenerator->GetStateSnapshot().GetDirectory());
+    std::string ignored_;
+    this->LocalGenerator->GetDeviceLinkFlags(computer, configName, ignored_,
+                                             linkFlags, ignored_, ignored_,
+                                             this->GeneratorTarget);
+
+    this->LocalGenerator->AddLanguageFlagsForLinking(
+      linkFlags, this->GeneratorTarget, "CUDA", configName);
+  }
   cudaLinkOptions.AppendFlagString("AdditionalOptions", linkFlags);
 
   // For static libraries that have device linking enabled compute
   // the  libraries
   if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY &&
       doDeviceLinking) {
-    cmComputeLinkInformation* pcli =
-      this->GeneratorTarget->GetLinkInformation(configName);
-    if (!pcli) {
-      cmSystemTools::Error(
-        "CMake can not compute cmComputeLinkInformation for target: " +
-        this->Name);
-      return false;
-    }
-
     cmComputeLinkInformation& cli = *pcli;
     cmLinkLineDeviceComputer computer(
       this->LocalGenerator,
diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx
index 00c65ed..16584f5 100644
--- a/Source/cmVisualStudioGeneratorOptions.cxx
+++ b/Source/cmVisualStudioGeneratorOptions.cxx
@@ -161,71 +161,12 @@
 
 void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration()
 {
-  // Extract temporary values stored by our flag table.
-  FlagValue arch = this->TakeFlag("cmake-temp-arch");
-  FlagValue code = this->TakeFlag("cmake-temp-code");
-  FlagValue gencode = this->TakeFlag("cmake-temp-gencode");
-
-  // No -code allowed without -arch.
-  if (arch.empty()) {
-    code.clear();
-  }
-
-  // Create a CodeGeneration field with [arch],[code] syntax in each entry.
-  // CUDA will convert it to `-gencode=arch=[arch],code="[code],[arch]"`.
-  FlagValue& result = this->FlagMap["CodeGeneration"];
-
-  // If there are no flags, leave the CodeGeneration field empty.
-  if (arch.empty() && gencode.empty()) {
-    return;
-  }
-
-  // First entries for the -arch=<arch> [-code=<code>,...] pair.
-  if (!arch.empty()) {
-    std::string arch_name = arch[0];
-    if (arch_name == "all" || arch_name == "all-major" ||
-        arch_name == "native") {
-      AppendFlagString("AdditionalOptions", "-arch=" + arch_name);
-      return;
-    }
-    std::vector<std::string> codes;
-    if (!code.empty()) {
-      codes = cmTokenize(code[0], ",");
-    }
-    if (codes.empty()) {
-      codes.push_back(arch_name);
-      // nvcc -arch=<arch> has a special case that allows a real
-      // architecture to be specified instead of a virtual arch.
-      // It translates to -arch=<virtual> -code=<real>.
-      cmSystemTools::ReplaceString(arch_name, "sm_", "compute_");
-    }
-    for (std::string const& c : codes) {
-      std::string entry = arch_name + "," + c;
-      result.push_back(entry);
-    }
-  }
-
-  // Now add entries for the following signatures:
-  // -gencode=<arch>,<code>
-  // -gencode=<arch>,[<code1>,<code2>]
-  // -gencode=<arch>,"<code1>,<code2>"
-  for (std::string const& e : gencode) {
-    std::string entry = e;
-    cmSystemTools::ReplaceString(entry, "arch=", "");
-    cmSystemTools::ReplaceString(entry, "code=", "");
-    cmSystemTools::ReplaceString(entry, "[", "");
-    cmSystemTools::ReplaceString(entry, "]", "");
-    cmSystemTools::ReplaceString(entry, "\"", "");
-
-    std::vector<std::string> codes = cmTokenize(entry, ",");
-    if (codes.size() >= 2) {
-      auto gencode_arch = cm::cbegin(codes);
-      for (auto ci = gencode_arch + 1; ci != cm::cend(codes); ++ci) {
-        std::string code_entry = *gencode_arch + "," + *ci;
-        result.push_back(code_entry);
-      }
-    }
-  }
+  // Create an empty CodeGeneration field, and pass the 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.
+  FlagValue& code_gen_flag = this->FlagMap["CodeGeneration"];
+  code_gen_flag = "";
 }
 
 void cmVisualStudioGeneratorOptions::FixManifestUACFlags()
diff --git a/Source/cmXCodeScheme.cxx b/Source/cmXCodeScheme.cxx
index adc500a..a62015f 100644
--- a/Source/cmXCodeScheme.cxx
+++ b/Source/cmXCodeScheme.cxx
@@ -147,7 +147,15 @@
                  "Xcode.DebuggerFoundation.Debugger.LLDB");
   xout.Attribute("selectedLauncherIdentifier",
                  "Xcode.DebuggerFoundation.Launcher.LLDB");
-  xout.Attribute("launchStyle", "0");
+  {
+    cmValue launchMode =
+      this->Target->GetTarget()->GetProperty("XCODE_SCHEME_LAUNCH_MODE");
+    std::string value = "0"; // == 'AUTO'
+    if (launchMode && *launchMode == "WAIT") {
+      value = "1";
+    }
+    xout.Attribute("launchStyle", value);
+  }
   WriteCustomWorkingDirectory(xout, configuration);
 
   xout.Attribute("ignoresPersistentStateOnLaunch", "NO");
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index 5889a4b..89a3cc7 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -3067,17 +3067,14 @@
   return ret;
 }
 
-bool SystemTools::FileIsDirectory(const std::string& inName)
+// Remove any trailing slash from the name except in a root component.
+static const char* RemoveTrailingSlashes(
+  const std::string& inName, char (&local_buffer)[KWSYS_SYSTEMTOOLS_MAXPATH],
+  std::string& string_buffer)
 {
-  if (inName.empty()) {
-    return false;
-  }
   size_t length = inName.size();
   const char* name = inName.c_str();
 
-  // Remove any trailing slash from the name except in a root component.
-  char local_buffer[KWSYS_SYSTEMTOOLS_MAXPATH];
-  std::string string_buffer;
   size_t last = length - 1;
   if (last > 0 && (name[last] == '/' || name[last] == '\\') &&
       strcmp(name, "/") != 0 && name[last - 1] != ':') {
@@ -3091,6 +3088,19 @@
     }
   }
 
+  return name;
+}
+
+bool SystemTools::FileIsDirectory(const std::string& inName)
+{
+  if (inName.empty()) {
+    return false;
+  }
+
+  char local_buffer[KWSYS_SYSTEMTOOLS_MAXPATH];
+  std::string string_buffer;
+  const auto name = RemoveTrailingSlashes(inName, local_buffer, string_buffer);
+
 // Now check the file node type.
 #if defined(_WIN32)
   DWORD attr =
@@ -3107,9 +3117,21 @@
   }
 }
 
-bool SystemTools::FileIsExecutable(const std::string& name)
+bool SystemTools::FileIsExecutable(const std::string& inName)
 {
-  return !FileIsDirectory(name) && TestFileAccess(name, TEST_FILE_EXECUTE);
+#ifdef _WIN32
+  char local_buffer[KWSYS_SYSTEMTOOLS_MAXPATH];
+  std::string string_buffer;
+  const auto name = RemoveTrailingSlashes(inName, local_buffer, string_buffer);
+  const auto attr =
+    GetFileAttributesW(Encoding::ToWindowsExtendedPath(name).c_str());
+
+  // On Windows any file that exists and is not a directory is considered
+  // readable and therefore also executable:
+  return attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY);
+#else
+  return !FileIsDirectory(inName) && TestFileAccess(inName, TEST_FILE_EXECUTE);
+#endif
 }
 
 #if defined(_WIN32)
diff --git a/Templates/MSBuild/FlagTables/v10_Cuda.json b/Templates/MSBuild/FlagTables/v10_Cuda.json
index b3230ac..b0765f5 100644
--- a/Templates/MSBuild/FlagTables/v10_Cuda.json
+++ b/Templates/MSBuild/FlagTables/v10_Cuda.json
@@ -70,118 +70,6 @@
     ]
   },
   {
-    "name":  "cmake-temp-gencode",
-    "switch": "gencode=",
-    "comment": "",
-    "value": "",
-    "flags": [
-      "UserValue",
-      "SemicolonAppendable"
-    ]
-  },
-  {
-    "name":  "cmake-temp-gencode",
-    "switch": "gencode",
-    "comment": "",
-    "value": "",
-    "flags": [
-      "UserFollowing",
-      "SemicolonAppendable"
-    ]
-  },
-  {
-    "name":  "cmake-temp-gencode",
-    "switch": "-generate-code=",
-    "comment": "",
-    "value": "",
-    "flags": [
-      "UserValue",
-      "SemicolonAppendable"
-    ]
-  },
-  {
-    "name":  "cmake-temp-gencode",
-    "switch": "-generate-code",
-    "comment": "",
-    "value": "",
-    "flags": [
-      "UserFollowing",
-      "SemicolonAppendable"
-    ]
-  },
-  {
-    "name":  "cmake-temp-code",
-    "switch": "code=",
-    "comment": "",
-    "value": "",
-    "flags": [
-      "UserValue"
-    ]
-  },
-  {
-    "name":  "cmake-temp-code",
-    "switch": "code",
-    "comment": "",
-    "value": "",
-    "flags": [
-      "UserFollowing"
-    ]
-  },
-  {
-    "name":  "cmake-temp-code",
-    "switch": "-gpu-code=",
-    "comment": "",
-    "value": "",
-    "flags": [
-      "UserValue"
-    ]
-  },
-  {
-    "name":  "cmake-temp-code",
-    "switch": "-gpu-code",
-    "comment": "",
-    "value": "",
-    "flags": [
-      "UserFollowing"
-    ]
-  },
-  {
-    "name":  "cmake-temp-arch",
-    "switch": "arch=",
-    "comment": "",
-    "value": "",
-    "flags": [
-      "UserValue"
-    ]
-  },
-  {
-    "name":  "cmake-temp-arch",
-    "switch": "arch",
-    "comment": "",
-    "value": "",
-    "flags": [
-      "UserFollowing"
-    ]
-  },
-  {
-    "name":  "cmake-temp-arch",
-    "switch": "-gpu-architecture=",
-    "comment": "",
-    "value": "",
-    "flags": [
-      "UserValue"
-    ]
-  },
-  {
-    "name":  "cmake-temp-arch",
-    "switch": "-gpu-architecture",
-    "comment": "",
-    "value": "",
-    "flags": [
-      "UserFollowing"
-    ]
-  },
-  {
     "name":  "FastMath",
     "switch": "use_fast_math",
     "comment": "",
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 24e98f4..3e3447f 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -1460,6 +1460,7 @@
             LTTngUST
             ODBC
             OpenACC
+            OpenAL
             OpenCL
             OpenGL
             OpenMP
diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt
index c9e41f5..6f19c13 100644
--- a/Tests/ExportImport/Export/CMakeLists.txt
+++ b/Tests/ExportImport/Export/CMakeLists.txt
@@ -155,6 +155,15 @@
     "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/testInterfaceIncludeUser>"
 )
 set_property(TARGET testInterfaceIncludeUser PROPERTY IMPORTED_NO_SYSTEM 1)
+
+add_library(testInterfaceIncludeUser2 INTERFACE)
+target_include_directories(testInterfaceIncludeUser2
+  INTERFACE
+    "$<INSTALL_INTERFACE:include/testInterfaceIncludeUser>"
+    "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/testInterfaceIncludeUser>"
+)
+set_property(TARGET testInterfaceIncludeUser2 PROPERTY EXPORT_NO_SYSTEM 1)
+
 install(
   FILES
     "${CMAKE_CURRENT_SOURCE_DIR}/include/testInterfaceIncludeUser/testInterfaceInclude.h"
@@ -562,6 +571,7 @@
   TopDirLib SubDirLinkA
   systemlib
   testInterfaceIncludeUser
+  testInterfaceIncludeUser2
   EXPORT exp
   RUNTIME DESTINATION $<1:bin>$<0:/wrong>
   LIBRARY DESTINATION $<1:lib>$<0:/wrong> NAMELINK_SKIP
@@ -622,6 +632,7 @@
   TopDirLib SubDirLinkA
   systemlib
   testInterfaceIncludeUser
+  testInterfaceIncludeUser2
   NAMESPACE bld_
   FILE ExportBuildTree.cmake
   )
diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt
index 272c7a9..5bafdf8 100644
--- a/Tests/ExportImport/Import/A/CMakeLists.txt
+++ b/Tests/ExportImport/Import/A/CMakeLists.txt
@@ -75,6 +75,10 @@
 target_include_directories(imp_testInterfaceInclude1 SYSTEM PRIVATE testInterfaceIncludeSystem)
 target_link_libraries(imp_testInterfaceInclude1 PRIVATE exp_testInterfaceIncludeUser)
 
+add_library(imp_testInterfaceInclude1b STATIC imp_testInterfaceInclude1.c)
+target_include_directories(imp_testInterfaceInclude1b SYSTEM PRIVATE testInterfaceIncludeSystem)
+target_link_libraries(imp_testInterfaceInclude1b PRIVATE exp_testInterfaceIncludeUser2)
+
 add_executable(imp_UseSharedLibWithHelper1 ../../../InterfaceLinkLibrariesDirect/UseSharedLibWithHelper.c)
 target_link_libraries(imp_UseSharedLibWithHelper1 PRIVATE exp_testSharedLibWithHelper testSharedLibHelperExclude)
 
@@ -122,9 +126,13 @@
   bld_testStaticLibWithPlugin
   )
 
-add_library(imp_testInterfaceInclude1b STATIC imp_testInterfaceInclude1.c)
-target_include_directories(imp_testInterfaceInclude1b SYSTEM PRIVATE testInterfaceIncludeSystem)
-target_link_libraries(imp_testInterfaceInclude1b PRIVATE bld_testInterfaceIncludeUser)
+add_library(imp_testInterfaceInclude1c STATIC imp_testInterfaceInclude1.c)
+target_include_directories(imp_testInterfaceInclude1c SYSTEM PRIVATE testInterfaceIncludeSystem)
+target_link_libraries(imp_testInterfaceInclude1c PRIVATE bld_testInterfaceIncludeUser)
+
+add_library(imp_testInterfaceInclude1d STATIC imp_testInterfaceInclude1.c)
+target_include_directories(imp_testInterfaceInclude1d SYSTEM PRIVATE testInterfaceIncludeSystem)
+target_link_libraries(imp_testInterfaceInclude1d PRIVATE bld_testInterfaceIncludeUser2)
 
 add_custom_target(check_testLib1_genex ALL
   COMMAND ${CMAKE_COMMAND} -DtestLib1=$<TARGET_FILE:exp_testLib1>
diff --git a/Tests/FindOpenAL/CMakeLists.txt b/Tests/FindOpenAL/CMakeLists.txt
new file mode 100644
index 0000000..fc4803e
--- /dev/null
+++ b/Tests/FindOpenAL/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindOpenAL.Test COMMAND
+  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+  --build-and-test
+  "${CMake_SOURCE_DIR}/Tests/FindOpenAL/Test"
+  "${CMake_BINARY_DIR}/Tests/FindOpenAL/Test"
+  ${build_generator_args}
+  --build-project TestFindOpenAL
+  --build-options ${build_options}
+  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+  )
diff --git a/Tests/FindOpenAL/Test/CMakeLists.txt b/Tests/FindOpenAL/Test/CMakeLists.txt
new file mode 100644
index 0000000..fa3e263
--- /dev/null
+++ b/Tests/FindOpenAL/Test/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.21)
+project(TestFindOpenAL CXX)
+include(CTest)
+
+find_package(OpenAL REQUIRED)
+
+add_executable(test_tgt main.cxx)
+target_link_libraries(test_tgt OpenAL::OpenAL)
+add_test(NAME test_tgt COMMAND test_tgt)
+
+add_executable(test_var main.cxx)
+target_include_directories(test_var PRIVATE ${OPENAL_INCLUDE_DIR})
+target_link_libraries(test_var PRIVATE ${OPENAL_LIBRARY})
+add_test(NAME test_var COMMAND test_var)
diff --git a/Tests/FindOpenAL/Test/main.cxx b/Tests/FindOpenAL/Test/main.cxx
new file mode 100644
index 0000000..bb45faf
--- /dev/null
+++ b/Tests/FindOpenAL/Test/main.cxx
@@ -0,0 +1,13 @@
+#include <AL/al.h>
+#include <AL/alc.h>
+#include <stdio.h>
+
+int main()
+{
+  /* Reference an AL symbol without requiring a context at runtime.  */
+  printf("&alGetString = %p\n", &alGetString);
+
+  /* Reference an ALC symbol without requiring a context at runtime.  */
+  printf("&alcGetString = %p\n", &alcGetString);
+  return 0;
+}
diff --git a/Tests/FindVulkan/Test/CMakeLists.txt b/Tests/FindVulkan/Test/CMakeLists.txt
index 42543ac..727e1ce 100644
--- a/Tests/FindVulkan/Test/CMakeLists.txt
+++ b/Tests/FindVulkan/Test/CMakeLists.txt
@@ -7,6 +7,7 @@
   glslang
   shaderc_combined
   SPIRV-Tools
+  volk
 )
 if(APPLE)
   list(APPEND components MoltenVK)
@@ -75,6 +76,10 @@
   add_test(NAME test_tgt_MoltenVK COMMAND test_tgt_MoltenVK)
 endif()
 
+add_executable(test_tgt_volk main-volk.cxx)
+target_link_libraries(test_tgt_volk Vulkan::volk)
+add_test(NAME test_tgt_volk COMMAND test_tgt_volk)
+
 if(Vulkan_GLSLC_EXECUTABLE)
   add_test(NAME test_glslc
     COMMAND ${CMAKE_COMMAND}
diff --git a/Tests/FindVulkan/Test/main-volk.cxx b/Tests/FindVulkan/Test/main-volk.cxx
new file mode 100644
index 0000000..2ec9fb4
--- /dev/null
+++ b/Tests/FindVulkan/Test/main-volk.cxx
@@ -0,0 +1,14 @@
+#include <iostream>
+
+#include <volk/volk.h>
+
+int main()
+{
+  if (volkInitialize() != VK_SUCCESS) {
+    std::cout << "volk initialization success!" << std::endl;
+  } else {
+    std::cout << "volk initialization failure!" << std::endl;
+  }
+
+  return 0;
+}
diff --git a/Tests/IncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/CMakeLists.txt
index bb4b92c..e82cea2 100644
--- a/Tests/IncludeDirectories/CMakeLists.txt
+++ b/Tests/IncludeDirectories/CMakeLists.txt
@@ -121,12 +121,66 @@
 target_include_directories(ordertest SYSTEM PUBLIC SystemIncludeDirectories/systemlib)
 target_include_directories(ordertest PUBLIC SystemIncludeDirectories/userlib)
 
+# Test "IMPORTED_NO_SYSTEM" property and its interaction with "SYSTEM"
 add_library(ordertest2 ordertest.cpp)
 target_include_directories(ordertest2 SYSTEM PRIVATE SystemIncludeDirectories/systemlib)
 target_link_libraries(ordertest2 PRIVATE ordertest2_userlib)
 add_library(ordertest2_userlib INTERFACE IMPORTED)
 target_include_directories(ordertest2_userlib INTERFACE SystemIncludeDirectories/userlib)
 set_property(TARGET ordertest2_userlib PROPERTY IMPORTED_NO_SYSTEM 1)
+get_property(system_prop_value TARGET ordertest2_userlib PROPERTY SYSTEM)
+if (NOT system_prop_value)
+  message(SEND_ERROR "ordertest2_userlib SYSTEM property should be ON.")
+endif()
+
+# Test "SYSTEM" property of non-imported libraries
+add_library(ordertest3_systemlib INTERFACE)
+target_include_directories(ordertest3_systemlib INTERFACE SystemIncludeDirectories/systemlib)
+set_property(TARGET ordertest3_systemlib PROPERTY SYSTEM 1)
+add_library(ordertest3_userlib INTERFACE)
+target_include_directories(ordertest3_userlib INTERFACE SystemIncludeDirectories/userlib)
+add_library(ordertest3 ordertest.cpp)
+target_link_libraries(ordertest3 PRIVATE ordertest3_systemlib ordertest3_userlib)
+
+# Test "SYSTEM" property of imported libraries and its interaction with "IMPORTED_NO_SYSTEM"
+add_library(ordertest4 ordertest.cpp)
+target_include_directories(ordertest4 SYSTEM PRIVATE SystemIncludeDirectories/systemlib)
+target_link_libraries(ordertest4 PRIVATE ordertest4_userlib)
+add_library(ordertest4_userlib INTERFACE IMPORTED)
+target_include_directories(ordertest4_userlib INTERFACE SystemIncludeDirectories/userlib)
+set_property(TARGET ordertest4_userlib PROPERTY SYSTEM 0)
+get_property(imported_no_system_prop_value TARGET ordertest4_userlib PROPERTY IMPORTED_NO_SYSTEM)
+if (imported_no_system_prop_value)
+  message(SEND_ERROR "ordertest4_userlib IMPORTED_NO_SYSTEM property should be OFF.")
+endif()
+
+# Test the interaction between "SYSTEM" and "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES"
+add_library(ordertest5_systemlib INTERFACE)
+target_include_directories(ordertest5_systemlib SYSTEM INTERFACE SystemIncludeDirectories/systemlib)
+# The default value of `SYSTEM` is already `OFF`. Here we explicitly set it again.
+set_property(TARGET ordertest5_systemlib PROPERTY SYSTEM 0)
+add_library(ordertest5_userlib INTERFACE)
+target_include_directories(ordertest5_userlib INTERFACE SystemIncludeDirectories/userlib)
+add_library(ordertest5 ordertest.cpp)
+target_link_libraries(ordertest5 PRIVATE ordertest5_systemlib ordertest5_userlib)
+
+# Test that the include of imported executable is treated as system by default.
+add_executable(ordertest6_systemexe IMPORTED)
+target_include_directories(ordertest6_systemexe INTERFACE SystemIncludeDirectories/systemlib)
+set_property(TARGET ordertest6_systemexe PROPERTY ENABLE_EXPORTS 1)
+add_library(ordertest6_userlib INTERFACE)
+target_include_directories(ordertest6_userlib INTERFACE SystemIncludeDirectories/userlib)
+add_library(ordertest6 ordertest.cpp)
+target_link_libraries(ordertest6 PRIVATE ordertest6_systemexe ordertest6_userlib)
+
+# Test that the include of imported executable is not treated as system if "SYSTEM" property is OFF.
+add_library(ordertest7 ordertest.cpp)
+target_include_directories(ordertest7 SYSTEM PRIVATE SystemIncludeDirectories/systemlib)
+target_link_libraries(ordertest7 PRIVATE ordertest7_userexe)
+add_library(ordertest7_userexe INTERFACE IMPORTED)
+target_include_directories(ordertest7_userexe INTERFACE SystemIncludeDirectories/userlib)
+set_property(TARGET ordertest7_userexe PROPERTY ENABLE_EXPORTS 1)
+set_property(TARGET ordertest7_userexe PROPERTY SYSTEM 0)
 
 add_subdirectory(StandardIncludeDirectories)
 add_subdirectory(TargetIncludeDirectories)
diff --git a/Tests/LoadCommand/CMakeCommands/cmTestCommand.c b/Tests/LoadCommand/CMakeCommands/cmTestCommand.c
index af7b092..7176ebe 100644
--- a/Tests/LoadCommand/CMakeCommands/cmTestCommand.c
+++ b/Tests/LoadCommand/CMakeCommands/cmTestCommand.c
@@ -75,10 +75,10 @@
   info->CAPI->DisplaySatus(mf, info->CAPI->GetStartOutputDirectory(mf));
   info->CAPI->DisplaySatus(mf, info->CAPI->GetCurrentDirectory(mf));
   info->CAPI->DisplaySatus(mf, info->CAPI->GetCurrentOutputDirectory(mf));
-  sprintf(buffer, "Cache version: %d.%d, CMake version: %d.%d",
-          info->CAPI->GetCacheMajorVersion(mf),
-          info->CAPI->GetCacheMinorVersion(mf),
-          info->CAPI->GetMajorVersion(mf), info->CAPI->GetMinorVersion(mf));
+  snprintf(
+    buffer, sizeof(buffer), "Cache version: %d.%d, CMake version: %d.%d",
+    info->CAPI->GetCacheMajorVersion(mf), info->CAPI->GetCacheMinorVersion(mf),
+    info->CAPI->GetMajorVersion(mf), info->CAPI->GetMinorVersion(mf));
   info->CAPI->DisplaySatus(mf, buffer);
   if (info->CAPI->CommandExists(mf, "SET")) {
     info->CAPI->DisplaySatus(mf, "Command SET exists");
@@ -91,10 +91,12 @@
 
   source_file = info->CAPI->CreateNewSourceFile(mf);
   cstr = info->CAPI->SourceFileGetSourceName(source_file);
-  sprintf(buffer, "Should be empty (source file name): [%s]", cstr);
+  snprintf(buffer, sizeof(buffer), "Should be empty (source file name): [%s]",
+           cstr);
   info->CAPI->DisplaySatus(mf, buffer);
   cstr = info->CAPI->SourceFileGetFullPath(source_file);
-  sprintf(buffer, "Should be empty (source file full path): [%s]", cstr);
+  snprintf(buffer, sizeof(buffer),
+           "Should be empty (source file full path): [%s]", cstr);
   info->CAPI->DisplaySatus(mf, buffer);
   info->CAPI->DefineSourceFileProperty(mf, "SOME_PROPERTY", "unused old prop",
                                        "This property is no longer used", 0);
@@ -106,7 +108,8 @@
                                        "This property is for testing.", 0);
   info->CAPI->SourceFileSetProperty(source_file, "SOME_PROPERTY2", "HERE");
   cstr = info->CAPI->SourceFileGetProperty(source_file, "ABSTRACT");
-  sprintf(buffer, "Should be 0 (source file abstract property): [%p]", cstr);
+  snprintf(buffer, sizeof(buffer),
+           "Should be 0 (source file abstract property): [%p]", cstr);
   info->CAPI->DisplaySatus(mf, buffer);
 
   info->CAPI->DestroySourceFile(source_file);
diff --git a/Tests/LoadCommandOneConfig/CMakeCommands/cmTestCommand.c b/Tests/LoadCommandOneConfig/CMakeCommands/cmTestCommand.c
index af7b092..7176ebe 100644
--- a/Tests/LoadCommandOneConfig/CMakeCommands/cmTestCommand.c
+++ b/Tests/LoadCommandOneConfig/CMakeCommands/cmTestCommand.c
@@ -75,10 +75,10 @@
   info->CAPI->DisplaySatus(mf, info->CAPI->GetStartOutputDirectory(mf));
   info->CAPI->DisplaySatus(mf, info->CAPI->GetCurrentDirectory(mf));
   info->CAPI->DisplaySatus(mf, info->CAPI->GetCurrentOutputDirectory(mf));
-  sprintf(buffer, "Cache version: %d.%d, CMake version: %d.%d",
-          info->CAPI->GetCacheMajorVersion(mf),
-          info->CAPI->GetCacheMinorVersion(mf),
-          info->CAPI->GetMajorVersion(mf), info->CAPI->GetMinorVersion(mf));
+  snprintf(
+    buffer, sizeof(buffer), "Cache version: %d.%d, CMake version: %d.%d",
+    info->CAPI->GetCacheMajorVersion(mf), info->CAPI->GetCacheMinorVersion(mf),
+    info->CAPI->GetMajorVersion(mf), info->CAPI->GetMinorVersion(mf));
   info->CAPI->DisplaySatus(mf, buffer);
   if (info->CAPI->CommandExists(mf, "SET")) {
     info->CAPI->DisplaySatus(mf, "Command SET exists");
@@ -91,10 +91,12 @@
 
   source_file = info->CAPI->CreateNewSourceFile(mf);
   cstr = info->CAPI->SourceFileGetSourceName(source_file);
-  sprintf(buffer, "Should be empty (source file name): [%s]", cstr);
+  snprintf(buffer, sizeof(buffer), "Should be empty (source file name): [%s]",
+           cstr);
   info->CAPI->DisplaySatus(mf, buffer);
   cstr = info->CAPI->SourceFileGetFullPath(source_file);
-  sprintf(buffer, "Should be empty (source file full path): [%s]", cstr);
+  snprintf(buffer, sizeof(buffer),
+           "Should be empty (source file full path): [%s]", cstr);
   info->CAPI->DisplaySatus(mf, buffer);
   info->CAPI->DefineSourceFileProperty(mf, "SOME_PROPERTY", "unused old prop",
                                        "This property is no longer used", 0);
@@ -106,7 +108,8 @@
                                        "This property is for testing.", 0);
   info->CAPI->SourceFileSetProperty(source_file, "SOME_PROPERTY2", "HERE");
   cstr = info->CAPI->SourceFileGetProperty(source_file, "ABSTRACT");
-  sprintf(buffer, "Should be 0 (source file abstract property): [%p]", cstr);
+  snprintf(buffer, sizeof(buffer),
+           "Should be 0 (source file abstract property): [%p]", cstr);
   info->CAPI->DisplaySatus(mf, buffer);
 
   info->CAPI->DestroySourceFile(source_file);
diff --git a/Tests/RunCMake/CMP0102/CMP0102-OLD-stderr.txt b/Tests/RunCMake/CMP0102/CMP0102-OLD-stderr.txt
new file mode 100644
index 0000000..5d09fcf
--- /dev/null
+++ b/Tests/RunCMake/CMP0102/CMP0102-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0102-OLD.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0102 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/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 5325a3a..bbf8ddc 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -564,6 +564,9 @@
 endif()
 add_RunCMake_test(DependencyGraph -DCMAKE_Fortran_COMPILER=${CMAKE_Fortran_COMPILER})
 
+# Add C++ Module tests.
+add_RunCMake_test(CXXModules -DCMake_TEST_MODULE_COMPILATION=${CMake_TEST_MODULE_COMPILATION} -DCMake_TEST_MODULE_COMPILATION_RULES=${CMake_TEST_MODULE_COMPILATION_RULES})
+
 # ctresalloc links against CMakeLib and CTestLib, which means it can't be built
 # if CMake_TEST_EXTERNAL_CMAKE is activated (the compiler might be different.)
 # So, it has to be provided in the original build tree.
diff --git a/Tests/RunCMake/CXXModules/CMakeLists.txt b/Tests/RunCMake/CXXModules/CMakeLists.txt
new file mode 100644
index 0000000..338a412
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.23)
+project(${RunCMake_TEST} NONE)
+
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "17be90bd-a850-44e0-be50-448de847d652")
+
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface-result.txt b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface-stderr.txt b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface-stderr.txt
new file mode 100644
index 0000000..d573a02
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface-stderr.txt
@@ -0,0 +1,12 @@
+CMake Warning \(dev\) at FileSetModuleHeaderUnitsInterface.cmake:2 \(target_sources\):
+  CMake's C\+\+ module support is experimental.  It is meant only for
+  experimentation and feedback to CMake developers.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:6 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Error at FileSetModuleHeaderUnitsInterface.cmake:2 \(target_sources\):
+  target_sources File set TYPEs "CXX_MODULES" and "CXX_MODULE_HEADER_UNITS"
+  may not have "INTERFACE" visibility
+Call Stack \(most recent call first\):
+  CMakeLists.txt:6 \(include\)
diff --git a/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface.cmake b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface.cmake
new file mode 100644
index 0000000..03ca17e
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsInterface.cmake
@@ -0,0 +1,8 @@
+add_library(module-header)
+target_sources(module-header
+  INTERFACE
+    FILE_SET fs TYPE CXX_MODULE_HEADER_UNITS FILES
+      sources/module-header.h)
+target_compile_features(module-header
+  PRIVATE
+    cxx_std_20)
diff --git a/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPrivate-stderr.txt b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPrivate-stderr.txt
new file mode 100644
index 0000000..a7ac88e
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPrivate-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at FileSetModuleHeaderUnitsPrivate.cmake:7 \(target_sources\):
+  CMake's C\+\+ module support is experimental.  It is meant only for
+  experimentation and feedback to CMake developers.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:6 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\):
+  C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+  experimental.  It is meant only for compiler developers to try.
+This warning is for project developers.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPrivate.cmake b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPrivate.cmake
new file mode 100644
index 0000000..ebf9853
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPrivate.cmake
@@ -0,0 +1,13 @@
+enable_language(CXX)
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)
+set(CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE "")
+
+add_library(module-header
+  sources/cxx-anchor.cxx)
+target_sources(module-header
+  PRIVATE
+    FILE_SET fs TYPE CXX_MODULE_HEADER_UNITS FILES
+      sources/module-header.h)
+target_compile_features(module-header
+  PRIVATE
+    cxx_std_20)
diff --git a/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPublic-stderr.txt b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPublic-stderr.txt
new file mode 100644
index 0000000..a5b4ede
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPublic-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at FileSetModuleHeaderUnitsPublic.cmake:7 \(target_sources\):
+  CMake's C\+\+ module support is experimental.  It is meant only for
+  experimentation and feedback to CMake developers.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:6 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\):
+  C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+  experimental.  It is meant only for compiler developers to try.
+This warning is for project developers.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPublic.cmake b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPublic.cmake
new file mode 100644
index 0000000..3dfccbb5
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/FileSetModuleHeaderUnitsPublic.cmake
@@ -0,0 +1,13 @@
+enable_language(CXX)
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)
+set(CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE "")
+
+add_library(module-header
+  sources/cxx-anchor.cxx)
+target_sources(module-header
+  PUBLIC
+    FILE_SET fs TYPE CXX_MODULE_HEADER_UNITS FILES
+      sources/module-header.h)
+target_compile_features(module-header
+  PRIVATE
+    cxx_std_20)
diff --git a/Tests/RunCMake/CXXModules/FileSetModulesInterface-result.txt b/Tests/RunCMake/CXXModules/FileSetModulesInterface-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/FileSetModulesInterface-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CXXModules/FileSetModulesInterface-stderr.txt b/Tests/RunCMake/CXXModules/FileSetModulesInterface-stderr.txt
new file mode 100644
index 0000000..81a35e8
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/FileSetModulesInterface-stderr.txt
@@ -0,0 +1,12 @@
+CMake Warning \(dev\) at FileSetModulesInterface.cmake:2 \(target_sources\):
+  CMake's C\+\+ module support is experimental.  It is meant only for
+  experimentation and feedback to CMake developers.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:6 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Error at FileSetModulesInterface.cmake:2 \(target_sources\):
+  target_sources File set TYPEs "CXX_MODULES" and "CXX_MODULE_HEADER_UNITS"
+  may not have "INTERFACE" visibility
+Call Stack \(most recent call first\):
+  CMakeLists.txt:6 \(include\)
diff --git a/Tests/RunCMake/CXXModules/FileSetModulesInterface.cmake b/Tests/RunCMake/CXXModules/FileSetModulesInterface.cmake
new file mode 100644
index 0000000..24cec3e
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/FileSetModulesInterface.cmake
@@ -0,0 +1,8 @@
+add_library(module)
+target_sources(module
+  INTERFACE
+    FILE_SET fs TYPE CXX_MODULES FILES
+      sources/module.cxx)
+target_compile_features(module
+  PRIVATE
+    cxx_std_20)
diff --git a/Tests/RunCMake/CXXModules/FileSetModulesPrivate-stderr.txt b/Tests/RunCMake/CXXModules/FileSetModulesPrivate-stderr.txt
new file mode 100644
index 0000000..03e06cc
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/FileSetModulesPrivate-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at FileSetModulesPrivate.cmake:6 \(target_sources\):
+  CMake's C\+\+ module support is experimental.  It is meant only for
+  experimentation and feedback to CMake developers.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:6 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\):
+  C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+  experimental.  It is meant only for compiler developers to try.
+This warning is for project developers.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CXXModules/FileSetModulesPrivate.cmake b/Tests/RunCMake/CXXModules/FileSetModulesPrivate.cmake
new file mode 100644
index 0000000..ca18982
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/FileSetModulesPrivate.cmake
@@ -0,0 +1,12 @@
+enable_language(CXX)
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)
+set(CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE "")
+
+add_library(module)
+target_sources(module
+  PRIVATE
+    FILE_SET fs TYPE CXX_MODULES FILES
+      sources/module.cxx)
+target_compile_features(module
+  PRIVATE
+    cxx_std_20)
diff --git a/Tests/RunCMake/CXXModules/FileSetModulesPublic-stderr.txt b/Tests/RunCMake/CXXModules/FileSetModulesPublic-stderr.txt
new file mode 100644
index 0000000..0c110c3
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/FileSetModulesPublic-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at FileSetModulesPublic.cmake:6 \(target_sources\):
+  CMake's C\+\+ module support is experimental.  It is meant only for
+  experimentation and feedback to CMake developers.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:6 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\):
+  C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+  experimental.  It is meant only for compiler developers to try.
+This warning is for project developers.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CXXModules/FileSetModulesPublic.cmake b/Tests/RunCMake/CXXModules/FileSetModulesPublic.cmake
new file mode 100644
index 0000000..58de174
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/FileSetModulesPublic.cmake
@@ -0,0 +1,12 @@
+enable_language(CXX)
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)
+set(CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE "")
+
+add_library(module)
+target_sources(module
+  PUBLIC
+    FILE_SET fs TYPE CXX_MODULES FILES
+      sources/module.cxx)
+target_compile_features(module
+  PRIVATE
+    cxx_std_20)
diff --git a/Tests/RunCMake/CXXModules/NoCXX-result.txt b/Tests/RunCMake/CXXModules/NoCXX-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NoCXX-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CXXModules/NoCXX-stderr.txt b/Tests/RunCMake/CXXModules/NoCXX-stderr.txt
new file mode 100644
index 0000000..aa7f406
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NoCXX-stderr.txt
@@ -0,0 +1,20 @@
+CMake Warning \(dev\) at NoCXX.cmake:4 \(target_sources\):
+  CMake's C\+\+ module support is experimental.  It is meant only for
+  experimentation and feedback to CMake developers.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:6 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Error in CMakeLists.txt:
+  The "nocxx" target has C\+\+ module sources but the "CXX" language has not
+  been enabled
+
+(
+CMake Error in CMakeLists.txt:
+(  The "nocxx" target has C\+\+ module sources but the "CXX" language has not
+  been enabled
+|  The "nocxx" target contains C\+\+ module sources which are not supported by
+  the generator
+)
+)*
+CMake Generate step failed.  Build files cannot be regenerated correctly.
diff --git a/Tests/RunCMake/CXXModules/NoCXX.cmake b/Tests/RunCMake/CXXModules/NoCXX.cmake
new file mode 100644
index 0000000..3c46f9d
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NoCXX.cmake
@@ -0,0 +1,9 @@
+enable_language(C)
+
+add_library(nocxx)
+target_sources(nocxx
+  PRIVATE
+    sources/c-anchor.c
+  PUBLIC
+    FILE_SET fs TYPE CXX_MODULES FILES
+      sources/module.cxx)
diff --git a/Tests/RunCMake/CXXModules/NoCXX20-result.txt b/Tests/RunCMake/CXXModules/NoCXX20-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NoCXX20-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CXXModules/NoCXX20-stderr.txt b/Tests/RunCMake/CXXModules/NoCXX20-stderr.txt
new file mode 100644
index 0000000..95d73b1
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NoCXX20-stderr.txt
@@ -0,0 +1,20 @@
+CMake Warning \(dev\) at NoCXX20.cmake:4 \(target_sources\):
+  CMake's C\+\+ module support is experimental.  It is meant only for
+  experimentation and feedback to CMake developers.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:6 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Error in CMakeLists.txt:
+  The "nocxx20" target has C\+\+ module sources but is not using at least
+  "cxx_std_20"
+
+(
+CMake Error in CMakeLists.txt:
+(  The "nocxx20" target has C\+\+ module sources but is not using at least
+  "cxx_std_20"
+|  The "nocxx20" target contains C\+\+ module sources which are not supported by
+  the generator
+)
+)*
+CMake Generate step failed.  Build files cannot be regenerated correctly.
diff --git a/Tests/RunCMake/CXXModules/NoCXX20.cmake b/Tests/RunCMake/CXXModules/NoCXX20.cmake
new file mode 100644
index 0000000..d502f7c
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NoCXX20.cmake
@@ -0,0 +1,10 @@
+enable_language(CXX)
+
+add_library(nocxx20)
+target_sources(nocxx20
+  PUBLIC
+    FILE_SET fs TYPE CXX_MODULES FILES
+      sources/module.cxx)
+target_compile_features(nocxx20
+  PRIVATE
+    cxx_std_17)
diff --git a/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-result.txt b/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-stderr.txt b/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-stderr.txt
new file mode 100644
index 0000000..5f90ec8
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag-stderr.txt
@@ -0,0 +1,20 @@
+CMake Warning \(dev\) at NoCXX20ModuleFlag.cmake:4 \(target_sources\):
+  CMake's C\+\+ module support is experimental.  It is meant only for
+  experimentation and feedback to CMake developers.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:6 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Error in CMakeLists.txt:
+  The "noexperimentalflag" target has C\+\+ module sources but its experimental
+  support has not been requested
+
+(
+CMake Error in CMakeLists.txt:
+(  The "noexperimentalflag" target has C\+\+ module sources but its experimental
+  support has not been requested
+|  The "noexperimentalflag" target contains C\+\+ module sources which are not
+  supported by the generator
+)
+)*
+CMake Generate step failed.  Build files cannot be regenerated correctly.
diff --git a/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag.cmake b/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag.cmake
new file mode 100644
index 0000000..5f896f9
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NoCXX20ModuleFlag.cmake
@@ -0,0 +1,10 @@
+enable_language(CXX)
+
+add_library(noexperimentalflag)
+target_sources(noexperimentalflag
+  PUBLIC
+    FILE_SET fs TYPE CXX_MODULES FILES
+      sources/module.cxx)
+target_compile_features(noexperimentalflag
+  PRIVATE
+    cxx_std_20)
diff --git a/Tests/RunCMake/CXXModules/NoDyndepSupport-result.txt b/Tests/RunCMake/CXXModules/NoDyndepSupport-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NoDyndepSupport-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt b/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt
new file mode 100644
index 0000000..52f781f
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt
@@ -0,0 +1,30 @@
+CMake Warning \(dev\) at NoDyndepSupport.cmake:10 \(target_sources\):
+  CMake's C\+\+ module support is experimental.  It is meant only for
+  experimentation and feedback to CMake developers.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:6 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+(CMake Warning \(dev\):
+  C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+  experimental.  It is meant only for compiler developers to try.
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Error:
+  The Ninja generator does not support C\+\+20 modules using Ninja version
+
+    .*
+
+  due to lack of required features.  Ninja 1.10 or higher is required.
+
+|CMake Error in CMakeLists.txt:
+  The "nodyndep" target contains C\+\+ module sources which are not supported
+  by the generator
+
+(
+CMake Error in CMakeLists.txt:
+  The "nodyndep" target contains C\+\+ module sources which are not supported
+  by the generator
+
+)*)
+CMake Generate step failed.  Build files cannot be regenerated correctly.
diff --git a/Tests/RunCMake/CXXModules/NoDyndepSupport.cmake b/Tests/RunCMake/CXXModules/NoDyndepSupport.cmake
new file mode 100644
index 0000000..0954400
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NoDyndepSupport.cmake
@@ -0,0 +1,16 @@
+enable_language(CXX)
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)
+set(CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE "")
+
+if (NOT CMAKE_CXX_STANDARD_DEFAULT)
+  set(CMAKE_CXX_STANDARD_DEFAULT "11")
+endif ()
+
+add_library(nodyndep)
+target_sources(nodyndep
+  PUBLIC
+    FILE_SET fs TYPE CXX_MODULES FILES
+      sources/module.cxx)
+target_compile_features(nodyndep
+  PRIVATE
+    cxx_std_20)
diff --git a/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits-result.txt b/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits-stderr.txt b/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits-stderr.txt
new file mode 100644
index 0000000..a93eb40
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits-stderr.txt
@@ -0,0 +1,22 @@
+CMake Warning \(dev\) at NotCXXSourceModuleHeaderUnits.cmake:7 \(target_sources\):
+  CMake's C\+\+ module support is experimental.  It is meant only for
+  experimentation and feedback to CMake developers.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:6 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\):
+  C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+  experimental.  It is meant only for compiler developers to try.
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Error in CMakeLists.txt:
+  Target "not-cxx-source" contains the source
+
+    .*/Tests/RunCMake/CXXModules/sources/c-anchor.c
+
+  in a file set of type "CXX_MODULE_HEADER_UNITS" but the source is not
+  classified as a "CXX" source.
+
+
+CMake Generate step failed.  Build files cannot be regenerated correctly.
diff --git a/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits.cmake b/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits.cmake
new file mode 100644
index 0000000..af4ddac
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NotCXXSourceModuleHeaderUnits.cmake
@@ -0,0 +1,15 @@
+enable_language(C)
+enable_language(CXX)
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)
+set(CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE "")
+
+add_library(not-cxx-source)
+target_sources(not-cxx-source
+  PRIVATE
+    sources/cxx-anchor.cxx
+  PUBLIC
+    FILE_SET fs TYPE CXX_MODULE_HEADER_UNITS FILES
+      sources/c-anchor.c)
+target_compile_features(not-cxx-source
+  PRIVATE
+    cxx_std_20)
diff --git a/Tests/RunCMake/CXXModules/NotCXXSourceModules-result.txt b/Tests/RunCMake/CXXModules/NotCXXSourceModules-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NotCXXSourceModules-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CXXModules/NotCXXSourceModules-stderr.txt b/Tests/RunCMake/CXXModules/NotCXXSourceModules-stderr.txt
new file mode 100644
index 0000000..d341c1f
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NotCXXSourceModules-stderr.txt
@@ -0,0 +1,17 @@
+CMake Warning \(dev\) at NotCXXSourceModules.cmake:7 \(target_sources\):
+  CMake's C\+\+ module support is experimental.  It is meant only for
+  experimentation and feedback to CMake developers.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:6 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Error in CMakeLists.txt:
+  Target "not-cxx-source" contains the source
+
+    .*/Tests/RunCMake/CXXModules/sources/c-anchor.c
+
+  in a file set of type "CXX_MODULES" but the source is not classified as a
+  "CXX" source.
+
+
+CMake Generate step failed.  Build files cannot be regenerated correctly.
diff --git a/Tests/RunCMake/CXXModules/NotCXXSourceModules.cmake b/Tests/RunCMake/CXXModules/NotCXXSourceModules.cmake
new file mode 100644
index 0000000..f7a6060
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/NotCXXSourceModules.cmake
@@ -0,0 +1,13 @@
+enable_language(C)
+enable_language(CXX)
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1)
+set(CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE "")
+
+add_library(not-cxx-source)
+target_sources(not-cxx-source
+  PUBLIC
+    FILE_SET fs TYPE CXX_MODULES FILES
+      sources/c-anchor.c)
+target_compile_features(not-cxx-source
+  PRIVATE
+    cxx_std_20)
diff --git a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake
new file mode 100644
index 0000000..68fdcae
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake
@@ -0,0 +1,120 @@
+include(RunCMake)
+
+# For `if (IN_LIST)`
+cmake_policy(SET CMP0057 NEW)
+
+run_cmake(compiler_introspection)
+include("${RunCMake_BINARY_DIR}/compiler_introspection-build/info.cmake")
+
+# Test negative cases where C++20 modules do not work.
+run_cmake(NoCXX)
+if ("cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
+  # This test requires that the compiler be told to compile in an older-than-20
+  # standard. If the compiler forces a standard to be used, skip it.
+  if (NOT forced_cxx_standard)
+    run_cmake(NoCXX20)
+  endif ()
+
+  # This test uses C++20, but another prerequisite is missing, so forced
+  # standards don't matter.
+  run_cmake(NoCXX20ModuleFlag)
+endif ()
+
+if (RunCMake_GENERATOR MATCHES "Ninja")
+  execute_process(
+    COMMAND "${CMAKE_MAKE_PROGRAM}" --version
+    RESULT_VARIABLE res
+    OUTPUT_VARIABLE ninja_version
+    ERROR_VARIABLE err
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+    ERROR_STRIP_TRAILING_WHITESPACE)
+
+  if (res)
+    message(WARNING
+      "Failed to determine `ninja` version: ${err}")
+    set(ninja_version "0")
+  endif ()
+endif ()
+
+# Test behavior when the generator does not support C++20 modules.
+if (NOT RunCMake_GENERATOR MATCHES "Ninja" OR
+    ninja_version VERSION_LESS "1.10" OR
+    NOT "cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
+  if ("cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
+    run_cmake(NoDyndepSupport)
+  endif ()
+
+  # Bail; the remaining tests require the generator to successfully generate
+  # with C++20 modules in the source list.
+  return ()
+endif ()
+
+set(fileset_types
+  Modules
+  ModuleHeaderUnits)
+set(scopes
+  Interface
+  Private
+  Public)
+foreach (fileset_type IN LISTS fileset_types)
+  foreach (scope IN LISTS scopes)
+    run_cmake("FileSet${fileset_type}${scope}")
+  endforeach ()
+
+  # Test the error message when a non-C++ source file is found in the source
+  # list.
+  run_cmake("NotCXXSource${fileset_type}")
+endforeach ()
+
+# 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 ()
+
+  set(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)
+  run_cmake_command("${test_name}-build" "${CMAKE_COMMAND}" --build . --config Debug)
+  run_cmake_command("${test_name}-test" "${CMAKE_CTEST_COMMAND}" -C Debug)
+endfunction ()
+
+string(REPLACE "," ";" CMake_TEST_MODULE_COMPILATION "${CMake_TEST_MODULE_COMPILATION}")
+
+# Tests which use named modules.
+if ("named" IN_LIST CMake_TEST_MODULE_COMPILATION)
+  run_cxx_module_test(simple)
+  run_cxx_module_test(library library-static -DBUILD_SHARED_LIBS=OFF)
+  run_cxx_module_test(generated)
+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 ()
diff --git a/Tests/RunCMake/CXXModules/compiler_introspection.cmake b/Tests/RunCMake/CXXModules/compiler_introspection.cmake
new file mode 100644
index 0000000..7a2df3d
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/compiler_introspection.cmake
@@ -0,0 +1,25 @@
+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 ()
+
+# Detect if the environment forces a C++ standard, let the test selection know.
+set(forced_cxx_standard 0)
+if (CMAKE_CXX_FLAGS MATCHES "-std=")
+  set(forced_cxx_standard 1)
+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(forced_cxx_standard \"${forced_cxx_standard}\")
+")
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/info.cmake" "${info}")
diff --git a/Tests/RunCMake/CXXModules/examples/cxx-modules-rules.cmake b/Tests/RunCMake/CXXModules/examples/cxx-modules-rules.cmake
new file mode 100644
index 0000000..91ad208
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/cxx-modules-rules.cmake
@@ -0,0 +1,18 @@
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "17be90bd-a850-44e0-be50-448de847d652")
+
+if (NOT EXISTS "${CMake_TEST_MODULE_COMPILATION_RULES}")
+  message(FATAL_ERROR
+    "The `CMake_TEST_MODULE_COMPILATION_RULES` file must be specified "
+    "for these tests to operate.")
+endif ()
+
+include("${CMake_TEST_MODULE_COMPILATION_RULES}")
+
+if (NOT CMake_TEST_CXXModules_UUID STREQUAL "a246741c-d067-4019-a8fb-3d16b0c9d1d3")
+  message(FATAL_ERROR
+    "The compilation rule file needs updated for changes in the test "
+    "suite. Please see the history for what needs to be updated.")
+endif ()
+
+include(CTest)
+enable_testing()
diff --git a/Tests/RunCMake/CXXModules/examples/generated-stderr.txt b/Tests/RunCMake/CXXModules/examples/generated-stderr.txt
new file mode 100644
index 0000000..b9bbf34
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/generated-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMakeLists.txt:12 \(target_sources\):
+  CMake's C\+\+ module support 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.
+
+CMake Warning \(dev\):
+  C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+  experimental.  It is meant only for compiler developers to try.
+This warning is for project developers.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CXXModules/examples/generated/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/generated/CMakeLists.txt
new file mode 100644
index 0000000..73f7ff7
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/generated/CMakeLists.txt
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 3.24)
+project(cxx_modules_generated CXX)
+
+include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
+
+configure_file(
+  "${CMAKE_CURRENT_SOURCE_DIR}/importable.cxx.in"
+  "${CMAKE_CURRENT_BINARY_DIR}/importable.cxx"
+  COPYONLY)
+
+add_executable(generated)
+target_sources(generated
+  PRIVATE
+    main.cxx
+  PRIVATE
+    FILE_SET CXX_MODULES
+      BASE_DIRS
+        "${CMAKE_CURRENT_BINARY_DIR}"
+      FILES
+        "${CMAKE_CURRENT_BINARY_DIR}/importable.cxx")
+target_compile_features(generated PUBLIC cxx_std_20)
+
+add_test(NAME generated COMMAND generated)
diff --git a/Tests/RunCMake/CXXModules/examples/generated/importable.cxx.in b/Tests/RunCMake/CXXModules/examples/generated/importable.cxx.in
new file mode 100644
index 0000000..a9287d7
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/generated/importable.cxx.in
@@ -0,0 +1,5 @@
+export module importable;
+
+export int from_import() {
+  return 0;
+}
diff --git a/Tests/RunCMake/CXXModules/examples/generated/main.cxx b/Tests/RunCMake/CXXModules/examples/generated/main.cxx
new file mode 100644
index 0000000..feb38d2
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/generated/main.cxx
@@ -0,0 +1,6 @@
+import importable;
+
+int main(int argc, char* argv[])
+{
+  return from_import();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/internal-partitions-stderr.txt b/Tests/RunCMake/CXXModules/examples/internal-partitions-stderr.txt
new file mode 100644
index 0000000..4652aec
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/internal-partitions-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMakeLists.txt:10 \(target_sources\):
+  CMake's C\+\+ module support 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.
+
+CMake Warning \(dev\):
+  C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+  experimental.  It is meant only for compiler developers to try.
+This warning is for project developers.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CXXModules/examples/internal-partitions/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/internal-partitions/CMakeLists.txt
new file mode 100644
index 0000000..f5e9d94
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/internal-partitions/CMakeLists.txt
@@ -0,0 +1,31 @@
+cmake_minimum_required(VERSION 3.24)
+project(cxx_modules_internal_partitions CXX)
+
+include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
+
+include(GenerateExportHeader)
+
+add_library(internal-partitions)
+generate_export_header(internal-partitions)
+target_sources(internal-partitions
+  PUBLIC
+    FILE_SET HEADERS
+      BASE_DIRS
+        "${CMAKE_CURRENT_BINARY_DIR}"
+      FILES
+        "${CMAKE_CURRENT_BINARY_DIR}/internal-partitions_export.h"
+    FILE_SET CXX_MODULES
+      BASE_DIRS
+        "${CMAKE_CURRENT_SOURCE_DIR}"
+      FILES
+        importable.cxx
+        partition.cxx)
+target_compile_features(internal-partitions PUBLIC cxx_std_20)
+
+add_executable(exe)
+target_link_libraries(exe PRIVATE internal-partitions)
+target_sources(exe
+  PRIVATE
+    main.cxx)
+
+add_test(NAME exe COMMAND exe)
diff --git a/Tests/RunCMake/CXXModules/examples/internal-partitions/importable.cxx b/Tests/RunCMake/CXXModules/examples/internal-partitions/importable.cxx
new file mode 100644
index 0000000..8be521b
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/internal-partitions/importable.cxx
@@ -0,0 +1,9 @@
+export module importable;
+import importable : internal_partition;
+
+#include "internal-partitions_export.h"
+
+export INTERNAL_PARTITIONS_EXPORT int from_import()
+{
+  return from_partition();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/internal-partitions/main.cxx b/Tests/RunCMake/CXXModules/examples/internal-partitions/main.cxx
new file mode 100644
index 0000000..feb38d2
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/internal-partitions/main.cxx
@@ -0,0 +1,6 @@
+import importable;
+
+int main(int argc, char* argv[])
+{
+  return from_import();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/internal-partitions/partition.cxx b/Tests/RunCMake/CXXModules/examples/internal-partitions/partition.cxx
new file mode 100644
index 0000000..b15f53c
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/internal-partitions/partition.cxx
@@ -0,0 +1,6 @@
+module importable : internal_partition;
+
+int from_partition()
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/CXXModules/examples/library-shared-stderr.txt b/Tests/RunCMake/CXXModules/examples/library-shared-stderr.txt
new file mode 100644
index 0000000..4652aec
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/library-shared-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMakeLists.txt:10 \(target_sources\):
+  CMake's C\+\+ module support 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.
+
+CMake Warning \(dev\):
+  C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+  experimental.  It is meant only for compiler developers to try.
+This warning is for project developers.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CXXModules/examples/library-static-stderr.txt b/Tests/RunCMake/CXXModules/examples/library-static-stderr.txt
new file mode 100644
index 0000000..4652aec
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/library-static-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMakeLists.txt:10 \(target_sources\):
+  CMake's C\+\+ module support 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.
+
+CMake Warning \(dev\):
+  C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+  experimental.  It is meant only for compiler developers to try.
+This warning is for project developers.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CXXModules/examples/library/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/library/CMakeLists.txt
new file mode 100644
index 0000000..27fd94f
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/library/CMakeLists.txt
@@ -0,0 +1,30 @@
+cmake_minimum_required(VERSION 3.24)
+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
new file mode 100644
index 0000000..72ed0df
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/library/importable.cxx
@@ -0,0 +1,8 @@
+export module importable;
+
+#include "library_export.h"
+
+export LIBRARY_EXPORT int from_import()
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/CXXModules/examples/library/main.cxx b/Tests/RunCMake/CXXModules/examples/library/main.cxx
new file mode 100644
index 0000000..feb38d2
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/library/main.cxx
@@ -0,0 +1,6 @@
+import importable;
+
+int main(int argc, char* argv[])
+{
+  return from_import();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/partitions-stderr.txt b/Tests/RunCMake/CXXModules/examples/partitions-stderr.txt
new file mode 100644
index 0000000..4652aec
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/partitions-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMakeLists.txt:10 \(target_sources\):
+  CMake's C\+\+ module support 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.
+
+CMake Warning \(dev\):
+  C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+  experimental.  It is meant only for compiler developers to try.
+This warning is for project developers.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CXXModules/examples/partitions/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/partitions/CMakeLists.txt
new file mode 100644
index 0000000..3a7b0d4
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/partitions/CMakeLists.txt
@@ -0,0 +1,31 @@
+cmake_minimum_required(VERSION 3.24)
+project(cxx_modules_partitions CXX)
+
+include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
+
+include(GenerateExportHeader)
+
+add_library(partitions)
+generate_export_header(partitions)
+target_sources(partitions
+  PUBLIC
+    FILE_SET HEADERS
+      BASE_DIRS
+        "${CMAKE_CURRENT_BINARY_DIR}"
+      FILES
+        "${CMAKE_CURRENT_BINARY_DIR}/partitions_export.h"
+    FILE_SET CXX_MODULES
+      BASE_DIRS
+        "${CMAKE_CURRENT_SOURCE_DIR}"
+      FILES
+        importable.cxx
+        partition.cxx)
+target_compile_features(partitions PUBLIC cxx_std_20)
+
+add_executable(exe)
+target_link_libraries(exe PRIVATE partitions)
+target_sources(exe
+  PRIVATE
+    main.cxx)
+
+add_test(NAME exe COMMAND exe)
diff --git a/Tests/RunCMake/CXXModules/examples/partitions/importable.cxx b/Tests/RunCMake/CXXModules/examples/partitions/importable.cxx
new file mode 100644
index 0000000..1e81aaf
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/partitions/importable.cxx
@@ -0,0 +1,9 @@
+export module importable;
+export import importable : partition;
+
+#include "partitions_export.h"
+
+export PARTITIONS_EXPORT int from_import()
+{
+  return from_partition();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/partitions/main.cxx b/Tests/RunCMake/CXXModules/examples/partitions/main.cxx
new file mode 100644
index 0000000..c5b78c9
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/partitions/main.cxx
@@ -0,0 +1,6 @@
+import importable;
+
+int main(int argc, char* argv[])
+{
+  return from_import() + from_partition();
+}
diff --git a/Tests/RunCMake/CXXModules/examples/partitions/partition.cxx b/Tests/RunCMake/CXXModules/examples/partitions/partition.cxx
new file mode 100644
index 0000000..a47a4fd
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/partitions/partition.cxx
@@ -0,0 +1,8 @@
+export module importable : partition;
+
+#include "partitions_export.h"
+
+export PARTITIONS_EXPORT int from_partition()
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/CXXModules/examples/simple-stderr.txt b/Tests/RunCMake/CXXModules/examples/simple-stderr.txt
new file mode 100644
index 0000000..5e4392a
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/simple-stderr.txt
@@ -0,0 +1,9 @@
+CMake Warning \(dev\) at CMakeLists.txt:7 \(target_sources\):
+  CMake's C\+\+ module support 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.
+
+CMake Warning \(dev\):
+  C\+\+20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP is
+  experimental.  It is meant only for compiler developers to try.
+This warning is for project developers.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CXXModules/examples/simple/CMakeLists.txt b/Tests/RunCMake/CXXModules/examples/simple/CMakeLists.txt
new file mode 100644
index 0000000..442e425
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/simple/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.24)
+project(cxx_modules_simple CXX)
+
+include("${CMAKE_SOURCE_DIR}/../cxx-modules-rules.cmake")
+
+add_executable(simple)
+target_sources(simple
+  PRIVATE
+    main.cxx
+  PRIVATE
+    FILE_SET CXX_MODULES
+      BASE_DIRS
+        "${CMAKE_CURRENT_SOURCE_DIR}"
+      FILES
+        importable.cxx)
+target_compile_features(simple PUBLIC cxx_std_20)
+
+add_test(NAME simple COMMAND simple)
diff --git a/Tests/RunCMake/CXXModules/examples/simple/importable.cxx b/Tests/RunCMake/CXXModules/examples/simple/importable.cxx
new file mode 100644
index 0000000..607680a
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/simple/importable.cxx
@@ -0,0 +1,6 @@
+export module importable;
+
+export int from_import()
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/CXXModules/examples/simple/main.cxx b/Tests/RunCMake/CXXModules/examples/simple/main.cxx
new file mode 100644
index 0000000..feb38d2
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/examples/simple/main.cxx
@@ -0,0 +1,6 @@
+import importable;
+
+int main(int argc, char* argv[])
+{
+  return from_import();
+}
diff --git a/Tests/RunCMake/CXXModules/sources/c-anchor.c b/Tests/RunCMake/CXXModules/sources/c-anchor.c
new file mode 100644
index 0000000..c782188
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/sources/c-anchor.c
@@ -0,0 +1,4 @@
+int c_anchor()
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/CXXModules/sources/cxx-anchor.cxx b/Tests/RunCMake/CXXModules/sources/cxx-anchor.cxx
new file mode 100644
index 0000000..9c94ec1
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/sources/cxx-anchor.cxx
@@ -0,0 +1,4 @@
+int cxx_anchor()
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/CXXModules/sources/module-header.h b/Tests/RunCMake/CXXModules/sources/module-header.h
new file mode 100644
index 0000000..982617e
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/sources/module-header.h
@@ -0,0 +1,9 @@
+#ifndef module_header_h
+#define module_header_h
+
+inline int h()
+{
+  return 0;
+}
+
+#endif
diff --git a/Tests/RunCMake/CXXModules/sources/module-impl.cxx b/Tests/RunCMake/CXXModules/sources/module-impl.cxx
new file mode 100644
index 0000000..4718999
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/sources/module-impl.cxx
@@ -0,0 +1,6 @@
+module M;
+
+int f()
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/CXXModules/sources/module-internal-part-impl.cxx b/Tests/RunCMake/CXXModules/sources/module-internal-part-impl.cxx
new file mode 100644
index 0000000..be77b0d
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/sources/module-internal-part-impl.cxx
@@ -0,0 +1,11 @@
+#ifdef _MSC_VER
+// Only MSVC supports this pattern.
+module M : internal_part;
+#else
+module M;
+#endif
+
+int i()
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/CXXModules/sources/module-internal-part.cxx b/Tests/RunCMake/CXXModules/sources/module-internal-part.cxx
new file mode 100644
index 0000000..fa82afb
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/sources/module-internal-part.cxx
@@ -0,0 +1,3 @@
+module M : internal_part;
+
+int i();
diff --git a/Tests/RunCMake/CXXModules/sources/module-part-impl.cxx b/Tests/RunCMake/CXXModules/sources/module-part-impl.cxx
new file mode 100644
index 0000000..46d5d9f
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/sources/module-part-impl.cxx
@@ -0,0 +1,13 @@
+#ifdef _MSC_VER
+// Only MSVC supports this pattern.
+module M : part;
+#else
+module M;
+#endif
+
+import M : internal_part;
+
+int p()
+{
+  return i();
+}
diff --git a/Tests/RunCMake/CXXModules/sources/module-part.cxx b/Tests/RunCMake/CXXModules/sources/module-part.cxx
new file mode 100644
index 0000000..137c16f
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/sources/module-part.cxx
@@ -0,0 +1,3 @@
+export module M : part;
+
+int p();
diff --git a/Tests/RunCMake/CXXModules/sources/module-use.cxx b/Tests/RunCMake/CXXModules/sources/module-use.cxx
new file mode 100644
index 0000000..2d060cd
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/sources/module-use.cxx
@@ -0,0 +1,6 @@
+import M;
+
+int main(int argc, char* argv[])
+{
+  return f() + p();
+}
diff --git a/Tests/RunCMake/CXXModules/sources/module.cxx b/Tests/RunCMake/CXXModules/sources/module.cxx
new file mode 100644
index 0000000..a631354
--- /dev/null
+++ b/Tests/RunCMake/CXXModules/sources/module.cxx
@@ -0,0 +1,5 @@
+export module M;
+export import M : part;
+import M : internal_part;
+
+int f();
diff --git a/Tests/RunCMake/VsDotnetSdk/RunCMakeTest.cmake b/Tests/RunCMake/VsDotnetSdk/RunCMakeTest.cmake
index 9c9074e..22e2bb3 100644
--- a/Tests/RunCMake/VsDotnetSdk/RunCMakeTest.cmake
+++ b/Tests/RunCMake/VsDotnetSdk/RunCMakeTest.cmake
@@ -4,6 +4,7 @@
 run_cmake(VsDotnetSdkCustomCommandsTarget)
 run_cmake(VsDotnetSdkCustomCommandsSource)
 run_cmake(VsDotnetSdkStartupObject)
+run_cmake(VsDotnetSdkDefines)
 run_cmake(DotnetSdkVariables)
 
 function(run_VsDotnetSdk)
diff --git a/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkDefines-check.cmake b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkDefines-check.cmake
new file mode 100644
index 0000000..eaeba24
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkDefines-check.cmake
@@ -0,0 +1,64 @@
+#
+# Check C# VS project for required elements.
+#
+set(csProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.csproj")
+if(NOT EXISTS "${csProjectFile}")
+  set(RunCMake_TEST_FAILED "Project file ${csProjectFile} does not exist.")
+  return()
+endif()
+
+
+set(inDebug FALSE)
+set(inRelease FALSE)
+set(debugOK FALSE)
+set(releaseOK FALSE)
+
+
+file(STRINGS "${csProjectFile}" lines)
+foreach(line IN LISTS lines)
+  #message(STATUS ${line})
+  if(line MATCHES "^ *<PropertyGroup .*Debug.*")
+    set(inDebug TRUE)
+  elseif(line MATCHES "^ *<PropertyGroup .*Release.*")
+    set(inRelease TRUE)
+  elseif(line MATCHES "^ *</PropertyGroup> *$")
+    set(inRelease FALSE)
+    set(inDebug  FALSE)
+  elseif(inDebug AND
+     (line MATCHES "^ *<DefineConstants>.*MY_FOO_DEFINE.*</DefineConstants> *$") AND
+     (line MATCHES "^ *<DefineConstants>.*DEFINE_ONLY_FOR_DEBUG.*</DefineConstants> *$") AND
+     (NOT (line MATCHES "^ *<DefineConstants>.*DEFINE_ONLY_FOR_RELEASE.*</DefineConstants> *$")) AND
+     (NOT (line MATCHES "^ *<DefineConstants>.*MY_BAR_ASSIGNMENT=bar.*</DefineConstants> *$"))
+    )
+    set(debugOK TRUE)
+  elseif(inRelease AND
+     (line MATCHES "^ *<DefineConstants>.*MY_FOO_DEFINE.*</DefineConstants> *$") AND
+     (line MATCHES "^ *<DefineConstants>.*DEFINE_ONLY_FOR_RELEASE.*</DefineConstants> *$") AND
+     (NOT (line MATCHES "^ *<DefineConstants>.*DEFINE_ONLY_FOR_DEBUG.*</DefineConstants> *$")) AND
+     (NOT (line MATCHES "^ *<DefineConstants>.*MY_BAR_ASSIGNMENT=bar.*</DefineConstants> *$"))
+    )
+    set(releaseOK TRUE)
+  endif()
+endforeach()
+
+function(print_csprojfile)
+  file(STRINGS "${csProjectFile}" lines)
+  foreach(line IN LISTS lines)
+    message(STATUS ${line})
+  endforeach()
+endfunction()
+
+
+if(NOT debugOK)
+  message(STATUS "Failed to set Debug configuration defines correctly.")
+  set(RunCMake_TEST_FAILED "Failed to set Debug configuration defines correctly.")
+  print_csprojfile()
+  return()
+endif()
+
+if(NOT releaseOK)
+  message(STATUS "Failed to set Release configuration defines correctly.")
+  set(RunCMake_TEST_FAILED "Failed to set Release configuration defines correctly.")
+  print_csprojfile()
+  return()
+endif()
diff --git a/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkDefines.cmake b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkDefines.cmake
new file mode 100644
index 0000000..d89f19b
--- /dev/null
+++ b/Tests/RunCMake/VsDotnetSdk/VsDotnetSdkDefines.cmake
@@ -0,0 +1,19 @@
+enable_language(CSharp)
+if(NOT CMAKE_CSharp_COMPILER)
+    return()
+endif()
+
+set(CMAKE_DOTNET_SDK "Microsoft.NET.Sdk")
+set(CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION "net5.0")
+
+add_executable(foo csharponly.cs lib1.cs)
+
+# Issue 23376
+target_compile_definitions(
+  foo
+    PUBLIC
+      MY_FOO_DEFINE
+      "MY_BAR_ASSIGNMENT=bar"
+      $<$<CONFIG:Debug>:DEFINE_ONLY_FOR_DEBUG>
+      $<$<CONFIG:Release>:DEFINE_ONLY_FOR_RELEASE>
+)
diff --git a/Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake b/Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake
index be44ecd..efd70cf 100644
--- a/Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake
+++ b/Tests/RunCMake/XcodeProject/XcodeSchemaProperty-check.cmake
@@ -43,6 +43,8 @@
 check_property("ENABLE_GPU_FRAME_CAPTURE_MODE_METAL" "enableGPUFrameCaptureMode=\"1\"")
 check_property("ENABLE_GPU_FRAME_CAPTURE_MODE_DISABLED_MIXED_CASE" "enableGPUFrameCaptureMode=\"3\"")
 check_property("ENABLE_GPU_FRAME_CAPTURE_MODE_METAL_MIXED_CASE" "enableGPUFrameCaptureMode=\"1\"")
+check_property("LAUNCH_MODE_AUTO" "launchStyle=\"0\"")
+check_property("LAUNCH_MODE_WAIT" "launchStyle=\"1\"")
 
 check_property("EXECUTABLE" "myExecutable")
 check_property("ARGUMENTS" [=["--foo"]=])
diff --git a/Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake b/Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake
index 126a9fc..5edbc89 100644
--- a/Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake
+++ b/Tests/RunCMake/XcodeProject/XcodeSchemaProperty.cmake
@@ -38,6 +38,8 @@
 create_scheme_for_property(ENABLE_GPU_FRAME_CAPTURE_MODE_METAL ENABLE_GPU_FRAME_CAPTURE_MODE Metal)
 create_scheme_for_property(ENABLE_GPU_FRAME_CAPTURE_MODE_DISABLED_MIXED_CASE ENABLE_GPU_FRAME_CAPTURE_MODE DISAbled)
 create_scheme_for_property(ENABLE_GPU_FRAME_CAPTURE_MODE_METAL_MIXED_CASE ENABLE_GPU_FRAME_CAPTURE_MODE METal)
+create_scheme_for_property(LAUNCH_MODE_AUTO LAUNCH_MODE AUTO)
+create_scheme_for_property(LAUNCH_MODE_WAIT LAUNCH_MODE WAIT)
 create_scheme_for_property(EXECUTABLE EXECUTABLE myExecutable)
 create_scheme_for_property(ARGUMENTS ARGUMENTS "--foo;--bar=baz")
 create_scheme_for_property(ENVIRONMENT ENVIRONMENT "FOO=foo;BAR=bar")
diff --git a/Tests/RunCMake/find_file/RunCMakeTest.cmake b/Tests/RunCMake/find_file/RunCMakeTest.cmake
index 23765d4..296bb71 100644
--- a/Tests/RunCMake/find_file/RunCMakeTest.cmake
+++ b/Tests/RunCMake/find_file/RunCMakeTest.cmake
@@ -7,6 +7,10 @@
 run_cmake(NO_CACHE)
 run_cmake(REGISTRY_VIEW-no-view)
 run_cmake(REGISTRY_VIEW-wrong-view)
+run_cmake(VALIDATOR-no-function)
+run_cmake(VALIDATOR-undefined-function)
+run_cmake(VALIDATOR-specify-macro)
+run_cmake(VALIDATOR)
 
 run_cmake_with_options(FromPATHEnvDebugVar --debug-find-var=PrefixInPATH_File)
 
diff --git a/Tests/RunCMake/find_file/VALIDATOR-no-function-result.txt b/Tests/RunCMake/find_file/VALIDATOR-no-function-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/find_file/VALIDATOR-no-function-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/find_file/VALIDATOR-no-function-stderr.txt b/Tests/RunCMake/find_file/VALIDATOR-no-function-stderr.txt
new file mode 100644
index 0000000..4d49649
--- /dev/null
+++ b/Tests/RunCMake/find_file/VALIDATOR-no-function-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at VALIDATOR-no-function.cmake:[0-9]+ \(find_file\):
+  find_file missing required argument for "VALIDATOR"
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/find_file/VALIDATOR-no-function.cmake b/Tests/RunCMake/find_file/VALIDATOR-no-function.cmake
new file mode 100644
index 0000000..4800fe9
--- /dev/null
+++ b/Tests/RunCMake/find_file/VALIDATOR-no-function.cmake
@@ -0,0 +1,2 @@
+
+find_file(result NAMES input.txt VALIDATOR)
diff --git a/Tests/RunCMake/find_file/VALIDATOR-specify-macro-result.txt b/Tests/RunCMake/find_file/VALIDATOR-specify-macro-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/find_file/VALIDATOR-specify-macro-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/find_file/VALIDATOR-specify-macro-stderr.txt b/Tests/RunCMake/find_file/VALIDATOR-specify-macro-stderr.txt
new file mode 100644
index 0000000..7e0eda0
--- /dev/null
+++ b/Tests/RunCMake/find_file/VALIDATOR-specify-macro-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at VALIDATOR-specify-macro.cmake:[0-9]+ \(find_file\):
+  find_file command specified for "VALIDATOR" is not a function: check.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/find_file/VALIDATOR-specify-macro.cmake b/Tests/RunCMake/find_file/VALIDATOR-specify-macro.cmake
new file mode 100644
index 0000000..ec0ce9a
--- /dev/null
+++ b/Tests/RunCMake/find_file/VALIDATOR-specify-macro.cmake
@@ -0,0 +1,5 @@
+
+macro(CHECK result path)
+endmacro()
+
+find_file(result NAMES input.txt VALIDATOR check)
diff --git a/Tests/RunCMake/find_file/VALIDATOR-stderr.txt b/Tests/RunCMake/find_file/VALIDATOR-stderr.txt
new file mode 100644
index 0000000..6c8159b
--- /dev/null
+++ b/Tests/RunCMake/find_file/VALIDATOR-stderr.txt
@@ -0,0 +1,3 @@
+CHECK='[^']+/Tests/RunCMake/find_file/include/PrefixInPATH.h'
+CHECK='[^']+/Tests/RunCMake/find_file/include/PrefixInPATH.h'
+CHECK='[^']+/Tests/RunCMake/find_file/include/PrefixInPATH.h'
diff --git a/Tests/RunCMake/find_file/VALIDATOR-stdout.txt b/Tests/RunCMake/find_file/VALIDATOR-stdout.txt
new file mode 100644
index 0000000..44fa77c
--- /dev/null
+++ b/Tests/RunCMake/find_file/VALIDATOR-stdout.txt
@@ -0,0 +1,3 @@
+-- FILE='[^']+/Tests/RunCMake/find_file/include/PrefixInPATH.h'
+-- FILE='[^']+/Tests/RunCMake/find_file/include/PrefixInPATH.h'
+-- FILE='FILE-NOTFOUND'
diff --git a/Tests/RunCMake/find_file/VALIDATOR-undefined-function-result.txt b/Tests/RunCMake/find_file/VALIDATOR-undefined-function-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/find_file/VALIDATOR-undefined-function-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/find_file/VALIDATOR-undefined-function-stderr.txt b/Tests/RunCMake/find_file/VALIDATOR-undefined-function-stderr.txt
new file mode 100644
index 0000000..b4125e6
--- /dev/null
+++ b/Tests/RunCMake/find_file/VALIDATOR-undefined-function-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at VALIDATOR-undefined-function.cmake:[0-9]+ \(find_file\):
+  find_file command specified for "VALIDATOR" is undefined: undefined.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/find_file/VALIDATOR-undefined-function.cmake b/Tests/RunCMake/find_file/VALIDATOR-undefined-function.cmake
new file mode 100644
index 0000000..c465887
--- /dev/null
+++ b/Tests/RunCMake/find_file/VALIDATOR-undefined-function.cmake
@@ -0,0 +1,2 @@
+
+find_file(result NAMES input.txt VALIDATOR undefined)
diff --git a/Tests/RunCMake/find_file/VALIDATOR.cmake b/Tests/RunCMake/find_file/VALIDATOR.cmake
new file mode 100644
index 0000000..72dd8f9
--- /dev/null
+++ b/Tests/RunCMake/find_file/VALIDATOR.cmake
@@ -0,0 +1,39 @@
+
+function(CHECK_DEFAULT result filename)
+  message("CHECK='${filename}'")
+endfunction()
+
+function(CHECK_OK result filename)
+  message("CHECK='${filename}'")
+  set(${result} TRUE PARENT_SCOPE)
+endfunction()
+
+function(CHECK_KO result filename)
+  message("CHECK='${filename}'")
+  set(${result} FALSE PARENT_SCOPE)
+endfunction()
+
+
+find_file(FILE
+  NAMES PrefixInPATH.h
+  HINTS ${CMAKE_CURRENT_SOURCE_DIR}/include
+  VALIDATOR check_default
+  )
+message(STATUS "FILE='${FILE}'")
+unset(FILE CACHE)
+
+find_file(FILE
+  NAMES PrefixInPATH.h
+  HINTS ${CMAKE_CURRENT_SOURCE_DIR}/include
+  VALIDATOR check_ok
+  )
+message(STATUS "FILE='${FILE}'")
+unset(FILE CACHE)
+
+find_file(FILE
+  NAMES PrefixInPATH.h
+  HINTS ${CMAKE_CURRENT_SOURCE_DIR}/include
+  VALIDATOR check_ko
+  )
+message(STATUS "FILE='${FILE}'")
+unset(FILE CACHE)
diff --git a/Tests/RunCMake/find_library/RunCMakeTest.cmake b/Tests/RunCMake/find_library/RunCMakeTest.cmake
index de0ee14..cc005d0 100644
--- a/Tests/RunCMake/find_library/RunCMakeTest.cmake
+++ b/Tests/RunCMake/find_library/RunCMakeTest.cmake
@@ -13,6 +13,10 @@
 run_cmake(NO_CACHE)
 run_cmake(REGISTRY_VIEW-no-view)
 run_cmake(REGISTRY_VIEW-wrong-view)
+run_cmake(VALIDATOR-no-function)
+run_cmake(VALIDATOR-undefined-function)
+run_cmake(VALIDATOR-specify-macro)
+run_cmake(VALIDATOR)
 
 run_cmake_script(FromScriptMode "-DTEMP_DIR=${RunCMake_BINARY_DIR}/FromScriptMode-temp")
 
diff --git a/Tests/RunCMake/find_library/VALIDATOR-no-function-result.txt b/Tests/RunCMake/find_library/VALIDATOR-no-function-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/find_library/VALIDATOR-no-function-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/find_library/VALIDATOR-no-function-stderr.txt b/Tests/RunCMake/find_library/VALIDATOR-no-function-stderr.txt
new file mode 100644
index 0000000..6c04aa4
--- /dev/null
+++ b/Tests/RunCMake/find_library/VALIDATOR-no-function-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at VALIDATOR-no-function.cmake:[0-9]+ \(find_library\):
+  find_library missing required argument for "VALIDATOR"
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/find_library/VALIDATOR-no-function.cmake b/Tests/RunCMake/find_library/VALIDATOR-no-function.cmake
new file mode 100644
index 0000000..516e54e
--- /dev/null
+++ b/Tests/RunCMake/find_library/VALIDATOR-no-function.cmake
@@ -0,0 +1,2 @@
+
+find_library(result NAMES input.txt VALIDATOR)
diff --git a/Tests/RunCMake/find_library/VALIDATOR-specify-macro-result.txt b/Tests/RunCMake/find_library/VALIDATOR-specify-macro-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/find_library/VALIDATOR-specify-macro-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/find_library/VALIDATOR-specify-macro-stderr.txt b/Tests/RunCMake/find_library/VALIDATOR-specify-macro-stderr.txt
new file mode 100644
index 0000000..03e7df9
--- /dev/null
+++ b/Tests/RunCMake/find_library/VALIDATOR-specify-macro-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at VALIDATOR-specify-macro.cmake:[0-9]+ \(find_library\):
+  find_library command specified for "VALIDATOR" is not a function: check.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/find_library/VALIDATOR-specify-macro.cmake b/Tests/RunCMake/find_library/VALIDATOR-specify-macro.cmake
new file mode 100644
index 0000000..fa90d72
--- /dev/null
+++ b/Tests/RunCMake/find_library/VALIDATOR-specify-macro.cmake
@@ -0,0 +1,5 @@
+
+macro(CHECK result path)
+endmacro()
+
+find_library(result NAMES input.txt VALIDATOR check)
diff --git a/Tests/RunCMake/find_library/VALIDATOR-stderr.txt b/Tests/RunCMake/find_library/VALIDATOR-stderr.txt
new file mode 100644
index 0000000..7211450
--- /dev/null
+++ b/Tests/RunCMake/find_library/VALIDATOR-stderr.txt
@@ -0,0 +1,3 @@
+CHECK='[^']+/Tests/RunCMake/find_library/lib/libPrefixInPATH.a'
+CHECK='[^']+/Tests/RunCMake/find_library/lib/libPrefixInPATH.a'
+CHECK='[^']+/Tests/RunCMake/find_library/lib/libPrefixInPATH.a'
diff --git a/Tests/RunCMake/find_library/VALIDATOR-stdout.txt b/Tests/RunCMake/find_library/VALIDATOR-stdout.txt
new file mode 100644
index 0000000..bd2549b
--- /dev/null
+++ b/Tests/RunCMake/find_library/VALIDATOR-stdout.txt
@@ -0,0 +1,3 @@
+-- LIB='[^']+/Tests/RunCMake/find_library/lib/libPrefixInPATH.a'
+-- LIB='[^']+/Tests/RunCMake/find_library/lib/libPrefixInPATH.a'
+-- LIB='LIB-NOTFOUND'
diff --git a/Tests/RunCMake/find_library/VALIDATOR-undefined-function-result.txt b/Tests/RunCMake/find_library/VALIDATOR-undefined-function-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/find_library/VALIDATOR-undefined-function-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/find_library/VALIDATOR-undefined-function-stderr.txt b/Tests/RunCMake/find_library/VALIDATOR-undefined-function-stderr.txt
new file mode 100644
index 0000000..dc7ad9e
--- /dev/null
+++ b/Tests/RunCMake/find_library/VALIDATOR-undefined-function-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at VALIDATOR-undefined-function.cmake:[0-9]+ \(find_library\):
+  find_library command specified for "VALIDATOR" is undefined: undefined.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/find_library/VALIDATOR-undefined-function.cmake b/Tests/RunCMake/find_library/VALIDATOR-undefined-function.cmake
new file mode 100644
index 0000000..9ac7ee0
--- /dev/null
+++ b/Tests/RunCMake/find_library/VALIDATOR-undefined-function.cmake
@@ -0,0 +1,2 @@
+
+find_library(result NAMES input.txt VALIDATOR undefined)
diff --git a/Tests/RunCMake/find_library/VALIDATOR.cmake b/Tests/RunCMake/find_library/VALIDATOR.cmake
new file mode 100644
index 0000000..7593941
--- /dev/null
+++ b/Tests/RunCMake/find_library/VALIDATOR.cmake
@@ -0,0 +1,41 @@
+list(APPEND CMAKE_FIND_LIBRARY_PREFIXES lib)
+list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES .a)
+
+function(CHECK_DEFAULT result filename)
+  message("CHECK='${filename}'")
+endfunction()
+
+function(CHECK_OK result filename)
+  message("CHECK='${filename}'")
+  set(${result} TRUE PARENT_SCOPE)
+endfunction()
+
+function(CHECK_KO result filename)
+  message("CHECK='${filename}'")
+  set(${result} FALSE PARENT_SCOPE)
+endfunction()
+
+
+find_library(LIB
+  NAMES PrefixInPATH
+  HINTS ${CMAKE_CURRENT_SOURCE_DIR}/lib
+  VALIDATOR check_default
+  )
+message(STATUS "LIB='${LIB}'")
+unset(LIB CACHE)
+
+find_library(LIB
+  NAMES PrefixInPATH
+  HINTS ${CMAKE_CURRENT_SOURCE_DIR}/lib
+  VALIDATOR check_ok
+  )
+message(STATUS "LIB='${LIB}'")
+unset(LIB CACHE)
+
+find_library(LIB
+  NAMES PrefixInPATH
+  HINTS ${CMAKE_CURRENT_SOURCE_DIR}/lib
+  VALIDATOR check_ko
+  )
+message(STATUS "LIB='${LIB}'")
+unset(LIB CACHE)
diff --git a/Tests/RunCMake/find_path/RunCMakeTest.cmake b/Tests/RunCMake/find_path/RunCMakeTest.cmake
index 63cadc2..9c76f2e 100644
--- a/Tests/RunCMake/find_path/RunCMakeTest.cmake
+++ b/Tests/RunCMake/find_path/RunCMakeTest.cmake
@@ -7,6 +7,10 @@
 run_cmake(NO_CACHE)
 run_cmake(REGISTRY_VIEW-no-view)
 run_cmake(REGISTRY_VIEW-wrong-view)
+run_cmake(VALIDATOR-no-function)
+run_cmake(VALIDATOR-undefined-function)
+run_cmake(VALIDATOR-specify-macro)
+run_cmake(VALIDATOR)
 
 if(APPLE)
   run_cmake(FrameworksWithSubdirs)
diff --git a/Tests/RunCMake/find_path/VALIDATOR-no-function-result.txt b/Tests/RunCMake/find_path/VALIDATOR-no-function-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/find_path/VALIDATOR-no-function-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/find_path/VALIDATOR-no-function-stderr.txt b/Tests/RunCMake/find_path/VALIDATOR-no-function-stderr.txt
new file mode 100644
index 0000000..1dfd064
--- /dev/null
+++ b/Tests/RunCMake/find_path/VALIDATOR-no-function-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at VALIDATOR-no-function.cmake:[0-9]+ \(find_path\):
+  find_path missing required argument for "VALIDATOR"
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/find_path/VALIDATOR-no-function.cmake b/Tests/RunCMake/find_path/VALIDATOR-no-function.cmake
new file mode 100644
index 0000000..bac2752
--- /dev/null
+++ b/Tests/RunCMake/find_path/VALIDATOR-no-function.cmake
@@ -0,0 +1,2 @@
+
+find_path(result NAMES input.txt VALIDATOR)
diff --git a/Tests/RunCMake/find_path/VALIDATOR-specify-macro-result.txt b/Tests/RunCMake/find_path/VALIDATOR-specify-macro-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/find_path/VALIDATOR-specify-macro-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/find_path/VALIDATOR-specify-macro-stderr.txt b/Tests/RunCMake/find_path/VALIDATOR-specify-macro-stderr.txt
new file mode 100644
index 0000000..92ee17e
--- /dev/null
+++ b/Tests/RunCMake/find_path/VALIDATOR-specify-macro-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at VALIDATOR-specify-macro.cmake:[0-9]+ \(find_path\):
+  find_path command specified for "VALIDATOR" is not a function: check.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/find_path/VALIDATOR-specify-macro.cmake b/Tests/RunCMake/find_path/VALIDATOR-specify-macro.cmake
new file mode 100644
index 0000000..62b44ed
--- /dev/null
+++ b/Tests/RunCMake/find_path/VALIDATOR-specify-macro.cmake
@@ -0,0 +1,5 @@
+
+macro(CHECK result path)
+endmacro()
+
+find_path(result NAMES input.txt VALIDATOR check)
diff --git a/Tests/RunCMake/find_path/VALIDATOR-stderr.txt b/Tests/RunCMake/find_path/VALIDATOR-stderr.txt
new file mode 100644
index 0000000..851353d
--- /dev/null
+++ b/Tests/RunCMake/find_path/VALIDATOR-stderr.txt
@@ -0,0 +1,3 @@
+CHECK='[^']+/Tests/RunCMake/find_path/include/'
+CHECK='[^']+/Tests/RunCMake/find_path/include/'
+CHECK='[^']+/Tests/RunCMake/find_path/include/'
diff --git a/Tests/RunCMake/find_path/VALIDATOR-stdout.txt b/Tests/RunCMake/find_path/VALIDATOR-stdout.txt
new file mode 100644
index 0000000..3fce030
--- /dev/null
+++ b/Tests/RunCMake/find_path/VALIDATOR-stdout.txt
@@ -0,0 +1,3 @@
+-- DIR='[^']+/Tests/RunCMake/find_path/include'
+-- DIR='[^']+/Tests/RunCMake/find_path/include'
+-- DIR='DIR-NOTFOUND'
diff --git a/Tests/RunCMake/find_path/VALIDATOR-undefined-function-result.txt b/Tests/RunCMake/find_path/VALIDATOR-undefined-function-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/find_path/VALIDATOR-undefined-function-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/find_path/VALIDATOR-undefined-function-stderr.txt b/Tests/RunCMake/find_path/VALIDATOR-undefined-function-stderr.txt
new file mode 100644
index 0000000..d3e0517
--- /dev/null
+++ b/Tests/RunCMake/find_path/VALIDATOR-undefined-function-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at VALIDATOR-undefined-function.cmake:[0-9]+ \(find_path\):
+  find_path command specified for "VALIDATOR" is undefined: undefined.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/find_path/VALIDATOR-undefined-function.cmake b/Tests/RunCMake/find_path/VALIDATOR-undefined-function.cmake
new file mode 100644
index 0000000..3fb55c5
--- /dev/null
+++ b/Tests/RunCMake/find_path/VALIDATOR-undefined-function.cmake
@@ -0,0 +1,2 @@
+
+find_path(result NAMES input.txt VALIDATOR undefined)
diff --git a/Tests/RunCMake/find_path/VALIDATOR.cmake b/Tests/RunCMake/find_path/VALIDATOR.cmake
new file mode 100644
index 0000000..1e01250
--- /dev/null
+++ b/Tests/RunCMake/find_path/VALIDATOR.cmake
@@ -0,0 +1,39 @@
+
+function(CHECK_DEFAULT result filename)
+  message("CHECK='${filename}'")
+endfunction()
+
+function(CHECK_OK result filename)
+  message("CHECK='${filename}'")
+  set(${result} TRUE PARENT_SCOPE)
+endfunction()
+
+function(CHECK_KO result filename)
+  message("CHECK='${filename}'")
+  set(${result} FALSE PARENT_SCOPE)
+endfunction()
+
+
+find_path(DIR
+  NAMES PrefixInPATH.h
+  HINTS ${CMAKE_CURRENT_SOURCE_DIR}/include
+  VALIDATOR check_default
+  )
+message(STATUS "DIR='${DIR}'")
+unset(DIR CACHE)
+
+find_path(DIR
+  NAMES PrefixInPATH.h
+  HINTS ${CMAKE_CURRENT_SOURCE_DIR}/include
+  VALIDATOR check_ok
+  )
+message(STATUS "DIR='${DIR}'")
+unset(DIR CACHE)
+
+find_path(DIR
+  NAMES PrefixInPATH.h
+  HINTS ${CMAKE_CURRENT_SOURCE_DIR}/include
+  VALIDATOR check_ko
+  )
+message(STATUS "DIR='${DIR}'")
+unset(DIR CACHE)
diff --git a/Tests/RunCMake/find_program/RunCMakeTest.cmake b/Tests/RunCMake/find_program/RunCMakeTest.cmake
index d0ce8fc..f8ecb8f 100644
--- a/Tests/RunCMake/find_program/RunCMakeTest.cmake
+++ b/Tests/RunCMake/find_program/RunCMakeTest.cmake
@@ -9,6 +9,10 @@
 run_cmake(IgnorePrefixPath)
 run_cmake(REGISTRY_VIEW-no-view)
 run_cmake(REGISTRY_VIEW-wrong-view)
+run_cmake(VALIDATOR-no-function)
+run_cmake(VALIDATOR-undefined-function)
+run_cmake(VALIDATOR-specify-macro)
+run_cmake(VALIDATOR)
 
 if(CMAKE_SYSTEM_NAME MATCHES "^(Windows|CYGWIN|MSYS)$")
   run_cmake(WindowsCom)
diff --git a/Tests/RunCMake/find_program/VALIDATOR-no-function-result.txt b/Tests/RunCMake/find_program/VALIDATOR-no-function-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/find_program/VALIDATOR-no-function-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/find_program/VALIDATOR-no-function-stderr.txt b/Tests/RunCMake/find_program/VALIDATOR-no-function-stderr.txt
new file mode 100644
index 0000000..b8868af
--- /dev/null
+++ b/Tests/RunCMake/find_program/VALIDATOR-no-function-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at VALIDATOR-no-function.cmake:[0-9]+ \(find_program\):
+  find_program missing required argument for "VALIDATOR"
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/find_program/VALIDATOR-no-function.cmake b/Tests/RunCMake/find_program/VALIDATOR-no-function.cmake
new file mode 100644
index 0000000..0d6a74f
--- /dev/null
+++ b/Tests/RunCMake/find_program/VALIDATOR-no-function.cmake
@@ -0,0 +1,2 @@
+
+find_program(result NAMES input.txt VALIDATOR)
diff --git a/Tests/RunCMake/find_program/VALIDATOR-specify-macro-result.txt b/Tests/RunCMake/find_program/VALIDATOR-specify-macro-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/find_program/VALIDATOR-specify-macro-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/find_program/VALIDATOR-specify-macro-stderr.txt b/Tests/RunCMake/find_program/VALIDATOR-specify-macro-stderr.txt
new file mode 100644
index 0000000..1ae5148
--- /dev/null
+++ b/Tests/RunCMake/find_program/VALIDATOR-specify-macro-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at VALIDATOR-specify-macro.cmake:[0-9]+ \(find_program\):
+  find_program command specified for "VALIDATOR" is not a function: check.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/find_program/VALIDATOR-specify-macro.cmake b/Tests/RunCMake/find_program/VALIDATOR-specify-macro.cmake
new file mode 100644
index 0000000..43bb9ec
--- /dev/null
+++ b/Tests/RunCMake/find_program/VALIDATOR-specify-macro.cmake
@@ -0,0 +1,5 @@
+
+macro(CHECK result path)
+endmacro()
+
+find_program(result NAMES input.txt VALIDATOR check)
diff --git a/Tests/RunCMake/find_program/VALIDATOR-stderr.txt b/Tests/RunCMake/find_program/VALIDATOR-stderr.txt
new file mode 100644
index 0000000..6704ed1
--- /dev/null
+++ b/Tests/RunCMake/find_program/VALIDATOR-stderr.txt
@@ -0,0 +1,3 @@
+CHECK='[^']+/Tests/RunCMake/find_program/A/testA'
+CHECK='[^']+/Tests/RunCMake/find_program/A/testA'
+CHECK='[^']+/Tests/RunCMake/find_program/A/testA'
diff --git a/Tests/RunCMake/find_program/VALIDATOR-stdout.txt b/Tests/RunCMake/find_program/VALIDATOR-stdout.txt
new file mode 100644
index 0000000..d434742
--- /dev/null
+++ b/Tests/RunCMake/find_program/VALIDATOR-stdout.txt
@@ -0,0 +1,3 @@
+-- PROG='[^']+/Tests/RunCMake/find_program/A/testA'
+-- PROG='[^']+/Tests/RunCMake/find_program/A/testA'
+-- PROG='PROG-NOTFOUND'
diff --git a/Tests/RunCMake/find_program/VALIDATOR-undefined-function-result.txt b/Tests/RunCMake/find_program/VALIDATOR-undefined-function-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/find_program/VALIDATOR-undefined-function-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/find_program/VALIDATOR-undefined-function-stderr.txt b/Tests/RunCMake/find_program/VALIDATOR-undefined-function-stderr.txt
new file mode 100644
index 0000000..a89ffa0
--- /dev/null
+++ b/Tests/RunCMake/find_program/VALIDATOR-undefined-function-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at VALIDATOR-undefined-function.cmake:[0-9]+ \(find_program\):
+  find_program command specified for "VALIDATOR" is undefined: undefined.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/find_program/VALIDATOR-undefined-function.cmake b/Tests/RunCMake/find_program/VALIDATOR-undefined-function.cmake
new file mode 100644
index 0000000..96be5fd
--- /dev/null
+++ b/Tests/RunCMake/find_program/VALIDATOR-undefined-function.cmake
@@ -0,0 +1,2 @@
+
+find_program(result NAMES input.txt VALIDATOR undefined)
diff --git a/Tests/RunCMake/find_program/VALIDATOR.cmake b/Tests/RunCMake/find_program/VALIDATOR.cmake
new file mode 100644
index 0000000..8be2b39
--- /dev/null
+++ b/Tests/RunCMake/find_program/VALIDATOR.cmake
@@ -0,0 +1,39 @@
+
+function(CHECK_DEFAULT result filename)
+  message("CHECK='${filename}'")
+endfunction()
+
+function(CHECK_OK result filename)
+  message("CHECK='${filename}'")
+  set(${result} TRUE PARENT_SCOPE)
+endfunction()
+
+function(CHECK_KO result filename)
+  message("CHECK='${filename}'")
+  set(${result} FALSE PARENT_SCOPE)
+endfunction()
+
+
+find_program(PROG
+  NAMES testA
+  HINTS ${CMAKE_CURRENT_SOURCE_DIR}/A
+  VALIDATOR check_default
+  )
+message(STATUS "PROG='${PROG}'")
+unset(PROG CACHE)
+
+find_program(PROG
+  NAMES testA
+  HINTS ${CMAKE_CURRENT_SOURCE_DIR}/A
+  VALIDATOR check_ok
+  )
+message(STATUS "PROG='${PROG}'")
+unset(PROG CACHE)
+
+find_program(PROG
+  NAMES testA
+  HINTS ${CMAKE_CURRENT_SOURCE_DIR}/A
+  VALIDATOR check_ko
+  )
+message(STATUS "PROG='${PROG}'")
+unset(PROG CACHE)
diff --git a/Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-stderr.txt b/Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-stderr.txt
new file mode 100644
index 0000000..f04e43f
--- /dev/null
+++ b/Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0101-BEFORE_keyword.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0101 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/target_sources/FileSetDefaultWrongTypeExperimental-result.txt b/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental-stderr.txt b/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental-stderr.txt
new file mode 100644
index 0000000..042d67d
--- /dev/null
+++ b/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental-stderr.txt
@@ -0,0 +1,12 @@
+^CMake Warning \(dev\) at FileSetDefaultWrongTypeExperimental.cmake:6 \(target_sources\):
+  CMake's C\+\+ module support is experimental.  It is meant only for
+  experimentation and feedback to CMake developers.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Error at FileSetDefaultWrongTypeExperimental\.cmake:[0-9]+ \(target_sources\):
+  target_sources File set TYPE may only be "HEADERS", "CXX_MODULES", or
+  "CXX_MODULE_HEADER_UNITS"
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental.cmake b/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental.cmake
new file mode 100644
index 0000000..2dbcee7
--- /dev/null
+++ b/Tests/RunCMake/target_sources/FileSetDefaultWrongTypeExperimental.cmake
@@ -0,0 +1,6 @@
+enable_language(C)
+
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "17be90bd-a850-44e0-be50-448de847d652")
+
+add_library(lib1 STATIC empty.c)
+target_sources(lib1 PRIVATE FILE_SET UNKNOWN)
diff --git a/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental-result.txt b/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental-stderr.txt b/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental-stderr.txt
new file mode 100644
index 0000000..a1b784f
--- /dev/null
+++ b/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental-stderr.txt
@@ -0,0 +1,12 @@
+^CMake Warning \(dev\) at FileSetWrongTypeExperimental.cmake:6 \(target_sources\):
+  CMake's C\+\+ module support is experimental.  It is meant only for
+  experimentation and feedback to CMake developers.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Error at FileSetWrongTypeExperimental\.cmake:[0-9]+ \(target_sources\):
+  target_sources File set TYPE may only be "HEADERS", "CXX_MODULES", or
+  "CXX_MODULE_HEADER_UNITS"
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental.cmake b/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental.cmake
new file mode 100644
index 0000000..024c2cb
--- /dev/null
+++ b/Tests/RunCMake/target_sources/FileSetWrongTypeExperimental.cmake
@@ -0,0 +1,6 @@
+enable_language(C)
+
+set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "17be90bd-a850-44e0-be50-448de847d652")
+
+add_library(lib1 STATIC empty.c)
+target_sources(lib1 PRIVATE FILE_SET a TYPE UNKNOWN)
diff --git a/Tests/RunCMake/target_sources/RunCMakeTest.cmake b/Tests/RunCMake/target_sources/RunCMakeTest.cmake
index e78ee9d..135777b 100644
--- a/Tests/RunCMake/target_sources/RunCMakeTest.cmake
+++ b/Tests/RunCMake/target_sources/RunCMakeTest.cmake
@@ -26,6 +26,8 @@
 run_cmake(FileSetNoType)
 run_cmake(FileSetWrongType)
 run_cmake(FileSetDefaultWrongType)
+run_cmake(FileSetWrongTypeExperimental)
+run_cmake(FileSetDefaultWrongTypeExperimental)
 run_cmake(FileSetChangeScope)
 run_cmake(FileSetChangeType)
 run_cmake(FileSetWrongBaseDirs)
diff --git a/Tests/RunCMake/try_compile/CxxStandard-stderr.txt b/Tests/RunCMake/try_compile/CxxStandard-stderr.txt
index ec7245f..cee1b44 100644
--- a/Tests/RunCMake/try_compile/CxxStandard-stderr.txt
+++ b/Tests/RunCMake/try_compile/CxxStandard-stderr.txt
@@ -1,6 +1,17 @@
-^CMake Error at .*/Tests/RunCMake/try_compile/CxxStandard-build/CMakeFiles/CMakeTmp/CMakeLists.txt:[0-9]+ \(add_executable\):
+^(CMake Error in .*/Tests/RunCMake/try_compile/CxxStandard-build/CMakeFiles/CMakeTmp/CMakeLists.txt:
+  The CXX_STANDARD property on target "cmTC_[0-9a-f]*" contained an invalid
+  value: "3".
+
+
+)?CMake Error at .*/Tests/RunCMake/try_compile/CxxStandard-build/CMakeFiles/CMakeTmp/CMakeLists.txt:[0-9]+ \(add_executable\):
   CXX_STANDARD is set to invalid value '3'
-+
+
+(
+CMake Error in .*/Tests/RunCMake/try_compile/CxxStandard-build/CMakeFiles/CMakeTmp/CMakeLists.txt:
+  The CXX_STANDARD property on target "cmTC_[0-9a-f]*" contained an invalid
+  value: "3".
+
+)?
 CMake Error at CxxStandard.cmake:[0-9]+ \(try_compile\):
   Failed to generate test project build system.
 Call Stack \(most recent call first\):
diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt
index b712c27..bc16350 100644
--- a/Utilities/Doxygen/CMakeLists.txt
+++ b/Utilities/Doxygen/CMakeLists.txt
@@ -3,7 +3,7 @@
 
 if(NOT CMake_SOURCE_DIR)
   set(CMakeDeveloperReference_STANDALONE 1)
-  cmake_minimum_required(VERSION 3.13...3.22 FATAL_ERROR)
+  cmake_minimum_required(VERSION 3.13...3.23 FATAL_ERROR)
   get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
   get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
   include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt
index fbce1c8..58c0573 100644
--- a/Utilities/Sphinx/CMakeLists.txt
+++ b/Utilities/Sphinx/CMakeLists.txt
@@ -3,7 +3,7 @@
 
 if(NOT CMake_SOURCE_DIR)
   set(CMakeHelp_STANDALONE 1)
-  cmake_minimum_required(VERSION 3.13...3.22 FATAL_ERROR)
+  cmake_minimum_required(VERSION 3.13...3.23 FATAL_ERROR)
   get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
   get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
   include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
diff --git a/bootstrap b/bootstrap
index 9a87413..f7e1544 100755
--- a/bootstrap
+++ b/bootstrap
@@ -328,6 +328,7 @@
   cmCustomCommand \
   cmCustomCommandGenerator \
   cmCustomCommandLines \
+  cmCxxModuleMapper \
   cmDefinePropertyCommand \
   cmDefinitions \
   cmDocumentationFormatter \
@@ -337,6 +338,7 @@
   cmExecProgramCommand \
   cmExecuteProcessCommand \
   cmExpandedCommandArgument \
+  cmExperimental \
   cmExportBuildFileGenerator \
   cmExportFileGenerator \
   cmExportInstallFileGenerator \