Merge branch 'release-3.20'
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d0b3b1e..465dc2c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -52,7 +52,7 @@
         - .cmake_doc_artifacts
         - .run_only_for_package
 
-.upload:source-package:
+upload:source-package:
     extends:
         - .rsync_upload
         - .run_only_for_package
@@ -115,10 +115,7 @@
         - .cmake_test_linux_release
         - .linux_builder_tags_qt
         - .run_dependent
-    dependencies:
-        - build:centos6-x86_64
-    needs:
-        - build:centos6-x86_64
+        - .needs_centos6_x86_64
 
 test:debian10-aarch64-ninja:
     extends:
@@ -126,10 +123,7 @@
         - .cmake_test_linux_release
         - .linux_builder_tags_aarch64_qt
         - .run_dependent
-    dependencies:
-        - build:centos7-aarch64
-    needs:
-        - build:centos7-aarch64
+        - .needs_centos7_aarch64
     variables:
         CMAKE_CI_NO_MR: "true"
 
@@ -139,10 +133,7 @@
         - .cmake_test_linux_release
         - .linux_builder_tags_qt
         - .run_dependent
-    dependencies:
-        - build:centos6-x86_64
-    needs:
-        - build:centos6-x86_64
+        - .needs_centos6_x86_64
 
 test:cuda10.2-nvidia:
     extends:
@@ -150,10 +141,7 @@
         - .cmake_test_linux_release
         - .linux_builder_tags_cuda
         - .run_dependent
-    dependencies:
-        - build:centos6-x86_64
-    needs:
-        - build:centos6-x86_64
+        - .needs_centos6_x86_64
 
 build:fedora33-ninja:
     extends:
@@ -186,6 +174,209 @@
     needs:
         - test:fedora33-ninja
 
+test:intel2016-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2016_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2016-el7
+
+test:intel2016u1-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2016u1_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2016u1-el7
+
+test:intel2016u2-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2016u2_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2016u2-el7
+
+test:intel2017-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2017_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017-el7
+
+test:intel2017u1-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2017u1_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017u1-el7
+
+test:intel2017u2-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2017u2_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017u2-el7
+
+test:intel2017u3-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2017u3_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017u3-el7
+
+test:intel2017u4-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2017u4_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017u4-el7
+
+test:intel2017u5-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2017u5_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017u5-el7
+
+test:intel2017u6-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2017u6_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017u6-el7
+
+test:intel2017u7-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2017u7_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017u7-el7
+
+test:intel2017u8-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2017u8_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2017u8-el7
+
+test:intel2018-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2018_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2018-el7
+
+test:intel2018u1-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2018u1_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2018u1-el7
+
+test:intel2018u2-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2018u2_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2018u2-el7
+
+test:intel2018u3-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2018u3_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2018u3-el7
+
+test:intel2018u4-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2018u4_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2018u4-el7
+
+test:intel2019-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2019_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2019-el7
+
+test:intel2019u1-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2019u1_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2019u1-el7
+
+test:intel2019u2-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2019u2_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2019u2-el7
+
+test:intel2019u3-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2019u3_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2019u3-el7
+
+test:intel2019u4-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2019u4_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2019u4-el7
+
+test:intel2020-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2020_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2020-el8
+
+test:intel2020u2-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2020u2_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2020u2-el8
+
+test:intel2020u4-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2020u4_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2020u4-el8
+
+test:intel2021.1.1-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2021.1.1_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2021.1.1-el8
+
+test:intel2021.1.2-makefiles:
+    extends:
+        - .cmake_test_linux_intelclassic_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: intel2021.1.2_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2021.1.2-el8
+
+test:oneapi2021.1.1-makefiles:
+    extends:
+        - .cmake_test_linux_inteloneapi_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: oneapi2021.1.1_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2021.1.1-el8
+
+test:oneapi2021.1.2-makefiles:
+    extends:
+        - .cmake_test_linux_inteloneapi_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: oneapi2021.1.2_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2021.1.2-el8
+
 build:linux-x86_64-package:
     extends:
         - .linux_package
@@ -199,7 +390,7 @@
     needs:
         - prep:doc-package
 
-.upload:linux-x86_64-package:
+upload:linux-x86_64-package:
     extends:
         - .rsync_upload
         - .run_only_for_package
@@ -223,7 +414,7 @@
     needs:
         - prep:doc-package
 
-.upload:linux-aarch64-package:
+upload:linux-aarch64-package:
     extends:
         - .rsync_upload
         - .run_only_for_package
@@ -335,7 +526,7 @@
     needs:
         - prep:doc-package
 
-.upload:macos-package:
+upload:macos-package:
     extends:
         - .rsync_upload
         - .run_only_for_package
@@ -358,7 +549,7 @@
     needs:
         - prep:doc-package
 
-.upload:macos10.10-package:
+upload:macos10.10-package:
     extends:
         - .rsync_upload
         - .run_only_for_package
diff --git a/.gitlab/ci/configure_debian10_aarch64_ninja.cmake b/.gitlab/ci/configure_debian10_aarch64_ninja.cmake
index 023cc9e..f665f7d 100644
--- a/.gitlab/ci/configure_debian10_aarch64_ninja.cmake
+++ b/.gitlab/ci/configure_debian10_aarch64_ninja.cmake
@@ -1,10 +1,11 @@
 set(CMake_TEST_FindALSA "ON" CACHE BOOL "")
-set(CMake_TEST_FindBLAS "ON" CACHE BOOL "")
+set(CMake_TEST_FindBLAS "All" CACHE STRING "")
 set(CMake_TEST_FindBoost "ON" CACHE BOOL "")
 set(CMake_TEST_FindBoost_Python "ON" CACHE BOOL "")
 set(CMake_TEST_FindBZip2 "ON" CACHE BOOL "")
 set(CMake_TEST_FindCups "ON" CACHE BOOL "")
 set(CMake_TEST_FindCURL "ON" CACHE BOOL "")
+set(CMake_TEST_FindDevIL "ON" CACHE BOOL "")
 set(CMake_TEST_FindDoxygen_Dot "ON" CACHE BOOL "")
 set(CMake_TEST_FindDoxygen "ON" CACHE BOOL "")
 set(CMake_TEST_FindEXPAT "ON" CACHE BOOL "")
@@ -22,7 +23,7 @@
 set(CMake_TEST_FindIntl "ON" CACHE BOOL "")
 set(CMake_TEST_FindJPEG "ON" CACHE BOOL "")
 set(CMake_TEST_FindJsonCpp "ON" CACHE BOOL "")
-set(CMake_TEST_FindLAPACK "ON" CACHE BOOL "")
+set(CMake_TEST_FindLAPACK "All" CACHE STRING "")
 set(CMake_TEST_FindLibArchive "ON" CACHE BOOL "")
 set(CMake_TEST_FindLibinput "ON" CACHE BOOL "")
 set(CMake_TEST_FindLibLZMA "ON" CACHE BOOL "")
diff --git a/.gitlab/ci/configure_debian10_ninja.cmake b/.gitlab/ci/configure_debian10_ninja.cmake
index 74d9f12..9de3013 100644
--- a/.gitlab/ci/configure_debian10_ninja.cmake
+++ b/.gitlab/ci/configure_debian10_ninja.cmake
@@ -1,10 +1,11 @@
 set(CMake_TEST_FindALSA "ON" CACHE BOOL "")
-set(CMake_TEST_FindBLAS "ON" CACHE BOOL "")
+set(CMake_TEST_FindBLAS "All" CACHE STRING "")
 set(CMake_TEST_FindBoost "ON" CACHE BOOL "")
 set(CMake_TEST_FindBoost_Python "ON" CACHE BOOL "")
 set(CMake_TEST_FindBZip2 "ON" CACHE BOOL "")
 set(CMake_TEST_FindCups "ON" CACHE BOOL "")
 set(CMake_TEST_FindCURL "ON" CACHE BOOL "")
+set(CMake_TEST_FindDevIL "ON" CACHE BOOL "")
 set(CMake_TEST_FindDoxygen_Dot "ON" CACHE BOOL "")
 set(CMake_TEST_FindDoxygen "ON" CACHE BOOL "")
 set(CMake_TEST_FindEXPAT "ON" CACHE BOOL "")
@@ -22,7 +23,7 @@
 set(CMake_TEST_FindIntl "ON" CACHE BOOL "")
 set(CMake_TEST_FindJPEG "ON" CACHE BOOL "")
 set(CMake_TEST_FindJsonCpp "ON" CACHE BOOL "")
-set(CMake_TEST_FindLAPACK "ON" CACHE BOOL "")
+set(CMake_TEST_FindLAPACK "All" CACHE STRING "")
 set(CMake_TEST_FindLibArchive "ON" CACHE BOOL "")
 set(CMake_TEST_FindLibinput "ON" CACHE BOOL "")
 set(CMake_TEST_FindLibLZMA "ON" CACHE BOOL "")
diff --git a/.gitlab/ci/configure_fedora33_makefiles.cmake b/.gitlab/ci/configure_fedora33_makefiles.cmake
index db2d005..4143134 100644
--- a/.gitlab/ci/configure_fedora33_makefiles.cmake
+++ b/.gitlab/ci/configure_fedora33_makefiles.cmake
@@ -1,10 +1,11 @@
 set(CMake_TEST_FindALSA "ON" CACHE BOOL "")
-set(CMake_TEST_FindBLAS "ON" CACHE BOOL "")
+set(CMake_TEST_FindBLAS "All" CACHE STRING "")
 set(CMake_TEST_FindBoost "ON" CACHE BOOL "")
 set(CMake_TEST_FindBoost_Python "ON" CACHE BOOL "")
 set(CMake_TEST_FindBZip2 "ON" CACHE BOOL "")
 set(CMake_TEST_FindCups "ON" CACHE BOOL "")
 set(CMake_TEST_FindCURL "ON" CACHE BOOL "")
+set(CMake_TEST_FindDevIL "ON" CACHE BOOL "")
 set(CMake_TEST_FindDoxygen_Dot "ON" CACHE BOOL "")
 set(CMake_TEST_FindDoxygen "ON" CACHE BOOL "")
 set(CMake_TEST_FindEXPAT "ON" CACHE BOOL "")
@@ -22,7 +23,7 @@
 set(CMake_TEST_FindIntl "ON" CACHE BOOL "")
 set(CMake_TEST_FindJPEG "ON" CACHE BOOL "")
 set(CMake_TEST_FindJsonCpp "ON" CACHE BOOL "")
-set(CMake_TEST_FindLAPACK "ON" CACHE BOOL "")
+set(CMake_TEST_FindLAPACK "All" CACHE STRING "")
 set(CMake_TEST_FindLibArchive "ON" CACHE BOOL "")
 set(CMake_TEST_FindLibinput "ON" CACHE BOOL "")
 set(CMake_TEST_FindLibLZMA "ON" CACHE BOOL "")
diff --git a/.gitlab/ci/configure_intelclassic_makefiles.cmake b/.gitlab/ci/configure_intelclassic_makefiles.cmake
new file mode 100644
index 0000000..469b825
--- /dev/null
+++ b/.gitlab/ci/configure_intelclassic_makefiles.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_LIST_DIR}/configure_intelcompiler_common.cmake")
diff --git a/.gitlab/ci/configure_intelcompiler_common.cmake b/.gitlab/ci/configure_intelcompiler_common.cmake
new file mode 100644
index 0000000..be3d15b
--- /dev/null
+++ b/.gitlab/ci/configure_intelcompiler_common.cmake
@@ -0,0 +1,4 @@
+set(CMake_TEST_FindBLAS "Intel10_64lp" CACHE STRING "")
+set(CMake_TEST_FindLAPACK "Intel10_64lp" CACHE STRING "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_inteloneapi_makefiles.cmake b/.gitlab/ci/configure_inteloneapi_makefiles.cmake
new file mode 100644
index 0000000..469b825
--- /dev/null
+++ b/.gitlab/ci/configure_inteloneapi_makefiles.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_LIST_DIR}/configure_intelcompiler_common.cmake")
diff --git a/.gitlab/ci/configure_windows_vs2019_x64_ninja.cmake b/.gitlab/ci/configure_windows_vs2019_x64_ninja.cmake
index 9c30a4b..e1ae81e 100644
--- a/.gitlab/ci/configure_windows_vs2019_x64_ninja.cmake
+++ b/.gitlab/ci/configure_windows_vs2019_x64_ninja.cmake
@@ -1,4 +1,7 @@
 set(CMake_TEST_WIX_NO_VERIFY "ON" CACHE BOOL "")
 set(CMake_TEST_GUI "ON" CACHE BOOL "")
+set(CMake_TEST_FindOpenGL "ON" CACHE BOOL "")
+set(CMake_TEST_IPO_WORKS_C "ON" CACHE BOOL "")
+set(CMake_TEST_IPO_WORKS_CXX "ON" CACHE BOOL "")
 
 include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_common.cmake")
diff --git a/.gitlab/ci/ctest_exclusions.cmake b/.gitlab/ci/ctest_exclusions.cmake
index a68a693..b885a6a 100644
--- a/.gitlab/ci/ctest_exclusions.cmake
+++ b/.gitlab/ci/ctest_exclusions.cmake
@@ -13,15 +13,6 @@
     "^ExternalProjectUpdateSetup$")
 endif ()
 
-if (CMAKE_HOST_WIN32)
-  list(APPEND test_exclusions
-    # This test often fails with an undiagnosed subtle race due to the test
-    # re-using the same objects for many files.  Some copy operations fail
-    # to open their input with ERROR_SHARING_VIOLATION.
-    "^Module.ExternalData$"
-    )
-endif()
-
 string(REPLACE ";" "|" test_exclusions "${test_exclusions}")
 if (test_exclusions)
   set(test_exclusions "(${test_exclusions})")
diff --git a/.gitlab/ci/env.sh b/.gitlab/ci/env.sh
new file mode 100644
index 0000000..7634f5d
--- /dev/null
+++ b/.gitlab/ci/env.sh
@@ -0,0 +1,14 @@
+quietly() {
+  readonly log="/tmp/quietly-$RANDOM.log"
+  if ! "$@" >"$log" 2>&1; then
+    ret=$?
+    cat "$log"
+    rm -f "$log"
+    exit $ret
+  fi
+  rm -f "$log"
+}
+
+if test -r ".gitlab/ci/env_${CMAKE_CONFIGURATION}.sh"; then
+  source ".gitlab/ci/env_${CMAKE_CONFIGURATION}.sh"
+fi
diff --git a/.gitlab/ci/env_intelclassic_common.sh b/.gitlab/ci/env_intelclassic_common.sh
new file mode 100644
index 0000000..22b1d03
--- /dev/null
+++ b/.gitlab/ci/env_intelclassic_common.sh
@@ -0,0 +1,9 @@
+source .gitlab/ci/env_intelcompiler_license.sh
+
+if test -r /opt/intel/oneapi/setvars.sh; then
+  source /opt/intel/oneapi/setvars.sh
+elif test -r /opt/intel/bin/compilervars.sh; then
+  source /opt/intel/bin/compilervars.sh intel64
+fi
+
+export CC=icc CXX=icpc FC=ifort
diff --git a/.gitlab/ci/env_intelclassic_makefiles.sh b/.gitlab/ci/env_intelclassic_makefiles.sh
new file mode 100644
index 0000000..d1ff85e
--- /dev/null
+++ b/.gitlab/ci/env_intelclassic_makefiles.sh
@@ -0,0 +1 @@
+source .gitlab/ci/env_intelclassic_common.sh
diff --git a/.gitlab/ci/env_intelcompiler_license.sh b/.gitlab/ci/env_intelcompiler_license.sh
new file mode 100644
index 0000000..54743b2
--- /dev/null
+++ b/.gitlab/ci/env_intelcompiler_license.sh
@@ -0,0 +1,8 @@
+if test -n "$CMAKE_CI_INTELCOMPILER_LICENSE"; then
+  if test -d /opt/intel/licenses; then
+    mv "$CMAKE_CI_INTELCOMPILER_LICENSE" /opt/intel/licenses/ci.lic
+  else
+    rm "$CMAKE_CI_INTELCOMPILER_LICENSE"
+  fi
+  unset CMAKE_CI_INTELCOMPILER_LICENSE
+fi
diff --git a/.gitlab/ci/env_inteloneapi_common.sh b/.gitlab/ci/env_inteloneapi_common.sh
new file mode 100644
index 0000000..beaf3fe
--- /dev/null
+++ b/.gitlab/ci/env_inteloneapi_common.sh
@@ -0,0 +1,7 @@
+source .gitlab/ci/env_intelcompiler_license.sh
+
+if test -r /opt/intel/oneapi/setvars.sh; then
+  source /opt/intel/oneapi/setvars.sh
+fi
+
+export CC=icx CXX=icpx FC=ifx
diff --git a/.gitlab/ci/env_inteloneapi_makefiles.sh b/.gitlab/ci/env_inteloneapi_makefiles.sh
new file mode 100644
index 0000000..eefcdda
--- /dev/null
+++ b/.gitlab/ci/env_inteloneapi_makefiles.sh
@@ -0,0 +1 @@
+source .gitlab/ci/env_inteloneapi_common.sh
diff --git a/.gitlab/ci/gitlab_ci.cmake b/.gitlab/ci/gitlab_ci.cmake
index f863a27..f166215 100644
--- a/.gitlab/ci/gitlab_ci.cmake
+++ b/.gitlab/ci/gitlab_ci.cmake
@@ -17,7 +17,11 @@
 endif ()
 
 # Set the build metadata.
-set(CTEST_BUILD_NAME "$ENV{CI_PROJECT_NAME}-$ENV{CMAKE_CONFIGURATION}")
+if(NOT "$ENV{CMAKE_CI_BUILD_NAME}" STREQUAL "")
+  set(CTEST_BUILD_NAME "$ENV{CI_PROJECT_NAME}-$ENV{CMAKE_CI_BUILD_NAME}")
+else()
+  set(CTEST_BUILD_NAME "$ENV{CI_PROJECT_NAME}-$ENV{CMAKE_CONFIGURATION}")
+endif()
 set(CTEST_SITE "gitlab-ci")
 set(ctest_model "Experimental")
 
diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml
index 2670ba5..81c4d8d 100644
--- a/.gitlab/os-linux.yml
+++ b/.gitlab/os-linux.yml
@@ -30,6 +30,18 @@
     variables:
         BOOTSTRAP_ARGS: '-- "-DCMake_DOC_ARTIFACT_PREFIX=$CI_PROJECT_DIR/build/install-doc"'
 
+.needs_centos6_x86_64:
+    dependencies:
+        - build:centos6-x86_64
+    needs:
+        - build:centos6-x86_64
+
+.needs_centos7_aarch64:
+    dependencies:
+        - build:centos7-aarch64
+    needs:
+        - build:centos7-aarch64
+
 ### Debian
 
 .debian10:
@@ -128,6 +140,27 @@
         CTEST_NO_WARNINGS_ALLOWED: 1
         CMAKE_GENERATOR: "Unix Makefiles"
 
+### Intel Compiler
+
+.intelcompiler:
+    image: "kitware/intelcompiler:$CMAKE_CI_INTELCOMPILER_IMAGE_TAG"
+    environment:
+        name: intel-compiler
+    variables:
+        CMAKE_ARCH: x86_64
+
+.intelclassic_makefiles:
+    extends: .intelcompiler
+    variables:
+        CMAKE_CONFIGURATION: intelclassic_makefiles
+        CMAKE_GENERATOR: "Unix Makefiles"
+
+.inteloneapi_makefiles:
+    extends: .intelcompiler
+    variables:
+        CMAKE_CONFIGURATION: inteloneapi_makefiles
+        CMAKE_GENERATOR: "Unix Makefiles"
+
 ### CUDA builds
 
 .cuda10.2:
@@ -195,6 +228,7 @@
 ## Linux-specific scripts
 
 .before_script_linux: &before_script_linux
+    - source .gitlab/ci/env.sh
     - .gitlab/ci/cmake.sh
     - .gitlab/ci/ninja.sh
     - export PATH=$PWD/.gitlab:$PWD/.gitlab/cmake/bin:$PATH
@@ -251,6 +285,7 @@
     stage: build
 
     script:
+        - source .gitlab/ci/env.sh
         # Bootstrap.
         - mkdir -p build/
         # Exclude documentation.  A job dependency provides it for packaging.
@@ -313,3 +348,23 @@
         - sccache --show-stats
 
     interruptible: true
+
+.cmake_test_linux_intelclassic_makefiles:
+    extends:
+        - .intelclassic_makefiles
+        - .cmake_test_linux_release
+        - .linux_builder_tags_qt
+        - .run_manually
+        - .needs_centos6_x86_64
+    variables:
+        CMAKE_CI_JOB_NIGHTLY: "true"
+
+.cmake_test_linux_inteloneapi_makefiles:
+    extends:
+        - .inteloneapi_makefiles
+        - .cmake_test_linux_release
+        - .linux_builder_tags_qt
+        - .run_manually
+        - .needs_centos6_x86_64
+    variables:
+        CMAKE_CI_JOB_NIGHTLY: "true"
diff --git a/.gitlab/rules.yml b/.gitlab/rules.yml
index b3e5342..5685463 100644
--- a/.gitlab/rules.yml
+++ b/.gitlab/rules.yml
@@ -6,6 +6,8 @@
           when: never
         - if: '$CMAKE_CI_NIGHTLY == "true"'
           when: on_success
+        - if: '$CMAKE_CI_JOB_NIGHTLY == "true"'
+          when: never
         - if: '($CMAKE_CI_PROJECT_CONTINUOUS_BRANCH != "" && $CI_COMMIT_BRANCH == $CMAKE_CI_PROJECT_CONTINUOUS_BRANCH && $CMAKE_CI_JOB_CONTINUOUS == "true")'
           when: delayed
           start_in: 5 minutes
@@ -24,6 +26,8 @@
           when: never
         - if: '$CMAKE_CI_NIGHTLY == "true"'
           when: on_success
+        - if: '$CMAKE_CI_JOB_NIGHTLY == "true"'
+          when: never
         - if: '($CMAKE_CI_PROJECT_CONTINUOUS_BRANCH != "" && $CI_COMMIT_BRANCH == $CMAKE_CI_PROJECT_CONTINUOUS_BRANCH && $CMAKE_CI_JOB_CONTINUOUS == "true")'
           when: on_success
         - if: '($CMAKE_CI_NO_MR == "true" && $CI_MERGE_REQUEST_ID)'
@@ -42,6 +46,8 @@
           when: always
         - if: '$CMAKE_CI_NIGHTLY == "true"'
           when: on_success
+        - if: '$CMAKE_CI_JOB_NIGHTLY == "true"'
+          when: never
         - if: '($CMAKE_CI_NO_MR == "true" && $CI_MERGE_REQUEST_ID)'
           when: never
         - if: '$CI_MERGE_REQUEST_ID'
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim
index 955beae..067f80d 100644
--- a/Auxiliary/vim/syntax/cmake.vim
+++ b/Auxiliary/vim/syntax/cmake.vim
@@ -92,6 +92,7 @@
             \ AUTOUIC_EXECUTABLE
             \ AUTOUIC_OPTIONS
             \ AUTOUIC_SEARCH_PATHS
+            \ AUTOUIC_SOURCE_GROUP
             \ BINARY_DIR
             \ BUILDSYSTEM_TARGETS
             \ BUILD_RPATH
diff --git a/CMakeCPack.cmake b/CMakeCPack.cmake
index 31c2fe4..9357804 100644
--- a/CMakeCPack.cmake
+++ b/CMakeCPack.cmake
@@ -133,6 +133,9 @@
   if(SPHINX_QTHELP)
     list(APPEND _CPACK_IFW_COMPONENTS_ALL sphinx-qthelp)
   endif()
+  if(SPHINX_LATEXPDF)
+    list(APPEND _CPACK_IFW_COMPONENTS_ALL sphinx-latexpdf)
+  endif()
   if(CMake_BUILD_DEVELOPER_REFERENCE)
     if(CMake_BUILD_DEVELOPER_REFERENCE_HTML)
       list(APPEND _CPACK_IFW_COMPONENTS_ALL cmake-developer-reference-html)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a2fcf2e..045a283 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.1...3.18 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.1...3.19 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)
 project(CMake)
diff --git a/Help/command/FIND_XXX.txt b/Help/command/FIND_XXX.txt
index 97eecfc..aae1c38 100644
--- a/Help/command/FIND_XXX.txt
+++ b/Help/command/FIND_XXX.txt
@@ -11,8 +11,8 @@
    |FIND_XXX| (
              <VAR>
              name | |NAMES|
-             [HINTS path1 [path2 ... ENV var]]
-             [PATHS path1 [path2 ... ENV var]]
+             [HINTS [path | ENV var]... ]
+             [PATHS [path | ENV var]... ]
              [PATH_SUFFIXES suffix1 [suffix2 ...]]
              [DOC "cache documentation string"]
              [REQUIRED]
diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst
index c0b9593..b6ff0ea 100644
--- a/Help/command/add_custom_command.rst
+++ b/Help/command/add_custom_command.rst
@@ -272,7 +272,9 @@
   .. versionadded:: 3.7
 
   Specify a ``.d`` depfile for the :generator:`Ninja` generator and
-  :ref:`Makefile Generators`.
+  :ref:`Makefile Generators`. The depfile may use "generator expressions" with
+  the syntax ``$<...>``. See the :manual:`generator-expressions(7)
+  <cmake-generator-expressions(7)>` manual for available expressions.
   A ``.d`` file holds dependencies usually emitted by the custom
   command itself.
   Using ``DEPFILE`` with other generators than :generator:`Ninja` or
@@ -281,6 +283,9 @@
   .. versionadded:: 3.20
     Added the support of :ref:`Makefile Generators`.
 
+  .. versionadded:: 3.21
+    Added the support of :manual:`generator expressions <cmake-generator-expressions(7)>`.
+
   If the ``DEPFILE`` argument is relative, it should be relative to
   :variable:`CMAKE_CURRENT_BINARY_DIR`, and any relative paths inside the
   ``DEPFILE`` should also be relative to :variable:`CMAKE_CURRENT_BINARY_DIR`
diff --git a/Help/command/configure_file.rst b/Help/command/configure_file.rst
index d00f08b..086668c 100644
--- a/Help/command/configure_file.rst
+++ b/Help/command/configure_file.rst
@@ -36,8 +36,30 @@
 depending on whether ``VAR`` is set in CMake to any value not considered
 a false constant by the :command:`if` command.  The "..." content on the
 line after the variable name, if any, is processed as above.
-Input file lines of the form ``#cmakedefine01 VAR`` will be replaced with
-either ``#define VAR 1`` or ``#define VAR 0`` similarly.
+
+Unlike lines of the form ``#cmakedefine VAR ...``, in lines of the form
+``#cmakedefine01 VAR``, ``VAR`` itself will expand to ``VAR 0`` or ``VAR 1``
+rather than being assigned the value ``...``. Therefore, input lines of the form
+
+.. code-block:: c
+
+  #cmakedefine01 VAR
+
+will be replaced with either
+
+.. code-block:: c
+
+  #define VAR 0
+
+or
+
+.. code-block:: c
+
+  #define VAR 1
+
+Input lines of the form ``#cmakedefine01 VAR ...`` will expand
+as ``#cmakedefine01 VAR ... 0`` or ``#cmakedefine01 VAR ... 0``,
+which may lead to undefined behavior.
 
 .. versionadded:: 3.10
   The result lines (with the exception of the ``#undef`` comments) can be
diff --git a/Help/command/file.rst b/Help/command/file.rst
index 24e43e9..2b445c5 100644
--- a/Help/command/file.rst
+++ b/Help/command/file.rst
@@ -38,7 +38,8 @@
 
   `Filesystem`_
     file({`GLOB`_ | `GLOB_RECURSE`_} <out-var> [...] [<globbing-expr>...])
-    file(`RENAME`_ <oldname> <newname>)
+    file(`RENAME`_ <oldname> <newname> [...])
+    file(`COPY_FILE`_ <oldname> <newname> [...])
     file({`REMOVE`_ | `REMOVE_RECURSE`_ } [<files>...])
     file(`MAKE_DIRECTORY`_ [<dir>...])
     file({`COPY`_ | `INSTALL`_} <file>... DESTINATION <dir> [...])
@@ -675,11 +676,46 @@
 
 .. code-block:: cmake
 
-  file(RENAME <oldname> <newname>)
+  file(RENAME <oldname> <newname>
+       [RESULT <result>]
+       [NO_REPLACE])
 
 Move a file or directory within a filesystem from ``<oldname>`` to
 ``<newname>``, replacing the destination atomically.
 
+The options are:
+
+``RESULT <result>``
+  Set ``<result>`` variable to ``0`` on success or an error message otherwise.
+  If ``RESULT`` is not specified and the operation fails, an error is emitted.
+
+``NO_REPLACE``
+  If the ``<newname>`` path already exists, do not replace it.
+  If ``RESULT <result>`` is used, the result variable will be
+  set to ``NO_REPLACE``.  Otherwise, an error is emitted.
+
+.. _COPY_FILE:
+
+.. code-block:: cmake
+
+  file(COPY_FILE <oldname> <newname>
+       [RESULT <result>]
+       [ONLY_IF_DIFFERENT])
+
+Copy a file from ``<oldname>`` to ``<newname>``. Directories are not
+supported. Symlinks are ignored and ``<oldfile>``'s content is read and
+written to ``<newname>`` as a new file.
+
+The options are:
+
+``RESULT <result>``
+  Set ``<result>`` variable to ``0`` on success or an error message otherwise.
+  If ``RESULT`` is not specified and the operation fails, an error is emitted.
+
+``ONLY_IF_DIFFERENT``
+  If the ``<newname>`` path already exists, do not replace it if it is the
+  same as ``<oldname>``. Otherwise, an error is emitted.
+
 .. _REMOVE:
 .. _REMOVE_RECURSE:
 
diff --git a/Help/command/project.rst b/Help/command/project.rst
index 6c931b6..8a6bc1e 100644
--- a/Help/command/project.rst
+++ b/Help/command/project.rst
@@ -20,12 +20,18 @@
 ``CMakeLists.txt`` also stores the project name in the
 variable :variable:`CMAKE_PROJECT_NAME`.
 
-Also sets the variables
+Also sets the variables:
 
-* :variable:`PROJECT_SOURCE_DIR`,
-  :variable:`<PROJECT-NAME>_SOURCE_DIR`
-* :variable:`PROJECT_BINARY_DIR`,
-  :variable:`<PROJECT-NAME>_BINARY_DIR`
+:variable:`PROJECT_SOURCE_DIR`, :variable:`<PROJECT-NAME>_SOURCE_DIR`
+  Absolute path to the source directory for the project.
+
+:variable:`PROJECT_BINARY_DIR`, :variable:`<PROJECT-NAME>_BINARY_DIR`
+  Absolute path to the binary directory for the project.
+
+:variable:`PROJECT_IS_TOP_LEVEL`, :variable:`<PROJECT-NAME>_IS_TOP_LEVEL`
+  .. versionadded:: 3.21
+
+  Boolean value indicating whether the project is top-level.
 
 Further variables are set by the optional arguments described in the following.
 If any of these arguments is not used, then the corresponding variables are
diff --git a/Help/cpack_gen/dmg.rst b/Help/cpack_gen/dmg.rst
index 4c662a6..ec2cf1e 100644
--- a/Help/cpack_gen/dmg.rst
+++ b/Help/cpack_gen/dmg.rst
@@ -103,6 +103,12 @@
 
  - Default: ``CPACK_PACKAGE_FILE_NAME-<component>``
 
+.. variable:: CPACK_DMG_FILESYSTEM
+
+ The filesystem format. Common values are ``APFS`` and ``HFS+``.
+ See ``man hdiutil`` for a full list of supported formats.
+ Defaults to ``HFS+``.
+
 .. variable:: CPACK_COMMAND_HDIUTIL
 
  Path to the ``hdiutil(1)`` command used to operate on disk image files on
diff --git a/Help/cpack_gen/nsis.rst b/Help/cpack_gen/nsis.rst
index de1f3b5..02e33ba 100644
--- a/Help/cpack_gen/nsis.rst
+++ b/Help/cpack_gen/nsis.rst
@@ -195,3 +195,9 @@
  If set, trim down the size of the control to the size of the branding text string.
  Allowed values for this variable are ``LEFT``, ``CENTER`` or ``RIGHT``.
  If not specified, the default behavior is ``LEFT``.
+
+.. variable:: CPACK_NSIS_EXECUTABLE
+
+ .. versionadded:: 3.21
+
+ If set, specify the name of the NSIS executable. Default is ``makensis``.
diff --git a/Help/dev/review.rst b/Help/dev/review.rst
index 8326e70..10ff87b 100644
--- a/Help/dev/review.rst
+++ b/Help/dev/review.rst
@@ -254,7 +254,8 @@
   The author date of the commit, in its original time zone, formatted as
   ``CCYY-MM-DD``.  ``git-log(1)`` shows the original time zone by default.
 
-This may be generated with
+This may be generated with ``git show -s --pretty=reference <commit>`` with
+Git 2.25 and newer. Older versions of Git can generate the same format via
 ``git show -s --date=short --pretty="format:%h (%s, %ad)" <commit>``.
 
 If the commit is a fix for the mentioned commit, consider using a ``Fixes:``
diff --git a/Help/guide/importing-exporting/MathFunctions/CMakeLists.txt b/Help/guide/importing-exporting/MathFunctions/CMakeLists.txt
index 9a9e40e..d277b54 100644
--- a/Help/guide/importing-exporting/MathFunctions/CMakeLists.txt
+++ b/Help/guide/importing-exporting/MathFunctions/CMakeLists.txt
@@ -1,6 +1,9 @@
 cmake_minimum_required(VERSION 3.15)
 project(MathFunctions)
 
+# make cache variables for install destinations
+include(GNUInstallDirs)
+
 # specify the C++ standard
 set(CMAKE_CXX_STANDARD 11)
 set(CMAKE_CXX_STANDARD_REQUIRED True)
@@ -12,26 +15,26 @@
 target_include_directories(MathFunctions
                            PUBLIC
                            "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
-                           "$<INSTALL_INTERFACE:include>"
+                           "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
 )
 
 # install the target and create export-set
 install(TARGETS MathFunctions
         EXPORT MathFunctionsTargets
-        LIBRARY DESTINATION lib
-        ARCHIVE DESTINATION lib
-        RUNTIME DESTINATION bin
-        INCLUDES DESTINATION include
+        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+        INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
 )
 
 # install header file
-install(FILES MathFunctions.h DESTINATION include)
+install(FILES MathFunctions.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
 
 # generate and install export file
 install(EXPORT MathFunctionsTargets
         FILE MathFunctionsTargets.cmake
         NAMESPACE MathFunctions::
-        DESTINATION lib/cmake/MathFunctions
+        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
 )
 
 # include CMakePackageConfigHelpers macro
@@ -58,14 +61,14 @@
 # create config file
 configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
   "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
-  INSTALL_DESTINATION lib/cmake/MathFunctions
+  INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
 )
 
 # install config files
 install(FILES
           "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
           "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
-        DESTINATION lib/cmake/MathFunctions
+        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
 )
 
 # generate the export targets for the build tree
diff --git a/Help/guide/importing-exporting/MathFunctionsComponents/Addition/CMakeLists.txt b/Help/guide/importing-exporting/MathFunctionsComponents/Addition/CMakeLists.txt
index 17ad952..9de935e 100644
--- a/Help/guide/importing-exporting/MathFunctionsComponents/Addition/CMakeLists.txt
+++ b/Help/guide/importing-exporting/MathFunctionsComponents/Addition/CMakeLists.txt
@@ -7,24 +7,24 @@
 target_include_directories(Addition
                            PUBLIC
                            "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
-                           $<INSTALL_INTERFACE:include>
+                           $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
 )
 
 # install the target and create export-set
 install(TARGETS Addition
         EXPORT AdditionTargets
-        LIBRARY DESTINATION lib
-        ARCHIVE DESTINATION lib
-        RUNTIME DESTINATION bin
-        INCLUDES DESTINATION include
+        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+        INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
 )
 
 # install header file
-install(FILES Addition.h DESTINATION include)
+install(FILES Addition.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
 
 # generate and install export file
 install(EXPORT AdditionTargets
         FILE MathFunctionsAdditionTargets.cmake
         NAMESPACE MathFunctions::
-        DESTINATION lib/cmake/MathFunctions
+        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
 )
diff --git a/Help/guide/importing-exporting/MathFunctionsComponents/CMakeLists.txt b/Help/guide/importing-exporting/MathFunctionsComponents/CMakeLists.txt
index fd95e28..90ee89f 100644
--- a/Help/guide/importing-exporting/MathFunctionsComponents/CMakeLists.txt
+++ b/Help/guide/importing-exporting/MathFunctionsComponents/CMakeLists.txt
@@ -1,6 +1,9 @@
 cmake_minimum_required(VERSION 3.15)
 project(MathFunctionsComponents)
 
+# make cache variables for install destinations
+include(GNUInstallDirs)
+
 # specify the C++ standard
 set(CMAKE_CXX_STANDARD 11)
 set(CMAKE_CXX_STANDARD_REQUIRED True)
@@ -24,7 +27,7 @@
 # create config file
 configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
   "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
-  INSTALL_DESTINATION lib/cmake/MathFunctions
+  INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
   NO_CHECK_REQUIRED_COMPONENTS_MACRO
 )
 
@@ -32,5 +35,5 @@
 install(FILES
           "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
           "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
-        DESTINATION lib/cmake/MathFunctions
+        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
 )
diff --git a/Help/guide/importing-exporting/MathFunctionsComponents/SquareRoot/CMakeLists.txt b/Help/guide/importing-exporting/MathFunctionsComponents/SquareRoot/CMakeLists.txt
index be5ae65..517c5e2 100644
--- a/Help/guide/importing-exporting/MathFunctionsComponents/SquareRoot/CMakeLists.txt
+++ b/Help/guide/importing-exporting/MathFunctionsComponents/SquareRoot/CMakeLists.txt
@@ -7,24 +7,24 @@
 target_include_directories(SquareRoot
                            PUBLIC
                            "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
-                           "$<INSTALL_INTERFACE:include>"
+                           "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
 )
 
 # install the target and create export-set
 install(TARGETS SquareRoot
         EXPORT SquareRootTargets
-        LIBRARY DESTINATION lib
-        ARCHIVE DESTINATION lib
-        RUNTIME DESTINATION bin
-        INCLUDES DESTINATION include
+        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+        INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
 )
 
 # install header file
-install(FILES SquareRoot.h DESTINATION include)
+install(FILES SquareRoot.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
 
 # generate and install export file
 install(EXPORT SquareRootTargets
         FILE MathFunctionsSquareRootTargets.cmake
         NAMESPACE MathFunctions::
-        DESTINATION lib/cmake/MathFunctions
+        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
 )
diff --git a/Help/guide/importing-exporting/index.rst b/Help/guide/importing-exporting/index.rst
index 2e6e06d..3e60250 100644
--- a/Help/guide/importing-exporting/index.rst
+++ b/Help/guide/importing-exporting/index.rst
@@ -202,6 +202,10 @@
   :language: cmake
   :end-before: # create library
 
+The :module:`GNUInstallDirs` module is included in order to provide the
+project with the flexibility to install into different platform layouts by
+making the directories available as cache variables.
+
 Create a library called ``MathFunctions`` with the :command:`add_library`
 command:
 
diff --git a/Help/manual/OPTIONS_BUILD.txt b/Help/manual/OPTIONS_BUILD.txt
index 0947e41..c4f9be8 100644
--- a/Help/manual/OPTIONS_BUILD.txt
+++ b/Help/manual/OPTIONS_BUILD.txt
@@ -76,6 +76,10 @@
  native build system to choose a compiler or SDK.  See the
  :variable:`CMAKE_GENERATOR_PLATFORM` variable for details.
 
+``--install-prefix <directory>``
+ Specify the installation directory, used by the
+ :variable:`CMAKE_INSTALL_PREFIX` variable. Must be an absolute path.
+
 ``-Wno-dev``
  Suppress developer warnings.
 
diff --git a/Help/manual/cmake-compile-features.7.rst b/Help/manual/cmake-compile-features.7.rst
index 0d15ddf..56d16c0 100644
--- a/Help/manual/cmake-compile-features.7.rst
+++ b/Help/manual/cmake-compile-features.7.rst
@@ -359,6 +359,7 @@
 versions specified for each:
 
 * ``Cray``: Cray Compiler Environment version 8.1+.
+* ``Fujitsu``: Fujitsu HPC compiler 4.0+.
 * ``PGI``: PGI version 12.10+.
 * ``NVHPC``: NVIDIA HPC compilers version 11.0+.
 * ``TI``: Texas Instruments compiler.
diff --git a/Help/manual/cmake-developer.7.rst b/Help/manual/cmake-developer.7.rst
index af9a8ab..fe146de 100644
--- a/Help/manual/cmake-developer.7.rst
+++ b/Help/manual/cmake-developer.7.rst
@@ -350,6 +350,24 @@
     PATHS ${PC_Foo_LIBRARY_DIRS}
   )
 
+Alternatively, if the library is available with multiple configurations, you can
+use :module:`SelectLibraryConfigurations` to automatically set the
+``Foo_LIBRARY`` variable instead:
+
+.. code-block:: cmake
+
+  find_library(Foo_LIBRARY_RELEASE
+    NAMES foo
+    PATHS ${PC_Foo_LIBRARY_DIRS}/Release
+  )
+  find_library(Foo_LIBRARY_DEBUG
+    NAMES foo
+    PATHS ${PC_Foo_LIBRARY_DIRS}/Debug
+  )
+
+  include(SelectLibraryConfigurations)
+  select_library_configurations(Foo)
+
 If you have a good way of getting the version (from a header file, for
 example), you can use that information to set ``Foo_VERSION`` (although
 note that find modules have traditionally used ``Foo_VERSION_STRING``,
diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst
index 89739b7..cbc3d6d 100644
--- a/Help/manual/cmake-file-api.7.rst
+++ b/Help/manual/cmake-file-api.7.rst
@@ -443,7 +443,8 @@
             "hasInstallRule": true,
             "minimumCMakeVersion": {
               "string": "3.14"
-            }
+            },
+            "jsonFile": "<file>"
           },
           {
             "source": "sub",
@@ -453,7 +454,8 @@
             "targetIndexes": [ 1 ],
             "minimumCMakeVersion": {
               "string": "3.14"
-            }
+            },
+            "jsonFile": "<file>"
           }
         ],
         "projects": [
@@ -569,6 +571,13 @@
       :command:`install` rules, i.e. whether a ``make install``
       or equivalent rule is available.
 
+    ``jsonFile``
+      A JSON string specifying a path relative to the codemodel file
+      to another JSON file containing a
+      `"codemodel" version 2 "directory" object`_.
+
+      This field was added in codemodel version 2.3.
+
   ``projects``
     A JSON array of entries corresponding to the top-level project
     and sub-projects defined in the build system.  Each (sub-)project
@@ -633,6 +642,182 @@
       to another JSON file containing a
       `"codemodel" version 2 "target" object`_.
 
+"codemodel" version 2 "directory" object
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A codemodel "directory" object is referenced by a `"codemodel" version 2`_
+object's ``directories`` array.  Each "directory" object is a JSON object
+with members:
+
+``paths``
+  A JSON object containing members:
+
+  ``source``
+    A string specifying the path to the source directory, represented
+    with forward slashes.  If the directory is inside the top-level
+    source directory then the path is specified relative to that
+    directory (with ``.`` for the top-level source directory itself).
+    Otherwise the path is absolute.
+
+  ``build``
+    A string specifying the path to the build directory, represented
+    with forward slashes.  If the directory is inside the top-level
+    build directory then the path is specified relative to that
+    directory (with ``.`` for the top-level build directory itself).
+    Otherwise the path is absolute.
+
+``installers``
+  A JSON array of entries corresponding to :command:`install` rules.
+  Each entry is a JSON object containing members:
+
+  ``component``
+    A string specifying the component selected by the corresponding
+    :command:`install` command invocation.
+
+  ``destination``
+    Optional member that is present for specific ``type`` values below.
+    The value is a string specifying the install destination path.
+    The path may be absolute or relative to the install prefix.
+
+  ``paths``
+    Optional member that is present for specific ``type`` values below.
+    The value is a JSON array of entries corresponding to the paths
+    (files or directories) to be installed.  Each entry is one of:
+
+    * A string specifying the path from which a file or directory
+      is to be installed.  The portion of the path not preceded by
+      a ``/`` also specifies the path (name) to which the file
+      or directory is to be installed under the destination.
+
+    * A JSON object with members:
+
+      ``from``
+        A string specifying the path from which a file or directory
+        is to be installed.
+
+      ``to``
+        A string specifying the path to which the file or directory
+        is to be installed under the destination.
+
+    In both cases the paths are represented with forward slashes.  If
+    the "from" path is inside the top-level directory documented by the
+    corresponding ``type`` value, then the path is specified relative
+    to that directory.  Otherwise the path is absolute.
+
+  ``type``
+    A string specifying the type of installation rule.  The value is one
+    of the following, with some variants providing additional members:
+
+    ``file``
+      An :command:`install(FILES)` or :command:`install(PROGRAMS)` call.
+      The ``destination`` and ``paths`` members are populated, with paths
+      under the top-level *source* directory expressed relative to it.
+      The ``isOptional`` member may exist.
+      This type has no additional members.
+
+    ``directory``
+      An :command:`install(DIRECTORY)` call.
+      The ``destination`` and ``paths`` members are populated, with paths
+      under the top-level *source* directory expressed relative to it.
+      The ``isOptional`` member may exist.
+      This type has no additional members.
+
+    ``target``
+      An :command:`install(TARGETS)` call.
+      The ``destination`` and ``paths`` members are populated, with paths
+      under the top-level *build* directory expressed relative to it.
+      The ``isOptional`` member may exist.
+      This type has additional members ``targetId``, ``targetIndex``,
+      ``targetIsImportLibrary``, and ``targetInstallNamelink``.
+
+    ``export``
+      An :command:`install(EXPORT)` call.
+      The ``destination`` and ``paths`` members are populated, with paths
+      under the top-level *build* directory expressed relative to it.
+      The ``paths`` entries refer to files generated automatically by
+      CMake for installation, and their actual values are considered
+      private implementation details.
+      This type has additional members ``exportName`` and ``exportTargets``.
+
+    ``script``
+      An :command:`install(SCRIPT)` call.
+      This type has additional member ``scriptFile``.
+
+    ``code``
+      An :command:`install(CODE)` call.
+      This type has no additional members.
+
+  ``isExcludeFromAll``
+    Optional member that is present with boolean value ``true`` when
+    :command:`install` is called with the ``EXCLUDE_FROM_ALL`` option.
+
+  ``isOptional``
+    Optional member that is present with boolean value ``true`` when
+    :command:`install` is called with the ``OPTIONAL`` option.
+    This is allowed when ``type`` is ``file``, ``directory``, or ``target``.
+
+  ``targetId``
+    Optional member that is present when ``type`` is ``target``.
+    The value is a string uniquely identifying the target to be installed.
+    This matches the ``id`` member of the target in the main
+    "codemodel" object's ``targets`` array.
+
+  ``targetIndex``
+    Optional member that is present when ``type`` is ``target``.
+    The value is an unsigned integer 0-based index into the main "codemodel"
+    object's ``targets`` array for the target to be installed.
+
+  ``targetIsImportLibrary``
+    Optional member that is present when ``type`` is ``target`` and
+    the installer is for a Windows DLL import library file or for an
+    AIX linker import file.  If present, it has boolean value ``true``.
+
+  ``targetInstallNamelink``
+    Optional member that is present when ``type`` is ``target`` and
+    the installer corresponds to a target that may use symbolic links
+    to implement the :prop_tgt:`VERSION` and :prop_tgt:`SOVERSION`
+    target properties.
+    The value is a string indicating how the installer is supposed to
+    handle the symlinks: ``skip`` means the installer should skip the
+    symlinks and install only the real file, and ``only`` means the
+    installer should install only the symlinks and not the real file.
+    In all cases the ``paths`` member lists what it actually installs.
+
+  ``exportName``
+    Optional member that is present when ``type`` is ``export``.
+    The value is a string specifying the name of the export.
+
+  ``exportTargets``
+    Optional member that is present when ``type`` is ``export``.
+    The value is a JSON array of entries corresponding to the targets
+    included in the export.  Each entry is a JSON object with members:
+
+    ``id``
+      A string uniquely identifying the target.  This matches
+      the ``id`` member of the target in the main "codemodel"
+      object's ``targets`` array.
+
+    ``index``
+      An unsigned integer 0-based index into the main "codemodel"
+      object's ``targets`` array for the target.
+
+  ``scriptFile``
+    Optional member that is present when ``type`` is ``script``.
+    The value is a string specifying the path to the script file on disk,
+    represented with forward slashes.  If the file is inside the top-level
+    source directory then the path is specified relative to that directory.
+    Otherwise the path is absolute.
+
+  ``backtrace``
+    Optional member that is present when a CMake language backtrace to
+    the :command:`install` or other command invocation that added this
+    installer is available.  The value is an unsigned integer 0-based
+    index into the ``backtraceGraph`` member's ``nodes`` array.
+
+``backtraceGraph``
+  A `"codemodel" version 2 "backtrace graph"`_ whose nodes are referenced
+  from ``backtrace`` members elsewhere in this "directory" object.
+
 "codemodel" version 2 "target" object
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -964,40 +1149,48 @@
       with forward slashes.
 
 ``backtraceGraph``
-  A JSON object describing the graph of backtraces whose nodes are
-  referenced from ``backtrace`` members elsewhere.  The members are:
+  A `"codemodel" version 2 "backtrace graph"`_ whose nodes are referenced
+  from ``backtrace`` members elsewhere in this "target" object.
 
-  ``nodes``
-    A JSON array listing nodes in the backtrace graph.  Each entry
-    is a JSON object with members:
+"codemodel" version 2 "backtrace graph"
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-    ``file``
-      An unsigned integer 0-based index into the backtrace ``files`` array.
+The ``backtraceGraph`` member of a `"codemodel" version 2 "directory" object`_,
+or `"codemodel" version 2 "target" object`_ is a JSON object describing a
+graph of backtraces.  Its nodes are referenced from ``backtrace`` members
+elsewhere in the containing object.  The backtrace graph object members are:
 
-    ``line``
-      An optional member present when the node represents a line within
-      the file.  The value is an unsigned integer 1-based line number.
+``nodes``
+  A JSON array listing nodes in the backtrace graph.  Each entry
+  is a JSON object with members:
 
-    ``command``
-      An optional member present when the node represents a command
-      invocation within the file.  The value is an unsigned integer
-      0-based index into the backtrace ``commands`` array.
+  ``file``
+    An unsigned integer 0-based index into the backtrace ``files`` array.
 
-    ``parent``
-      An optional member present when the node is not the bottom of
-      the call stack.  The value is an unsigned integer 0-based index
-      of another entry in the backtrace ``nodes`` array.
+  ``line``
+    An optional member present when the node represents a line within
+    the file.  The value is an unsigned integer 1-based line number.
 
-  ``commands``
-    A JSON array listing command names referenced by backtrace nodes.
-    Each entry is a string specifying a command name.
+  ``command``
+    An optional member present when the node represents a command
+    invocation within the file.  The value is an unsigned integer
+    0-based index into the backtrace ``commands`` array.
 
-  ``files``
-    A JSON array listing CMake language files referenced by backtrace nodes.
-    Each entry is a string specifying the path to a file, represented
-    with forward slashes.  If the file is inside the top-level source
-    directory then the path is specified relative to that directory.
-    Otherwise the path is absolute.
+  ``parent``
+    An optional member present when the node is not the bottom of
+    the call stack.  The value is an unsigned integer 0-based index
+    of another entry in the backtrace ``nodes`` array.
+
+``commands``
+  A JSON array listing command names referenced by backtrace nodes.
+  Each entry is a string specifying a command name.
+
+``files``
+  A JSON array listing CMake language files referenced by backtrace nodes.
+  Each entry is a string specifying the path to a file, represented
+  with forward slashes.  If the file is inside the top-level source
+  directory then the path is specified relative to that directory.
+  Otherwise the path is absolute.
 
 Object Kind "cache"
 -------------------
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index 7bc490f..775067a 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -940,6 +940,29 @@
   :ref:`Target Usage Requirements` this is the consuming target rather
   than the target specifying the requirement.
 
+.. genex:: $<TARGET_RUNTIME_DLLS:tgt>
+
+  List of DLLs that the target depends on at runtime. This is determined by
+  the locations of all the ``SHARED`` and ``MODULE`` targets in the target's
+  transitive dependencies. Using this generator expression on targets other
+  than executables, ``SHARED`` libraries, and ``MODULE`` libraries is an error.
+  On non-DLL platforms, it evaluates to an empty string.
+
+  This generator expression can be used to copy all of the DLLs that a target
+  depends on into its output directory in a ``POST_BUILD`` custom command. For
+  example:
+
+  .. code-block:: cmake
+
+    find_package(foo REQUIRED)
+
+    add_executable(exe main.c)
+    target_link_libraries(exe PRIVATE foo::foo foo::bar)
+    add_custom_command(TARGET exe POST_BUILD
+      COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:exe> $<TARGET_FILE_DIR:exe>
+      COMMAND_EXPAND_LISTS
+      )
+
 .. genex:: $<INSTALL_PREFIX>
 
   Content of the install prefix when the target is exported via
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index bd6b2f0..5dfa894 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -51,6 +51,15 @@
 to determine whether to report an error on use of deprecated macros or
 functions.
 
+Policies Introduced by CMake 3.21
+=================================
+
+.. toctree::
+   :maxdepth: 1
+
+   CMP0122: UseSWIG use standard library name conventions for csharp language. </policy/CMP0122>
+   CMP0121: The list command detects invalid indicies. </policy/CMP0121>
+
 Policies Introduced by CMake 3.20
 =================================
 
diff --git a/Help/manual/cmake-presets.7.rst b/Help/manual/cmake-presets.7.rst
index 467818d..3714004 100644
--- a/Help/manual/cmake-presets.7.rst
+++ b/Help/manual/cmake-presets.7.rst
@@ -39,7 +39,7 @@
 ``version``
 
   A required integer representing the version of the JSON schema.
-  The supported versions are ``1`` and ``2``.
+  The supported versions are ``1``, ``2``, and ``3``.
 
 ``cmakeMinimumRequired``
 
@@ -70,17 +70,17 @@
 ``configurePresets``
 
   An optional array of `Configure Preset`_ objects.
-  This is allowed in preset files specifying version 1 or above.
+  This is allowed in preset files specifying version ``1`` or above.
 
 ``buildPresets``
 
   An optional array of `Build Preset`_ objects.
-  This is allowed in preset files specifying version 2 or above.
+  This is allowed in preset files specifying version ``2`` or above.
 
 ``testPresets``
 
   An optional array of `Test Preset`_ objects.
-  This is allowed in preset files specifying version 2 or above.
+  This is allowed in preset files specifying version ``2`` or above.
 
 Configure Preset
 ^^^^^^^^^^^^^^^^
@@ -119,6 +119,11 @@
   This field can also be a string, which is equivalent to an array
   containing one string.
 
+``condition``
+
+  An optional `Condition`_ object. This is allowed in preset files specifying
+  version ``3`` or above.
+
 ``vendor``
 
   An optional map containing vendor-specific information. CMake does not
@@ -140,7 +145,9 @@
 
   An optional string representing the generator to use for the preset. If
   ``generator`` is not specified, it must be inherited from the
-  ``inherits`` preset (unless this preset is ``hidden``).
+  ``inherits`` preset (unless this preset is ``hidden``). In version ``3``
+  or above, this field may be omitted to fall back to regular generator
+  discovery procedure.
 
   Note that for Visual Studio generators, unlike in the command line ``-G``
   argument, you cannot include the platform name in the generator name. Use
@@ -181,7 +188,15 @@
   This field supports `macro expansion`_. If a relative path is specified,
   it is calculated relative to the source directory. If ``binaryDir`` is not
   specified, it must be inherited from the ``inherits`` preset (unless this
-  preset is ``hidden``).
+  preset is ``hidden``). In version ``3`` or above, this field may be
+  omitted.
+
+``installDir``
+
+  An optional string representing the path to the installation directory.
+  This field supports `macro expansion`_. If a relative path is specified,
+  it is calculated relative to the source directory. This is allowed in
+  preset files specifying version ``3`` or above.
 
 ``cmakeExecutable``
 
@@ -338,6 +353,11 @@
   This field can also be a string, which is equivalent to an array
   containing one string.
 
+``condition``
+
+  An optional `Condition`_ object. This is allowed in preset files specifying
+  version ``3`` or above.
+
 ``vendor``
 
   An optional map containing vendor-specific information. CMake does not
@@ -457,6 +477,11 @@
   This field can also be a string, which is equivalent to an array
   containing one string.
 
+``condition``
+
+  An optional `Condition`_ object. This is allowed in preset files specifying
+  version ``3`` or above.
+
 ``vendor``
 
   An optional map containing vendor-specific information. CMake does not
@@ -782,6 +807,103 @@
 
       Equivalent to passing ``--no-tests=ignore`` on the command line.
 
+Condition
+^^^^^^^^^
+
+The ``condition`` field of a preset, allowed in preset files specifying version
+``3`` or above, is used to determine whether or not the preset is enabled. For
+example, this can be used to disable a preset on platforms other than Windows.
+``condition`` may be either a boolean, ``null``, or an object. If it is a
+boolean, the boolean indicates whether the preset is enabled or disabled. If it
+is ``null``, the preset is enabled, but the ``null`` condition is not inherited
+by any presets that may inherit from the preset. Sub-conditions (for example in
+a ``not``, ``anyOf``, or ``allOf`` condition) may not be ``null``. If it is an
+object, it has the following fields:
+
+``type``
+
+  A required string with one of the following values:
+
+  ``"const"``
+
+    Indicates that the condition is constant. This is equivalent to using a
+    boolean in place of the object. The condition object will have the
+    following additional fields:
+
+    ``value``
+
+      A required boolean which provides a constant value for the condition's
+      evaluation.
+
+  ``"equals"``
+
+  ``"notEquals"``
+
+    Indicates that the condition compares two strings to see if they are equal
+    (or not equal). The condition object will have the following additional
+    fields:
+
+    ``lhs``
+
+      First string to compare. This field supports macro expansion.
+
+    ``rhs``
+
+      Second string to compare. This field supports macro expansion.
+
+  ``"inList"``
+
+  ``"notInList"``
+
+    Indicates that the condition searches for a string in a list of strings.
+    The condition object will have the following additional fields:
+
+    ``string``
+
+      A required string to search for. This field supports macro expansion.
+
+    ``list``
+
+      A required list of strings to search. This field supports macro
+      expansion, and uses short-circuit evaluation.
+
+  ``"matches"``
+
+  ``"notMatches"``
+
+    Indicates that the condition searches for a regular expression in a string.
+    The condition object will have the following additional fields:
+
+    ``string``
+
+      A required string to search. This field supports macro expansion.
+
+    ``regex``
+
+      A required regular expression to search for. This field supports macro
+      expansion.
+
+  ``"anyOf"``
+
+  ``"allOf"``
+
+    Indicates that the condition is an aggregation of zero or more nested
+    conditions. The condition object will have the following additional fields:
+
+    ``conditions``
+
+      A required array of condition objects. These conditions use short-circuit
+      evaluation.
+
+  ``"not"``
+
+    Indicates that the condition is an inversion of another condition. The
+    condition object will have the following additional fields:
+
+    ``condition``
+
+      A required condition object.
+
 Macro Expansion
 ^^^^^^^^^^^^^^^
 
@@ -823,6 +945,12 @@
   test presets, this will evaluate to the generator specified by
   ``configurePreset``.
 
+``${hostSystemName}``
+
+  The name of the host operating system. Contains the same value as
+  :variable:`CMAKE_HOST_SYSTEM_NAME`. This is allowed in preset files
+  specifying version ``3`` or above.
+
 ``${dollar}``
 
   A literal dollar sign (``$``).
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index af170da..60a4028 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -21,6 +21,7 @@
    /prop_gbl/AUTOMOC_SOURCE_GROUP
    /prop_gbl/AUTOMOC_TARGETS_FOLDER
    /prop_gbl/AUTORCC_SOURCE_GROUP
+   /prop_gbl/AUTOUIC_SOURCE_GROUP
    /prop_gbl/CMAKE_C_KNOWN_FEATURES
    /prop_gbl/CMAKE_CUDA_KNOWN_FEATURES
    /prop_gbl/CMAKE_CXX_KNOWN_FEATURES
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 4317dd4..37ef053 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -130,6 +130,7 @@
    /variable/PROJECT-NAME_BINARY_DIR
    /variable/PROJECT-NAME_DESCRIPTION
    /variable/PROJECT-NAME_HOMEPAGE_URL
+   /variable/PROJECT-NAME_IS_TOP_LEVEL
    /variable/PROJECT-NAME_SOURCE_DIR
    /variable/PROJECT-NAME_VERSION
    /variable/PROJECT-NAME_VERSION_MAJOR
@@ -139,6 +140,7 @@
    /variable/PROJECT_BINARY_DIR
    /variable/PROJECT_DESCRIPTION
    /variable/PROJECT_HOMEPAGE_URL
+   /variable/PROJECT_IS_TOP_LEVEL
    /variable/PROJECT_NAME
    /variable/PROJECT_SOURCE_DIR
    /variable/PROJECT_VERSION
diff --git a/Help/manual/ctest.1.rst b/Help/manual/ctest.1.rst
index 175359d..68409e1 100644
--- a/Help/manual/ctest.1.rst
+++ b/Help/manual/ctest.1.rst
@@ -155,7 +155,10 @@
  Run tests with labels matching regular expression.
 
  This option tells CTest to run only the tests whose labels match the
- given regular expression.
+ given regular expression.  When more than one ``-L`` option is given,
+ a test will only be run if each regular expression matches at least one
+ of the test's labels (i.e. the multiple ``-L`` labels form an ``AND``
+ relationship).  See `Label Matching`_.
 
 ``-R <regex>, --tests-regex <regex>``
  Run tests matching regular expression.
@@ -173,7 +176,10 @@
  Exclude tests with labels matching regular expression.
 
  This option tells CTest to NOT run the tests whose labels match the
- given regular expression.
+ given regular expression.  When more than one ``-LE`` option is given,
+ a test will only be excluded if each regular expression matches at least one
+ of the test's labels (i.e. the multiple ``-LE`` labels form an ``AND``
+ relationship).  See `Label Matching`_.
 
 ``-FA <regex>, --fixture-exclude-any <regex>``
  Exclude fixtures matching ``<regex>`` from automatically adding any tests to
@@ -398,6 +404,46 @@
 
 .. include:: OPTIONS_HELP.txt
 
+.. _`Label Matching`:
+
+Label Matching
+==============
+
+Tests may have labels attached to them. Tests may be included
+or excluded from a test run by filtering on the labels.
+Each individual filter is a regular expression applied to
+the labels attached to a test.
+
+When ``-L`` is used, in order for a test to be included in a
+test run, each regular expression must match at least one
+label.  Using more than one ``-L`` option means "match **all**
+of these".
+
+The ``-LE`` option works just like ``-L``, but excludes tests
+rather than including them. A test is excluded if each regular
+expression matches at least one label.
+
+If a test has no labels attached to it, then ``-L`` will never
+include that test, and ``-LE`` will never exclude that test.
+As an example of tests with labels, consider five tests,
+with the following labels:
+
+* *test1* has labels *tuesday* and *production*
+* *test2* has labels *tuesday* and *test*
+* *test3* has labels *wednesday* and *production*
+* *test4* has label *wednesday*
+* *test5* has labels *friday* and *test*
+
+Running ``ctest`` with ``-L tuesday -L test`` will select *test2*, which has
+both labels. Running CTest with ``-L test`` will select *test2* and
+*test5*, because both of them have a label that matches that regular
+expression.
+
+Because the matching works with regular expressions, take note that
+running CTest with ``-L es`` will match all five tests.
+To select the *tuesday* and *wednesday* tests together, use a single
+regular expression that matches either of them, like ``-L "tue|wed"``.
+
 .. _`Label and Subproject Summary`:
 
 Label and Subproject Summary
diff --git a/Help/manual/presets/example.json b/Help/manual/presets/example.json
index dfc2910..346f342 100644
--- a/Help/manual/presets/example.json
+++ b/Help/manual/presets/example.json
@@ -1,5 +1,5 @@
 {
-  "version": 2,
+  "version": 3,
   "cmakeMinimumRequired": {
     "major": 3,
     "minor": 20,
@@ -35,6 +35,17 @@
       "displayName": "Ninja Multi-Config",
       "description": "Default build using Ninja Multi-Config generator",
       "generator": "Ninja Multi-Config"
+    },
+    {
+      "name": "windows-only",
+      "inherits": "default",
+      "displayName": "Windows-only configuration",
+      "description": "This build is only available on Windows",
+      "condition": {
+        "type": "equals",
+        "lhs": "${hostSystemName}",
+        "rhs": "Windows"
+      }
     }
   ],
   "buildPresets": [
diff --git a/Help/manual/presets/schema.json b/Help/manual/presets/schema.json
index f8faf3d..e066362 100644
--- a/Help/manual/presets/schema.json
+++ b/Help/manual/presets/schema.json
@@ -11,7 +11,7 @@
         },
         "cmakeMinimumRequired": { "$ref": "#/definitions/cmakeMinimumRequired"},
         "vendor": { "$ref": "#/definitions/vendor" },
-        "configurePresets": { "$ref": "#/definitions/configurePresets"}
+        "configurePresets": { "$ref": "#/definitions/configurePresetsV1"}
       },
       "additionalProperties": false
     },
@@ -23,9 +23,23 @@
         },
         "cmakeMinimumRequired": { "$ref": "#/definitions/cmakeMinimumRequired"},
         "vendor": { "$ref": "#/definitions/vendor" },
-        "configurePresets": { "$ref": "#/definitions/configurePresets"},
-        "buildPresets": { "$ref": "#/definitions/buildPresets"},
-        "testPresets": { "$ref": "#/definitions/testPresets"}
+        "configurePresets": { "$ref": "#/definitions/configurePresetsV1"},
+        "buildPresets": { "$ref": "#/definitions/buildPresetsV2"},
+        "testPresets": { "$ref": "#/definitions/testPresetsV2"}
+      },
+      "additionalProperties": false
+    },
+    {
+      "properties": {
+        "version": {
+          "const": 3,
+          "description": "A required integer representing the version of the JSON schema."
+        },
+        "cmakeMinimumRequired": { "$ref": "#/definitions/cmakeMinimumRequired"},
+        "vendor": { "$ref": "#/definitions/vendor" },
+        "configurePresets": { "$ref": "#/definitions/configurePresetsV3"},
+        "buildPresets": { "$ref": "#/definitions/buildPresetsV3"},
+        "testPresets": { "$ref": "#/definitions/testPresetsV3"}
       },
       "additionalProperties": false
     }
@@ -58,7 +72,30 @@
       "description": "An optional map containing vendor-specific information. CMake does not interpret the contents of this field except to verify that it is a map if it does exist. However, the keys should be a vendor-specific domain name followed by a /-separated path. For example, the Example IDE 1.0 could use example.com/ExampleIDE/1.0. The value of each field can be anything desired by the vendor, though will typically be a map.",
       "properties": {}
     },
-    "configurePresets": {
+    "configurePresetsItemsV3": {
+      "type": "array",
+      "description": "A configure preset object.",
+      "items": {
+        "type": "object",
+        "description": "A configure preset object.",
+        "properties": {
+          "binaryDir": {
+            "type": "string",
+            "description": "An optional string representing the path to the output binary directory. This field supports macro expansion. If a relative path is specified, it is calculated relative to the source directory. If binaryDir is not specified, the path is calculated using regular methods."
+          },
+          "generator": {
+            "type": "string",
+            "description": "An optional string representing the generator to use for the preset. If generator is not specified, the normal generator discovery procedure is used. Note that for Visual Studio generators, unlike in the command line -G argument, you cannot include the platform name in the generator name. Use the architecture field instead."
+          },
+          "installDir": {
+            "type": "string",
+            "description": "An optional string representing the path to the output binary directory. This field supports macro expansion. If a relative path is specified, it is calculated relative to the source directory. If binaryDir is not specified, it must be inherited from the inherits preset (unless this preset is hidden)."
+          },
+          "condition": { "$ref": "#/definitions/topCondition" }
+        }
+      }
+    },
+    "configurePresetsItemsV1": {
       "type": "array",
       "description": "An optional array of configure preset objects.",
       "items": {
@@ -302,6 +339,36 @@
             },
             "additionalProperties": false
           }
+        }
+      }
+    },
+    "configurePresetsV3": {
+      "type": "array",
+      "description": "An optional array of configure preset objects.",
+      "allOf": [
+        { "$ref": "#/definitions/configurePresetsItemsV1" },
+        { "$ref": "#/definitions/configurePresetsItemsV3" }
+      ],
+      "items": {
+        "properties": {
+          "name": {},
+          "hidden": {},
+          "inherits": {},
+          "vendor": {},
+          "displayName": {},
+          "description": {},
+          "generator": {},
+          "architecture": {},
+          "toolset": {},
+          "binaryDir": {},
+          "installDir": {},
+          "cmakeExecutable": {},
+          "cacheVariables": {},
+          "environment": {},
+          "warnings": {},
+          "errors": {},
+          "debug": {},
+          "condition": {}
         },
         "required": [
           "name"
@@ -309,7 +376,48 @@
         "additionalProperties": false
       }
     },
-    "buildPresets": {
+    "configurePresetsV1": {
+      "type": "array",
+      "description": "An optional array of configure preset objects.",
+      "allOf": [
+        { "$ref": "#/definitions/configurePresetsItemsV1" }
+      ],
+      "items": {
+        "properties": {
+          "name": {},
+          "hidden": {},
+          "inherits": {},
+          "vendor": {},
+          "displayName": {},
+          "description": {},
+          "generator": {},
+          "architecture": {},
+          "toolset": {},
+          "binaryDir": {},
+          "cmakeExecutable": {},
+          "cacheVariables": {},
+          "environment": {},
+          "warnings": {},
+          "errors": {},
+          "debug": {}
+        },
+        "required": [
+          "name"
+        ],
+        "additionalProperties": false
+      }
+    },
+    "buildPresetsItemsV3": {
+      "type": "array",
+      "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 2 and higher.",
+      "items": {
+        "type": "object",
+        "properties": {
+          "condition": { "$ref": "#/definitions/topCondition" }
+        }
+      }
+    },
+    "buildPresetsItemsV2": {
       "type": "array",
       "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 2 and higher.",
       "items": {
@@ -427,11 +535,84 @@
         },
         "required": [
           "name"
+        ]
+      }
+    },
+    "buildPresetsV3": {
+      "type": "array",
+      "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 2 and higher.",
+      "allOf": [
+        { "$ref": "#/definitions/buildPresetsItemsV3" },
+        { "$ref": "#/definitions/buildPresetsItemsV2" }
+      ],
+      "items": {
+        "type": "object",
+        "properties": {
+          "name": {},
+          "hidden": {},
+          "inherits": {},
+          "configurePreset": {},
+          "vendor": {},
+          "displayName": {},
+          "description": {},
+          "inheritConfigureEnvironment": {},
+          "environment": {},
+          "jobs": {},
+          "targets": {},
+          "configuration": {},
+          "cleanFirst": {},
+          "verbose": {},
+          "nativeToolOptions": {},
+          "condition": {}
+        },
+        "required": [
+          "name"
         ],
         "additionalProperties": false
       }
     },
-    "testPresets": {
+    "buildPresetsV2": {
+      "type": "array",
+      "description": "An optional array of build preset objects. Used to specify arguments to cmake --build. Available in version 2 and higher.",
+      "allOf": [
+        { "$ref": "#/definitions/buildPresetsItemsV2" }
+      ],
+      "items": {
+        "type": "object",
+        "properties": {
+          "name": {},
+          "hidden": {},
+          "inherits": {},
+          "configurePreset": {},
+          "vendor": {},
+          "displayName": {},
+          "description": {},
+          "inheritConfigureEnvironment": {},
+          "environment": {},
+          "jobs": {},
+          "targets": {},
+          "configuration": {},
+          "cleanFirst": {},
+          "verbose": {},
+          "nativeToolOptions": {}
+        },
+        "required": [
+          "name"
+        ],
+        "additionalProperties": false
+      }
+    },
+    "testPresetsItemsV3": {
+      "type": "array",
+      "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 2 and higher.",
+      "items": {
+        "type": "object",
+        "properties": {
+          "condition": { "$ref": "#/definitions/topCondition" }
+        }
+      }
+    },
+    "testPresetsItemsV2": {
       "type": "array",
       "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 2 and higher.",
       "items": {
@@ -743,9 +924,312 @@
         },
         "required": [
           "name"
+        ]
+      }
+    },
+    "testPresetsV3": {
+      "type": "array",
+      "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 2 and higher.",
+      "allOf": [
+        { "$ref": "#/definitions/testPresetsItemsV2" },
+        { "$ref": "#/definitions/testPresetsItemsV3" }
+      ],
+      "items": {
+        "type": "object",
+        "properties": {
+          "name": {},
+          "hidden": {},
+          "inherits": {},
+          "configurePreset": {},
+          "vendor": {},
+          "displayName": {},
+          "description": {},
+          "inheritConfigureEnvironment": {},
+          "environment": {},
+          "configuration": {},
+          "overwriteConfigurationFile": {},
+          "output": {},
+          "filter": {},
+          "execution": {},
+          "condition": {}
+        },
+        "required": [
+          "name"
         ],
         "additionalProperties": false
       }
+    },
+    "testPresetsV2": {
+      "type": "array",
+      "description": "An optional array of test preset objects. Used to specify arguments to ctest. Available in version 2 and higher.",
+      "allOf": [
+        { "$ref": "#/definitions/testPresetsItemsV2" }
+      ],
+      "items": {
+        "type": "object",
+        "properties": {
+          "name": {},
+          "hidden": {},
+          "inherits": {},
+          "configurePreset": {},
+          "vendor": {},
+          "displayName": {},
+          "description": {},
+          "inheritConfigureEnvironment": {},
+          "environment": {},
+          "configuration": {},
+          "overwriteConfigurationFile": {},
+          "output": {},
+          "filter": {},
+          "execution": {}
+        },
+        "required": [
+          "name"
+        ],
+        "additionalProperties": false
+      }
+    },
+    "condition": {
+      "anyOf": [
+        {
+          "type": "boolean",
+          "description": "A boolean which provides a constant value for the condition's evaluation."
+        },
+        {
+          "type": "object",
+          "properties": {
+            "type": {
+              "type": "string",
+              "description": "A required string specifying the type of the condition.",
+              "const": "const"
+            },
+            "value": {
+              "type": "boolean",
+              "description": "A required boolean which provides a constant value for the condition's evaluation."
+            }
+          },
+          "required": [
+            "type",
+            "value"
+          ],
+          "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "properties": {
+            "type": {
+              "type": "string",
+              "description": "A required string specifying the type of the condition.",
+              "const": "equals"
+            },
+            "lhs": {
+              "type": "string",
+              "description": "First string to compare. This field supports macro expansion."
+            },
+            "rhs": {
+              "type": "string",
+              "description": "Second string to compare. This field supports macro expansion."
+            }
+          },
+          "required": [
+            "type",
+            "lhs",
+            "rhs"
+          ],
+          "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "properties": {
+            "type": {
+              "type": "string",
+              "description": "A required string specifying the type of the condition.",
+              "const": "notEquals"
+            },
+            "lhs": {
+              "type": "string",
+              "description": "First string to compare. This field supports macro expansion."
+            },
+            "rhs": {
+              "type": "string",
+              "description": "Second string to compare. This field supports macro expansion."
+            }
+          },
+          "required": [
+            "type",
+            "lhs",
+            "rhs"
+          ],
+          "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "properties": {
+            "type": {
+              "type": "string",
+              "description": "A required string specifying the type of the condition.",
+              "const": "inList"
+            },
+            "string": {
+              "type": "string",
+              "description": "A required string to search for. This field supports macro expansion."
+            },
+            "list": {
+              "type": "array",
+              "description": "A required list of strings to search. This field supports macro expansion, and uses short-circuit evaluation.",
+              "items": {
+                "type": "string"
+              }
+            }
+          },
+          "required": [
+            "type",
+            "string",
+            "list"
+          ],
+          "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "properties": {
+            "type": {
+              "type": "string",
+              "description": "A required string specifying the type of the condition.",
+              "const": "notInList"
+            },
+            "string": {
+              "type": "string",
+              "description": "A required string to search for. This field supports macro expansion."
+            },
+            "list": {
+              "type": "array",
+              "description": "A required list of strings to search. This field supports macro expansion, and uses short-circuit evaluation.",
+              "items": {
+                "type": "string"
+              }
+            }
+          },
+          "required": [
+            "type",
+            "string",
+            "list"
+          ],
+          "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "properties": {
+            "type": {
+              "type": "string",
+              "description": "A required string specifying the type of the condition.",
+              "const": "matches"
+            },
+            "string": {
+              "type": "string",
+              "description": "A required string to search. This field supports macro expansion."
+            },
+            "regex": {
+              "type": "string",
+              "description": "A required regular expression to search for. This field supports macro expansion."
+            }
+          },
+          "required": [
+            "type",
+            "string",
+            "regex"
+          ],
+          "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "properties": {
+            "type": {
+              "type": "string",
+              "description": "A required string specifying the type of the condition.",
+              "const": "notMatches"
+            },
+            "string": {
+              "type": "string",
+              "description": "A required string to search. This field supports macro expansion."
+            },
+            "regex": {
+              "type": "string",
+              "description": "A required regular expression to search for. This field supports macro expansion."
+            }
+          },
+          "required": [
+            "type",
+            "string",
+            "regex"
+          ],
+          "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "properties": {
+            "type": {
+              "type": "string",
+              "description": "A required string specifying the type of the condition.",
+              "const": "anyOf"
+            },
+            "conditions": {
+              "type": "array",
+              "description": "A required array of condition objects. These conditions use short-circuit evaluation.",
+              "items": { "$ref": "#/definitions/condition" }
+            }
+          },
+          "required": [
+            "type",
+            "conditions"
+          ],
+          "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "properties": {
+            "type": {
+              "type": "string",
+              "description": "A required string specifying the type of the condition.",
+              "const": "allOf"
+            },
+            "conditions": {
+              "type": "array",
+              "description": "A required array of condition objects. These conditions use short-circuit evaluation.",
+              "items": { "$ref": "#/definitions/condition" }
+            }
+          },
+          "required": [
+            "type",
+            "conditions"
+          ],
+          "additionalProperties": false
+        },
+        {
+          "type": "object",
+          "properties": {
+            "type": {
+              "type": "string",
+              "description": "A required string specifying the type of the condition.",
+              "const": "not"
+            },
+            "condition": { "$ref": "#/definitions/condition" }
+          },
+          "required": [
+            "type",
+            "condition"
+          ],
+          "additionalProperties": false
+        }
+      ]
+    },
+    "topCondition": {
+      "anyOf": [
+        { "$ref": "#/definitions/condition" },
+        {
+          "type": "null",
+          "description": "Null indicates that the condition always evaluates to true and is not inherited."
+        }
+      ]
     }
   }
 }
diff --git a/Help/policy/CMP0121.rst b/Help/policy/CMP0121.rst
new file mode 100644
index 0000000..5ef2856
--- /dev/null
+++ b/Help/policy/CMP0121.rst
@@ -0,0 +1,21 @@
+CMP0121
+-------
+
+.. versionadded:: 3.21
+
+The :command:`list` command now detects invalid indicies.
+
+Prior to CMake version 3.21, the :command:`list` command's ``GET``,
+``INSERT``, ``SUBLIST``, and ``REMOVE_AT`` subcommands did not detect invalid
+index arguments.
+
+The ``OLD`` behavior of this policy is for invalid indicies to be treated as
+their integer value (if any) at the start of the string. For example,
+``2good4you`` is a ``2`` and ``not_an_integer`` is a ``0``. The ``NEW``
+behavior is for invalid indicies to trigger an error.
+
+This policy was introduced in CMake version 3.21.  CMake version |release|
+warns when the policy is not set and uses ``OLD`` behavior. Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0122.rst b/Help/policy/CMP0122.rst
new file mode 100644
index 0000000..1ff8c48
--- /dev/null
+++ b/Help/policy/CMP0122.rst
@@ -0,0 +1,17 @@
+CMP0122
+-------
+
+.. versionadded:: 3.21
+
+:module:`UseSWIG` use library name conventions for ``CSharp`` language.
+
+Starting with CMake 3.21, :module:`UseSWIG` generates now a library using
+default naming conventions. This policy provides compatibility with projects
+that expect the legacy behavior.
+
+This policy was introduced in CMake version 3.21.  CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/prop_gbl/AUTOGEN_SOURCE_GROUP.rst b/Help/prop_gbl/AUTOGEN_SOURCE_GROUP.rst
index 2e32320..07c732b 100644
--- a/Help/prop_gbl/AUTOGEN_SOURCE_GROUP.rst
+++ b/Help/prop_gbl/AUTOGEN_SOURCE_GROUP.rst
@@ -3,15 +3,16 @@
 
 .. versionadded:: 3.9
 
-Name of the  :command:`source_group` for :prop_tgt:`AUTOMOC` and
-:prop_tgt:`AUTORCC` generated files.
+Name of the  :command:`source_group` for :prop_tgt:`AUTOMOC`,
+:prop_tgt:`AUTORCC` and :prop_tgt:`AUTOUIC` generated files.
 
-Files generated by :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTORCC` are not always
-known at configure time and therefore can't be passed to
-:command:`source_group`.
-:prop_gbl:`AUTOGEN_SOURCE_GROUP` an be used instead to generate or select
-a source group for :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTORCC` generated files.
+Files generated by :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTORCC` and
+:prop_tgt:`AUTOUIC` are not always known at configure time and therefore can't
+be passed to :command:`source_group`.
+:prop_gbl:`AUTOGEN_SOURCE_GROUP` can be used instead to generate or select
+a source group for :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTORCC` and
+:prop_tgt:`AUTOUIC` generated files.
 
-For :prop_tgt:`AUTOMOC` and :prop_tgt:`AUTORCC` specific overrides see
-:prop_gbl:`AUTOMOC_SOURCE_GROUP` and :prop_gbl:`AUTORCC_SOURCE_GROUP`
-respectively.
+For :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTORCC` and :prop_tgt:`AUTOUIC` specific
+overrides see :prop_gbl:`AUTOMOC_SOURCE_GROUP`, :prop_gbl:`AUTORCC_SOURCE_GROUP`
+and :prop_gbl:`AUTOUIC_SOURCE_GROUP` respectively.
diff --git a/Help/prop_gbl/AUTOUIC_SOURCE_GROUP.rst b/Help/prop_gbl/AUTOUIC_SOURCE_GROUP.rst
new file mode 100644
index 0000000..79ebfe0
--- /dev/null
+++ b/Help/prop_gbl/AUTOUIC_SOURCE_GROUP.rst
@@ -0,0 +1,9 @@
+AUTOUIC_SOURCE_GROUP
+--------------------
+
+.. versionadded:: 3.21
+
+Name of the  :command:`source_group` for :prop_tgt:`AUTOUIC` generated files.
+
+When set this is used instead of :prop_gbl:`AUTOGEN_SOURCE_GROUP` for
+files generated by :prop_tgt:`AUTOUIC`.
diff --git a/Help/prop_gbl/CMAKE_C_KNOWN_FEATURES.rst b/Help/prop_gbl/CMAKE_C_KNOWN_FEATURES.rst
index 7166381..2bd0feb 100644
--- a/Help/prop_gbl/CMAKE_C_KNOWN_FEATURES.rst
+++ b/Help/prop_gbl/CMAKE_C_KNOWN_FEATURES.rst
@@ -24,6 +24,12 @@
 ``c_std_11``
   Compiler mode is at least C 11.
 
+``c_std_17``
+  Compiler mode is at least C 17.
+
+``c_std_23``
+  Compiler mode is at least C 23.
+
 ``c_function_prototypes``
   Function prototypes, as defined in ``ISO/IEC 9899:1990``.
 
diff --git a/Help/prop_sf/GENERATED.rst b/Help/prop_sf/GENERATED.rst
index 6ef4580..216dfe8 100644
--- a/Help/prop_sf/GENERATED.rst
+++ b/Help/prop_sf/GENERATED.rst
@@ -32,9 +32,10 @@
 ``make clean``.
 
 Generated sources may be hidden in some IDE tools, while in others they might
-be shown. For the special case of sources generated by CMake's :prop_tgt:`AUTOMOC`
-or :prop_tgt:`AUTORCC` functionality, the :prop_gbl:`AUTOGEN_SOURCE_GROUP`,
-:prop_gbl:`AUTOMOC_SOURCE_GROUP` and :prop_gbl:`AUTORCC_SOURCE_GROUP` target
+be shown. For the special case of sources generated by CMake's :prop_tgt:`AUTOMOC`,
+:prop_tgt:`AUTORCC` or :prop_tgt:`AUTOUIC` functionality, the
+:prop_gbl:`AUTOGEN_SOURCE_GROUP`, :prop_gbl:`AUTOMOC_SOURCE_GROUP`,
+:prop_gbl:`AUTORCC_SOURCE_GROUP` and :prop_gbl:`AUTOUIC_SOURCE_GROUP` target
 properties may influence where the generated sources are grouped in the project's
 file lists.
 
diff --git a/Help/prop_tgt/C_STANDARD.rst b/Help/prop_tgt/C_STANDARD.rst
index 3f0d242..e22b775 100644
--- a/Help/prop_tgt/C_STANDARD.rst
+++ b/Help/prop_tgt/C_STANDARD.rst
@@ -11,7 +11,7 @@
 have no notion of a C standard level, such as Microsoft Visual C++ before
 VS 16.7, this property has no effect.
 
-Supported values are ``90``, ``99`` and ``11``.
+Supported values are ``90``, ``99``, ``11``, ``17``, ``23``.
 
 If the value requested does not result in a compile flag being added for
 the compiler in use, a previous standard flag will be added instead.  This
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/FindDevIL-imported-targets.rst b/Help/release/dev/FindDevIL-imported-targets.rst
new file mode 100644
index 0000000..aa0929e
--- /dev/null
+++ b/Help/release/dev/FindDevIL-imported-targets.rst
@@ -0,0 +1,4 @@
+FindDevIL
+---------
+
+* The :module:`FindDevIL` module now provides imported targets.
diff --git a/Help/release/dev/FindIconv-version.rst b/Help/release/dev/FindIconv-version.rst
new file mode 100644
index 0000000..3546d86
--- /dev/null
+++ b/Help/release/dev/FindIconv-version.rst
@@ -0,0 +1,4 @@
+FindIconv-version
+-----------------
+
+* The :module:`FindIconv` module now has version support.
diff --git a/Help/release/dev/FindIntl-version.rst b/Help/release/dev/FindIntl-version.rst
new file mode 100644
index 0000000..5365cf1
--- /dev/null
+++ b/Help/release/dev/FindIntl-version.rst
@@ -0,0 +1,4 @@
+FindIntl-version
+----------------
+
+* The :module:`FindIntl` module now has version support.
diff --git a/Help/release/dev/UseSWIG-csharp.rst b/Help/release/dev/UseSWIG-csharp.rst
new file mode 100644
index 0000000..dbbeaf1
--- /dev/null
+++ b/Help/release/dev/UseSWIG-csharp.rst
@@ -0,0 +1,5 @@
+UseSWIG-csharp
+--------------
+
+* The :module:`UseSWIG` module use now standard library name conventions for
+  ``CSharp`` language. See policy :policy:`CMP0122`.
diff --git a/Help/release/dev/add_custom_command-DEPFILE-genex.rst b/Help/release/dev/add_custom_command-DEPFILE-genex.rst
new file mode 100644
index 0000000..52e5e9f
--- /dev/null
+++ b/Help/release/dev/add_custom_command-DEPFILE-genex.rst
@@ -0,0 +1,5 @@
+add_custom_command-DEPFILE-genex
+--------------------------------
+
+* The :command:`add_custom_command` command ``DEPFILE`` option learned to
+  support :manual:`generator expressions <cmake-generator-expressions(7)>`.
diff --git a/Help/release/dev/c-std.rst b/Help/release/dev/c-std.rst
new file mode 100644
index 0000000..44daa85
--- /dev/null
+++ b/Help/release/dev/c-std.rst
@@ -0,0 +1,6 @@
+c-std
+-----
+
+* :prop_tgt:`C_STANDARD` and the
+  :manual:`Compile Features <cmake-compile-features(7)>` functionality gained
+  support for C17 and C23.
diff --git a/Help/release/dev/cmake-install-prefix-command.rst b/Help/release/dev/cmake-install-prefix-command.rst
new file mode 100644
index 0000000..2de5d91
--- /dev/null
+++ b/Help/release/dev/cmake-install-prefix-command.rst
@@ -0,0 +1,8 @@
+cmake-install-prefix-command
+----------------------------
+
+* The :manual:`cmake(1)` command gained the ``--install-prefix <dir>``
+  command line option to specify the location of the install prefix.
+
+* :manual:`cmake-presets(7)` configure preset gained support for specifying
+  the install prefix.
diff --git a/Help/release/dev/cmake-presets-condition.rst b/Help/release/dev/cmake-presets-condition.rst
new file mode 100644
index 0000000..aa01bc1
--- /dev/null
+++ b/Help/release/dev/cmake-presets-condition.rst
@@ -0,0 +1,4 @@
+cmake-presets-condition
+-----------------------
+
+* :manual:`cmake-presets(7)` now support conditional enabling of presets.
diff --git a/Help/release/dev/cmake-presets-host-system-name.rst b/Help/release/dev/cmake-presets-host-system-name.rst
new file mode 100644
index 0000000..8036939
--- /dev/null
+++ b/Help/release/dev/cmake-presets-host-system-name.rst
@@ -0,0 +1,5 @@
+cmake-presets-host-system-name
+------------------------------
+
+* :manual:`cmake-presets(7)` gained support for a new ``${hostSystemName}``
+  macro.
diff --git a/Help/release/dev/cmake-presets-optional-generator-and-binarydir.rst b/Help/release/dev/cmake-presets-optional-generator-and-binarydir.rst
new file mode 100644
index 0000000..7973489
--- /dev/null
+++ b/Help/release/dev/cmake-presets-optional-generator-and-binarydir.rst
@@ -0,0 +1,5 @@
+cmake-presets-optional-generator-and-binarydir
+----------------------------------------------
+
+* :manual:`cmake-presets(7)` now support omitting the ``generator`` and
+  ``binaryDir`` fields.
diff --git a/Help/release/dev/cmake-system-name-version.rst b/Help/release/dev/cmake-system-name-version.rst
new file mode 100644
index 0000000..9cfe401
--- /dev/null
+++ b/Help/release/dev/cmake-system-name-version.rst
@@ -0,0 +1,10 @@
+cmake-system-name-version
+-------------------------
+
+* :variable:`CMAKE_HOST_SYSTEM_NAME`'s undocumented version-stripping behavior
+  has been moved earlier, before :command:`project` or
+  :command:`enable_language` is called.
+* :variable:`CMAKE_SYSTEM_NAME`'s undocumented version-stripping behavior has
+  been removed entirely. If it is set by a ``-D`` flag or by a
+  :manual:`toolchain file <cmake-toolchains(7)>`, it is left unaltered, even if
+  it still contains a version number.
diff --git a/Help/release/dev/cpack-dmg-filesystem.rst b/Help/release/dev/cpack-dmg-filesystem.rst
new file mode 100644
index 0000000..e2a4742
--- /dev/null
+++ b/Help/release/dev/cpack-dmg-filesystem.rst
@@ -0,0 +1,5 @@
+cpack-dmg-filesystem
+--------------------
+
+* The :cpack_gen:`CPack DragNDrop Generator` gained option
+  :variable:`CPACK_DMG_FILESYSTEM` to control the ``.dmg`` filesystem.
diff --git a/Help/release/dev/cpack-nsis-executable-name.rst b/Help/release/dev/cpack-nsis-executable-name.rst
new file mode 100644
index 0000000..a3818db
--- /dev/null
+++ b/Help/release/dev/cpack-nsis-executable-name.rst
@@ -0,0 +1,6 @@
+cpack-nsis-executable-name
+--------------------------
+
+* The :cpack_gen:`CPack NSIS Generator` gained a new variable
+  :variable:`CPACK_NSIS_EXECUTABLE` to specify the makensis
+  executable to use instead of the default one.
diff --git a/Help/release/dev/cxx-module-extensions.rst b/Help/release/dev/cxx-module-extensions.rst
new file mode 100644
index 0000000..b9d0a8a
--- /dev/null
+++ b/Help/release/dev/cxx-module-extensions.rst
@@ -0,0 +1,4 @@
+cxx-module-extensions
+---------------------
+
+* Source file extensions ``.ixx`` and ``.cppm`` are now treated as C++.
diff --git a/Help/release/dev/file-COPY_FILE.rst b/Help/release/dev/file-COPY_FILE.rst
new file mode 100644
index 0000000..2f0cdf0
--- /dev/null
+++ b/Help/release/dev/file-COPY_FILE.rst
@@ -0,0 +1,4 @@
+file-COPY_ONLY
+--------------
+
+* The :command:`file(COPY_FILE)` command was added to copy a file to another.
diff --git a/Help/release/dev/file-RENAME.rst b/Help/release/dev/file-RENAME.rst
new file mode 100644
index 0000000..6c1314d
--- /dev/null
+++ b/Help/release/dev/file-RENAME.rst
@@ -0,0 +1,6 @@
+file-RENAME
+-----------
+
+* The :command:`file(RENAME)` command learned to optionally capture
+  failure in a result variable.  It also gained a ``NO_REPLACE``
+  option to fail if the destination exists.
diff --git a/Help/release/dev/fileapi-codemodel-directory.rst b/Help/release/dev/fileapi-codemodel-directory.rst
new file mode 100644
index 0000000..f6515fd
--- /dev/null
+++ b/Help/release/dev/fileapi-codemodel-directory.rst
@@ -0,0 +1,10 @@
+fileapi-codemodel-directory
+---------------------------
+
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 ``version`` field has
+  component been updated to 2.3.
+
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 gained a
+  new "directory" object containing directory-level information.
+  This includes a list of installers generated by the :command:`install`
+  command.
diff --git a/Help/release/dev/fujitsu-compiler-support.rst b/Help/release/dev/fujitsu-compiler-support.rst
new file mode 100644
index 0000000..c6f8cfb
--- /dev/null
+++ b/Help/release/dev/fujitsu-compiler-support.rst
@@ -0,0 +1,11 @@
+fujitsu-compiler-support
+------------------------
+
+* Addition of the ``Fujitsu`` compiler ID operating in traditional ``Trad``
+  mode and ``FujitsuClang`` operating in ``Clang`` mode.
+* The :module:`FindOpenMP` module learned to support ``Fujitsu`` and
+  ``FujitsuClang``.
+* The :module:`FindMPI` module learned to support ``Fujitsu`` and
+  ``FujitsuClang`` in both host and cross compiling modes.
+* The :module:`FindBLAS` and :module:`FindLAPACK` modules learned to support
+  the serial ``Fujitsu SSL2`` and parallel ``Fujitsu SSL2BLAMP`` libraries.
diff --git a/Help/release/dev/ifw-default-version-operator.rst b/Help/release/dev/ifw-default-version-operator.rst
new file mode 100644
index 0000000..4aeace2
--- /dev/null
+++ b/Help/release/dev/ifw-default-version-operator.rst
@@ -0,0 +1,7 @@
+ifw-default-version-operator
+----------------------------
+
+* Names given as ``DEPENDS`` or ``DEPENDENCIES`` arguments to
+  :command:`cpack_ifw_configure_component` or
+  :command:`cpack_ifw_configure_component_group` may now contain hyphens.
+  This requires QtIFW 3.1 or later.
diff --git a/Help/release/dev/list-index-arg-parsing.rst b/Help/release/dev/list-index-arg-parsing.rst
new file mode 100644
index 0000000..2ea525b
--- /dev/null
+++ b/Help/release/dev/list-index-arg-parsing.rst
@@ -0,0 +1,7 @@
+list-index-arg-parsing
+----------------------
+
+* The :command:`list` command's ``GET``, ``INSERT``, ``SUBLIST``, and
+  ``REMOVE_AT`` subcommands now error with invalid (i.e., non-integer) values
+  are given as any of their index arguments based on the setting of policy
+  :policy:`CMP0121`.
diff --git a/Help/release/dev/project-is-top-level.rst b/Help/release/dev/project-is-top-level.rst
new file mode 100644
index 0000000..568afe0
--- /dev/null
+++ b/Help/release/dev/project-is-top-level.rst
@@ -0,0 +1,6 @@
+project-is-top-level
+--------------------
+
+* :command:`project` now sets variables :variable:`PROJECT_IS_TOP_LEVEL` and
+  :variable:`<PROJECT-NAME>_IS_TOP_LEVEL` to indicate whether it was called
+  in a top level ``CMakeLists.txt`` file.
diff --git a/Help/release/dev/runtime-dll-deps.rst b/Help/release/dev/runtime-dll-deps.rst
new file mode 100644
index 0000000..831410f
--- /dev/null
+++ b/Help/release/dev/runtime-dll-deps.rst
@@ -0,0 +1,4 @@
+runtime-dll-deps
+----------------
+
+* A new :genex:`TARGET_RUNTIME_DLLS` generator expression was added.
diff --git a/Help/release/index.rst b/Help/release/index.rst
index 95b41fb..5dfca05 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_GENERATOR_TOOLSET.rst b/Help/variable/CMAKE_GENERATOR_TOOLSET.rst
index 53ad2f3..45f2d32 100644
--- a/Help/variable/CMAKE_GENERATOR_TOOLSET.rst
+++ b/Help/variable/CMAKE_GENERATOR_TOOLSET.rst
@@ -63,3 +63,27 @@
   Specify an alternative ``VCTargetsPath`` value for Visual Studio
   project files.  This allows use of VS platform extension configuration
   files (``.props`` and ``.targets``) that are not installed with VS.
+
+Visual Studio Toolset Customization
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+**These are unstable interfaces with no compatibility guarantees**
+because they hook into undocumented internal CMake implementation details.
+Institutions may use these to internally maintain support for non-public
+Visual Studio platforms and toolsets, but must accept responsibility to
+make updates as changes are made to CMake.
+
+Additional ``key=value`` pairs are available:
+
+``customFlagTableDir=<path>``
+  .. versionadded:: 3.21
+
+  Specify the absolute path to a directory from which to load custom
+  flag tables stored as JSON documents with file names of the form
+  ``<platform>_<toolset>_<tool>.json`` or ``<platform>_<tool>.json``,
+  where ``<platform>`` is the :variable:`CMAKE_VS_PLATFORM_NAME`,
+  ``<toolset>`` is the :variable:`CMAKE_VS_PLATFORM_TOOLSET`,
+  and ``<tool>`` is the tool for which the flag table is meant.
+  **This naming pattern is an internal CMake implementation detail.**
+  The ``<tool>`` names are undocumented.  The format of the ``.json``
+  flag table files is undocumented.
diff --git a/Help/variable/CMAKE_LANG_COMPILER_ID.rst b/Help/variable/CMAKE_LANG_COMPILER_ID.rst
index 89d9e27..0abedde 100644
--- a/Help/variable/CMAKE_LANG_COMPILER_ID.rst
+++ b/Help/variable/CMAKE_LANG_COMPILER_ID.rst
@@ -19,6 +19,8 @@
   Cray = Cray Compiler (cray.com)
   Embarcadero, Borland = Embarcadero (embarcadero.com)
   Flang = Flang LLVM Fortran Compiler
+  Fujitsu = Fujitsu HPC compiler (Trad mode)
+  FujitsuClang = Fujitsu HPC compiler (Clang mode)
   G95 = G95 Fortran (g95.org)
   GNU = GNU Compiler Collection (gcc.gnu.org)
   GHS = Green Hills Software (www.ghs.com)
diff --git a/Help/variable/CMAKE_LANG_FLAGS.rst b/Help/variable/CMAKE_LANG_FLAGS.rst
index 14b2694..11864f8 100644
--- a/Help/variable/CMAKE_LANG_FLAGS.rst
+++ b/Help/variable/CMAKE_LANG_FLAGS.rst
@@ -15,3 +15,6 @@
   Initialized by the :envvar:`CUDAFLAGS` environment variable.
 * ``CMAKE_Fortran_FLAGS``:
   Initialized by the :envvar:`FFLAGS` environment variable.
+
+This value is a command-line string fragment. Therefore, multiple options
+should be separated by spaces, and options with spaces should be quoted.
diff --git a/Help/variable/CMAKE_LANG_FLAGS_INIT.rst b/Help/variable/CMAKE_LANG_FLAGS_INIT.rst
index 67ff2cb..ca13a29 100644
--- a/Help/variable/CMAKE_LANG_FLAGS_INIT.rst
+++ b/Help/variable/CMAKE_LANG_FLAGS_INIT.rst
@@ -12,6 +12,8 @@
 where ``xxx`` will be language-specific but not necessarily the same as
 ``<LANG>`` (e.g. :envvar:`CXXFLAGS` for ``CXX``, :envvar:`FFLAGS` for
 ``Fortran``, and so on).
+This value is a command-line string fragment. Therefore, multiple options
+should be separated by spaces, and options with spaces should be quoted.
 
 See also the configuration-specific
 :variable:`CMAKE_<LANG>_FLAGS_<CONFIG>_INIT` variable.
diff --git a/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR.rst b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR.rst
index 74db6b1..a19e7e1 100644
--- a/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR.rst
+++ b/Help/variable/CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR.rst
@@ -9,10 +9,9 @@
 a standalone (non-installed) NVIDIA CUDA toolkit.  The path
 may be specified by a field in :variable:`CMAKE_GENERATOR_TOOLSET` of
 the form ``cuda=C:\path\to\cuda``.  The given directory must at least
-contain a folder ``.\nvcc`` and must provide Visual Studio integration
-files in path ``.\CUDAVisualStudioIntegration\extras\
-visual_studio_integration\MSBuildExtensions\``. One can create a standalone
-CUDA toolkit directory by either opening a installer with 7zip or
-copying the files that are extracted by the running installer.
-The value may be empty if no path to a standalone CUDA Toolkit was
-specified.
+contain the nvcc compiler in path ``.\bin`` and must provide Visual Studio
+integration files in path ``.\extras\visual_studio_integration\
+MSBuildExtensions\``. One can create a standalone CUDA toolkit directory by
+either opening a installer with 7zip or copying the files that are extracted
+by the running installer. The value may be empty if no path to a standalone
+CUDA Toolkit was specified.
diff --git a/Help/variable/PROJECT-NAME_IS_TOP_LEVEL.rst b/Help/variable/PROJECT-NAME_IS_TOP_LEVEL.rst
new file mode 100644
index 0000000..953e978
--- /dev/null
+++ b/Help/variable/PROJECT-NAME_IS_TOP_LEVEL.rst
@@ -0,0 +1,11 @@
+<PROJECT-NAME>_IS_TOP_LEVEL
+---------------------------
+
+.. versionadded:: 3.21
+
+A boolean variable indicating whether the named project was called in a top
+level ``CMakeLists.txt`` file.
+
+To obtain the value from the most recent call to :command:`project` in
+the current directory scope or above, see the
+:variable:`PROJECT_IS_TOP_LEVEL` variable.
diff --git a/Help/variable/PROJECT_IS_TOP_LEVEL.rst b/Help/variable/PROJECT_IS_TOP_LEVEL.rst
new file mode 100644
index 0000000..e5eb6c1
--- /dev/null
+++ b/Help/variable/PROJECT_IS_TOP_LEVEL.rst
@@ -0,0 +1,21 @@
+PROJECT_IS_TOP_LEVEL
+--------------------
+
+.. versionadded:: 3.21
+
+A boolean variable indicating whether :command:`project` was called in a top
+level ``CMakeLists.txt`` file.
+
+Some modules should only be included as part of the top level
+``CMakeLists.txt`` file to not cause unintended side effects in the build
+tree, and this variable can be used to conditionally execute such code. For
+example, consider the :module:`CTest` module, which creates targets and
+options:
+
+.. code-block:: cmake
+
+  project(MyProject)
+  ...
+  if(PROJECT_IS_TOP_LEVEL)
+    include(CTest)
+  endif()
diff --git a/Modules/CMakeASM_NASMInformation.cmake b/Modules/CMakeASM_NASMInformation.cmake
index 97cb488..27b93ec 100644
--- a/Modules/CMakeASM_NASMInformation.cmake
+++ b/Modules/CMakeASM_NASMInformation.cmake
@@ -38,6 +38,15 @@
   set(CMAKE_ASM_NASM_COMPILE_OBJECT "<CMAKE_ASM_NASM_COMPILER> <INCLUDES> <FLAGS> -f ${CMAKE_ASM_NASM_OBJECT_FORMAT} -o <OBJECT> <SOURCE>")
 endif()
 
+set(CMAKE_DEPFILE_FLAGS_ASM_NASM "-MD <DEP_FILE> -MT <DEP_TARGET>")
+
+if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
+    AND CMAKE_GENERATOR MATCHES "Makefiles|WMake")
+  # dependencies are computed by the compiler itself
+  set(CMAKE_ASM_NASM_DEPFILE_FORMAT gcc)
+  set(CMAKE_ASM_NASM_DEPENDS_USE_COMPILER TRUE)
+endif()
+
 # Load the generic ASMInformation file:
 set(ASM_DIALECT "_NASM")
 include(CMakeASMInformation)
diff --git a/Modules/CMakeCCompiler.cmake.in b/Modules/CMakeCCompiler.cmake.in
index 7f73891..754f235 100644
--- a/Modules/CMakeCCompiler.cmake.in
+++ b/Modules/CMakeCCompiler.cmake.in
@@ -9,6 +9,8 @@
 set(CMAKE_C90_COMPILE_FEATURES "@CMAKE_C90_COMPILE_FEATURES@")
 set(CMAKE_C99_COMPILE_FEATURES "@CMAKE_C99_COMPILE_FEATURES@")
 set(CMAKE_C11_COMPILE_FEATURES "@CMAKE_C11_COMPILE_FEATURES@")
+set(CMAKE_C17_COMPILE_FEATURES "@CMAKE_C17_COMPILE_FEATURES@")
+set(CMAKE_C23_COMPILE_FEATURES "@CMAKE_C23_COMPILE_FEATURES@")
 
 set(CMAKE_C_PLATFORM_ID "@CMAKE_C_PLATFORM_ID@")
 set(CMAKE_C_SIMULATE_ID "@CMAKE_C_SIMULATE_ID@")
diff --git a/Modules/CMakeCCompilerId.c.in b/Modules/CMakeCCompilerId.c.in
index 14e1282..75e9d1a 100644
--- a/Modules/CMakeCCompilerId.c.in
+++ b/Modules/CMakeCCompilerId.c.in
@@ -33,13 +33,16 @@
 @CMAKE_C_COMPILER_ID_PLATFORM_CONTENT@
 @CMAKE_C_COMPILER_ID_ERROR_FOR_TEST@
 
-#if !defined(__STDC__)
-# if (defined(_MSC_VER) && !defined(__clang__)) \
-  || (defined(__ibmxl__) || defined(__IBMC__))
+#if !defined(__STDC__) && !defined(__clang__)
+# if defined(_MSC_VER) || defined(__ibmxl__) || defined(__IBMC__)
 #  define C_DIALECT "90"
 # else
 #  define C_DIALECT
 # endif
+#elif __STDC_VERSION__ > 201710L
+# define C_DIALECT "23"
+#elif __STDC_VERSION__ >= 201710L
+# define C_DIALECT "17"
 #elif __STDC_VERSION__ >= 201000L
 # define C_DIALECT "11"
 #elif __STDC_VERSION__ >= 199901L
diff --git a/Modules/CMakeCUDAInformation.cmake b/Modules/CMakeCUDAInformation.cmake
index 5fd54c1..44e2c2c 100644
--- a/Modules/CMakeCUDAInformation.cmake
+++ b/Modules/CMakeCUDAInformation.cmake
@@ -9,15 +9,15 @@
 set(CMAKE_INCLUDE_FLAG_CUDA "-I")
 
 # Set implicit links early so compiler-specific modules can use them.
-set(__IMPLICT_LINKS )
+set(__IMPLICIT_LINKS)
 foreach(dir ${CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES})
-  string(APPEND __IMPLICT_LINKS " -L\"${dir}\"")
+  string(APPEND __IMPLICIT_LINKS " -L\"${dir}\"")
 endforeach()
 foreach(lib ${CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES})
   if(${lib} MATCHES "/")
-    string(APPEND __IMPLICT_LINKS " \"${lib}\"")
+    string(APPEND __IMPLICIT_LINKS " \"${lib}\"")
   else()
-    string(APPEND __IMPLICT_LINKS " -l${lib}")
+    string(APPEND __IMPLICIT_LINKS " -l${lib}")
   endif()
 endforeach()
 
@@ -120,7 +120,7 @@
 # create a shared library
 if(NOT CMAKE_CUDA_CREATE_SHARED_LIBRARY)
   set(CMAKE_CUDA_CREATE_SHARED_LIBRARY
-      "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>${__IMPLICT_LINKS}")
+      "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
 endif()
 
 # create a shared module copy the shared library rule by default
@@ -160,32 +160,32 @@
 # compile a cu file into an executable
 if(NOT CMAKE_CUDA_LINK_EXECUTABLE)
   set(CMAKE_CUDA_LINK_EXECUTABLE
-    "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICT_LINKS}")
+    "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
 endif()
 
 # Add implicit host link directories that contain device libraries
 # to the device link line.
-set(__IMPLICT_DLINK_DIRS ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
-if(__IMPLICT_DLINK_DIRS)
-  list(REMOVE_ITEM __IMPLICT_DLINK_DIRS ${CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES})
+set(__IMPLICIT_DLINK_DIRS ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+if(__IMPLICIT_DLINK_DIRS)
+  list(REMOVE_ITEM __IMPLICIT_DLINK_DIRS ${CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES})
 endif()
-set(__IMPLICT_DLINK_FLAGS )
-foreach(dir ${__IMPLICT_DLINK_DIRS})
+set(__IMPLICIT_DLINK_FLAGS)
+foreach(dir ${__IMPLICIT_DLINK_DIRS})
   if(EXISTS "${dir}/libcurand_static.a")
-    string(APPEND __IMPLICT_DLINK_FLAGS " -L\"${dir}\"")
+    string(APPEND __IMPLICIT_DLINK_FLAGS " -L\"${dir}\"")
   endif()
 endforeach()
-unset(__IMPLICT_DLINK_DIRS)
+unset(__IMPLICIT_DLINK_DIRS)
 
 
 #These are used when linking relocatable (dc) cuda code
 if(NOT CMAKE_CUDA_DEVICE_LINK_LIBRARY)
   set(CMAKE_CUDA_DEVICE_LINK_LIBRARY
-    "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICT_DLINK_FLAGS}")
+    "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICIT_DLINK_FLAGS}")
 endif()
 if(NOT CMAKE_CUDA_DEVICE_LINK_EXECUTABLE)
   set(CMAKE_CUDA_DEVICE_LINK_EXECUTABLE
-    "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICT_DLINK_FLAGS}")
+    "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${CMAKE_CUDA_COMPILE_OPTIONS_PIC} ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICIT_DLINK_FLAGS}")
 endif()
 
 # Used when device linking is handled by CMake.
@@ -193,6 +193,6 @@
   set(CMAKE_CUDA_DEVICE_LINK_COMPILE "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <FLAGS> -D__CUDA_INCLUDE_COMPILER_INTERNAL_HEADERS__ -D__NV_EXTRA_INITIALIZATION=\"\" -D__NV_EXTRA_FINALIZATION=\"\" -DREGISTERLINKBINARYFILE=\\\"<REGISTER_FILE>\\\" -DFATBINFILE=\\\"<FATBINARY>\\\" ${_CMAKE_COMPILE_AS_CUDA_FLAG} -c \"${CMAKE_CUDA_COMPILER_TOOLKIT_LIBRARY_ROOT}/bin/crt/link.stub\" -o <OBJECT>")
 endif()
 
-unset(__IMPLICT_DLINK_FLAGS)
+unset(__IMPLICIT_DLINK_FLAGS)
 
 set(CMAKE_CUDA_INFORMATION_LOADED 1)
diff --git a/Modules/CMakeCXXCompiler.cmake.in b/Modules/CMakeCXXCompiler.cmake.in
index 45acfe7..d0ce77a 100644
--- a/Modules/CMakeCXXCompiler.cmake.in
+++ b/Modules/CMakeCXXCompiler.cmake.in
@@ -44,7 +44,7 @@
   set(MINGW 1)
 endif()
 set(CMAKE_CXX_COMPILER_ID_RUN 1)
-set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;mpp;CPP)
+set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;mpp;CPP;ixx;cppm)
 set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC)
 
 foreach (lang C OBJC OBJCXX)
diff --git a/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake b/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
index 2dc75d6..05174de 100644
--- a/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
+++ b/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake
@@ -8,7 +8,7 @@
 
 macro (CHECK_COMPILER_FLAG_COMMON_PATTERNS _VAR)
   set(${_VAR}
-    FAIL_REGEX "[Uu]nrecogni[sz]ed .*option"               # GNU, NAG
+    FAIL_REGEX "[Uu]nrecogni[sz]ed .*option"               # GNU, NAG, Fujitsu
     FAIL_REGEX "switch .* is no longer supported"          # GNU
     FAIL_REGEX "unknown .*option"                          # Clang
     FAIL_REGEX "optimization flag .* not supported"        # Clang
diff --git a/Modules/CMakeCompilerIdDetection.cmake b/Modules/CMakeCompilerIdDetection.cmake
index 214d58a..c79d423 100644
--- a/Modules/CMakeCompilerIdDetection.cmake
+++ b/Modules/CMakeCompilerIdDetection.cmake
@@ -66,6 +66,7 @@
       PGI
       Cray
       TI
+      FujitsuClang
       Fujitsu
       GHS
     )
diff --git a/Modules/CMakeDetermineCUDACompiler.cmake b/Modules/CMakeDetermineCUDACompiler.cmake
index 1ba537a..0f507ea 100644
--- a/Modules/CMakeDetermineCUDACompiler.cmake
+++ b/Modules/CMakeDetermineCUDACompiler.cmake
@@ -31,7 +31,9 @@
       set(CMAKE_CUDA_COMPILER_LIST nvcc)
     endif()
 
+    set(_CMAKE_CUDA_COMPILER_PATHS "$ENV{CUDA_PATH}/bin")
     _cmake_find_compiler(CUDA)
+    unset(_CMAKE_CUDA_COMPILER_PATHS)
   else()
     _cmake_find_compiler_path(CUDA)
   endif()
diff --git a/Modules/CMakeDetermineCompileFeatures.cmake b/Modules/CMakeDetermineCompileFeatures.cmake
index c03a85f..f767847 100644
--- a/Modules/CMakeDetermineCompileFeatures.cmake
+++ b/Modules/CMakeDetermineCompileFeatures.cmake
@@ -10,6 +10,8 @@
     set(CMAKE_C90_COMPILE_FEATURES)
     set(CMAKE_C99_COMPILE_FEATURES)
     set(CMAKE_C11_COMPILE_FEATURES)
+    set(CMAKE_C17_COMPILE_FEATURES)
+    set(CMAKE_C23_COMPILE_FEATURES)
 
     include("${CMAKE_ROOT}/Modules/Internal/FeatureTesting.cmake")
 
@@ -20,6 +22,12 @@
       return()
     endif()
 
+    if (CMAKE_C17_COMPILE_FEATURES AND CMAKE_C23_COMPILE_FEATURES)
+      list(REMOVE_ITEM CMAKE_C23_COMPILE_FEATURES ${CMAKE_C17_COMPILE_FEATURES})
+    endif()
+    if (CMAKE_C11_COMPILE_FEATURES AND CMAKE_C17_COMPILE_FEATURES)
+      list(REMOVE_ITEM CMAKE_C17_COMPILE_FEATURES ${CMAKE_C11_COMPILE_FEATURES})
+    endif()
     if (CMAKE_C99_COMPILE_FEATURES AND CMAKE_C11_COMPILE_FEATURES)
       list(REMOVE_ITEM CMAKE_C11_COMPILE_FEATURES ${CMAKE_C99_COMPILE_FEATURES})
     endif()
@@ -32,6 +40,8 @@
         ${CMAKE_C90_COMPILE_FEATURES}
         ${CMAKE_C99_COMPILE_FEATURES}
         ${CMAKE_C11_COMPILE_FEATURES}
+        ${CMAKE_C17_COMPILE_FEATURES}
+        ${CMAKE_C23_COMPILE_FEATURES}
       )
     endif()
 
@@ -39,6 +49,8 @@
     set(CMAKE_C90_COMPILE_FEATURES ${CMAKE_C90_COMPILE_FEATURES} PARENT_SCOPE)
     set(CMAKE_C99_COMPILE_FEATURES ${CMAKE_C99_COMPILE_FEATURES} PARENT_SCOPE)
     set(CMAKE_C11_COMPILE_FEATURES ${CMAKE_C11_COMPILE_FEATURES} PARENT_SCOPE)
+    set(CMAKE_C17_COMPILE_FEATURES ${CMAKE_C17_COMPILE_FEATURES} PARENT_SCOPE)
+    set(CMAKE_C23_COMPILE_FEATURES ${CMAKE_C23_COMPILE_FEATURES} PARENT_SCOPE)
 
     message(CHECK_PASS "done")
 
diff --git a/Modules/CMakeDetermineCompiler.cmake b/Modules/CMakeDetermineCompiler.cmake
index 2780399..6430793 100644
--- a/Modules/CMakeDetermineCompiler.cmake
+++ b/Modules/CMakeDetermineCompiler.cmake
@@ -68,6 +68,16 @@
       )
   endif()
   find_program(CMAKE_${lang}_COMPILER NAMES ${CMAKE_${lang}_COMPILER_LIST} DOC "${lang} compiler")
+  if(_CMAKE_${lang}_COMPILER_PATHS)
+    # As a last fall-back, search in language-specific paths
+    find_program(CMAKE_${lang}_COMPILER
+      NAMES ${CMAKE_${lang}_COMPILER_LIST}
+      NAMES_PER_DIR
+      PATHS ${_CMAKE_${lang}_COMPILER_PATHS}
+      DOC "${lang} compiler"
+      NO_DEFAULT_PATH
+      )
+  endif()
   if(CMAKE_${lang}_COMPILER_INIT AND NOT CMAKE_${lang}_COMPILER)
     set_property(CACHE CMAKE_${lang}_COMPILER PROPERTY VALUE "${CMAKE_${lang}_COMPILER_INIT}")
   endif()
diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake
index ad9503c..d7b7f26 100644
--- a/Modules/CMakeDetermineCompilerId.cmake
+++ b/Modules/CMakeDetermineCompilerId.cmake
@@ -166,6 +166,25 @@
     endif()
   endif()
 
+  # The Fujitsu compiler does not always convey version information through
+  # preprocessor symbols so we extract through command line info
+  if (CMAKE_${lang}_COMPILER_ID STREQUAL "Fujitsu")
+    if(NOT CMAKE_${lang}_COMPILER_VERSION)
+      execute_process(
+        COMMAND "${CMAKE_${lang}_COMPILER}" -V
+        OUTPUT_VARIABLE output
+        ERROR_VARIABLE output
+        RESULT_VARIABLE result
+        TIMEOUT 10
+      )
+      if (result EQUAL 0)
+        if (output MATCHES [[Fujitsu [^ ]* Compiler ([0-9]+\.[0-9]+\.[0-9]+)]])
+          set(CMAKE_${lang}_COMPILER_VERSION "${CMAKE_MATCH_1}")
+        endif()
+      endif()
+    endif()
+  endif()
+
   # if the format is unknown after all files have been checked, put "Unknown" in the cache
   if(NOT CMAKE_EXECUTABLE_FORMAT)
     set(CMAKE_EXECUTABLE_FORMAT "Unknown" CACHE INTERNAL "Executable file format")
@@ -453,9 +472,19 @@
       set(id_ItemDefinitionGroup_entry "<CudaCompile>${cuda_target}<AdditionalOptions>%(AdditionalOptions)-v</AdditionalOptions><CodeGeneration>${cuda_codegen}</CodeGeneration></CudaCompile>")
       set(id_PostBuildEvent_Command [[echo CMAKE_CUDA_COMPILER=$(CudaToolkitBinDir)\nvcc.exe]])
       if(CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR)
-        set(id_CudaToolkitCustomDir "<CudaToolkitCustomDir>${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}nvcc</CudaToolkitCustomDir>")
-        string(CONCAT id_Import_props "<Import Project=\"${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}\\CUDAVisualStudioIntegration\\extras\\visual_studio_integration\\MSBuildExtensions\\${cuda_tools}.props\" />")
-        string(CONCAT id_Import_targets "<Import Project=\"${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}\\CUDAVisualStudioIntegration\\extras\\visual_studio_integration\\MSBuildExtensions\\${cuda_tools}.targets\" />")
+        # check for legacy cuda custom toolkit folder structure
+        if(EXISTS ${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}nvcc)
+            set(id_CudaToolkitCustomDir "<CudaToolkitCustomDir>${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}nvcc</CudaToolkitCustomDir>")
+        else()
+            set(id_CudaToolkitCustomDir "<CudaToolkitCustomDir>${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}</CudaToolkitCustomDir>")
+        endif()
+        if(EXISTS ${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}CUDAVisualStudioIntegration)
+            string(CONCAT id_Import_props "<Import Project=\"${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}CUDAVisualStudioIntegration\\extras\\visual_studio_integration\\MSBuildExtensions\\${cuda_tools}.props\" />")
+            string(CONCAT id_Import_targets "<Import Project=\"${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}CUDAVisualStudioIntegration\\extras\\visual_studio_integration\\MSBuildExtensions\\${cuda_tools}.targets\" />")
+        else()
+            string(CONCAT id_Import_props "<Import Project=\"${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}\\extras\\visual_studio_integration\\MSBuildExtensions\\${cuda_tools}.props\" />")
+            string(CONCAT id_Import_targets "<Import Project=\"${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}\\extras\\visual_studio_integration\\MSBuildExtensions\\${cuda_tools}.targets\" />")
+        endif()
       else()
         string(CONCAT id_Import_props [[<Import Project="$(VCTargetsPath)\BuildCustomizations\]] "${cuda_tools}" [[.props" />]])
         string(CONCAT id_Import_targets [[<Import Project="$(VCTargetsPath)\BuildCustomizations\]] "${cuda_tools}" [[.targets" />]])
@@ -821,8 +850,10 @@
         string(REGEX REPLACE "\\.0+([0-9])" ".\\1" COMPILER_VERSION "${COMPILER_VERSION}")
       endif()
       if("${info}" MATCHES "INFO:compiler_version_internal\\[([^]\"]*)\\]")
-        string(REGEX REPLACE "^0+([0-9])" "\\1" COMPILER_VERSION_INTERNAL "${CMAKE_MATCH_1}")
-        string(REGEX REPLACE "\\.0+([0-9])" ".\\1" COMPILER_VERSION_INTERNAL "${COMPILER_VERSION_INTERNAL}")
+        set(COMPILER_VERSION_INTERNAL "${CMAKE_MATCH_1}")
+        string(REGEX REPLACE "^0+([0-9]+)" "\\1" COMPILER_VERSION_INTERNAL "${COMPILER_VERSION_INTERNAL}")
+        string(REGEX REPLACE "\\.0+([0-9]+)" ".\\1" COMPILER_VERSION_INTERNAL "${COMPILER_VERSION_INTERNAL}")
+        string(STRIP "${COMPILER_VERSION_INTERNAL}" COMPILER_VERSION_INTERNAL)
       endif()
       foreach(comp MAJOR MINOR PATCH TWEAK)
         foreach(digit 1 2 3 4 5 6 7 8 9)
diff --git a/Modules/CMakeDetermineSystem.cmake b/Modules/CMakeDetermineSystem.cmake
index bae270d..c3f2b74 100644
--- a/Modules/CMakeDetermineSystem.cmake
+++ b/Modules/CMakeDetermineSystem.cmake
@@ -158,37 +158,14 @@
 
 include(Platform/${CMAKE_SYSTEM_NAME}-Determine OPTIONAL)
 
-macro(ADJUST_CMAKE_SYSTEM_VARIABLES _PREFIX)
-  if(NOT ${_PREFIX}_NAME)
-    set(${_PREFIX}_NAME "UnknownOS")
-  endif()
-
-  # fix for BSD/OS , remove the /
-  if(${_PREFIX}_NAME MATCHES BSD.OS)
-    set(${_PREFIX}_NAME BSDOS)
-  endif()
-
-  # fix for GNU/kFreeBSD, remove the GNU/
-  if(${_PREFIX}_NAME MATCHES kFreeBSD)
-    set(${_PREFIX}_NAME kFreeBSD)
-  endif()
-
-  # fix for CYGWIN which has windows version in it
-  if(${_PREFIX}_NAME MATCHES CYGWIN)
-    set(${_PREFIX}_NAME CYGWIN)
-  endif()
-
-  # set CMAKE_SYSTEM to the CMAKE_SYSTEM_NAME
-  set(${_PREFIX}  ${${_PREFIX}_NAME})
-  # if there is a CMAKE_SYSTEM_VERSION then add a -${CMAKE_SYSTEM_VERSION}
-  if(${_PREFIX}_VERSION)
-    set(${_PREFIX} ${${_PREFIX}}-${${_PREFIX}_VERSION})
-  endif()
-
-endmacro()
-
-ADJUST_CMAKE_SYSTEM_VARIABLES(CMAKE_SYSTEM)
-ADJUST_CMAKE_SYSTEM_VARIABLES(CMAKE_HOST_SYSTEM)
+set(CMAKE_SYSTEM ${CMAKE_SYSTEM_NAME})
+if(CMAKE_SYSTEM_VERSION)
+  string(APPEND CMAKE_SYSTEM -${CMAKE_SYSTEM_VERSION})
+endif()
+set(CMAKE_HOST_SYSTEM ${CMAKE_HOST_SYSTEM_NAME})
+if(CMAKE_HOST_SYSTEM_VERSION)
+  string(APPEND CMAKE_HOST_SYSTEM -${CMAKE_HOST_SYSTEM_VERSION})
+endif()
 
 # this file is also executed from cpack, then we don't need to generate these files
 # in this case there is no CMAKE_BINARY_DIR
diff --git a/Modules/CMakeFortranCompilerId.F.in b/Modules/CMakeFortranCompilerId.F.in
index 0f547e9..f61a3f2 100644
--- a/Modules/CMakeFortranCompilerId.F.in
+++ b/Modules/CMakeFortranCompilerId.F.in
@@ -139,6 +139,15 @@
 #define COMPILER_VERSION_MAJOR DEC(__NAG_COMPILER_RELEASE/10)
 #define COMPILER_VERSION_MINOR DEC(__NAG_COMPILER_RELEASE % 10)
 #define COMPILER_VERSION_PATCH DEC(__NAG_COMPILER_BUILD)
+#elif defined(__FUJITSU)
+        PRINT *, 'INFO:compiler[Fujitsu]'
+# if defined(__FRT_major__)
+#   define COMPILER_VERSION_MAJOR DEC(__FRT_major__)
+#   define COMPILER_VERSION_MINOR DEC(__FRT_minor__)
+#   define COMPILER_VERSION_PATCH DEC(__FRT_patchlevel__)
+# elif defined(__FRT_version__)
+        PRINT *, 'INFO:compiler_version['//__FRT_version__//']'
+# endif
 #else
         PRINT *, 'INFO:compiler[]'
 #endif
diff --git a/Modules/CMakeParseImplicitIncludeInfo.cmake b/Modules/CMakeParseImplicitIncludeInfo.cmake
index 7cd7548..a8e6ac0 100644
--- a/Modules/CMakeParseImplicitIncludeInfo.cmake
+++ b/Modules/CMakeParseImplicitIncludeInfo.cmake
@@ -146,6 +146,21 @@
     endif()
   endif()
 
+  # Fujitsu compiler
+  if(CMAKE_${lang}_COMPILER_ID STREQUAL "Fujitsu" AND
+     line MATCHES "/ccpcom")
+    string(REGEX MATCHALL " (-I *|--sys_include=|--preinclude +)(\"[^\"]+\"|[^ \"]+)" incs "${line}")
+    foreach(inc IN LISTS incs)
+      string(REGEX REPLACE " (-I *|--sys_include=|--preinclude +)(\"[^\"]+\"|[^ \"]+)" "\\2" idir "${inc}")
+      list(APPEND rv "${idir}")
+    endforeach()
+    if(rv)
+      string(APPEND log "  got implicit includes via fujitsu ccpcom parser!\n")
+    else()
+      string(APPEND log "  warning: fujitsu ccpcom parse failed!\n")
+    endif()
+  endif()
+
   if(log)
     set(${log_var} "${log}" PARENT_SCOPE)
   else()
diff --git a/Modules/CMakePlatformId.h.in b/Modules/CMakePlatformId.h.in
index 1dc12c0..2643874 100644
--- a/Modules/CMakePlatformId.h.in
+++ b/Modules/CMakePlatformId.h.in
@@ -256,8 +256,12 @@
   ('0' + ((n)>>4  & 0xF)), \
   ('0' + ((n)     & 0xF))
 
+/* Construct a string literal encoding the version number. */
+#ifdef COMPILER_VERSION
+char const* info_version = "INFO" ":" "compiler_version[" COMPILER_VERSION "]";
+
 /* Construct a string literal encoding the version number components. */
-#ifdef COMPILER_VERSION_MAJOR
+#elif defined(COMPILER_VERSION_MAJOR)
 char const info_version[] = {
   'I', 'N', 'F', 'O', ':',
   'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[',
@@ -281,6 +285,8 @@
   'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_',
   'i','n','t','e','r','n','a','l','[',
   COMPILER_VERSION_INTERNAL,']','\0'};
+#elif defined(COMPILER_VERSION_INTERNAL_STR)
+char const* info_version_internal = "INFO" ":" "compiler_version_internal[" COMPILER_VERSION_INTERNAL_STR "]";
 #endif
 
 /* Construct a string literal encoding the version number components. */
diff --git a/Modules/CMakePrintHelpers.cmake b/Modules/CMakePrintHelpers.cmake
index d652ffa..8c25a73 100644
--- a/Modules/CMakePrintHelpers.cmake
+++ b/Modules/CMakePrintHelpers.cmake
@@ -101,7 +101,10 @@
   if(CPP_CACHE_ENTRIES)
     set(items ${CPP_CACHE_ENTRIES})
     set(mode ${mode} CACHE_ENTRIES)
-    set(keyword CACHE)
+    # This is a workaround for the fact that passing `CACHE` as an argument to
+    # set() causes a cache variable to be set.
+    set(keyword "")
+    string(APPEND keyword CACHE)
   endif()
 
   if(NOT mode)
diff --git a/Modules/CPackIFW.cmake b/Modules/CPackIFW.cmake
index d57cf18..2087a51 100644
--- a/Modules/CPackIFW.cmake
+++ b/Modules/CPackIFW.cmake
@@ -125,6 +125,11 @@
     list of dependency component or component group identifiers in
     QtIFW style.
 
+    .. versionadded:: 3.21
+
+    Component or group names listed as dependencies may contain hyphens.
+    This requires QtIFW 3.1 or later.
+
   ``AUTO_DEPEND_ON``
     .. versionadded:: 3.8
 
@@ -260,6 +265,11 @@
     list of dependency component or component group identifiers in
     QtIFW style.
 
+    .. versionadded:: 3.21
+
+    Component or group names listed as dependencies may contain hyphens.
+    This requires QtIFW 3.1 or later.
+
   ``AUTO_DEPEND_ON``
     .. versionadded:: 3.8
 
diff --git a/Modules/Compiler/CMakeCommonCompilerMacros.cmake b/Modules/Compiler/CMakeCommonCompilerMacros.cmake
index cd897c5..29e6730 100644
--- a/Modules/Compiler/CMakeCommonCompilerMacros.cmake
+++ b/Modules/Compiler/CMakeCommonCompilerMacros.cmake
@@ -64,6 +64,12 @@
 # Define to allow compile features to be automatically determined
 macro(cmake_record_c_compile_features)
   set(_result 0)
+  if(_result EQUAL 0 AND DEFINED CMAKE_C23_STANDARD_COMPILE_OPTION)
+    _has_compiler_features_c(23)
+  endif()
+  if(_result EQUAL 0 AND DEFINED CMAKE_C17_STANDARD_COMPILE_OPTION)
+    _has_compiler_features_c(17)
+  endif()
   if(_result EQUAL 0 AND DEFINED CMAKE_C11_STANDARD_COMPILE_OPTION)
     if(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT)
       _has_compiler_features_c(11)
diff --git a/Modules/Compiler/Clang-C.cmake b/Modules/Compiler/Clang-C.cmake
index 5609abf..cf493d7 100644
--- a/Modules/Compiler/Clang-C.cmake
+++ b/Modules/Compiler/Clang-C.cmake
@@ -25,37 +25,60 @@
   endif()
 endif()
 
-if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
-  if(NOT "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
+if("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
+  if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 2.1)
     set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
     set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90")
-    set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
 
     set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
     set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
-    set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+  endif()
 
+  if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.1)
     set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
     set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
-    set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+  elseif(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.0)
+    set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c1x")
+    set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu1x")
+  endif()
+
+  if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 6.0)
+    set(CMAKE_C17_STANDARD_COMPILE_OPTION "-std=c17")
+    set(CMAKE_C17_EXTENSION_COMPILE_OPTION "-std=gnu17")
+  endif()
+
+  if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 9.0)
+    set(CMAKE_C23_STANDARD_COMPILE_OPTION "-std=c2x")
+    set(CMAKE_C23_EXTENSION_COMPILE_OPTION "-std=gnu2x")
+  endif()
+else()
+  set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
+  set(CMAKE_C90_EXTENSION_COMPILE_OPTION "")
+  set(CMAKE_C99_STANDARD_COMPILE_OPTION "")
+  set(CMAKE_C99_EXTENSION_COMPILE_OPTION "")
+
+  if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.0)
+    set(CMAKE_C11_STANDARD_COMPILE_OPTION "/std:c11")
+    set(CMAKE_C11_EXTENSION_COMPILE_OPTION "/std:c11")
+
+    set(CMAKE_C17_STANDARD_COMPILE_OPTION "/std:c17")
+    set(CMAKE_C17_EXTENSION_COMPILE_OPTION "/std:c17")
   else()
-    # clang-cl doesn't have any of these
-    set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
-    set(CMAKE_C90_EXTENSION_COMPILE_OPTION "")
-    set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
-
-    set(CMAKE_C99_STANDARD_COMPILE_OPTION "")
-    set(CMAKE_C99_EXTENSION_COMPILE_OPTION "")
-    set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
-
     set(CMAKE_C11_STANDARD_COMPILE_OPTION "")
     set(CMAKE_C11_EXTENSION_COMPILE_OPTION "")
-    set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+
+    set(CMAKE_C17_STANDARD_COMPILE_OPTION "")
+    set(CMAKE_C17_EXTENSION_COMPILE_OPTION "")
   endif()
 endif()
 
-if(NOT "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
-  __compiler_check_default_language_standard(C 3.4 99 3.6 11)
-else()
-  set(CMAKE_C_STANDARD_DEFAULT "")
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 2.1)
+  set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+  set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
 endif()
+
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.0)
+  set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+__compiler_check_default_language_standard(C 2.1 99 3.5.2 11 11.0 17)
diff --git a/Modules/Compiler/Clang-CUDA.cmake b/Modules/Compiler/Clang-CUDA.cmake
index cafc7dd..0223081 100644
--- a/Modules/Compiler/Clang-CUDA.cmake
+++ b/Modules/Compiler/Clang-CUDA.cmake
@@ -22,8 +22,8 @@
 set(_CMAKE_CUDA_DEVICE_CODE "-fgpu-rdc -c")
 
 # RulePlaceholderExpander expands crosscompile variables like sysroot and target only for CMAKE_<LANG>_COMPILER. Override the default.
-set(CMAKE_CUDA_LINK_EXECUTABLE "<CMAKE_CUDA_COMPILER> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICT_LINKS}")
-set(CMAKE_CUDA_CREATE_SHARED_LIBRARY "<CMAKE_CUDA_COMPILER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>${__IMPLICT_LINKS}")
+set(CMAKE_CUDA_LINK_EXECUTABLE "<CMAKE_CUDA_COMPILER> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
+set(CMAKE_CUDA_CREATE_SHARED_LIBRARY "<CMAKE_CUDA_COMPILER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
 
 set(CMAKE_CUDA_RUNTIME_LIBRARY_DEFAULT "STATIC")
 set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_STATIC "cudadevrt;cudart_static")
diff --git a/Modules/Compiler/Fujitsu-C.cmake b/Modules/Compiler/Fujitsu-C.cmake
new file mode 100644
index 0000000..0e0f1dc
--- /dev/null
+++ b/Modules/Compiler/Fujitsu-C.cmake
@@ -0,0 +1,20 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+include(Compiler/Fujitsu)
+__compiler_fujitsu(C)
+
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 4)
+  set(CMAKE_C89_STANDARD_COMPILE_OPTION  -std=c89)
+  set(CMAKE_C89_EXTENSION_COMPILE_OPTION -std=gnu89)
+  set(CMAKE_C89_STANDARD__HAS_FULL_SUPPORT ON)
+
+  set(CMAKE_C99_STANDARD_COMPILE_OPTION  -std=c99)
+  set(CMAKE_C99_EXTENSION_COMPILE_OPTION -std=gnu99)
+  set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
+
+  set(CMAKE_C11_STANDARD_COMPILE_OPTION  -std=c11)
+  set(CMAKE_C11_EXTENSION_COMPILE_OPTION -std=gnu11)
+  set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+__compiler_check_default_language_standard(C 4 11)
diff --git a/Modules/Compiler/Fujitsu-CXX.cmake b/Modules/Compiler/Fujitsu-CXX.cmake
new file mode 100644
index 0000000..0f42196
--- /dev/null
+++ b/Modules/Compiler/Fujitsu-CXX.cmake
@@ -0,0 +1,47 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+include(Compiler/Fujitsu)
+__compiler_fujitsu(CXX)
+
+#set(CMAKE_PCH_EXTENSION .pch)
+#set(CMAKE_PCH_EPILOGUE "#pragma hdrstop")
+#set(CMAKE_CXX_COMPILE_OPTIONS_USE_PCH --no_pch_messages -include <PCH_HEADER> --use_pch <PCH_FILE>)
+#set(CMAKE_CXX_COMPILE_OPTIONS_CREATE_PCH --no_pch_messages -include <PCH_HEADER> --create_pch <PCH_FILE>)
+
+# The Fujitsu compiler offers both a 98 and 03 mode.  These two are
+# essentially interchangeable as 03 simply provides clarity to some 98
+# ambiguyity.
+#
+# Re: Stroustrup's C++ FAQ:
+#   What is the difference between C++98 and C++03?
+#     From a programmer's view there is none. The C++03 revision of the
+#     standard was a bug fix release for implementers to ensure greater
+#     consistency and portability. In particular, tutorial and reference
+#     material describing C++98 and C++03 can be used interchangeably by all
+#     except compiler writers and standards gurus.
+#
+# Since CMake doesn't actually have an 03 mode and they're effectively
+# interchangeable then we're just going to explicitly use 03 mode in the
+# compiler when 98 is requested.
+
+# The version matching is messy here.  The std support seems to be related to
+# the compiler tweak version derived from the patch id in the version string.
+
+if(CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 4)
+  set(CMAKE_CXX98_STANDARD_COMPILE_OPTION  -std=c++03)
+  set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION -std=gnu++03)
+  set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
+
+  set(CMAKE_CXX11_STANDARD_COMPILE_OPTION  -std=c++11)
+  set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION -std=gnu++11)
+  set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+
+  set(CMAKE_CXX14_STANDARD_COMPILE_OPTION  -std=c++14)
+  set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION -std=gnu++14)
+  set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+
+  set(CMAKE_CXX17_STANDARD_COMPILE_OPTION  -std=c++17)
+  set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION -std=gnu++17)
+endif()
+
+__compiler_check_default_language_standard(CXX 4 14)
diff --git a/Modules/Compiler/Fujitsu-DetermineCompiler.cmake b/Modules/Compiler/Fujitsu-DetermineCompiler.cmake
index 73ee38c..8534916 100644
--- a/Modules/Compiler/Fujitsu-DetermineCompiler.cmake
+++ b/Modules/Compiler/Fujitsu-DetermineCompiler.cmake
@@ -1,2 +1,17 @@
 
-set(_compiler_id_pp_test "defined(__FUJITSU) || defined(__FCC_VERSION) || defined(__fcc_version)")
+set(_compiler_id_pp_test "defined(__FUJITSU)")
+
+set(_compiler_id_version_compute "
+# if defined(__FCC_version__)
+#   define @PREFIX@COMPILER_VERSION __FCC_version__
+# elif defined(__FCC_major__)
+#   define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__FCC_major__)
+#   define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__FCC_minor__)
+#   define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__FCC_patchlevel__)
+# endif
+# if defined(__fcc_version)
+#   define @PREFIX@COMPILER_VERSION_INTERNAL @MACRO_DEC@(__fcc_version)
+# elif defined(__FCC_VERSION)
+#   define @PREFIX@COMPILER_VERSION_INTERNAL @MACRO_DEC@(__FCC_VERSION)
+# endif
+")
diff --git a/Modules/Compiler/Fujitsu-Fortran.cmake b/Modules/Compiler/Fujitsu-Fortran.cmake
new file mode 100644
index 0000000..0f687bc
--- /dev/null
+++ b/Modules/Compiler/Fujitsu-Fortran.cmake
@@ -0,0 +1,16 @@
+include(Compiler/Fujitsu)
+__compiler_fujitsu(Fortran)
+
+set(CMAKE_Fortran_SUBMODULE_SEP ".")
+set(CMAKE_Fortran_SUBMODULE_EXT ".smod")
+
+set(CMAKE_Fortran_PREPROCESS_SOURCE
+  "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -Cpp -E <SOURCE> > <PREPROCESSED_SOURCE>")
+set(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON "-Cpp")
+
+set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-Fixed")
+set(CMAKE_Fortran_FORMAT_FREE_FLAG "-Free")
+
+string(APPEND CMAKE_Fortran_FLAGS_DEBUG_INIT "")
+
+set(CMAKE_Fortran_MODDIR_FLAG "-M ")
diff --git a/Modules/Compiler/Fujitsu.cmake b/Modules/Compiler/Fujitsu.cmake
new file mode 100644
index 0000000..13bc57c
--- /dev/null
+++ b/Modules/Compiler/Fujitsu.cmake
@@ -0,0 +1,33 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_FUJITSU)
+  return()
+endif()
+set(__COMPILER_FUJITSU 1)
+
+include(Compiler/CMakeCommonCompilerMacros)
+
+macro(__compiler_fujitsu lang)
+  set(CMAKE_${lang}_VERBOSE_FLAG "-###")
+
+  # Initial configuration flags
+  string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
+  string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g -O0")
+  string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3 -DNDEBUG")
+  string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG")
+
+  # PIC flags
+  set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
+  set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIE")
+
+  # Passing link options to the compiler
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Wl,")
+  set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP ",")
+
+  # How to actually call the compiler
+  set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE
+  "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E $<$<COMPILE_LANGUAGE:Fortran>:-Cpp> <SOURCE> > <PREPROCESSED_SOURCE>")
+  set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+endmacro()
diff --git a/Modules/Compiler/FujitsuClang-C.cmake b/Modules/Compiler/FujitsuClang-C.cmake
new file mode 100644
index 0000000..f700d2d
--- /dev/null
+++ b/Modules/Compiler/FujitsuClang-C.cmake
@@ -0,0 +1,6 @@
+include(Compiler/FujitsuClang)
+
+set(_fjclang_ver "${CMAKE_C_COMPILER_VERSION_INTERNAL}")
+set(CMAKE_C_COMPILER_VERSION "${CMAKE_C_COMPILER_VERSION_INTERNAL}")
+include(Compiler/Clang-C)
+set(CMAKE_C_COMPILER_VERSION "${_fjclang_ver}")
diff --git a/Modules/Compiler/FujitsuClang-CXX.cmake b/Modules/Compiler/FujitsuClang-CXX.cmake
new file mode 100644
index 0000000..c8790cd
--- /dev/null
+++ b/Modules/Compiler/FujitsuClang-CXX.cmake
@@ -0,0 +1,6 @@
+include(Compiler/FujitsuClang)
+
+set(_fjclang_ver "${CMAKE_CXX_COMPILER_VERSION_INTERNAL}")
+set(CMAKE_CXX_COMPILER_VERSION "${CMAKE_CXX_COMPILER_VERSION_INTERNAL}")
+include(Compiler/Clang-CXX)
+set(CMAKE_CXX_COMPILER_VERSION "${_fjclang_ver}")
diff --git a/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake b/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake
new file mode 100644
index 0000000..f6719b1
--- /dev/null
+++ b/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake
@@ -0,0 +1,9 @@
+
+set(_compiler_id_pp_test "defined(__CLANG_FUJITSU)")
+
+set(_compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__FCC_major__)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__FCC_minor__)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__FCC_patchlevel__)
+# define @PREFIX@COMPILER_VERSION_INTERNAL_STR __clang_version__
+")
diff --git a/Modules/Compiler/FujitsuClang.cmake b/Modules/Compiler/FujitsuClang.cmake
new file mode 100644
index 0000000..a848248
--- /dev/null
+++ b/Modules/Compiler/FujitsuClang.cmake
@@ -0,0 +1,11 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_FUJITSUCLANG)
+  return()
+endif()
+set(__COMPILER_FUJITSUCLANG 1)
+
+include(Compiler/Clang)
diff --git a/Modules/Compiler/GNU-C.cmake b/Modules/Compiler/GNU-C.cmake
index 86b4d83..39e9c72 100644
--- a/Modules/Compiler/GNU-C.cmake
+++ b/Modules/Compiler/GNU-C.cmake
@@ -36,4 +36,14 @@
   set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu1x")
 endif()
 
-__compiler_check_default_language_standard(C 3.4 90 5.0 11)
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.1)
+  set(CMAKE_C17_STANDARD_COMPILE_OPTION "-std=c17")
+  set(CMAKE_C17_EXTENSION_COMPILE_OPTION "-std=gnu17")
+endif()
+
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 9.1)
+  set(CMAKE_C23_STANDARD_COMPILE_OPTION "-std=c23")
+  set(CMAKE_C23_EXTENSION_COMPILE_OPTION "-std=gnu23")
+endif()
+
+__compiler_check_default_language_standard(C 3.4 90 5.0 11 8.1 17)
diff --git a/Modules/Compiler/IntelLLVM-C.cmake b/Modules/Compiler/IntelLLVM-C.cmake
index fce2971..beb7132 100644
--- a/Modules/Compiler/IntelLLVM-C.cmake
+++ b/Modules/Compiler/IntelLLVM-C.cmake
@@ -37,6 +37,9 @@
 
   set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
   set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+
+  set(CMAKE_C17_STANDARD_COMPILE_OPTION "-std=c17")
+  set(CMAKE_C17_EXTENSION_COMPILE_OPTION "-std=gnu17")
 else()
   # clang-cl doesn't have any of these
   set(CMAKE_C90_STANDARD_COMPILE_OPTION "")
@@ -47,12 +50,13 @@
 
   set(CMAKE_C11_STANDARD_COMPILE_OPTION "")
   set(CMAKE_C11_EXTENSION_COMPILE_OPTION "")
+
+  set(CMAKE_C17_STANDARD_COMPILE_OPTION "")
+  set(CMAKE_C17_EXTENSION_COMPILE_OPTION "")
 endif()
 
 if(NOT "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
-  # FIXME: The compiler actually defaults to C17, but
-  # CMake does not yet model or detect that standard.
-  __compiler_check_default_language_standard(C 2020 11)
+  __compiler_check_default_language_standard(C 2020 17)
 else()
   set(CMAKE_C_STANDARD_DEFAULT "")
 endif()
diff --git a/Modules/ExternalData.cmake b/Modules/ExternalData.cmake
index d6fbae9..1850e74 100644
--- a/Modules/ExternalData.cmake
+++ b/Modules/ExternalData.cmake
@@ -941,10 +941,11 @@
         file(RELATIVE_PATH tgt "${dst_dir}" "${src}")
       endif()
     endif()
-    execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink "${tgt}" "${tmp}" RESULT_VARIABLE result)
+    # Create link (falling back to copying if there's a problem).
+    file(CREATE_LINK "${tgt}" "${tmp}" RESULT result COPY_ON_ERROR SYMBOLIC)
   else()
     # Create a copy.
-    execute_process(COMMAND "${CMAKE_COMMAND}" -E copy "${src}" "${tmp}" RESULT_VARIABLE result)
+    file(COPY_FILE "${src}" "${tmp}" RESULT result)
   endif()
   if(result)
     file(REMOVE "${tmp}")
@@ -1101,7 +1102,14 @@
 
   set(success 1)
   if(found)
-    file(RENAME "${tmp}" "${obj}")
+    # Atomically create the object.  If we lose a race with another process,
+    # do not replace it.  Content-addressing ensures it has what we expect.
+    file(RENAME "${tmp}" "${obj}" NO_REPLACE RESULT result)
+    if (result STREQUAL "NO_REPLACE")
+      file(REMOVE "${tmp}")
+    elseif (result)
+      message(FATAL_ERROR "Failed to rename:\n  \"${tmp}\"\nto:\n  \"${obj}\"\nwith error:\n  ${result}")
+    endif()
     message(STATUS "Downloaded object: \"${obj}\"")
   elseif(EXISTS "${staged}")
     set(obj "${staged}")
diff --git a/Modules/FetchContent.cmake b/Modules/FetchContent.cmake
index 8adef47..88f7ed6 100644
--- a/Modules/FetchContent.cmake
+++ b/Modules/FetchContent.cmake
@@ -34,7 +34,7 @@
   FetchContent_Declare(
     googletest
     GIT_REPOSITORY https://github.com/google/googletest.git
-    GIT_TAG        release-1.8.0
+    GIT_TAG        703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
   )
 
 For most typical cases, populating the content can then be done with a single
@@ -126,13 +126,13 @@
     FetchContent_Declare(
       googletest
       GIT_REPOSITORY https://github.com/google/googletest.git
-      GIT_TAG        release-1.8.0
+      GIT_TAG        703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
     )
 
     FetchContent_Declare(
       myCompanyIcons
       URL      https://intranet.mycompany.com/assets/iconset_1.12.tar.gz
-      URL_HASH 5588a7b18261c20068beabfb4f530b87
+      URL_HASH MD5=5588a7b18261c20068beabfb4f530b87
     )
 
     FetchContent_Declare(
@@ -141,6 +141,11 @@
       SVN_REVISION   -r12345
     )
 
+  Where contents are being fetched from a remote location and you do not
+  control that server, it is advisable to use a hash for ``GIT_TAG`` rather
+  than a branch or tag name.  A commit hash is more secure and helps to
+  confirm that the downloaded contents are what you expected.
+
 Populating The Content
 """"""""""""""""""""""
 
@@ -456,12 +461,12 @@
   FetchContent_Declare(
     googletest
     GIT_REPOSITORY https://github.com/google/googletest.git
-    GIT_TAG        release-1.8.0
+    GIT_TAG        703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
   )
   FetchContent_Declare(
     Catch2
     GIT_REPOSITORY https://github.com/catchorg/Catch2.git
-    GIT_TAG        v2.5.0
+    GIT_TAG        de6fe184a9ac1a06895cdd1c9b437f0a0bdf14ad # v2.13.4
   )
 
   # After the following call, the CMake targets defined by googletest and
@@ -480,7 +485,7 @@
   FetchContent_Declare(
     protobuf
     GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git
-    GIT_TAG        v3.12.0
+    GIT_TAG        ae50d9b9902526efd6c7a1907d09739f959c6297 # v3.15.0
     SOURCE_SUBDIR  cmake
   )
   set(protobuf_BUILD_TESTS OFF)
@@ -517,7 +522,7 @@
   FetchContent_Declare(
     projE
     GIT_REPOSITORY git@mycompany.com:git/projE.git
-    GIT_TAG        origin/release/2.3-rc1
+    GIT_TAG        v2.3-rc1
   )
 
   # Order is important, see notes in the discussion further below
diff --git a/Modules/FindBLAS.cmake b/Modules/FindBLAS.cmake
index b4650b2..c23e41b 100644
--- a/Modules/FindBLAS.cmake
+++ b/Modules/FindBLAS.cmake
@@ -55,6 +55,8 @@
   * ``Arm_ilp64_mp``
   * ``EML``
   * ``EML_mt``
+  * ``Fujitsu_SSL2`` (Fujitsu serial blas / lapack)
+  * ``Fujitsu_SSL2BLAMP`` (Fujitsu parallel blas / lapack)
   * ``Generic``
 
   .. versionadded:: 3.6
@@ -78,6 +80,7 @@
 
   .. versionadded:: 3.20
     Elbrus Math Library support (``EML``, ``EML_mt``).
+    Fujitsu SSL2 Library support (``Fujitsu_SSL2``, ``Fujitsu_SSL2BLAMP``)
 
 ``BLA_F95``
   if ``ON`` tries to find the BLAS95 interfaces
@@ -153,13 +156,18 @@
 endif()
 
 function(_add_blas_target)
-  if(NOT TARGET BLAS::BLAS)
+  if(BLAS_FOUND AND NOT TARGET BLAS::BLAS)
     add_library(BLAS::BLAS INTERFACE IMPORTED)
     if(BLAS_LIBRARIES)
       set_target_properties(BLAS::BLAS PROPERTIES
         INTERFACE_LINK_LIBRARIES "${BLAS_LIBRARIES}"
       )
     endif()
+    if(BLAS_LINKER_FLAGS)
+      set_target_properties(BLAS::BLAS PROPERTIES
+        INTERFACE_LINK_OPTIONS "${BLAS_LINKER_FLAGS}"
+      )
+    endif()
   endif()
 endfunction()
 
@@ -200,22 +208,16 @@
 
 # TODO: move this stuff to a separate module
 
-macro(CHECK_BLAS_LIBRARIES LIBRARIES _prefix _name _flags _list _threadlibs _addlibdir _subdirs)
-  # This macro checks for the existence of the combination of fortran libraries
-  # given by _list.  If the combination is found, this macro checks (using the
-  # Check_Fortran_Function_Exists macro) whether can link against that library
-  # combination using the name of a routine given by _name using the linker
-  # flags given by _flags.  If the combination of libraries is found and passes
-  # the link test, LIBRARIES is set to the list of complete library paths that
-  # have been found.  Otherwise, LIBRARIES is set to FALSE.
-
-  # N.B. _prefix is the prefix applied to the names of all cached variables that
-  # are generated internally and marked advanced by this macro.
-  # _addlibdir is a list of additional search paths. _subdirs is a list of path
-  # suffixes to be used by find_library().
+function(CHECK_BLAS_LIBRARIES LIBRARIES _prefix _name _flags _list _deps _addlibdir _subdirs)
+  # This function checks for the existence of the combination of libraries
+  # given by _list.  If the combination is found, this checks whether can link
+  # against that library combination using the name of a routine given by _name
+  # using the linker flags given by _flags.  If the combination of libraries is
+  # found and passes the link test, ${LIBRARIES} is set to the list of complete
+  # library paths that have been found.  Otherwise, ${LIBRARIES} is set to FALSE.
 
   set(_libraries_work TRUE)
-  set(${LIBRARIES})
+  set(_libraries)
   set(_combined_name)
 
   set(_extaddlibdir "${_addlibdir}")
@@ -229,33 +231,36 @@
   list(APPEND _extaddlibdir "${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}")
 
   foreach(_library ${_list})
-    if(_library MATCHES "^-Wl,--(start|end)-group$")
-      # Respect linker flags like --start/end-group (required by MKL)
-      set(${LIBRARIES} ${${LIBRARIES}} "${_library}")
+    if(_library MATCHES "^-")
+      # Respect linker flags as-is (required by MKL)
+      list(APPEND _libraries "${_library}")
     else()
-      set(_combined_name ${_combined_name}_${_library})
-      if(NOT "${_threadlibs}" STREQUAL "")
-        set(_combined_name ${_combined_name}_threadlibs)
+      string(REGEX REPLACE "[^A-Za-z0-9]" "_" _lib_var "${_library}")
+      set(_combined_name ${_combined_name}_${_lib_var})
+      if(NOT "${_deps}" STREQUAL "")
+        set(_combined_name ${_combined_name}_deps)
       endif()
       if(_libraries_work)
-        find_library(${_prefix}_${_library}_LIBRARY
+        find_library(${_prefix}_${_lib_var}_LIBRARY
           NAMES ${_library}
           NAMES_PER_DIR
           PATHS ${_extaddlibdir}
           PATH_SUFFIXES ${_subdirs}
         )
-        #message("DEBUG: find_library(${_library}) got ${${_prefix}_${_library}_LIBRARY}")
-        mark_as_advanced(${_prefix}_${_library}_LIBRARY)
-        set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_library}_LIBRARY})
-        set(_libraries_work ${${_prefix}_${_library}_LIBRARY})
+        mark_as_advanced(${_prefix}_${_lib_var}_LIBRARY)
+        list(APPEND _libraries ${${_prefix}_${_lib_var}_LIBRARY})
+        set(_libraries_work ${${_prefix}_${_lib_var}_LIBRARY})
       endif()
     endif()
   endforeach()
 
+  foreach(_flag ${_flags})
+    string(REGEX REPLACE "[^A-Za-z0-9]" "_" _flag_var "${_flag}")
+    set(_combined_name ${_combined_name}_${_flag_var})
+  endforeach()
   if(_libraries_work)
     # Test this combination of libraries.
-    set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}} ${_threadlibs})
-    #message("DEBUG: CMAKE_REQUIRED_LIBRARIES = ${CMAKE_REQUIRED_LIBRARIES}")
+    set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${_libraries} ${_deps})
     if(CMAKE_Fortran_COMPILER_LOADED)
       check_fortran_function_exists("${_name}" ${_prefix}${_combined_name}_WORKS)
     else()
@@ -267,19 +272,20 @@
 
   if(_libraries_work)
     if("${_list}" STREQUAL "")
-      set(${LIBRARIES} "${LIBRARIES}-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
+      set(_libraries "${LIBRARIES}-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
     else()
-      set(${LIBRARIES} ${${LIBRARIES}} ${_threadlibs})
+      list(APPEND _libraries ${_deps})
     endif()
   else()
-    set(${LIBRARIES} FALSE)
+    set(_libraries FALSE)
   endif()
-  #message("DEBUG: ${LIBRARIES} = ${${LIBRARIES}}")
-endmacro()
+  set(${LIBRARIES} "${_libraries}" PARENT_SCOPE)
+endfunction()
 
 set(BLAS_LINKER_FLAGS)
 set(BLAS_LIBRARIES)
 set(BLAS95_LIBRARIES)
+set(_blas_fphsa_req_var BLAS_LIBRARIES)
 if(NOT $ENV{BLA_VENDOR} STREQUAL "")
   set(BLA_VENDOR $ENV{BLA_VENDOR})
 else()
@@ -302,6 +308,9 @@
       ""
       )
   endif()
+  if(BLAS_WORKS)
+    set(_blas_fphsa_req_var BLAS_WORKS)
+  endif()
 endif()
 
 # BLAS in the Intel MKL 10+ library?
@@ -1025,6 +1034,31 @@
 
 endif()
 
+# Fujitsu SSL2 Library?
+if(NOT BLAS_LIBRARIES AND
+    BLA_VENDOR MATCHES "Fujitsu_SSL2" OR BLA_VENDOR STREQUAL "All")
+  if(BLA_VENDOR STREQUAL "Fujitsu_SSL2BLAMP")
+    set(_ssl2_suffix BLAMP)
+  else()
+    set(_ssl2_suffix)
+  endif()
+  check_blas_libraries(
+    BLAS_LIBRARIES
+    BLAS
+    sgemm
+    "-SSL2${_ssl2_suffix}"
+    ""
+    ""
+    ""
+    ""
+    )
+  if(BLAS_LIBRARIES)
+    set(BLAS_LINKER_FLAGS "-SSL2${_ssl2_suffix}")
+    set(_blas_fphsa_req_var BLAS_LINKER_FLAGS)
+  endif()
+  unset(_ssl2_suffix)
+endif()
+
 # Generic BLAS library?
 if(BLA_VENDOR STREQUAL "Generic" OR BLA_VENDOR STREQUAL "All")
   if(NOT BLAS_LIBRARIES)
@@ -1041,17 +1075,16 @@
   endif()
 endif()
 
-if(NOT BLA_F95)
-  find_package_handle_standard_args(BLAS REQUIRED_VARS BLAS_LIBRARIES)
-endif()
-
-
-# On compilers that implicitly link BLAS (such as ftn, cc, and CC on Cray HPC machines)
-# we used a placeholder for empty BLAS_LIBRARIES to get through our logic above.
+# On compilers that implicitly link BLAS (i.e. CrayPrgEnv) we used a
+# placeholder for empty BLAS_LIBRARIES to get through our logic above.
 if(BLAS_LIBRARIES STREQUAL "BLAS_LIBRARIES-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
   set(BLAS_LIBRARIES "")
 endif()
 
+if(NOT BLA_F95)
+  find_package_handle_standard_args(BLAS REQUIRED_VARS ${_blas_fphsa_req_var})
+endif()
+
 _add_blas_target()
 cmake_pop_check_state()
 set(CMAKE_FIND_LIBRARY_SUFFIXES ${_blas_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake
index f8887ad..3080062 100644
--- a/Modules/FindBoost.cmake
+++ b/Modules/FindBoost.cmake
@@ -189,7 +189,7 @@
   (adds ``-DBOOST_ALL_NO_LIB``).
 
 ``Boost::dynamic_linking``
-  Interface target to enable dynamic linking linking with MSVC
+  Interface target to enable dynamic linking with MSVC
   (adds ``-DBOOST_ALL_DYN_LINK``).
 
 Implicit dependencies such as ``Boost::filesystem`` requiring
diff --git a/Modules/FindDevIL.cmake b/Modules/FindDevIL.cmake
index 9984943..c8e5e31 100644
--- a/Modules/FindDevIL.cmake
+++ b/Modules/FindDevIL.cmake
@@ -10,26 +10,57 @@
 This module locates the developer's image library.
 http://openil.sourceforge.net/
 
+IMPORTED Targets
+^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.21
+
+This module defines the :prop_tgt:`IMPORTED` targets:
+
+``DevIL::IL``
+ Defined if the system has DevIL.
+
+``DevIL::ILU``
+ Defined if the system has DevIL Utilities.
+
+``DevIL::ILUT``
+ Defined if the system has DevIL Utility Toolkit.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
 This module sets:
 
-::
+``IL_LIBRARIES``
+  The name of the IL library. These include the full path to
+  the core DevIL library. This one has to be linked into the
+  application.
 
-   IL_LIBRARIES -   the name of the IL library. These include the full path to
-                    the core DevIL library. This one has to be linked into the
-                    application.
-   ILU_LIBRARIES -  the name of the ILU library. Again, the full path. This
-                    library is for filters and effects, not actual loading. It
-                    doesn't have to be linked if the functionality it provides
-                    is not used.
-   ILUT_LIBRARIES - the name of the ILUT library. Full path. This part of the
-                    library interfaces with OpenGL. It is not strictly needed
-                    in applications.
-   IL_INCLUDE_DIR - where to find the il.h, ilu.h and ilut.h files.
-   DevIL_FOUND    - this is set to TRUE if all the above variables were set.
-                    This will be set to false if ILU or ILUT are not found,
-                    even if they are not needed. In most systems, if one
-                    library is found all the others are as well. That's the
-                    way the DevIL developers release it.
+``ILU_LIBRARIES``
+  The name of the ILU library. Again, the full path. This
+  library is for filters and effects, not actual loading. It
+  doesn't have to be linked if the functionality it provides
+  is not used.
+
+``ILUT_LIBRARIES``
+  The name of the ILUT library. Full path. This part of the
+  library interfaces with OpenGL. It is not strictly needed
+  in applications.
+
+``IL_INCLUDE_DIR``
+  where to find the il.h, ilu.h and ilut.h files.
+
+``DevIL_FOUND``
+  This is set to TRUE if all the above variables were set.
+  This will be set to false if ILU or ILUT are not found,
+  even if they are not needed. In most systems, if one
+  library is found all the others are as well. That's the
+  way the DevIL developers release it.
+
+``DevIL_ILUT_FOUND``
+  .. versionadded:: 3.21
+
+  This is set to TRUE if the ILUT library is found.
 #]=======================================================================]
 
 # TODO: Add version support.
@@ -73,3 +104,36 @@
                                   IL_INCLUDE_DIR)
 # provide legacy variable for compatibility
 set(IL_FOUND ${DevIL_FOUND})
+
+# create imported targets ONLY if we found DevIL.
+if(DevIL_FOUND)
+  # Report the ILUT found if ILUT_LIBRARIES contains valid path.
+  if (ILUT_LIBRARIES)
+    set(DevIL_ILUT_FOUND TRUE)
+  else()
+    set(DevIL_ILUT_FOUND FALSE)
+  endif()
+
+  if(NOT TARGET DevIL::IL)
+    add_library(DevIL::IL UNKNOWN IMPORTED)
+    set_target_properties(DevIL::IL PROPERTIES
+      INTERFACE_INCLUDE_DIRECTORIES "${IL_INCLUDE_DIR}"
+      IMPORTED_LOCATION "${IL_LIBRARIES}")
+  endif()
+
+  # DevIL Utilities target
+  if(NOT TARGET DevIL::ILU)
+    add_library(DevIL::ILU UNKNOWN IMPORTED)
+    set_target_properties(DevIL::ILU PROPERTIES
+      IMPORTED_LOCATION "${ILU_LIBRARIES}")
+    target_link_libraries(DevIL::ILU INTERFACE DevIL::IL)
+  endif()
+
+  # ILUT (if found)
+  if(NOT TARGET DevIL::ILUT AND DevIL_ILUT_FOUND)
+    add_library(DevIL::ILUT UNKNOWN IMPORTED)
+    set_target_properties(DevIL::ILUT PROPERTIES
+      IMPORTED_LOCATION "${ILUT_LIBRARIES}")
+    target_link_libraries(DevIL::ILUT INTERFACE DevIL::ILU)
+  endif()
+endif()
diff --git a/Modules/FindDoxygen.cmake b/Modules/FindDoxygen.cmake
index bbf941e..4a16e31 100644
--- a/Modules/FindDoxygen.cmake
+++ b/Modules/FindDoxygen.cmake
@@ -223,7 +223,8 @@
 items separated by semi-colons, so a conversion needs to be performed. The
 ``doxygen_add_docs()`` command specifically checks the following Doxygen config
 options and will convert their associated CMake variable's contents into the
-required form if set.
+required form if set. CMake variables are named ``DOXYGEN_<name>`` for the
+Doxygen settings specified here.
 
 ::
 
@@ -395,6 +396,7 @@
 #]=======================================================================]
 
 cmake_policy(PUSH)
+cmake_policy(SET CMP0054 NEW) # quoted if arguments
 cmake_policy(SET CMP0057 NEW) # if IN_LIST
 
 # For backwards compatibility support
diff --git a/Modules/FindHDF5.cmake b/Modules/FindHDF5.cmake
index ec5ebdd..e335355 100644
--- a/Modules/FindHDF5.cmake
+++ b/Modules/FindHDF5.cmake
@@ -811,25 +811,8 @@
     endif()
 
     foreach(_lang IN LISTS HDF5_LANGUAGE_BINDINGS)
-        # find the HDF5 include directories
-        if("${_lang}" STREQUAL "Fortran")
-            set(HDF5_INCLUDE_FILENAME hdf5.mod HDF5.mod)
-        elseif("${_lang}" STREQUAL "CXX")
-            set(HDF5_INCLUDE_FILENAME H5Cpp.h)
-        else()
-            set(HDF5_INCLUDE_FILENAME hdf5.h)
-        endif()
-
-        find_path(HDF5_${_lang}_INCLUDE_DIR ${HDF5_INCLUDE_FILENAME}
-            HINTS ${HDF5_ROOT}
-            PATHS $ENV{HOME}/.local/include
-            PATH_SUFFIXES include Include ${_inc_suffixes} ${_lib_suffixes}
-            ${_HDF5_SEARCH_OPTS}
-        )
-        mark_as_advanced(HDF5_${_lang}_INCLUDE_DIR)
-        # set the _DIRS variable as this is what the user will normally use
-        set(HDF5_${_lang}_INCLUDE_DIRS ${HDF5_${_lang}_INCLUDE_DIR})
-        list(APPEND HDF5_INCLUDE_DIRS ${HDF5_${_lang}_INCLUDE_DIR})
+        # The "main" library.
+        set(_hdf5_main_library "")
 
         # find the HDF5 libraries
         foreach(LIB IN LISTS HDF5_${_lang}_LIBRARY_NAMES)
@@ -861,6 +844,15 @@
                 ${_HDF5_SEARCH_OPTS}
             )
 
+            # Set the "main" library if not already set.
+            if (NOT _hdf5_main_library)
+              if (HDF5_${LIB}_LIBRARY_RELEASE)
+                set(_hdf5_main_library "${HDF5_${LIB}_LIBRARY_RELEASE}")
+              elseif (HDF5_${LIB}_LIBRARY_DEBUG)
+                set(_hdf5_main_library "${HDF5_${LIB}_LIBRARY_DEBUG}")
+              endif ()
+            endif ()
+
             select_library_configurations( HDF5_${LIB} )
             list(APPEND HDF5_${_lang}_LIBRARIES ${HDF5_${LIB}_LIBRARY})
         endforeach()
@@ -872,6 +864,43 @@
         # required libraries.
         list(APPEND HDF5_LIBRARIES ${HDF5_${_lang}_LIBRARIES})
 
+        # find the HDF5 include directories
+        set(_hdf5_inc_extra_paths)
+        set(_hdf5_inc_extra_suffixes)
+        if("${_lang}" STREQUAL "Fortran")
+            set(HDF5_INCLUDE_FILENAME hdf5.mod HDF5.mod)
+
+            # Add library-based search paths for Fortran modules.
+            if (NOT _hdf5_main_library STREQUAL "")
+              # gfortran module directory
+              if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
+                get_filename_component(_hdf5_library_dir "${_hdf5_main_library}" DIRECTORY)
+                list(APPEND _hdf5_inc_extra_paths "${_hdf5_library_dir}")
+                unset(_hdf5_library_dir)
+                list(APPEND _hdf5_inc_extra_suffixes gfortran/modules)
+              endif ()
+            endif ()
+        elseif("${_lang}" STREQUAL "CXX")
+            set(HDF5_INCLUDE_FILENAME H5Cpp.h)
+        else()
+            set(HDF5_INCLUDE_FILENAME hdf5.h)
+        endif()
+
+        unset(_hdf5_main_library)
+
+        find_path(HDF5_${_lang}_INCLUDE_DIR ${HDF5_INCLUDE_FILENAME}
+            HINTS ${HDF5_ROOT}
+            PATHS $ENV{HOME}/.local/include ${_hdf5_inc_extra_paths}
+            PATH_SUFFIXES include Include ${_inc_suffixes} ${_lib_suffixes} ${_hdf5_inc_extra_suffixes}
+            ${_HDF5_SEARCH_OPTS}
+        )
+        mark_as_advanced(HDF5_${_lang}_INCLUDE_DIR)
+        unset(_hdf5_inc_extra_paths)
+        unset(_hdf5_inc_extra_suffixes)
+        # set the _DIRS variable as this is what the user will normally use
+        set(HDF5_${_lang}_INCLUDE_DIRS ${HDF5_${_lang}_INCLUDE_DIR})
+        list(APPEND HDF5_INCLUDE_DIRS ${HDF5_${_lang}_INCLUDE_DIR})
+
         if(HDF5_FIND_HL)
             foreach(LIB IN LISTS HDF5_${_lang}_HL_LIBRARY_NAMES)
                 if(HDF5_USE_STATIC_LIBRARIES)
diff --git a/Modules/FindIconv.cmake b/Modules/FindIconv.cmake
index 41b7550..5ec12b2 100644
--- a/Modules/FindIconv.cmake
+++ b/Modules/FindIconv.cmake
@@ -25,6 +25,24 @@
 
   The iconv libraries to be linked.
 
+.. variable:: Iconv_VERSION
+
+  .. versionadded:: 3.21
+
+  The version of iconv found (x.y)
+
+.. variable:: Iconv_VERSION_MAJOR
+
+  .. versionadded:: 3.21
+
+  The major version of iconv
+
+.. variable:: Iconv_VERSION_MINOR
+
+  .. versionadded:: 3.21
+
+  The minor version of iconv
+
 .. variable:: Iconv_IS_BUILT_IN
 
   A variable indicating whether iconv support is stemming from the
@@ -51,6 +69,10 @@
   On POSIX platforms, iconv might be part of the C library and the cache
   variables ``Iconv_INCLUDE_DIR`` and ``Iconv_LIBRARY`` might be empty.
 
+.. note::
+  Some libiconv implementations don't embed the version number in their header files.
+  In this case the variables ``Iconv_VERSION*`` will be empty.
+
 #]=======================================================================]
 
 include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
@@ -118,9 +140,29 @@
 mark_as_advanced(Iconv_INCLUDE_DIR)
 mark_as_advanced(Iconv_LIBRARY)
 
+# NOTE: glibc's iconv.h does not define _LIBICONV_VERSION
+if(Iconv_INCLUDE_DIR AND NOT Iconv_IS_BUILT_IN)
+  file(STRINGS ${Iconv_INCLUDE_DIR}/iconv.h Iconv_VERSION_DEFINE REGEX "_LIBICONV_VERSION (.*)")
+
+  if(Iconv_VERSION_DEFINE MATCHES "(0x[A-Fa-f0-9]+)")
+    set(Iconv_VERSION_NUMBER "${CMAKE_MATCH_1}")
+    # encoding -> version number: (major<<8) + minor
+    math(EXPR Iconv_VERSION_MAJOR "${Iconv_VERSION_NUMBER} >> 8" OUTPUT_FORMAT HEXADECIMAL)
+    math(EXPR Iconv_VERSION_MINOR "${Iconv_VERSION_NUMBER} - (${Iconv_VERSION_MAJOR} << 8)" OUTPUT_FORMAT HEXADECIMAL)
+
+    math(EXPR Iconv_VERSION_MAJOR "${Iconv_VERSION_MAJOR}" OUTPUT_FORMAT DECIMAL)
+    math(EXPR Iconv_VERSION_MINOR "${Iconv_VERSION_MINOR}" OUTPUT_FORMAT DECIMAL)
+    set(Iconv_VERSION "${Iconv_VERSION_MAJOR}.${Iconv_VERSION_MINOR}")
+  endif()
+
+  unset(Iconv_VERSION_DEFINE)
+  unset(Iconv_VERSION_NUMBER)
+endif()
+
 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 if(NOT Iconv_IS_BUILT_IN)
-  find_package_handle_standard_args(Iconv REQUIRED_VARS Iconv_LIBRARY Iconv_INCLUDE_DIR)
+  find_package_handle_standard_args(Iconv REQUIRED_VARS Iconv_LIBRARY Iconv_INCLUDE_DIR
+                                    VERSION_VAR Iconv_VERSION)
 else()
   find_package_handle_standard_args(Iconv REQUIRED_VARS Iconv_LIBRARY)
 endif()
diff --git a/Modules/FindIntl.cmake b/Modules/FindIntl.cmake
index 43398c1..038f4da 100644
--- a/Modules/FindIntl.cmake
+++ b/Modules/FindIntl.cmake
@@ -24,6 +24,30 @@
 
   The intl libraries to be linked.
 
+.. variable:: Intl_VERSION
+
+  .. versionadded:: 3.21
+
+  The version of intl found (x.y.z)
+
+.. variable:: Intl_VERSION_MAJOR
+
+  .. versionadded:: 3.21
+
+  The major version of intl
+
+.. variable:: Intl_VERSION_MINOR
+
+  .. versionadded:: 3.21
+
+  The minor version of intl
+
+.. variable:: Intl_VERSION_PATCH
+
+  .. versionadded:: 3.21
+
+  The patch version of intl
+
 .. versionadded:: 3.20
   This module defines :prop_tgt:`IMPORTED` target ``Intl::Intl``.
 
@@ -50,6 +74,10 @@
   case.
 
 .. note::
+  Some libintl implementations don't embed the version number in their header files.
+  In this case the variables ``Intl_VERSION*`` will be empty.
+
+.. note::
   If you wish to use the Gettext tools (``msgmerge``,
   ``msgfmt``, etc.), use :module:`FindGettext`.
 #]=======================================================================]
@@ -106,10 +134,32 @@
   mark_as_advanced(Intl_LIBRARY)
 endif()
 
+# NOTE: glibc's libintl.h does not define LIBINTL_VERSION
+if(Intl_INCLUDE_DIR AND EXISTS "${Intl_INCLUDE_DIR}/libintl.h")
+  file(STRINGS ${Intl_INCLUDE_DIR}/libintl.h Intl_VERSION_DEFINE REGEX "LIBINTL_VERSION (.*)")
+
+  if(Intl_VERSION_DEFINE MATCHES "(0x[A-Fa-f0-9]+)")
+    set(Intl_VERSION_NUMBER "${CMAKE_MATCH_1}")
+    # encoding -> version number: (major<<16) + (minor<<8) + patch
+    math(EXPR Intl_VERSION_MAJOR "${Intl_VERSION_NUMBER} >> 16" OUTPUT_FORMAT HEXADECIMAL)
+    math(EXPR Intl_VERSION_MINOR "(${Intl_VERSION_NUMBER} - (${Intl_VERSION_MAJOR} << 16)) >> 8" OUTPUT_FORMAT HEXADECIMAL)
+    math(EXPR Intl_VERSION_PATCH "${Intl_VERSION_NUMBER} - ((${Intl_VERSION_MAJOR} << 16) + (${Intl_VERSION_MINOR} << 8))" OUTPUT_FORMAT HEXADECIMAL)
+
+    math(EXPR Intl_VERSION_MAJOR "${Intl_VERSION_MAJOR}" OUTPUT_FORMAT DECIMAL)
+    math(EXPR Intl_VERSION_MINOR "${Intl_VERSION_MINOR}" OUTPUT_FORMAT DECIMAL)
+    math(EXPR Intl_VERSION_PATCH "${Intl_VERSION_PATCH}" OUTPUT_FORMAT DECIMAL)
+    set(Intl_VERSION "${Intl_VERSION_MAJOR}.${Intl_VERSION_MINOR}.${Intl_VERSION_PATCH}")
+  endif()
+
+  unset(Intl_VERSION_DEFINE)
+  unset(Intl_VERSION_NUMBER)
+endif()
+
 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 FIND_PACKAGE_HANDLE_STANDARD_ARGS(Intl
                                   FOUND_VAR Intl_FOUND
                                   REQUIRED_VARS ${_Intl_REQUIRED_VARS}
+                                  VERSION_VAR Intl_VERSION
                                   FAIL_MESSAGE "Failed to find Gettext libintl")
 unset(_Intl_REQUIRED_VARS)
 unset(_Intl_IS_BUILT_IN_MSG)
diff --git a/Modules/FindLAPACK.cmake b/Modules/FindLAPACK.cmake
index 45e4be7..d89c40d 100644
--- a/Modules/FindLAPACK.cmake
+++ b/Modules/FindLAPACK.cmake
@@ -45,6 +45,8 @@
   * ``Arm_ilp64_mp``
   * ``EML``
   * ``EML_mt``
+  * ``Fujitsu_SSL2`` (Fujitsu serial blas / lapack)
+  * ``Fujitsu_SSL2BLAMP`` (Fujitsu parallel blas / lapack)
   * ``Generic``
 
   .. versionadded:: 3.6
@@ -68,6 +70,7 @@
 
   .. versionadded:: 3.20
     Elbrus Math Library support (``EML``, ``EML_mt``).
+    Fujitsu SSL2 Library support (``Fujitsu_SSL2``, ``Fujitsu_SSL2BLAMP``)
 
 ``BLA_F95``
   if ``ON`` tries to find the BLAS95/LAPACK95 interfaces
@@ -130,20 +133,33 @@
 function(_add_lapack_target)
   if(LAPACK_FOUND AND NOT TARGET LAPACK::LAPACK)
     add_library(LAPACK::LAPACK INTERFACE IMPORTED)
+
+    # Filter out redundant BLAS info and replace with the BLAS target
     set(_lapack_libs "${LAPACK_LIBRARIES}")
-    if(_lapack_libs AND TARGET BLAS::BLAS)
-      # remove the ${BLAS_LIBRARIES} from the interface and replace it
-      # with the BLAS::BLAS target
-      list(REMOVE_ITEM _lapack_libs "${BLAS_LIBRARIES}")
+    set(_lapack_flags "${LAPACK_LINKER_FLAGS}")
+    if(TARGET BLAS::BLAS)
+      if(_lapack_libs AND BLAS_LIBRARIES)
+        foreach(_blas_lib IN LISTS BLAS_LIBRARIES)
+          list(REMOVE_ITEM _lapack_libs "${_blas_lib}")
+        endforeach()
+      endif()
+      if(_lapack_flags AND BLAS_LINKER_FLAGS)
+        foreach(_blas_flag IN LISTS BLAS_LINKER_FLAGS)
+          list(REMOVE_ITEM _lapack_flags "${_blas_flag}")
+        endforeach()
+      endif()
       list(APPEND _lapack_libs BLAS::BLAS)
     endif()
-
     if(_lapack_libs)
       set_target_properties(LAPACK::LAPACK PROPERTIES
         INTERFACE_LINK_LIBRARIES "${_lapack_libs}"
       )
     endif()
-    unset(_lapack_libs)
+    if(_lapack_flags)
+      set_target_properties(LAPACK::LAPACK PROPERTIES
+        INTERFACE_LINK_OPTIONS "${_lapack_flags}"
+      )
+    endif()
   endif()
 endfunction()
 
@@ -174,22 +190,16 @@
 
 # TODO: move this stuff to a separate module
 
-macro(CHECK_LAPACK_LIBRARIES LIBRARIES _prefix _name _flags _list _threadlibs _addlibdir _subdirs _blas)
-  # This macro checks for the existence of the combination of fortran libraries
-  # given by _list.  If the combination is found, this macro checks (using the
-  # Check_Fortran_Function_Exists macro) whether can link against that library
-  # combination using the name of a routine given by _name using the linker
-  # flags given by _flags.  If the combination of libraries is found and passes
-  # the link test, LIBRARIES is set to the list of complete library paths that
-  # have been found.  Otherwise, LIBRARIES is set to FALSE.
-
-  # N.B. _prefix is the prefix applied to the names of all cached variables that
-  # are generated internally and marked advanced by this macro.
-  # _addlibdir is a list of additional search paths. _subdirs is a list of path
-  # suffixes to be used by find_library().
+function(CHECK_LAPACK_LIBRARIES LIBRARIES _prefix _name _flags _list _deps _addlibdir _subdirs _blas)
+  # This function checks for the existence of the combination of libraries
+  # given by _list.  If the combination is found, this checks whether can link
+  # against that library combination using the name of a routine given by _name
+  # using the linker flags given by _flags.  If the combination of libraries is
+  # found and passes the link test, ${LIBRARIES} is set to the list of complete
+  # library paths that have been found.  Otherwise, ${LIBRARIES} is set to FALSE.
 
   set(_libraries_work TRUE)
-  set(${LIBRARIES})
+  set(_libraries)
   set(_combined_name)
 
   set(_extaddlibdir "${_addlibdir}")
@@ -203,31 +213,36 @@
   list(APPEND _extaddlibdir "${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}")
 
   foreach(_library ${_list})
-    if(_library MATCHES "^-Wl,--(start|end)-group$")
-      # Respect linker flags like --start/end-group (required by MKL)
-      set(${LIBRARIES} ${${LIBRARIES}} "${_library}")
+    if(_library MATCHES "^-")
+      # Respect linker flags as-is (required by MKL)
+      list(APPEND _libraries "${_library}")
     else()
-      set(_combined_name ${_combined_name}_${_library})
+      string(REGEX REPLACE "[^A-Za-z0-9]" "_" _lib_var "${_library}")
+      set(_combined_name ${_combined_name}_${_lib_var})
+      if(NOT "${_deps}" STREQUAL "")
+        set(_combined_name ${_combined_name}_deps)
+      endif()
       if(_libraries_work)
-        find_library(${_prefix}_${_library}_LIBRARY
+        find_library(${_prefix}_${_lib_var}_LIBRARY
           NAMES ${_library}
           NAMES_PER_DIR
           PATHS ${_extaddlibdir}
           PATH_SUFFIXES ${_subdirs}
         )
-        #message("DEBUG: find_library(${_library}) got ${${_prefix}_${_library}_LIBRARY}")
-        mark_as_advanced(${_prefix}_${_library}_LIBRARY)
-        set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_library}_LIBRARY})
-        set(_libraries_work ${${_prefix}_${_library}_LIBRARY})
+        mark_as_advanced(${_prefix}_${_lib_var}_LIBRARY)
+        list(APPEND _libraries ${${_prefix}_${_lib_var}_LIBRARY})
+        set(_libraries_work ${${_prefix}_${_lib_var}_LIBRARY})
       endif()
     endif()
   endforeach()
-  unset(_library)
 
+  foreach(_flag ${_flags})
+    string(REGEX REPLACE "[^A-Za-z0-9]" "_" _flag_var "${_flag}")
+    set(_combined_name ${_combined_name}_${_flag_var})
+  endforeach()
   if(_libraries_work)
     # Test this combination of libraries.
-    set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}} ${_blas} ${_threadlibs})
-    #message("DEBUG: CMAKE_REQUIRED_LIBRARIES = ${CMAKE_REQUIRED_LIBRARIES}")
+    set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${_libraries} ${_blas} ${_deps})
     if(CMAKE_Fortran_COMPILER_LOADED)
       check_fortran_function_exists("${_name}" ${_prefix}${_combined_name}_WORKS)
     else()
@@ -239,19 +254,15 @@
 
   if(_libraries_work)
     if("${_list}${_blas}" STREQUAL "")
-      set(${LIBRARIES} "${LIBRARIES}-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
+      set(_libraries "${LIBRARIES}-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
     else()
-      set(${LIBRARIES} ${${LIBRARIES}} ${_blas} ${_threadlibs})
+      list(APPEND _libraries ${_blas} ${_deps})
     endif()
   else()
-    set(${LIBRARIES} FALSE)
+    set(_libraries FALSE)
   endif()
-
-  unset(_extaddlibdir)
-  unset(_libraries_work)
-  unset(_combined_name)
-  #message("DEBUG: ${LIBRARIES} = ${${LIBRARIES}}")
-endmacro()
+  set(${LIBRARIES} "${_libraries}" PARENT_SCOPE)
+endfunction()
 
 macro(_lapack_find_dependency dep)
   set(_lapack_quiet_arg)
@@ -279,6 +290,7 @@
 set(LAPACK_LINKER_FLAGS)
 set(LAPACK_LIBRARIES)
 set(LAPACK95_LIBRARIES)
+set(_lapack_fphsa_req_var LAPACK_LIBRARIES)
 
 # Check the language being used
 if(NOT (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED))
@@ -585,6 +597,38 @@
     )
   endif()
 
+  # Fujitsu SSL2 Library?
+  if(NOT LAPACK_LIBRARIES
+      AND BLA_VENDOR MATCHES "Fujitsu_SSL2" OR BLA_VENDOR STREQUAL "All")
+    if(BLA_VENDOR STREQUAL "Fujitsu_SSL2BLAMP")
+      set(_ssl2_suffix BLAMP)
+    else()
+      set(_ssl2_suffix)
+    endif()
+    set(_ssl2_blas)
+    if(BLAS_LIBRARIES STREQUAL "")
+      set(_ssl2_blas "${BLAS_LINKER_FLAGS}")
+    else()
+      set(_ssl2_blas "${BLAS_LIBRARIES} ${BLAS_LINKER_FLAGS}")
+    endif()
+    check_lapack_libraries(
+      LAPACK_LIBRARIES
+      LAPACK
+      cheev
+      "-SSL2${_ssl2_suffix}"
+      ""
+      ""
+      ""
+      ""
+      "${_ssl2_blas}"
+    )
+    if(LAPACK_LIBRARIES)
+      set(LAPACK_LINKER_FLAGS "-SSL2${_ssl2_suffix}")
+      set(_lapack_fphsa_req_var LAPACK_LINKER_FLAGS)
+    endif()
+    unset(_ssl2_suffix)
+  endif()
+
   # Generic LAPACK library?
   if(NOT LAPACK_LIBRARIES
       AND (BLA_VENDOR STREQUAL "Generic"
@@ -612,7 +656,7 @@
   set(LAPACK_NOT_FOUND_MESSAGE
     REASON_FAILURE_MESSAGE ${LAPACK_NOT_FOUND_MESSAGE})
 endif()
-find_package_handle_standard_args(LAPACK REQUIRED_VARS LAPACK_LIBRARIES
+find_package_handle_standard_args(LAPACK REQUIRED_VARS ${_lapack_fphsa_req_var}
   ${LAPACK_NOT_FOUND_MESSAGE})
 unset(LAPACK_NOT_FOUND_MESSAGE)
 
diff --git a/Modules/FindMPI.cmake b/Modules/FindMPI.cmake
index de38ac2..c48decb 100644
--- a/Modules/FindMPI.cmake
+++ b/Modules/FindMPI.cmake
@@ -277,6 +277,11 @@
                                            mpif77   mpif77_r  mpf77   mpf77_r
                                            mpifc)
 
+#Fujitsu cross/own compiler names
+set(_MPI_Fujitsu_C_COMPILER_NAMES        mpifccpx mpifcc)
+set(_MPI_Fujitsu_CXX_COMPILER_NAMES      mpiFCCpx mpiFCC)
+set(_MPI_Fujitsu_Fortran_COMPILER_NAMES  mpifrtpx mpifrt)
+
 # GNU compiler names
 set(_MPI_GNU_C_COMPILER_NAMES              mpigcc mpgcc mpigcc_r mpgcc_r)
 set(_MPI_GNU_CXX_COMPILER_NAMES            mpig++ mpg++ mpig++_r mpg++_r mpigxx)
@@ -337,7 +342,7 @@
 # pick up the right settings for it.
 foreach (LANG IN ITEMS C CXX Fortran)
   set(_MPI_${LANG}_COMPILER_NAMES "")
-  foreach (id IN ITEMS GNU Intel IntelLLVM MSVC PGI XL)
+  foreach (id IN ITEMS Fujitsu FujitsuClang GNU Intel IntelLLVM MSVC PGI XL)
     if (NOT CMAKE_${LANG}_COMPILER_ID OR CMAKE_${LANG}_COMPILER_ID STREQUAL id)
       foreach(_COMPILER_NAME IN LISTS _MPI_${id}_${LANG}_COMPILER_NAMES)
         list(APPEND _MPI_${LANG}_COMPILER_NAMES ${_COMPILER_NAME}${MPI_EXECUTABLE_SUFFIX})
diff --git a/Modules/FindOpenMP.cmake b/Modules/FindOpenMP.cmake
index 52330a4..e982e2d 100644
--- a/Modules/FindOpenMP.cmake
+++ b/Modules/FindOpenMP.cmake
@@ -130,6 +130,8 @@
     set(OMP_FLAG_XL "-qsmp=omp")
     # Cray compiler activate OpenMP with -h omp, which is enabled by default.
     set(OMP_FLAG_Cray " " "-h omp")
+    set(OMP_FLAG_Fujitsu "-Kopenmp" "-KOMP")
+    set(OMP_FLAG_FujitsuClang "-fopenmp" "-Kopenmp")
 
     # If we know the correct flags, use those
     if(DEFINED OMP_FLAG_${CMAKE_${LANG}_COMPILER_ID})
diff --git a/Modules/FindRuby.cmake b/Modules/FindRuby.cmake
index ee07f83..759f57c 100644
--- a/Modules/FindRuby.cmake
+++ b/Modules/FindRuby.cmake
@@ -435,7 +435,7 @@
 
 
 # Determine the list of possible names for the ruby library
-set(_Ruby_POSSIBLE_LIB_NAMES ruby ruby-static ruby${_Ruby_VERSION_SHORT} ruby${_Ruby_VERSION_SHORT_NODOT} ruby-${_Ruby_VERSION_SHORT} ruby-${Ruby_VERSION})
+set(_Ruby_POSSIBLE_LIB_NAMES ruby ruby-static ruby${_Ruby_VERSION_SHORT} ruby${_Ruby_VERSION_SHORT_NODOT} ruby${_Ruby_NODOT_VERSION} ruby-${_Ruby_VERSION_SHORT} ruby-${Ruby_VERSION})
 
 if(WIN32)
   set(_Ruby_POSSIBLE_MSVC_RUNTIMES "msvcrt;vcruntime140;vcruntime140_1")
diff --git a/Modules/FindThreads.cmake b/Modules/FindThreads.cmake
index 87e88bc..28dffc0 100644
--- a/Modules/FindThreads.cmake
+++ b/Modules/FindThreads.cmake
@@ -119,7 +119,10 @@
         ${CMAKE_BINARY_DIR}
         ${_threads_src}
         CMAKE_FLAGS -DLINK_LIBRARIES:STRING=-pthread
-        OUTPUT_VARIABLE OUTPUT)
+        OUTPUT_VARIABLE _cmake_check_pthreads_output)
+
+      string(APPEND _cmake_find_threads_output "${_cmake_check_pthreads_output}")
+      unset(_cmake_check_pthreads_output)
       unset(_threads_src)
 
       if(THREADS_HAVE_PTHREAD_ARG)
@@ -127,9 +130,6 @@
         message(CHECK_PASS "yes")
       else()
         message(CHECK_FAIL "no")
-        file(APPEND
-          ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
-          "Determining if compiler accepts -pthread failed with the following output:\n${OUTPUT}\n\n")
       endif()
 
     endif()
@@ -249,4 +249,10 @@
   if(CMAKE_THREAD_LIBS_INIT)
     set_property(TARGET Threads::Threads PROPERTY INTERFACE_LINK_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}")
   endif()
+elseif(NOT THREADS_FOUND AND _cmake_find_threads_output)
+  file(APPEND
+    ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+    "Determining if compiler accepts -pthread failed with the following output:\n${_cmake_find_threads_output}\n\n")
 endif()
+
+unset(_cmake_find_threads_output)
diff --git a/Modules/FortranCInterface/Detect.cmake b/Modules/FortranCInterface/Detect.cmake
index 998faf1..9e5726b 100644
--- a/Modules/FortranCInterface/Detect.cmake
+++ b/Modules/FortranCInterface/Detect.cmake
@@ -6,14 +6,17 @@
 
 # Detect the Fortran/C interface on the first run or when the
 # configuration changes.
-if(${FortranCInterface_BINARY_DIR}/Input.cmake
-    IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake
-    OR ${FortranCInterface_SOURCE_DIR}/Output.cmake.in
-    IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake
-    OR ${FortranCInterface_SOURCE_DIR}/CMakeLists.txt
-    IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake
-    OR ${CMAKE_CURRENT_LIST_FILE}
-    IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake
+if(NOT EXISTS ${FortranCInterface_BINARY_DIR}/Output.cmake
+    OR NOT EXISTS ${FortranCInterface_BINARY_DIR}/Input.cmake
+    OR NOT EXISTS ${FortranCInterface_BINARY_DIR}/Output.cmake.in
+    OR NOT ${FortranCInterface_BINARY_DIR}/Output.cmake
+      IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Input.cmake
+    OR NOT ${FortranCInterface_SOURCE_DIR}/Output.cmake
+      IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake.in
+    OR NOT ${FortranCInterface_BINARY_DIR}/Output.cmake
+      IS_NEWER_THAN ${FortranCInterface_SOURCE_DIR}/CMakeLists.txt
+    OR NOT ${FortranCInterface_BINARY_DIR}/Output.cmake
+      IS_NEWER_THAN ${CMAKE_CURRENT_LIST_FILE}
     )
   message(CHECK_START "Detecting Fortran/C Interface")
 else()
diff --git a/Modules/GoogleTest.cmake b/Modules/GoogleTest.cmake
index 2ea9e74..80d8e23 100644
--- a/Modules/GoogleTest.cmake
+++ b/Modules/GoogleTest.cmake
@@ -504,7 +504,8 @@
 
     string(CONCAT ctest_include_content
       "if(EXISTS \"$<TARGET_FILE:${TARGET}>\")"                                    "\n"
-      "  if(\"$<TARGET_FILE:${TARGET}>\" IS_NEWER_THAN \"${ctest_tests_file}\")"   "\n"
+      "  if(NOT EXISTS \"${ctest_tests_file}\" OR"                                 "\n"
+      "     NOT \"${ctest_tests_file}\" IS_NEWER_THAN \"$<TARGET_FILE:${TARGET}>\")" "\n"
       "    include(\"${_GOOGLETEST_DISCOVER_TESTS_SCRIPT}\")"                      "\n"
       "    gtest_discover_tests_impl("                                             "\n"
       "      TEST_EXECUTABLE"        " [==[" "$<TARGET_FILE:${TARGET}>"   "]==]"   "\n"
diff --git a/Modules/Internal/CPack/CPackRPM.cmake b/Modules/Internal/CPack/CPackRPM.cmake
index 08bbc68..bece2dd 100644
--- a/Modules/Internal/CPack/CPackRPM.cmake
+++ b/Modules/Internal/CPack/CPackRPM.cmake
@@ -6,6 +6,56 @@
 cmake_policy(PUSH)
 cmake_policy(SET CMP0057 NEW) # if IN_LIST
 
+function(set_spec_script_if_enabled TYPE PACKAGE_NAME VAR)
+  if(NOT "${VAR}" STREQUAL "" AND NOT "${VAR}" STREQUAL "\n")
+    if(PACKAGE_NAME)
+      set(PACKAGE_NAME " -n ${PACKAGE_NAME}")
+    endif()
+    set(${TYPE}_
+      "%${TYPE}${PACKAGE_NAME}\n"
+      "${VAR}\n" PARENT_SCOPE)
+  else()
+    set(${TYPE} "" PARENT_SCOPE)
+  endif()
+endfunction()
+
+macro(set_spec_scripts PACKAGE_NAME)
+  # we should only set scripts that were provided
+  # as script announcement without content inside
+  # spec file will generate unneeded dependency
+  # on shell
+
+  set_spec_script_if_enabled(
+    "post"
+    "${PACKAGE_NAME}"
+    "${RPM_SYMLINK_POSTINSTALL}\n${CPACK_RPM_SPEC_POSTINSTALL}")
+
+  set_spec_script_if_enabled(
+    "posttrans"
+    "${PACKAGE_NAME}"
+    "${CPACK_RPM_SPEC_POSTTRANS}")
+
+  set_spec_script_if_enabled(
+    "postun"
+    "${PACKAGE_NAME}"
+    "${CPACK_RPM_SPEC_POSTUNINSTALL}")
+
+  set_spec_script_if_enabled(
+    "pre"
+    "${PACKAGE_NAME}"
+    "${CPACK_RPM_SPEC_PREINSTALL}")
+
+  set_spec_script_if_enabled(
+    "pretrans"
+    "${PACKAGE_NAME}"
+    "${CPACK_RPM_SPEC_PRETRANS}")
+
+  set_spec_script_if_enabled(
+    "preun"
+    "${PACKAGE_NAME}"
+    "${CPACK_RPM_SPEC_PREUNINSTALL}")
+endmacro()
+
 function(get_file_permissions FILE RETURN_VAR)
   execute_process(COMMAND ls -l ${FILE}
           OUTPUT_VARIABLE permissions_
@@ -1349,15 +1399,21 @@
             continue()
           endif()
 
-          file(GLOB_RECURSE files_for_move_ LIST_DIRECTORIES false RELATIVE
+          file(GLOB_RECURSE files_for_move_ LIST_DIRECTORIES true RELATIVE
             "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}/${component_}"
             "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}/${component_}/*")
 
           foreach(f_ IN LISTS files_for_move_)
-            get_filename_component(dir_path_ "${f_}" DIRECTORY)
             set(src_file_
               "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}/${component_}/${f_}")
 
+            if(IS_DIRECTORY "${src_file_}")
+              file(MAKE_DIRECTORY "${WDIR}/${f_}")
+              continue()
+            endif()
+
+            get_filename_component(dir_path_ "${f_}" DIRECTORY)
+
             # check that we are not overriding an existing file that doesn't
             # match the file that we want to copy
             if(EXISTS "${src_file_}" AND EXISTS "${WDIR}/${f_}")
@@ -1607,6 +1663,9 @@
     )
 
   elseif(GENERATE_SPEC_PARTS) # binary rpm with single debuginfo package
+
+    set_spec_scripts("${CPACK_RPM_PACKAGE_NAME}")
+
     file(WRITE ${CPACK_RPM_BINARY_SPECFILE}.in
         "# -*- rpm-spec -*-
 %package -n \@CPACK_RPM_PACKAGE_NAME\@
@@ -1637,6 +1696,13 @@
 %description -n \@CPACK_RPM_PACKAGE_NAME\@
 \@CPACK_RPM_PACKAGE_DESCRIPTION\@
 
+\@post_\@
+\@posttrans_\@
+\@postun_\@
+\@pre_\@
+\@pretrans_\@
+\@preun_\@
+
 %files -n \@CPACK_RPM_PACKAGE_NAME\@
 %defattr(\@TMP_DEFAULT_FILE_PERMISSIONS\@,\@TMP_DEFAULT_USER\@,\@TMP_DEFAULT_GROUP\@,\@TMP_DEFAULT_DIR_PERMISSIONS\@)
 \@CPACK_RPM_INSTALL_FILES\@
@@ -1662,6 +1728,8 @@
     set(RPMBUILD_FLAGS "-bb")
     if(CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_TEMPLATE OR NOT CPACK_RPM_USER_BINARY_SPECFILE)
 
+      set_spec_scripts("")
+
       file(WRITE ${CPACK_RPM_BINARY_SPECFILE}.in
         "# Restore old style debuginfo creation for rpm >= 4.14.
 %undefine _debugsource_packages
@@ -1725,24 +1793,12 @@
 
 %clean
 
-%post
-\@RPM_SYMLINK_POSTINSTALL\@
-\@CPACK_RPM_SPEC_POSTINSTALL\@
-
-%posttrans
-\@CPACK_RPM_SPEC_POSTTRANS\@
-
-%postun
-\@CPACK_RPM_SPEC_POSTUNINSTALL\@
-
-%pre
-\@CPACK_RPM_SPEC_PREINSTALL\@
-
-%pretrans
-\@CPACK_RPM_SPEC_PRETRANS\@
-
-%preun
-\@CPACK_RPM_SPEC_PREUNINSTALL\@
+\@post_\@
+\@posttrans_\@
+\@postun_\@
+\@pre_\@
+\@pretrans_\@
+\@preun_\@
 
 %files
 %defattr(\@TMP_DEFAULT_FILE_PERMISSIONS\@,\@TMP_DEFAULT_USER\@,\@TMP_DEFAULT_GROUP\@,\@TMP_DEFAULT_DIR_PERMISSIONS\@)
diff --git a/Modules/Platform/Apple-NVIDIA-CUDA.cmake b/Modules/Platform/Apple-NVIDIA-CUDA.cmake
index bec3948..35e759a 100644
--- a/Modules/Platform/Apple-NVIDIA-CUDA.cmake
+++ b/Modules/Platform/Apple-NVIDIA-CUDA.cmake
@@ -1,19 +1,19 @@
 include(Platform/Darwin)
 
-set(__IMPLICT_LINKS )
+set(__IMPLICIT_LINKS)
 foreach(dir ${CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES})
-  string(APPEND __IMPLICT_LINKS " -L\"${dir}\"")
+  string(APPEND __IMPLICIT_LINKS " -L\"${dir}\"")
 endforeach()
 foreach(lib ${CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES})
   if(${lib} MATCHES "/")
-    string(APPEND __IMPLICT_LINKS " \"${lib}\"")
+    string(APPEND __IMPLICIT_LINKS " \"${lib}\"")
   else()
-    string(APPEND __IMPLICT_LINKS " -l${lib}")
+    string(APPEND __IMPLICIT_LINKS " -l${lib}")
   endif()
 endforeach()
 
 set(CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS "-shared -Wl,-headerpad_max_install_names")
 set(CMAKE_SHARED_MODULE_CREATE_CUDA_FLAGS "-shared -Wl,-headerpad_max_install_names")
 
-set(CMAKE_CUDA_CREATE_SHARED_LIBRARY "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS> -o <TARGET> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> <OBJECTS> <LINK_LIBRARIES>${__IMPLICT_LINKS}")
-set(CMAKE_CUDA_CREATE_SHARED_MODULE "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>${__IMPLICT_LINKS}")
+set(CMAKE_CUDA_CREATE_SHARED_LIBRARY "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS> -o <TARGET> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> <OBJECTS> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
+set(CMAKE_CUDA_CREATE_SHARED_MODULE "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <CMAKE_SHARED_LIBRARY_CUDA_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CUDA_FLAGS> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
diff --git a/Modules/Platform/CYGWIN-GNU.cmake b/Modules/Platform/CYGWIN-GNU.cmake
index 4fa14ce..b81bd4d 100644
--- a/Modules/Platform/CYGWIN-GNU.cmake
+++ b/Modules/Platform/CYGWIN-GNU.cmake
@@ -10,7 +10,6 @@
 
 # TODO: Is -Wl,--enable-auto-import now always default?
 string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " -Wl,--enable-auto-import")
-set(CMAKE_CREATE_WIN32_EXE  "-mwindows")
 
 set(CMAKE_GNULD_IMAGE_VERSION
   "-Wl,--major-image-version,<TARGET_VERSION_MAJOR>,--minor-image-version,<TARGET_VERSION_MINOR>")
@@ -23,6 +22,7 @@
     "<CMAKE_${lang}_COMPILER> <LANGUAGE_COMPILE_FLAGS> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>")
   set(CMAKE_${lang}_LINK_EXECUTABLE
     "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>")
+  set(CMAKE_${lang}_CREATE_WIN32_EXE "-mwindows")
 
    # No -fPIC on cygwin
   set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "")
diff --git a/Modules/Platform/Linux-Fujitsu-C.cmake b/Modules/Platform/Linux-Fujitsu-C.cmake
new file mode 100644
index 0000000..e37573d
--- /dev/null
+++ b/Modules/Platform/Linux-Fujitsu-C.cmake
@@ -0,0 +1 @@
+include(Platform/Linux-Clang-C)
diff --git a/Modules/Platform/Linux-Fujitsu-CXX.cmake b/Modules/Platform/Linux-Fujitsu-CXX.cmake
new file mode 100644
index 0000000..5257f13
--- /dev/null
+++ b/Modules/Platform/Linux-Fujitsu-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/Linux-Clang-CXX)
diff --git a/Modules/Platform/Linux-Fujitsu.cmake b/Modules/Platform/Linux-Fujitsu.cmake
new file mode 100644
index 0000000..be11b0a
--- /dev/null
+++ b/Modules/Platform/Linux-Fujitsu.cmake
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__LINUX_COMPILER_FUJITSU)
+  return()
+endif()
+set(__LINUX_COMPILER_FUJITSU 1)
+
+macro(__linux_compiler_fujitsu lang)
+  set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "-fPIC")
+  set(CMAKE_${lang}_COMPILE_OPTIONS_PIE "-fPIE")
+  set(CMAKE_${lang}_COMPILE_OPTIONS_VISIBILITY "-fvisibility=")
+  set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-fPIC")
+  set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared")
+endmacro()
diff --git a/Modules/Platform/Windows-Clang.cmake b/Modules/Platform/Windows-Clang.cmake
index c508ac1..7365ff5 100644
--- a/Modules/Platform/Windows-Clang.cmake
+++ b/Modules/Platform/Windows-Clang.cmake
@@ -71,8 +71,8 @@
   set(CMAKE_${lang}_LINK_EXECUTABLE
     "<CMAKE_${lang}_COMPILER> -fuse-ld=lld-link -nostartfiles -nostdlib <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Xlinker /implib:<TARGET_IMPLIB> -Xlinker /pdb:<TARGET_PDB> -Xlinker /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>")
 
-  set(CMAKE_CREATE_WIN32_EXE "-Xlinker /subsystem:windows")
-  set(CMAKE_CREATE_CONSOLE_EXE "-Xlinker /subsystem:console")
+  set(CMAKE_${lang}_CREATE_WIN32_EXE "-Xlinker /subsystem:windows")
+  set(CMAKE_${lang}_CREATE_CONSOLE_EXE "-Xlinker /subsystem:console")
 
   if(NOT "${lang}" STREQUAL "ASM")
     set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         -Xclang -flto-visibility-public-std -D_MT -Xclang --dependent-lib=libcmt)
diff --git a/Modules/Platform/Windows-Embarcadero.cmake b/Modules/Platform/Windows-Embarcadero.cmake
index 8f1d024..4ecc2c2 100644
--- a/Modules/Platform/Windows-Embarcadero.cmake
+++ b/Modules/Platform/Windows-Embarcadero.cmake
@@ -51,11 +51,6 @@
 # Borland cannot handle + in the file name, so mangle object file name
 set (CMAKE_MANGLE_OBJECT_FILE_NAMES "ON")
 
-# extra flags for a win32 exe
-set(CMAKE_CREATE_WIN32_EXE "${_tW}" )
-# extra flags for a console app
-set(CMAKE_CREATE_CONSOLE_EXE "${_tC}" )
-
 set (CMAKE_BUILD_TYPE Debug CACHE STRING
      "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel.")
 
@@ -124,6 +119,9 @@
     "tlib ${CMAKE_START_TEMP_FILE}/p512 <LINK_FLAGS> /a <TARGET_QUOTED> <OBJECTS>${CMAKE_END_TEMP_FILE}"
     )
 
+  set(CMAKE_${lang}_CREATE_WIN32_EXE "${_tW}")
+  set(CMAKE_${lang}_CREATE_CONSOLE_EXE "${_tC}")
+
   # Precompile Headers
   if (EMBARCADERO)
     set(CMAKE_PCH_EXTENSION .pch)
diff --git a/Modules/Platform/Windows-GNU.cmake b/Modules/Platform/Windows-GNU.cmake
index a2e3811..e50c215 100644
--- a/Modules/Platform/Windows-GNU.cmake
+++ b/Modules/Platform/Windows-GNU.cmake
@@ -35,7 +35,6 @@
 set(CMAKE_LINK_LIBRARY_FLAG "-l")
 set(CMAKE_LINK_DEF_FILE_FLAG "") # Empty string: passing the file is enough
 set(CMAKE_LINK_LIBRARY_SUFFIX "")
-set(CMAKE_CREATE_WIN32_EXE  "-mwindows")
 
 set(CMAKE_GNULD_IMAGE_VERSION
   "-Wl,--major-image-version,<TARGET_VERSION_MAJOR>,--minor-image-version,<TARGET_VERSION_MINOR>")
@@ -105,6 +104,7 @@
     "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>")
   set(CMAKE_${lang}_LINK_EXECUTABLE
     "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>")
+  set(CMAKE_${lang}_CREATE_WIN32_EXE "-mwindows")
 
   list(APPEND CMAKE_${lang}_ABI_FILES "Platform/Windows-GNU-${lang}-ABI")
 
diff --git a/Modules/Platform/Windows-MSVC.cmake b/Modules/Platform/Windows-MSVC.cmake
index e384af4..4223bde 100644
--- a/Modules/Platform/Windows-MSVC.cmake
+++ b/Modules/Platform/Windows-MSVC.cmake
@@ -27,12 +27,8 @@
 endif()
 
 if(CMAKE_SYSTEM_NAME STREQUAL "WindowsCE")
-  set(CMAKE_CREATE_WIN32_EXE "/entry:WinMainCRTStartup")
-  set(CMAKE_CREATE_CONSOLE_EXE "/entry:mainACRTStartup")
   set(_PLATFORM_LINK_FLAGS " /subsystem:windowsce")
 else()
-  set(CMAKE_CREATE_WIN32_EXE "/subsystem:windows")
-  set(CMAKE_CREATE_CONSOLE_EXE "/subsystem:console")
   set(_PLATFORM_LINK_FLAGS "")
 endif()
 
@@ -351,6 +347,14 @@
   set(CMAKE_${lang}_LINK_EXECUTABLE
     "${_CMAKE_VS_LINK_EXE}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}")
 
+  if(CMAKE_SYSTEM_NAME STREQUAL "WindowsCE")
+    set(CMAKE_${lang}_CREATE_WIN32_EXE "/entry:WinMainCRTStartup")
+    set(CMAKE_${lang}_CREATE_CONSOLE_EXE "/entry:mainACRTStartup")
+  else()
+    set(CMAKE_${lang}_CREATE_WIN32_EXE "/subsystem:windows")
+    set(CMAKE_${lang}_CREATE_CONSOLE_EXE "/subsystem:console")
+  endif()
+
   set(CMAKE_PCH_EXTENSION .pch)
   set(CMAKE_LINK_PCH ON)
   if (CMAKE_${lang}_COMPILER_ID STREQUAL "Clang")
diff --git a/Modules/Platform/Windows-NVIDIA-CUDA.cmake b/Modules/Platform/Windows-NVIDIA-CUDA.cmake
index a88f4bc..b83932e 100644
--- a/Modules/Platform/Windows-NVIDIA-CUDA.cmake
+++ b/Modules/Platform/Windows-NVIDIA-CUDA.cmake
@@ -7,49 +7,49 @@
 set(CMAKE_CUDA_COMPILE_WHOLE_COMPILATION
   "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <DEFINES> <INCLUDES> <FLAGS> ${_CMAKE_COMPILE_AS_CUDA_FLAG} -c <SOURCE> -o <OBJECT> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS")
 
-set(__IMPLICT_LINKS )
+set(__IMPLICIT_LINKS)
 foreach(dir ${CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES})
-  string(APPEND __IMPLICT_LINKS " -LIBPATH:\"${dir}\"")
+  string(APPEND __IMPLICIT_LINKS " -LIBPATH:\"${dir}\"")
 endforeach()
 foreach(lib ${CMAKE_CUDA_HOST_IMPLICIT_LINK_LIBRARIES})
-  string(APPEND __IMPLICT_LINKS " \"${lib}\"")
+  string(APPEND __IMPLICIT_LINKS " \"${lib}\"")
 endforeach()
 set(CMAKE_CUDA_LINK_EXECUTABLE
-   "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <LINK_FLAGS> <OBJECTS> /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <LINK_LIBRARIES>${__IMPLICT_LINKS}")
+   "<CMAKE_CUDA_HOST_LINK_LAUNCHER> <LINK_FLAGS> <OBJECTS> /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <LINK_LIBRARIES>${__IMPLICIT_LINKS}")
 
 set(_CMAKE_VS_LINK_DLL "<CMAKE_COMMAND> -E vs_link_dll --intdir=<OBJECT_DIR> --rc=<CMAKE_RC_COMPILER> --mt=<CMAKE_MT> --manifests <MANIFESTS> -- ")
 set(_CMAKE_VS_LINK_EXE "<CMAKE_COMMAND> -E vs_link_exe --intdir=<OBJECT_DIR> --rc=<CMAKE_RC_COMPILER> --mt=<CMAKE_MT> --manifests <MANIFESTS> -- ")
 set(CMAKE_CUDA_CREATE_SHARED_LIBRARY
-  "${_CMAKE_VS_LINK_DLL}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /dll /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <LINK_FLAGS> <LINK_LIBRARIES>${__IMPLICT_LINKS} ${CMAKE_END_TEMP_FILE}")
+  "${_CMAKE_VS_LINK_DLL}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /dll /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <LINK_FLAGS> <LINK_LIBRARIES>${__IMPLICIT_LINKS} ${CMAKE_END_TEMP_FILE}")
 
 set(CMAKE_CUDA_CREATE_SHARED_MODULE ${CMAKE_CUDA_CREATE_SHARED_LIBRARY})
 set(CMAKE_CUDA_CREATE_STATIC_LIBRARY  "<CMAKE_AR> ${CMAKE_CL_NOLOGO} <LINK_FLAGS> /out:<TARGET> <OBJECTS> ")
 set(CMAKE_CUDA_LINKER_SUPPORTS_PDB ON)
 set(CMAKE_CUDA_LINK_EXECUTABLE
-  "${_CMAKE_VS_LINK_EXE}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <LINK_FLAGS> <LINK_LIBRARIES>${__IMPLICT_LINKS} ${CMAKE_END_TEMP_FILE}")
-unset(_CMAKE_VS_LINK_EXE)
+  "${_CMAKE_VS_LINK_EXE}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <LINK_FLAGS> <LINK_LIBRARIES>${__IMPLICIT_LINKS} ${CMAKE_END_TEMP_FILE}")
+unset(_CMAKE_VS_LINK_DLL)
 unset(_CMAKE_VS_LINK_EXE)
 
 
 # Add implicit host link directories that contain device libraries
 # to the device link line.
-set(__IMPLICT_DLINK_DIRS ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
-if(__IMPLICT_DLINK_DIRS)
-  list(REMOVE_ITEM __IMPLICT_DLINK_DIRS ${CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES})
+set(__IMPLICIT_DLINK_DIRS ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
+if(__IMPLICIT_DLINK_DIRS)
+  list(REMOVE_ITEM __IMPLICIT_DLINK_DIRS ${CMAKE_CUDA_HOST_IMPLICIT_LINK_DIRECTORIES})
 endif()
-set(__IMPLICT_DLINK_FLAGS )
-foreach(dir ${__IMPLICT_DLINK_DIRS})
+set(__IMPLICIT_DLINK_FLAGS)
+foreach(dir ${__IMPLICIT_DLINK_DIRS})
   if(EXISTS "${dir}/curand_static.lib")
-    string(APPEND __IMPLICT_DLINK_FLAGS " -L\"${dir}\"")
+    string(APPEND __IMPLICIT_DLINK_FLAGS " -L\"${dir}\"")
   endif()
 endforeach()
-unset(__IMPLICT_DLINK_DIRS)
+unset(__IMPLICIT_DLINK_DIRS)
 
 set(CMAKE_CUDA_DEVICE_LINK_LIBRARY
-  "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICT_DLINK_FLAGS}")
+  "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICIT_DLINK_FLAGS}")
 set(CMAKE_CUDA_DEVICE_LINK_EXECUTABLE
-  "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICT_DLINK_FLAGS}")
-unset(__IMPLICT_DLINK_FLAGS)
+  "<CMAKE_CUDA_COMPILER> ${_CMAKE_CUDA_EXTRA_FLAGS} <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> ${_CMAKE_CUDA_EXTRA_DEVICE_LINK_FLAGS} -shared -dlink <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Xcompiler=-Fd<TARGET_COMPILE_PDB>,-FS${__IMPLICIT_DLINK_FLAGS}")
+unset(__IMPLICIT_DLINK_FLAGS)
 
 string(REPLACE "/D" "-D" _PLATFORM_DEFINES_CUDA "${_PLATFORM_DEFINES}${_PLATFORM_DEFINES_CXX}")
 
@@ -69,14 +69,6 @@
 endif()
 unset(_cmp0092)
 
-set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_STATIC  "cudadevrt;cudart_static")
-set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_SHARED  "cudadevrt;cudart")
-set(CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_NONE    "")
-
-if(UNIX)
-  list(APPEND CMAKE_CUDA_RUNTIME_LIBRARY_LINK_OPTIONS_STATIC "rt" "pthread" "dl")
-endif()
-
 string(APPEND CMAKE_CUDA_FLAGS_INIT " ${PLATFORM_DEFINES_CUDA} -D_WINDOWS -Xcompiler=\"${_W3}${_FLAGS_CXX}\"")
 string(APPEND CMAKE_CUDA_FLAGS_DEBUG_INIT " -Xcompiler=\"${_MDd}-Zi -Ob0 -Od ${_RTC1}\"")
 string(APPEND CMAKE_CUDA_FLAGS_RELEASE_INIT " -Xcompiler=\"${_MD}-O2 -Ob2\" -DNDEBUG")
diff --git a/Modules/Platform/Windows-OpenWatcom-C.cmake b/Modules/Platform/Windows-OpenWatcom-C.cmake
index ce9bc45..b82a4cb 100644
--- a/Modules/Platform/Windows-OpenWatcom-C.cmake
+++ b/Modules/Platform/Windows-OpenWatcom-C.cmake
@@ -1 +1,2 @@
 include(Platform/Windows-OpenWatcom)
+__windows_open_watcom(C)
diff --git a/Modules/Platform/Windows-OpenWatcom-CXX.cmake b/Modules/Platform/Windows-OpenWatcom-CXX.cmake
index ce9bc45..ac90d28 100644
--- a/Modules/Platform/Windows-OpenWatcom-CXX.cmake
+++ b/Modules/Platform/Windows-OpenWatcom-CXX.cmake
@@ -1 +1,2 @@
 include(Platform/Windows-OpenWatcom)
+__windows_open_watcom(CXX)
diff --git a/Modules/Platform/Windows-OpenWatcom.cmake b/Modules/Platform/Windows-OpenWatcom.cmake
index 70055da..19bcb97 100644
--- a/Modules/Platform/Windows-OpenWatcom.cmake
+++ b/Modules/Platform/Windows-OpenWatcom.cmake
@@ -6,8 +6,6 @@
 
 set(CMAKE_BUILD_TYPE_INIT Debug)
 
-set(CMAKE_CREATE_WIN32_EXE "system nt_win" )
-set(CMAKE_CREATE_CONSOLE_EXE "system nt" )
 string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " system nt_dll")
 string(APPEND CMAKE_MODULE_LINKER_FLAGS_INIT " system nt_dll")
 
@@ -30,3 +28,8 @@
     set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES $ENV{WATCOM}/h $ENV{WATCOM}/h/nt)
   endif()
 endif()
+
+macro(__windows_open_watcom lang)
+  set(CMAKE_${lang}_CREATE_WIN32_EXE "system nt_win")
+  set(CMAKE_${lang}_CREATE_CONSOLE_EXE "system nt")
+endmacro()
diff --git a/Modules/Platform/Windows-df.cmake b/Modules/Platform/Windows-df.cmake
index 8b824bc..c823423 100644
--- a/Modules/Platform/Windows-df.cmake
+++ b/Modules/Platform/Windows-df.cmake
@@ -27,8 +27,8 @@
 set(CMAKE_Fortran_LINK_EXECUTABLE
     "<CMAKE_Fortran_COMPILER> ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE} <FLAGS> /exe:<TARGET> <OBJECTS> /link <CMAKE_Fortran_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}")
 
-set(CMAKE_CREATE_WIN32_EXE /winapp)
-set(CMAKE_CREATE_CONSOLE_EXE )
+set(CMAKE_Fortran_CREATE_WIN32_EXE /winapp)
+set(CMAKE_Fortran_CREATE_CONSOLE_EXE )
 
 # does the compiler support pdbtype and is it the newer compiler
 
diff --git a/Modules/UseSWIG.cmake b/Modules/UseSWIG.cmake
index 6073125..8852df8 100644
--- a/Modules/UseSWIG.cmake
+++ b/Modules/UseSWIG.cmake
@@ -38,7 +38,13 @@
 
   .. versionchanged:: 3.15
     Alternate library name (set with the :prop_tgt:`OUTPUT_NAME` property,
-    for example) will be passed on to Python and CSharp wrapper libraries.
+    for example) will be passed on to ``Python`` and ``CSharp`` wrapper
+    libraries.
+
+  .. versionchanged:: 3.21
+    Generated library use standard naming conventions for ``CSharp`` language
+    when policy :policy:`CMP0122` is set to ``NEW``. Otherwise, the legacy
+    behavior is applied.
 
   .. note::
 
@@ -952,6 +958,17 @@
     endif ()
   elseif (swig_lowercase_language STREQUAL "fortran")
     # Do *not* override the target's library prefix
+  elseif (swig_lowercase_language STREQUAL "csharp")
+    cmake_policy(GET CMP0122 csharp_naming_policy)
+    if (csharp_naming_policy STREQUAL "NEW")
+      # Do *not* override the target's library prefix
+    else()
+      if (NOT csharp_naming_policy)
+        cmake_policy(GET_WARNING CMP0122 _cmp0122_warning)
+        message(AUTHOR_WARNING "${_cmp0122_warning}\n")
+      endif()
+      set_target_properties (${target_name} PROPERTIES PREFIX "")
+    endif()
   else()
     # assume empty prefix because we expect the module to be dynamically loaded
     set_target_properties (${target_name} PROPERTIES PREFIX "")
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 6adc9cf..938745c 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -198,6 +198,8 @@
   cmCMakePath.cxx
   cmCMakePresetsFile.cxx
   cmCMakePresetsFile.h
+  cmCMakePresetsFileInternal.h
+  cmCMakePresetsFileReadJSON.cxx
   cmCommandArgumentParserHelper.cxx
   cmCommonTargetGenerator.cxx
   cmCommonTargetGenerator.h
@@ -785,8 +787,6 @@
       cmVisualStudioGeneratorOptions.cxx
       cmVisualStudio10TargetGenerator.h
       cmVisualStudio10TargetGenerator.cxx
-      cmVisualStudio10ToolsetOptions.h
-      cmVisualStudio10ToolsetOptions.cxx
       cmLocalVisualStudio10Generator.cxx
       cmLocalVisualStudio10Generator.h
       cmGlobalVisualStudio10Generator.h
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 8b9029f..985d944 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 20)
-set(CMake_VERSION_PATCH 1)
+set(CMake_VERSION_PATCH 20210416)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
diff --git a/Source/CPack/IFW/cmCPackIFWPackage.cxx b/Source/CPack/IFW/cmCPackIFWPackage.cxx
index c4bd7f1..1429c46 100644
--- a/Source/CPack/IFW/cmCPackIFWPackage.cxx
+++ b/Source/CPack/IFW/cmCPackIFWPackage.cxx
@@ -7,6 +7,8 @@
 #include <sstream>
 #include <utility>
 
+#include <cm/string_view>
+
 #include "cmCPackComponentGroup.h"
 #include "cmCPackIFWCommon.h"
 #include "cmCPackIFWGenerator.h"
@@ -30,44 +32,67 @@
 cmCPackIFWPackage::DependenceStruct::DependenceStruct(
   const std::string& dependence)
 {
-  // Search compare section
-  size_t pos = std::string::npos;
-  if ((pos = dependence.find("<=")) != std::string::npos) {
-    this->Compare.Type = cmCPackIFWPackage::CompareLessOrEqual;
-    this->Compare.Value = dependence.substr(pos + 2);
-  } else if ((pos = dependence.find(">=")) != std::string::npos) {
-    this->Compare.Type = cmCPackIFWPackage::CompareGreaterOrEqual;
-    this->Compare.Value = dependence.substr(pos + 2);
-  } else if ((pos = dependence.find('<')) != std::string::npos) {
-    this->Compare.Type = cmCPackIFWPackage::CompareLess;
-    this->Compare.Value = dependence.substr(pos + 1);
-  } else if ((pos = dependence.find('=')) != std::string::npos) {
-    this->Compare.Type = cmCPackIFWPackage::CompareEqual;
-    this->Compare.Value = dependence.substr(pos + 1);
-  } else if ((pos = dependence.find('>')) != std::string::npos) {
-    this->Compare.Type = cmCPackIFWPackage::CompareGreater;
-    this->Compare.Value = dependence.substr(pos + 1);
-  } else if ((pos = dependence.find('-')) != std::string::npos) {
-    this->Compare.Type = cmCPackIFWPackage::CompareNone;
-    this->Compare.Value = dependence.substr(pos + 1);
+  // Preferred format is name and version are separated by a colon (:), but
+  // note that this is only supported with QtIFW 3.1 or later. Backward
+  // compatibility allows a hyphen (-) as a separator instead, but names then
+  // cannot contain a hyphen.
+  size_t pos;
+  if ((pos = dependence.find(':')) == std::string::npos) {
+    pos = dependence.find('-');
   }
-  size_t dashPos = dependence.find('-');
-  if (dashPos != std::string::npos) {
-    pos = dashPos;
+
+  if (pos != std::string::npos) {
+    this->Name = dependence.substr(0, pos);
+    ++pos;
+    if (pos == dependence.size()) {
+      // Nothing after the separator. Treat this as no version constraint.
+      return;
+    }
+
+    const auto versionPart =
+      cm::string_view(dependence.data() + pos, dependence.size() - pos);
+
+    if (cmHasLiteralPrefix(versionPart, "<=")) {
+      this->Compare.Type = cmCPackIFWPackage::CompareLessOrEqual;
+      this->Compare.Value = std::string(versionPart.substr(2));
+    } else if (cmHasLiteralPrefix(versionPart, ">=")) {
+      this->Compare.Type = cmCPackIFWPackage::CompareGreaterOrEqual;
+      this->Compare.Value = std::string(versionPart.substr(2));
+    } else if (cmHasPrefix(versionPart, '<')) {
+      this->Compare.Type = cmCPackIFWPackage::CompareLess;
+      this->Compare.Value = std::string(versionPart.substr(1));
+    } else if (cmHasPrefix(versionPart, '=')) {
+      this->Compare.Type = cmCPackIFWPackage::CompareEqual;
+      this->Compare.Value = std::string(versionPart.substr(1));
+    } else if (cmHasPrefix(versionPart, '>')) {
+      this->Compare.Type = cmCPackIFWPackage::CompareGreater;
+      this->Compare.Value = std::string(versionPart.substr(1));
+    } else {
+      // We found no operator but a version specification is still expected to
+      // follow. The default behavior is to treat this the same as =. We
+      // explicitly record that as our type (it simplifies our logic a little
+      // and is also clearer).
+      this->Compare.Type = cmCPackIFWPackage::CompareEqual;
+      this->Compare.Value = std::string(versionPart);
+    }
+  } else {
+    this->Name = dependence;
   }
-  this->Name = dependence.substr(0, pos);
 }
 
 std::string cmCPackIFWPackage::DependenceStruct::NameWithCompare() const
 {
-  if (this->Compare.Type == cmCPackIFWPackage::CompareNone) {
-    return this->Name;
-  }
-
   std::string result = this->Name;
-
-  if (this->Compare.Type != cmCPackIFWPackage::CompareNone ||
-      !this->Compare.Value.empty()) {
+  if (this->Name.find('-') != std::string::npos) {
+    // When a name contains a hyphen, we must use a colon after the name to
+    // prevent the hyphen from being parsed by QtIFW as the separator between
+    // the name and the version. Note that a colon is only supported with
+    // QtIFW 3.1 or later.
+    result += ":";
+  } else if (this->Compare.Type != cmCPackIFWPackage::CompareNone ||
+             !this->Compare.Value.empty()) {
+    // No hyphen in the name and we know a version part will follow. Use a
+    // hyphen as a separator since this works for all QtIFW versions.
     result += "-";
   }
 
@@ -609,6 +634,9 @@
   }
 
   // Dependencies
+  const bool hyphensInNamesUnsupported = this->Generator &&
+    !this->Generator->FrameworkVersion.empty() && this->IsVersionLess("3.1");
+  bool warnUnsupportedNames = false;
   std::set<DependenceStruct> compDepSet;
   for (DependenceStruct* ad : this->AlienDependencies) {
     compDepSet.insert(*ad);
@@ -620,9 +648,13 @@
   if (!compDepSet.empty()) {
     std::ostringstream dependencies;
     auto it = compDepSet.begin();
+    warnUnsupportedNames |=
+      hyphensInNamesUnsupported && it->Name.find('-') != std::string::npos;
     dependencies << it->NameWithCompare();
     ++it;
     while (it != compDepSet.end()) {
+      warnUnsupportedNames |=
+        hyphensInNamesUnsupported && it->Name.find('-') != std::string::npos;
       dependencies << "," << it->NameWithCompare();
       ++it;
     }
@@ -638,15 +670,28 @@
   if (!compAutoDepSet.empty()) {
     std::ostringstream dependencies;
     auto it = compAutoDepSet.begin();
+    warnUnsupportedNames |=
+      hyphensInNamesUnsupported && it->Name.find('-') != std::string::npos;
     dependencies << it->NameWithCompare();
     ++it;
     while (it != compAutoDepSet.end()) {
+      warnUnsupportedNames |=
+        hyphensInNamesUnsupported && it->Name.find('-') != std::string::npos;
       dependencies << "," << it->NameWithCompare();
       ++it;
     }
     xout.Element("AutoDependOn", dependencies.str());
   }
 
+  if (warnUnsupportedNames) {
+    cmCPackIFWLogger(
+      WARNING,
+      "The dependencies for component \""
+        << this->Name << "\" specify names that contain hyphens. "
+        << "This requires QtIFW 3.1 or later, but you are using version "
+        << this->Generator->FrameworkVersion << std::endl);
+  }
+
   // Licenses (copy to meta dir)
   std::vector<std::string> licenses = this->Licenses;
   for (size_t i = 1; i < licenses.size(); i += 2) {
diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx
index cefb906..0d56e5f 100644
--- a/Source/CPack/cmCPackDragNDropGenerator.cxx
+++ b/Source/CPack/cmCPackDragNDropGenerator.cxx
@@ -273,6 +273,11 @@
     ? this->GetOption("CPACK_DMG_FORMAT")
     : "UDZO";
 
+  const std::string cpack_dmg_filesystem =
+    this->GetOption("CPACK_DMG_FILESYSTEM")
+    ? this->GetOption("CPACK_DMG_FILESYSTEM")
+    : "HFS+";
+
   // Get optional arguments ...
   std::string cpack_license_file =
     this->GetOption("CPACK_RESOURCE_FILE_LICENSE")
@@ -418,7 +423,7 @@
   temp_image_command << " -ov";
   temp_image_command << " -srcfolder \"" << staging.str() << "\"";
   temp_image_command << " -volname \"" << cpack_dmg_volume_name << "\"";
-  temp_image_command << " -fs HFS+";
+  temp_image_command << " -fs \"" << cpack_dmg_filesystem << "\"";
   temp_image_command << " -format " << temp_image_format;
   temp_image_command << " \"" << temp_image << "\"";
 
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
index 3db4162..c512a36 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -384,7 +384,8 @@
       for (std::string const& gf : this->files) {
         bool skip = false;
         std::string inFile = gf;
-        if (cmSystemTools::FileIsDirectory(gf)) {
+        if (cmSystemTools::FileIsDirectory(gf) &&
+            !cmSystemTools::FileIsSymlink(gf)) {
           inFile += '/';
         }
         for (cmsys::RegularExpression& reg : ignoreFilesRegex) {
diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx
index f1cc677..6bd0d1b 100644
--- a/Source/CPack/cmCPackNSISGenerator.cxx
+++ b/Source/CPack/cmCPackNSISGenerator.cxx
@@ -437,7 +437,9 @@
   }
 #endif
 
-  nsisPath = cmSystemTools::FindProgram("makensis", path, false);
+  this->SetOptionIfNotSet("CPACK_NSIS_EXECUTABLE", "makensis");
+  nsisPath = cmSystemTools::FindProgram(
+    this->GetOption("CPACK_NSIS_EXECUTABLE"), path, false);
 
   if (nsisPath.empty()) {
     cmCPackLogger(
diff --git a/Source/CPack/cmCPackSTGZGenerator.cxx b/Source/CPack/cmCPackSTGZGenerator.cxx
index 3e36e8c..ad0a3e2 100644
--- a/Source/CPack/cmCPackSTGZGenerator.cxx
+++ b/Source/CPack/cmCPackSTGZGenerator.cxx
@@ -51,15 +51,16 @@
    * so we must iterate over generated packages.
    */
   for (std::string const& pfn : this->packageFileNames) {
-    retval &= cmSystemTools::SetPermissions(pfn.c_str(),
+    retval &= static_cast<bool>(
+      cmSystemTools::SetPermissions(pfn.c_str(),
 #if defined(_MSC_VER) || defined(__MINGW32__)
-                                            S_IREAD | S_IWRITE | S_IEXEC
+                                    S_IREAD | S_IWRITE | S_IEXEC
 #else
-                                            S_IRUSR | S_IWUSR | S_IXUSR |
-                                              S_IRGRP | S_IWGRP | S_IXGRP |
-                                              S_IROTH | S_IWOTH | S_IXOTH
+                                    S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
+                                      S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH |
+                                      S_IXOTH
 #endif
-    );
+                                    ));
   }
   return retval;
 }
diff --git a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
index 051c117..af495bb 100644
--- a/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
+++ b/Source/CTest/cmCTestEmptyBinaryDirectoryCommand.cxx
@@ -16,7 +16,7 @@
     return false;
   }
 
-  if (!cmCTestScriptHandler::EmptyBinaryDirectory(args[0].c_str())) {
+  if (!cmCTestScriptHandler::EmptyBinaryDirectory(args[0])) {
     std::ostringstream ostr;
     ostr << "problem removing the binary directory: " << args[0];
     this->SetError(ostr.str());
diff --git a/Source/CTest/cmCTestGenericHandler.cxx b/Source/CTest/cmCTestGenericHandler.cxx
index 91818bb..cc756d7 100644
--- a/Source/CTest/cmCTestGenericHandler.cxx
+++ b/Source/CTest/cmCTestGenericHandler.cxx
@@ -21,32 +21,47 @@
 
 cmCTestGenericHandler::~cmCTestGenericHandler() = default;
 
-void cmCTestGenericHandler::SetOption(const std::string& op, const char* value)
+/* Modify the given `map`, setting key `op` to `value` if `value`
+ * is non-null, otherwise removing key `op` (if it exists).
+ */
+static void SetMapValue(cmCTestGenericHandler::t_StringToString& map,
+                        const std::string& op, const char* value)
 {
   if (!value) {
-    auto remit = this->Options.find(op);
-    if (remit != this->Options.end()) {
-      this->Options.erase(remit);
-    }
+    map.erase(op);
     return;
   }
 
-  this->Options[op] = value;
+  map[op] = value;
+}
+
+void cmCTestGenericHandler::SetOption(const std::string& op, const char* value)
+{
+  SetMapValue(this->Options, op, value);
 }
 
 void cmCTestGenericHandler::SetPersistentOption(const std::string& op,
                                                 const char* value)
 {
   this->SetOption(op, value);
-  if (!value) {
-    auto remit = this->PersistentOptions.find(op);
-    if (remit != this->PersistentOptions.end()) {
-      this->PersistentOptions.erase(remit);
-    }
-    return;
-  }
+  SetMapValue(this->PersistentOptions, op, value);
+}
 
-  this->PersistentOptions[op] = value;
+void cmCTestGenericHandler::AddMultiOption(const std::string& op,
+                                           const std::string& value)
+{
+  if (!value.empty()) {
+    this->MultiOptions[op].emplace_back(value);
+  }
+}
+
+void cmCTestGenericHandler::AddPersistentMultiOption(const std::string& op,
+                                                     const std::string& value)
+{
+  if (!value.empty()) {
+    this->MultiOptions[op].emplace_back(value);
+    this->PersistentMultiOptions[op].emplace_back(value);
+  }
 }
 
 void cmCTestGenericHandler::Initialize()
@@ -68,6 +83,17 @@
   return remit->second.c_str();
 }
 
+std::vector<std::string> cmCTestGenericHandler::GetMultiOption(
+  const std::string& optionName) const
+{
+  // Avoid inserting a key, which MultiOptions[op] would do.
+  auto remit = this->MultiOptions.find(optionName);
+  if (remit == this->MultiOptions.end()) {
+    return {};
+  }
+  return remit->second;
+}
+
 bool cmCTestGenericHandler::StartResultingXML(cmCTest::Part part,
                                               const char* name,
                                               cmGeneratedFileStream& xofs)
diff --git a/Source/CTest/cmCTestGenericHandler.h b/Source/CTest/cmCTestGenericHandler.h
index 89d7596..6f44545 100644
--- a/Source/CTest/cmCTestGenericHandler.h
+++ b/Source/CTest/cmCTestGenericHandler.h
@@ -72,11 +72,41 @@
   virtual ~cmCTestGenericHandler();
 
   using t_StringToString = std::map<std::string, std::string>;
+  using t_StringToMultiString =
+    std::map<std::string, std::vector<std::string>>;
 
+  /**
+   * Options collect a single value from flags; passing the
+   * flag multiple times on the command-line *overwrites* values,
+   * and only the last one specified counts. Set an option to
+   * nullptr to "unset" it.
+   *
+   * The value is stored as a string. The values set for single
+   * and multi-options (see below) live in different spaces,
+   * so calling a single-getter for a key that has only been set
+   * as a multi-value will return nullptr.
+   */
   void SetPersistentOption(const std::string& op, const char* value);
   void SetOption(const std::string& op, const char* value);
   const char* GetOption(const std::string& op);
 
+  /**
+   * Multi-Options collect one or more values from flags; passing
+   * the flag multiple times on the command-line *adds* values,
+   * rather than overwriting the previous values.
+   *
+   * Adding an empty value does nothing.
+   *
+   * The value is stored as a vector of strings. The values set for single
+   * (see above) and multi-options live in different spaces,
+   * so calling a multi-getter for a key that has only been set
+   * as a single-value will return an empty vector.
+   */
+  void AddPersistentMultiOption(const std::string& optionName,
+                                const std::string& value);
+  void AddMultiOption(const std::string& optionName, const std::string& value);
+  std::vector<std::string> GetMultiOption(const std::string& op) const;
+
   void SetCommand(cmCTestCommand* command) { this->Command = command; }
 
   void SetSubmitIndex(int idx) { this->SubmitIndex = idx; }
@@ -100,6 +130,8 @@
   cmCTest* CTest;
   t_StringToString Options;
   t_StringToString PersistentOptions;
+  t_StringToMultiString MultiOptions;
+  t_StringToMultiString PersistentMultiOptions;
   t_StringToString LogFileNames;
 
   cmCTestCommand* Command;
diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index 852f9d9..86a8e00 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -587,24 +587,24 @@
         onlyRunSerialTestsLeft = false;
       }
     }
-    cmCTestLog(this->CTest, HANDLER_OUTPUT, "***** WAITING, ");
+    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "***** WAITING, ");
 
     if (this->SerialTestRunning) {
-      cmCTestLog(this->CTest, HANDLER_OUTPUT,
+      cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                  "Waiting for RUN_SERIAL test to finish.");
     } else if (onlyRunSerialTestsLeft) {
-      cmCTestLog(this->CTest, HANDLER_OUTPUT,
+      cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                  "Only RUN_SERIAL tests remain, awaiting available slot.");
     } else {
       /* clang-format off */
-      cmCTestLog(this->CTest, HANDLER_OUTPUT,
+      cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                  "System Load: " << systemLoad << ", "
                  "Max Allowed Load: " << this->TestLoad << ", "
                  "Smallest test " << testWithMinProcessors <<
                  " requires " << minProcessorsRequired);
       /* clang-format on */
     }
-    cmCTestLog(this->CTest, HANDLER_OUTPUT, "*****" << std::endl);
+    cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "*****" << std::endl);
 
     // Wait between 1 and 5 seconds before trying again.
     unsigned int milliseconds = (cmSystemTools::RandomSeed() % 5 + 1) * 1000;
diff --git a/Source/CTest/cmCTestRunScriptCommand.cxx b/Source/CTest/cmCTestRunScriptCommand.cxx
index f59ca57..7661d4d 100644
--- a/Source/CTest/cmCTestRunScriptCommand.cxx
+++ b/Source/CTest/cmCTestRunScriptCommand.cxx
@@ -37,8 +37,8 @@
       ++i;
     } else {
       int ret;
-      cmCTestScriptHandler::RunScript(this->CTest, this->Makefile,
-                                      args[i].c_str(), !np, &ret);
+      cmCTestScriptHandler::RunScript(this->CTest, this->Makefile, args[i],
+                                      !np, &ret);
       this->Makefile->AddDefinition(returnVariable, std::to_string(ret));
     }
   }
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index 4808c36..d2cad39 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -4,7 +4,6 @@
 
 #include <cstdio>
 #include <cstdlib>
-#include <cstring>
 #include <map>
 #include <ratio>
 #include <sstream>
@@ -91,7 +90,7 @@
 cmCTestScriptHandler::~cmCTestScriptHandler() = default;
 
 // just adds an argument to the vector
-void cmCTestScriptHandler::AddConfigurationScript(const char* script,
+void cmCTestScriptHandler::AddConfigurationScript(const std::string& script,
                                                   bool pscope)
 {
   this->ConfigurationScripts.emplace_back(script);
@@ -676,7 +675,7 @@
 
   // clear the binary directory?
   if (this->EmptyBinDir) {
-    if (!cmCTestScriptHandler::EmptyBinaryDirectory(this->BinaryDir.c_str())) {
+    if (!cmCTestScriptHandler::EmptyBinaryDirectory(this->BinaryDir)) {
       cmCTestLog(this->CTest, ERROR_MESSAGE,
                  "Problem removing the binary directory" << std::endl);
     }
@@ -724,8 +723,8 @@
 
   // put the initial cache into the bin dir
   if (!this->InitialCache.empty()) {
-    if (!cmCTestScriptHandler::WriteInitialCache(this->BinaryDir.c_str(),
-                                                 this->InitialCache.c_str())) {
+    if (!cmCTestScriptHandler::WriteInitialCache(this->BinaryDir,
+                                                 this->InitialCache)) {
       this->RestoreBackupDirectories();
       return 9;
     }
@@ -812,8 +811,8 @@
   return 0;
 }
 
-bool cmCTestScriptHandler::WriteInitialCache(const char* directory,
-                                             const char* text)
+bool cmCTestScriptHandler::WriteInitialCache(const std::string& directory,
+                                             const std::string& text)
 {
   std::string cacheFile = cmStrCat(directory, "/CMakeCache.txt");
   cmGeneratedFileStream fout(cacheFile);
@@ -821,9 +820,7 @@
     return false;
   }
 
-  if (text != nullptr) {
-    fout.write(text, strlen(text));
-  }
+  fout.write(text.data(), text.size());
 
   // Make sure the operating system has finished writing the file
   // before closing it.  This will ensure the file is finished before
@@ -852,7 +849,7 @@
 }
 
 bool cmCTestScriptHandler::RunScript(cmCTest* ctest, cmMakefile* mf,
-                                     const char* sname, bool InProcess,
+                                     const std::string& sname, bool InProcess,
                                      int* returnValue)
 {
   auto sh = cm::make_unique<cmCTestScriptHandler>();
@@ -866,10 +863,10 @@
   return true;
 }
 
-bool cmCTestScriptHandler::EmptyBinaryDirectory(const char* sname)
+bool cmCTestScriptHandler::EmptyBinaryDirectory(const std::string& sname)
 {
   // try to avoid deleting root
-  if (!sname || strlen(sname) < 2) {
+  if (sname.size() < 2) {
     return false;
   }
 
@@ -924,7 +921,7 @@
     }
   }
 
-  return cmSystemTools::RemoveADirectory(directoryPath);
+  return static_cast<bool>(cmSystemTools::RemoveADirectory(directoryPath));
 }
 
 cmDuration cmCTestScriptHandler::GetRemainingTimeAllowed()
diff --git a/Source/CTest/cmCTestScriptHandler.h b/Source/CTest/cmCTestScriptHandler.h
index 8eb9658..b7764b2 100644
--- a/Source/CTest/cmCTestScriptHandler.h
+++ b/Source/CTest/cmCTestScriptHandler.h
@@ -62,7 +62,7 @@
   /**
    * Add a script to run, and if is should run in the current process
    */
-  void AddConfigurationScript(const char*, bool pscope);
+  void AddConfigurationScript(const std::string&, bool pscope);
 
   /**
    * Run a dashboard using a specified confiuration script
@@ -72,19 +72,21 @@
   /*
    * Run a script
    */
-  static bool RunScript(cmCTest* ctest, cmMakefile* mf, const char* script,
-                        bool InProcess, int* returnValue);
+  static bool RunScript(cmCTest* ctest, cmMakefile* mf,
+                        const std::string& script, bool InProcess,
+                        int* returnValue);
   int RunCurrentScript();
 
   /*
    * Empty Binary Directory
    */
-  static bool EmptyBinaryDirectory(const char* dir);
+  static bool EmptyBinaryDirectory(const std::string& dir);
 
   /*
    * Write an initial CMakeCache.txt from the given contents.
    */
-  static bool WriteInitialCache(const char* directory, const char* text);
+  static bool WriteInitialCache(const std::string& directory,
+                                const std::string& text);
 
   /*
    * Some elapsed time handling functions
diff --git a/Source/CTest/cmCTestTestCommand.cxx b/Source/CTest/cmCTestTestCommand.cxx
index 4403733..886c263 100644
--- a/Source/CTest/cmCTestTestCommand.cxx
+++ b/Source/CTest/cmCTestTestCommand.cxx
@@ -73,11 +73,11 @@
     handler->SetOption("IncludeRegularExpression", this->Include.c_str());
   }
   if (!this->ExcludeLabel.empty()) {
-    handler->SetOption("ExcludeLabelRegularExpression",
-                       this->ExcludeLabel.c_str());
+    handler->AddMultiOption("ExcludeLabelRegularExpression",
+                            this->ExcludeLabel);
   }
   if (!this->IncludeLabel.empty()) {
-    handler->SetOption("LabelRegularExpression", this->IncludeLabel.c_str());
+    handler->AddMultiOption("LabelRegularExpression", this->IncludeLabel);
   }
   if (!this->ExcludeFixture.empty()) {
     handler->SetOption("ExcludeFixtureRegularExpression",
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index 1cb5d00..db5cb9c 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -287,8 +287,6 @@
 {
   this->UseUnion = false;
 
-  this->UseIncludeLabelRegExpFlag = false;
-  this->UseExcludeLabelRegExpFlag = false;
   this->UseIncludeRegExpFlag = false;
   this->UseExcludeRegExpFlag = false;
   this->UseExcludeRegExpFirst = false;
@@ -327,13 +325,11 @@
 
   this->TestsToRun.clear();
 
-  this->UseIncludeLabelRegExpFlag = false;
-  this->UseExcludeLabelRegExpFlag = false;
   this->UseIncludeRegExpFlag = false;
   this->UseExcludeRegExpFlag = false;
   this->UseExcludeRegExpFirst = false;
-  this->IncludeLabelRegularExpression = "";
-  this->ExcludeLabelRegularExpression = "";
+  this->IncludeLabelRegularExpressions.clear();
+  this->ExcludeLabelRegularExpressions.clear();
   this->IncludeRegExp.clear();
   this->ExcludeRegExp.clear();
   this->ExcludeFixtureRegExp.clear();
@@ -479,6 +475,22 @@
   return 0;
 }
 
+/* Given a multi-option value `parts`, compile those parts into
+ * regular expressions in `expressions`. Skip empty values.
+ * Returns true if there were any expressions.
+ */
+static bool BuildLabelRE(const std::vector<std::string>& parts,
+                         std::vector<cmsys::RegularExpression>& expressions)
+{
+  expressions.clear();
+  for (const auto& p : parts) {
+    if (!p.empty()) {
+      expressions.emplace_back(p);
+    }
+  }
+  return !expressions.empty();
+}
+
 bool cmCTestTestHandler::ProcessOptions()
 {
   // Update internal data structure from generic one
@@ -519,18 +531,11 @@
     this->CTest->SetStopOnFailure(true);
   }
 
-  const char* val;
-  val = this->GetOption("LabelRegularExpression");
-  if (val) {
-    this->UseIncludeLabelRegExpFlag = true;
-    this->IncludeLabelRegExp = val;
-  }
-  val = this->GetOption("ExcludeLabelRegularExpression");
-  if (val) {
-    this->UseExcludeLabelRegExpFlag = true;
-    this->ExcludeLabelRegExp = val;
-  }
-  val = this->GetOption("IncludeRegularExpression");
+  BuildLabelRE(this->GetMultiOption("LabelRegularExpression"),
+               this->IncludeLabelRegularExpressions);
+  BuildLabelRE(this->GetMultiOption("ExcludeLabelRegularExpression"),
+               this->ExcludeLabelRegularExpressions);
+  const char* val = this->GetOption("IncludeRegularExpression");
   if (val) {
     this->UseIncludeRegExp();
     this->SetIncludeRegExp(val);
@@ -763,10 +768,40 @@
   cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "\n", this->Quiet);
 }
 
+/**
+ * Check if the labels (from a test) match all the expressions.
+ *
+ * Each of the RE's must match at least one label
+ * (e.g. all of the REs must match **some** label,
+ * in order for the filter to apply to the test).
+ */
+static bool MatchLabelsAgainstFilterRE(
+  const std::vector<std::string>& labels,
+  const std::vector<cmsys::RegularExpression>& expressions)
+{
+  for (const auto& re : expressions) {
+    // check to see if the label regular expression matches
+    bool found = false; // assume it does not match
+    cmsys::RegularExpressionMatch match;
+    // loop over all labels and look for match
+    for (std::string const& l : labels) {
+      if (re.find(l.c_str(), match)) {
+        found = true;
+        break;
+      }
+    }
+    // if no match was found, exclude the test
+    if (!found) {
+      return false;
+    }
+  }
+  return true;
+}
+
 void cmCTestTestHandler::CheckLabelFilterInclude(cmCTestTestProperties& it)
 {
   // if not using Labels to filter then return
-  if (!this->UseIncludeLabelRegExpFlag) {
+  if (this->IncludeLabelRegularExpressions.empty()) {
     return;
   }
   // if there are no labels and we are filtering by labels
@@ -775,16 +810,9 @@
     it.IsInBasedOnREOptions = false;
     return;
   }
-  // check to see if the label regular expression matches
-  bool found = false; // assume it does not match
-  // loop over all labels and look for match
-  for (std::string const& l : it.Labels) {
-    if (this->IncludeLabelRegularExpression.find(l)) {
-      found = true;
-    }
-  }
   // if no match was found, exclude the test
-  if (!found) {
+  if (!MatchLabelsAgainstFilterRE(it.Labels,
+                                  this->IncludeLabelRegularExpressions)) {
     it.IsInBasedOnREOptions = false;
   }
 }
@@ -792,7 +820,7 @@
 void cmCTestTestHandler::CheckLabelFilterExclude(cmCTestTestProperties& it)
 {
   // if not using Labels to filter then return
-  if (!this->UseExcludeLabelRegExpFlag) {
+  if (this->ExcludeLabelRegularExpressions.empty()) {
     return;
   }
   // if there are no labels and we are excluding by labels
@@ -800,16 +828,9 @@
   if (it.Labels.empty()) {
     return;
   }
-  // check to see if the label regular expression matches
-  bool found = false; // assume it does not match
-  // loop over all labels and look for match
-  for (std::string const& l : it.Labels) {
-    if (this->ExcludeLabelRegularExpression.find(l)) {
-      found = true;
-    }
-  }
   // if match was found, exclude the test
-  if (found) {
+  if (MatchLabelsAgainstFilterRE(it.Labels,
+                                 this->ExcludeLabelRegularExpressions)) {
     it.IsInBasedOnREOptions = false;
   }
 }
@@ -1704,19 +1725,11 @@
 
 bool cmCTestTestHandler::GetListOfTests()
 {
-  if (!this->IncludeLabelRegExp.empty()) {
-    this->IncludeLabelRegularExpression.compile(
-      this->IncludeLabelRegExp.c_str());
-  }
-  if (!this->ExcludeLabelRegExp.empty()) {
-    this->ExcludeLabelRegularExpression.compile(
-      this->ExcludeLabelRegExp.c_str());
-  }
   if (!this->IncludeRegExp.empty()) {
-    this->IncludeTestsRegularExpression.compile(this->IncludeRegExp.c_str());
+    this->IncludeTestsRegularExpression.compile(this->IncludeRegExp);
   }
   if (!this->ExcludeRegExp.empty()) {
-    this->ExcludeTestsRegularExpression.compile(this->ExcludeRegExp.c_str());
+    this->ExcludeTestsRegularExpression.compile(this->ExcludeRegExp);
   }
   cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                      "Constructing a list of tests" << std::endl, this->Quiet);
@@ -1868,7 +1881,7 @@
   std::string dirName = this->CTest->GetBinaryDir() + "/Testing/Temporary";
 
   cmsys::Directory directory;
-  if (directory.Load(dirName) == 0) {
+  if (!directory.Load(dirName)) {
     cmCTestLog(this->CTest, ERROR_MESSAGE,
                "Unable to read the contents of " << dirName << std::endl);
     return;
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index aa29eeb..6fa18a9 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -320,20 +320,16 @@
 
   std::vector<int> TestsToRun;
 
-  bool UseIncludeLabelRegExpFlag;
-  bool UseExcludeLabelRegExpFlag;
   bool UseIncludeRegExpFlag;
   bool UseExcludeRegExpFlag;
   bool UseExcludeRegExpFirst;
-  std::string IncludeLabelRegExp;
-  std::string ExcludeLabelRegExp;
   std::string IncludeRegExp;
   std::string ExcludeRegExp;
   std::string ExcludeFixtureRegExp;
   std::string ExcludeFixtureSetupRegExp;
   std::string ExcludeFixtureCleanupRegExp;
-  cmsys::RegularExpression IncludeLabelRegularExpression;
-  cmsys::RegularExpression ExcludeLabelRegularExpression;
+  std::vector<cmsys::RegularExpression> IncludeLabelRegularExpressions;
+  std::vector<cmsys::RegularExpression> ExcludeLabelRegularExpressions;
   cmsys::RegularExpression IncludeTestsRegularExpression;
   cmsys::RegularExpression ExcludeTestsRegularExpression;
 
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
index f593f83..6796e25 100644
--- a/Source/QtDialog/QCMake.cxx
+++ b/Source/QtDialog/QCMake.cxx
@@ -160,7 +160,7 @@
       auto const& expandedPreset =
         this->CMakePresetsFile.ConfigurePresets[presetName].Expanded;
       if (expandedPreset) {
-        if (setBinary) {
+        if (setBinary && !expandedPreset->BinaryDir.empty()) {
           QString binaryDir =
             QString::fromLocal8Bit(expandedPreset->BinaryDir.data());
           this->setBinaryDirectory(binaryDir);
@@ -557,7 +557,7 @@
     preset.toolset = std::move(QString::fromLocal8Bit(p.Toolset.data()));
     preset.setToolset = !p.ToolsetStrategy ||
       p.ToolsetStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set;
-    preset.enabled = it.Expanded &&
+    preset.enabled = it.Expanded && it.Expanded->ConditionResult &&
       std::find_if(this->AvailableGenerators.begin(),
                    this->AvailableGenerators.end(),
                    [&p](const cmake::GeneratorInfo& g) {
diff --git a/Source/cmCMakePresetsFile.cxx b/Source/cmCMakePresetsFile.cxx
index dda3661..39cce98 100644
--- a/Source/cmCMakePresetsFile.cxx
+++ b/Source/cmCMakePresetsFile.cxx
@@ -9,28 +9,17 @@
 #include <iterator>
 #include <utility>
 
-#include <cmext/string_view>
+#include <cm/string_view>
 
-#include <cm3p/json/reader.h>
-#include <cm3p/json/value.h>
+#include "cmsys/RegularExpression.hxx"
 
-#include "cmsys/FStream.hxx"
-
-#include "cmJSONHelpers.h"
+#include "cmCMakePresetsFileInternal.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
-#include "cmVersion.h"
 
-#define CHECK_OK(expr)                                                        \
+#define CHECK_EXPAND(out, field, expanders, version)                          \
   {                                                                           \
-    auto _result = expr;                                                      \
-    if (_result != ReadFileResult::READ_OK)                                   \
-      return _result;                                                         \
-  }
-
-#define CHECK_EXPAND(out, field, expanders)                                   \
-  {                                                                           \
-    switch (ExpandMacros(field, expanders)) {                                 \
+    switch (ExpandMacros(field, expanders, version)) {                        \
       case ExpandMacroResult::Error:                                          \
         return false;                                                         \
       case ExpandMacroResult::Ignore:                                         \
@@ -50,673 +39,11 @@
 };
 
 using ReadFileResult = cmCMakePresetsFile::ReadFileResult;
-using CacheVariable = cmCMakePresetsFile::CacheVariable;
 using ConfigurePreset = cmCMakePresetsFile::ConfigurePreset;
 using BuildPreset = cmCMakePresetsFile::BuildPreset;
 using TestPreset = cmCMakePresetsFile::TestPreset;
-using ArchToolsetStrategy = cmCMakePresetsFile::ArchToolsetStrategy;
-
-constexpr int MIN_VERSION = 1;
-constexpr int MAX_VERSION = 2;
-
-struct CMakeVersion
-{
-  unsigned int Major = 0;
-  unsigned int Minor = 0;
-  unsigned int Patch = 0;
-};
-
-struct RootPresets
-{
-  CMakeVersion CMakeMinimumRequired;
-  std::vector<cmCMakePresetsFile::ConfigurePreset> ConfigurePresets;
-  std::vector<cmCMakePresetsFile::BuildPreset> BuildPresets;
-  std::vector<cmCMakePresetsFile::TestPreset> TestPresets;
-};
-
-cmJSONHelper<std::nullptr_t, ReadFileResult> VendorHelper(ReadFileResult error)
-{
-  return [error](std::nullptr_t& /*out*/,
-                 const Json::Value* value) -> ReadFileResult {
-    if (!value) {
-      return ReadFileResult::READ_OK;
-    }
-
-    if (!value->isObject()) {
-      return error;
-    }
-
-    return ReadFileResult::READ_OK;
-  };
-}
-
-auto const VersionIntHelper = cmJSONIntHelper<ReadFileResult>(
-  ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION);
-
-auto const VersionHelper = cmJSONRequiredHelper<int, ReadFileResult>(
-  ReadFileResult::NO_VERSION, VersionIntHelper);
-
-auto const RootVersionHelper =
-  cmJSONObjectHelper<int, ReadFileResult>(ReadFileResult::READ_OK,
-                                          ReadFileResult::INVALID_ROOT)
-    .Bind("version"_s, VersionHelper, false);
-
-auto const VariableStringHelper = cmJSONStringHelper<ReadFileResult>(
-  ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE);
-
-ReadFileResult VariableValueHelper(std::string& out, const Json::Value* value)
-{
-  if (!value) {
-    out.clear();
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->isBool()) {
-    out = value->asBool() ? "TRUE" : "FALSE";
-    return ReadFileResult::READ_OK;
-  }
-
-  return VariableStringHelper(out, value);
-}
-
-auto const VariableObjectHelper =
-  cmJSONObjectHelper<CacheVariable, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE, false)
-    .Bind("type"_s, &CacheVariable::Type, VariableStringHelper, false)
-    .Bind("value"_s, &CacheVariable::Value, VariableValueHelper);
-
-ReadFileResult VariableHelper(cm::optional<CacheVariable>& out,
-                              const Json::Value* value)
-{
-  if (value->isBool()) {
-    out = CacheVariable{
-      /*Type=*/"BOOL",
-      /*Value=*/value->asBool() ? "TRUE" : "FALSE",
-    };
-    return ReadFileResult::READ_OK;
-  }
-  if (value->isString()) {
-    out = CacheVariable{
-      /*Type=*/"",
-      /*Value=*/value->asString(),
-    };
-    return ReadFileResult::READ_OK;
-  }
-  if (value->isObject()) {
-    out.emplace();
-    return VariableObjectHelper(*out, value);
-  }
-  if (value->isNull()) {
-    out = cm::nullopt;
-    return ReadFileResult::READ_OK;
-  }
-  return ReadFileResult::INVALID_VARIABLE;
-}
-
-auto const VariablesHelper =
-  cmJSONMapHelper<cm::optional<CacheVariable>, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, VariableHelper);
-
-auto const PresetStringHelper = cmJSONStringHelper<ReadFileResult>(
-  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
-
-ReadFileResult EnvironmentHelper(cm::optional<std::string>& out,
-                                 const Json::Value* value)
-{
-  if (!value || value->isNull()) {
-    out = cm::nullopt;
-    return ReadFileResult::READ_OK;
-  }
-  if (value->isString()) {
-    out = value->asString();
-    return ReadFileResult::READ_OK;
-  }
-  return ReadFileResult::INVALID_PRESET;
-}
-
-auto const EnvironmentMapHelper =
-  cmJSONMapHelper<cm::optional<std::string>, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
-    EnvironmentHelper);
-
-auto const PresetVectorStringHelper =
-  cmJSONVectorHelper<std::string, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
-    PresetStringHelper);
-
-ReadFileResult PresetInheritsHelper(std::vector<std::string>& out,
-                                    const Json::Value* value)
-{
-  out.clear();
-  if (!value) {
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->isString()) {
-    out.push_back(value->asString());
-    return ReadFileResult::READ_OK;
-  }
-
-  return PresetVectorStringHelper(out, value);
-}
-
-auto const PresetBoolHelper = cmJSONBoolHelper<ReadFileResult>(
-  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
-
-auto const PresetOptionalBoolHelper =
-  cmJSONOptionalHelper<bool, ReadFileResult>(ReadFileResult::READ_OK,
-                                             PresetBoolHelper);
-
-auto const PresetIntHelper = cmJSONIntHelper<ReadFileResult>(
-  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
-
-auto const PresetOptionalIntHelper = cmJSONOptionalHelper<int, ReadFileResult>(
-  ReadFileResult::READ_OK, PresetIntHelper);
-
-auto const PresetVectorIntHelper = cmJSONVectorHelper<int, ReadFileResult>(
-  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, PresetIntHelper);
-
-auto const PresetWarningsHelper =
-  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-    .Bind("dev"_s, &ConfigurePreset::WarnDev, PresetOptionalBoolHelper, false)
-    .Bind("deprecated"_s, &ConfigurePreset::WarnDeprecated,
-          PresetOptionalBoolHelper, false)
-    .Bind("uninitialized"_s, &ConfigurePreset::WarnUninitialized,
-          PresetOptionalBoolHelper, false)
-    .Bind("unusedCli"_s, &ConfigurePreset::WarnUnusedCli,
-          PresetOptionalBoolHelper, false)
-    .Bind("systemVars"_s, &ConfigurePreset::WarnSystemVars,
-          PresetOptionalBoolHelper, false);
-
-auto const PresetErrorsHelper =
-  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-    .Bind("dev"_s, &ConfigurePreset::ErrorDev, PresetOptionalBoolHelper, false)
-    .Bind("deprecated"_s, &ConfigurePreset::ErrorDeprecated,
-          PresetOptionalBoolHelper, false);
-
-auto const PresetDebugHelper =
-  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-    .Bind("output"_s, &ConfigurePreset::DebugOutput, PresetOptionalBoolHelper,
-          false)
-    .Bind("tryCompile"_s, &ConfigurePreset::DebugTryCompile,
-          PresetOptionalBoolHelper, false)
-    .Bind("find"_s, &ConfigurePreset::DebugFind, PresetOptionalBoolHelper,
-          false);
-
-ReadFileResult ArchToolsetStrategyHelper(
-  cm::optional<ArchToolsetStrategy>& out, const Json::Value* value)
-{
-  if (!value) {
-    out = cm::nullopt;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (!value->isString()) {
-    return ReadFileResult::INVALID_PRESET;
-  }
-
-  if (value->asString() == "set") {
-    out = ArchToolsetStrategy::Set;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->asString() == "external") {
-    out = ArchToolsetStrategy::External;
-    return ReadFileResult::READ_OK;
-  }
-
-  return ReadFileResult::INVALID_PRESET;
-}
-
-std::function<ReadFileResult(ConfigurePreset&, const Json::Value*)>
-ArchToolsetHelper(
-  std::string ConfigurePreset::*valueField,
-  cm::optional<ArchToolsetStrategy> ConfigurePreset::*strategyField)
-{
-  auto const objectHelper =
-    cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
-      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-      .Bind("value", valueField, PresetStringHelper, false)
-      .Bind("strategy", strategyField, ArchToolsetStrategyHelper, false);
-  return [valueField, strategyField, objectHelper](
-           ConfigurePreset& out, const Json::Value* value) -> ReadFileResult {
-    if (!value) {
-      (out.*valueField).clear();
-      out.*strategyField = cm::nullopt;
-      return ReadFileResult::READ_OK;
-    }
-
-    if (value->isString()) {
-      out.*valueField = value->asString();
-      out.*strategyField = cm::nullopt;
-      return ReadFileResult::READ_OK;
-    }
-
-    if (value->isObject()) {
-      return objectHelper(out, value);
-    }
-
-    return ReadFileResult::INVALID_PRESET;
-  };
-}
-
-auto const ArchitectureHelper = ArchToolsetHelper(
-  &ConfigurePreset::Architecture, &ConfigurePreset::ArchitectureStrategy);
-auto const ToolsetHelper = ArchToolsetHelper(
-  &ConfigurePreset::Toolset, &ConfigurePreset::ToolsetStrategy);
-
-auto const ConfigurePresetHelper =
-  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-    .Bind("name"_s, &ConfigurePreset::Name, PresetStringHelper)
-    .Bind("inherits"_s, &ConfigurePreset::Inherits, PresetInheritsHelper,
-          false)
-    .Bind("hidden"_s, &ConfigurePreset::Hidden, PresetBoolHelper, false)
-    .Bind<std::nullptr_t>("vendor"_s, nullptr,
-                          VendorHelper(ReadFileResult::INVALID_PRESET), false)
-    .Bind("displayName"_s, &ConfigurePreset::DisplayName, PresetStringHelper,
-          false)
-    .Bind("description"_s, &ConfigurePreset::Description, PresetStringHelper,
-          false)
-    .Bind("generator"_s, &ConfigurePreset::Generator, PresetStringHelper,
-          false)
-    .Bind("architecture"_s, ArchitectureHelper, false)
-    .Bind("toolset"_s, ToolsetHelper, false)
-    .Bind("binaryDir"_s, &ConfigurePreset::BinaryDir, PresetStringHelper,
-          false)
-    .Bind<std::string>("cmakeExecutable"_s, nullptr, PresetStringHelper, false)
-    .Bind("cacheVariables"_s, &ConfigurePreset::CacheVariables,
-          VariablesHelper, false)
-    .Bind("environment"_s, &ConfigurePreset::Environment, EnvironmentMapHelper,
-          false)
-    .Bind("warnings"_s, PresetWarningsHelper, false)
-    .Bind("errors"_s, PresetErrorsHelper, false)
-    .Bind("debug"_s, PresetDebugHelper, false);
-
-auto const BuildPresetHelper =
-  cmJSONObjectHelper<BuildPreset, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-    .Bind("name"_s, &BuildPreset::Name, PresetStringHelper)
-    .Bind("inherits"_s, &BuildPreset::Inherits, PresetInheritsHelper, false)
-    .Bind("hidden"_s, &BuildPreset::Hidden, PresetBoolHelper, false)
-    .Bind<std::nullptr_t>("vendor"_s, nullptr,
-                          VendorHelper(ReadFileResult::INVALID_PRESET), false)
-    .Bind("displayName"_s, &BuildPreset::DisplayName, PresetStringHelper,
-          false)
-    .Bind("description"_s, &BuildPreset::Description, PresetStringHelper,
-          false)
-    .Bind("environment"_s, &BuildPreset::Environment, EnvironmentMapHelper,
-          false)
-    .Bind("configurePreset"_s, &BuildPreset::ConfigurePreset,
-          PresetStringHelper, false)
-    .Bind("inheritConfigureEnvironment"_s,
-          &BuildPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper,
-          false)
-    .Bind("jobs"_s, &BuildPreset::Jobs, PresetOptionalIntHelper, false)
-    .Bind("targets"_s, &BuildPreset::Targets, PresetVectorStringHelper, false)
-    .Bind("configuration"_s, &BuildPreset::Configuration, PresetStringHelper,
-          false)
-    .Bind("cleanFirst"_s, &BuildPreset::CleanFirst, PresetOptionalBoolHelper,
-          false)
-    .Bind("verbose"_s, &BuildPreset::Verbose, PresetOptionalBoolHelper, false)
-    .Bind("nativeToolOptions"_s, &BuildPreset::NativeToolOptions,
-          PresetVectorStringHelper, false);
-
-ReadFileResult TestPresetOutputVerbosityHelper(
-  TestPreset::OutputOptions::VerbosityEnum& out, const Json::Value* value)
-{
-  if (!value) {
-    out = TestPreset::OutputOptions::VerbosityEnum::Default;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (!value->isString()) {
-    return ReadFileResult::INVALID_PRESET;
-  }
-
-  if (value->asString() == "default") {
-    out = TestPreset::OutputOptions::VerbosityEnum::Default;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->asString() == "verbose") {
-    out = TestPreset::OutputOptions::VerbosityEnum::Verbose;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->asString() == "extra") {
-    out = TestPreset::OutputOptions::VerbosityEnum::Extra;
-    return ReadFileResult::READ_OK;
-  }
-
-  return ReadFileResult::INVALID_PRESET;
-}
-
-auto const TestPresetOptionalOutputVerbosityHelper =
-  cmJSONOptionalHelper<TestPreset::OutputOptions::VerbosityEnum,
-                       ReadFileResult>(ReadFileResult::READ_OK,
-                                       TestPresetOutputVerbosityHelper);
-
-auto const TestPresetOptionalOutputHelper =
-  cmJSONOptionalHelper<TestPreset::OutputOptions, ReadFileResult>(
-    ReadFileResult::READ_OK,
-    cmJSONObjectHelper<TestPreset::OutputOptions, ReadFileResult>(
-      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-      .Bind("shortProgress"_s, &TestPreset::OutputOptions::ShortProgress,
-            PresetOptionalBoolHelper, false)
-      .Bind("verbosity"_s, &TestPreset::OutputOptions::Verbosity,
-            TestPresetOptionalOutputVerbosityHelper, false)
-      .Bind("debug"_s, &TestPreset::OutputOptions::Debug,
-            PresetOptionalBoolHelper, false)
-      .Bind("outputOnFailure"_s, &TestPreset::OutputOptions::OutputOnFailure,
-            PresetOptionalBoolHelper, false)
-      .Bind("quiet"_s, &TestPreset::OutputOptions::Quiet,
-            PresetOptionalBoolHelper, false)
-      .Bind("outputLogFile"_s, &TestPreset::OutputOptions::OutputLogFile,
-            PresetStringHelper, false)
-      .Bind("labelSummary"_s, &TestPreset::OutputOptions::LabelSummary,
-            PresetOptionalBoolHelper, false)
-      .Bind("subprojectSummary"_s,
-            &TestPreset::OutputOptions::SubprojectSummary,
-            PresetOptionalBoolHelper, false)
-      .Bind("maxPassedTestOutputSize"_s,
-            &TestPreset::OutputOptions::MaxPassedTestOutputSize,
-            PresetOptionalIntHelper, false)
-      .Bind("maxFailedTestOutputSize"_s,
-            &TestPreset::OutputOptions::MaxFailedTestOutputSize,
-            PresetOptionalIntHelper, false)
-      .Bind("maxTestNameWidth"_s, &TestPreset::OutputOptions::MaxTestNameWidth,
-            PresetOptionalIntHelper, false));
-
-auto const TestPresetOptionalFilterIncludeIndexObjectHelper =
-  cmJSONOptionalHelper<TestPreset::IncludeOptions::IndexOptions,
-                       ReadFileResult>(
-    ReadFileResult::READ_OK,
-    cmJSONObjectHelper<TestPreset::IncludeOptions::IndexOptions,
-                       ReadFileResult>(ReadFileResult::READ_OK,
-                                       ReadFileResult::INVALID_PRESET)
-      .Bind("start"_s, &TestPreset::IncludeOptions::IndexOptions::Start,
-            PresetOptionalIntHelper, false)
-      .Bind("end"_s, &TestPreset::IncludeOptions::IndexOptions::End,
-            PresetOptionalIntHelper, false)
-      .Bind("stride"_s, &TestPreset::IncludeOptions::IndexOptions::Stride,
-            PresetOptionalIntHelper, false)
-      .Bind("specificTests"_s,
-            &TestPreset::IncludeOptions::IndexOptions::SpecificTests,
-            PresetVectorIntHelper, false));
-
-ReadFileResult TestPresetOptionalFilterIncludeIndexHelper(
-  cm::optional<TestPreset::IncludeOptions::IndexOptions>& out,
-  const Json::Value* value)
-{
-  if (!value) {
-    out = cm::nullopt;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->isString()) {
-    out.emplace();
-    out->IndexFile = value->asString();
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->isObject()) {
-    return TestPresetOptionalFilterIncludeIndexObjectHelper(out, value);
-  }
-
-  return ReadFileResult::INVALID_PRESET;
-}
-
-auto const TestPresetOptionalFilterIncludeHelper =
-  cmJSONOptionalHelper<TestPreset::IncludeOptions, ReadFileResult>(
-    ReadFileResult::READ_OK,
-    cmJSONObjectHelper<TestPreset::IncludeOptions, ReadFileResult>(
-      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
-      .Bind("name"_s, &TestPreset::IncludeOptions::Name, PresetStringHelper,
-            false)
-      .Bind("label"_s, &TestPreset::IncludeOptions::Label, PresetStringHelper,
-            false)
-      .Bind("index"_s, &TestPreset::IncludeOptions::Index,
-            TestPresetOptionalFilterIncludeIndexHelper, false)
-      .Bind("useUnion"_s, &TestPreset::IncludeOptions::UseUnion,
-            PresetOptionalBoolHelper, false));
-
-auto const TestPresetOptionalFilterExcludeFixturesHelper =
-  cmJSONOptionalHelper<TestPreset::ExcludeOptions::FixturesOptions,
-                       ReadFileResult>(
-    ReadFileResult::READ_OK,
-    cmJSONObjectHelper<TestPreset::ExcludeOptions::FixturesOptions,
-                       ReadFileResult>(ReadFileResult::READ_OK,
-                                       ReadFileResult::INVALID_PRESET)
-      .Bind("any"_s, &TestPreset::ExcludeOptions::FixturesOptions::Any,
-            PresetStringHelper, false)
-      .Bind("setup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Setup,
-            PresetStringHelper, false)
-      .Bind("cleanup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Cleanup,
-            PresetStringHelper, false));
-
-auto const TestPresetOptionalFilterExcludeHelper =
-  cmJSONOptionalHelper<TestPreset::ExcludeOptions, ReadFileResult>(
-    ReadFileResult::READ_OK,
-    cmJSONObjectHelper<TestPreset::ExcludeOptions, ReadFileResult>(
-      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
-      .Bind("name"_s, &TestPreset::ExcludeOptions::Name, PresetStringHelper,
-            false)
-      .Bind("label"_s, &TestPreset::ExcludeOptions::Label, PresetStringHelper,
-            false)
-      .Bind("fixtures"_s, &TestPreset::ExcludeOptions::Fixtures,
-            TestPresetOptionalFilterExcludeFixturesHelper, false));
-
-ReadFileResult TestPresetExecutionShowOnlyHelper(
-  TestPreset::ExecutionOptions::ShowOnlyEnum& out, const Json::Value* value)
-{
-  if (!value || !value->isString()) {
-    return ReadFileResult::INVALID_PRESET;
-  }
-
-  if (value->asString() == "human") {
-    out = TestPreset::ExecutionOptions::ShowOnlyEnum::Human;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->asString() == "json-v1") {
-    out = TestPreset::ExecutionOptions::ShowOnlyEnum::JsonV1;
-    return ReadFileResult::READ_OK;
-  }
-
-  return ReadFileResult::INVALID_PRESET;
-}
-
-auto const TestPresetOptionalExecutionShowOnlyHelper =
-  cmJSONOptionalHelper<TestPreset::ExecutionOptions::ShowOnlyEnum,
-                       ReadFileResult>(ReadFileResult::READ_OK,
-                                       TestPresetExecutionShowOnlyHelper);
-
-ReadFileResult TestPresetExecutionModeHelper(
-  TestPreset::ExecutionOptions::RepeatOptions::ModeEnum& out,
-  const Json::Value* value)
-{
-  if (!value) {
-    return ReadFileResult::READ_OK;
-  }
-
-  if (!value->isString()) {
-    return ReadFileResult::INVALID_PRESET;
-  }
-
-  if (value->asString() == "until-fail") {
-    out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilFail;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->asString() == "until-pass") {
-    out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilPass;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->asString() == "after-timeout") {
-    out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::AfterTimeout;
-    return ReadFileResult::READ_OK;
-  }
-
-  return ReadFileResult::INVALID_PRESET;
-}
-
-auto const TestPresetOptionalExecutionRepeatHelper =
-  cmJSONOptionalHelper<TestPreset::ExecutionOptions::RepeatOptions,
-                       ReadFileResult>(
-    ReadFileResult::READ_OK,
-    cmJSONObjectHelper<TestPreset::ExecutionOptions::RepeatOptions,
-                       ReadFileResult>(ReadFileResult::READ_OK,
-                                       ReadFileResult::INVALID_PRESET)
-      .Bind("mode"_s, &TestPreset::ExecutionOptions::RepeatOptions::Mode,
-            TestPresetExecutionModeHelper, true)
-      .Bind("count"_s, &TestPreset::ExecutionOptions::RepeatOptions::Count,
-            PresetIntHelper, true));
-
-ReadFileResult TestPresetExecutionNoTestsActionHelper(
-  TestPreset::ExecutionOptions::NoTestsActionEnum& out,
-  const Json::Value* value)
-{
-  if (!value) {
-    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (!value->isString()) {
-    return ReadFileResult::INVALID_PRESET;
-  }
-
-  if (value->asString() == "default") {
-    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->asString() == "error") {
-    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Error;
-    return ReadFileResult::READ_OK;
-  }
-
-  if (value->asString() == "ignore") {
-    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Ignore;
-    return ReadFileResult::READ_OK;
-  }
-
-  return ReadFileResult::INVALID_PRESET;
-}
-
-auto const TestPresetOptionalExecutionNoTestsActionHelper =
-  cmJSONOptionalHelper<TestPreset::ExecutionOptions::NoTestsActionEnum,
-                       ReadFileResult>(ReadFileResult::READ_OK,
-                                       TestPresetExecutionNoTestsActionHelper);
-
-auto const TestPresetExecutionHelper =
-  cmJSONOptionalHelper<TestPreset::ExecutionOptions, ReadFileResult>(
-    ReadFileResult::READ_OK,
-    cmJSONObjectHelper<TestPreset::ExecutionOptions, ReadFileResult>(
-      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
-      .Bind("stopOnFailure"_s, &TestPreset::ExecutionOptions::StopOnFailure,
-            PresetOptionalBoolHelper, false)
-      .Bind("enableFailover"_s, &TestPreset::ExecutionOptions::EnableFailover,
-            PresetOptionalBoolHelper, false)
-      .Bind("jobs"_s, &TestPreset::ExecutionOptions::Jobs,
-            PresetOptionalIntHelper, false)
-      .Bind("resourceSpecFile"_s,
-            &TestPreset::ExecutionOptions::ResourceSpecFile,
-            PresetStringHelper, false)
-      .Bind("testLoad"_s, &TestPreset::ExecutionOptions::TestLoad,
-            PresetOptionalIntHelper, false)
-      .Bind("showOnly"_s, &TestPreset::ExecutionOptions::ShowOnly,
-            TestPresetOptionalExecutionShowOnlyHelper, false)
-      .Bind("repeat"_s, &TestPreset::ExecutionOptions::Repeat,
-            TestPresetOptionalExecutionRepeatHelper, false)
-      .Bind("interactiveDebugging"_s,
-            &TestPreset::ExecutionOptions::InteractiveDebugging,
-            PresetOptionalBoolHelper, false)
-      .Bind("scheduleRandom"_s, &TestPreset::ExecutionOptions::ScheduleRandom,
-            PresetOptionalBoolHelper, false)
-      .Bind("timeout"_s, &TestPreset::ExecutionOptions::Timeout,
-            PresetOptionalIntHelper, false)
-      .Bind("noTestsAction"_s, &TestPreset::ExecutionOptions::NoTestsAction,
-            TestPresetOptionalExecutionNoTestsActionHelper, false));
-
-auto const TestPresetFilterHelper =
-  cmJSONOptionalHelper<TestPreset::FilterOptions, ReadFileResult>(
-    ReadFileResult::READ_OK,
-    cmJSONObjectHelper<TestPreset::FilterOptions, ReadFileResult>(
-      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
-      .Bind("include"_s, &TestPreset::FilterOptions::Include,
-            TestPresetOptionalFilterIncludeHelper, false)
-      .Bind("exclude"_s, &TestPreset::FilterOptions::Exclude,
-            TestPresetOptionalFilterExcludeHelper, false));
-
-auto const TestPresetHelper =
-  cmJSONObjectHelper<TestPreset, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
-    .Bind("name"_s, &TestPreset::Name, PresetStringHelper)
-    .Bind("inherits"_s, &TestPreset::Inherits, PresetInheritsHelper, false)
-    .Bind("hidden"_s, &TestPreset::Hidden, PresetBoolHelper, false)
-    .Bind<std::nullptr_t>("vendor"_s, nullptr,
-                          VendorHelper(ReadFileResult::INVALID_PRESET), false)
-    .Bind("displayName"_s, &TestPreset::DisplayName, PresetStringHelper, false)
-    .Bind("description"_s, &TestPreset::Description, PresetStringHelper, false)
-    .Bind("environment"_s, &TestPreset::Environment, EnvironmentMapHelper,
-          false)
-    .Bind("configurePreset"_s, &TestPreset::ConfigurePreset,
-          PresetStringHelper, false)
-    .Bind("inheritConfigureEnvironment"_s,
-          &TestPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper,
-          false)
-    .Bind("configuration"_s, &TestPreset::Configuration, PresetStringHelper,
-          false)
-    .Bind("overwriteConfigurationFile"_s,
-          &TestPreset::OverwriteConfigurationFile, PresetVectorStringHelper,
-          false)
-    .Bind("output"_s, &TestPreset::Output, TestPresetOptionalOutputHelper,
-          false)
-    .Bind("filter"_s, &TestPreset::Filter, TestPresetFilterHelper, false)
-    .Bind("execution"_s, &TestPreset::Execution, TestPresetExecutionHelper,
-          false);
-
-auto const ConfigurePresetsHelper =
-  cmJSONVectorHelper<ConfigurePreset, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
-    ConfigurePresetHelper);
-
-auto const BuildPresetsHelper =
-  cmJSONVectorHelper<BuildPreset, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
-    BuildPresetHelper);
-
-auto const TestPresetsHelper = cmJSONVectorHelper<TestPreset, ReadFileResult>(
-  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, TestPresetHelper);
-
-auto const CMakeVersionUIntHelper = cmJSONUIntHelper<ReadFileResult>(
-  ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION);
-
-auto const CMakeVersionHelper =
-  cmJSONObjectHelper<CMakeVersion, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_CMAKE_VERSION, false)
-    .Bind("major"_s, &CMakeVersion::Major, CMakeVersionUIntHelper, false)
-    .Bind("minor"_s, &CMakeVersion::Minor, CMakeVersionUIntHelper, false)
-    .Bind("patch"_s, &CMakeVersion::Patch, CMakeVersionUIntHelper, false);
-
-auto const RootPresetsHelper =
-  cmJSONObjectHelper<RootPresets, ReadFileResult>(
-    ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false)
-    .Bind<int>("version"_s, nullptr, VersionHelper)
-    .Bind("configurePresets"_s, &RootPresets::ConfigurePresets,
-          ConfigurePresetsHelper, false)
-    .Bind("buildPresets"_s, &RootPresets::BuildPresets, BuildPresetsHelper,
-          false)
-    .Bind("testPresets"_s, &RootPresets::TestPresets, TestPresetsHelper, false)
-    .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired,
-          CMakeVersionHelper, false)
-    .Bind<std::nullptr_t>("vendor"_s, nullptr,
-                          VendorHelper(ReadFileResult::INVALID_ROOT), false);
+using ExpandMacroResult = cmCMakePresetsFileInternal::ExpandMacroResult;
+using MacroExpander = cmCMakePresetsFileInternal::MacroExpander;
 
 void InheritString(std::string& child, const std::string& parent)
 {
@@ -751,7 +78,7 @@
 template <class T>
 ReadFileResult VisitPreset(
   T& preset, std::map<std::string, cmCMakePresetsFile::PresetPair<T>>& presets,
-  std::map<std::string, CycleStatus> cycleStatus)
+  std::map<std::string, CycleStatus> cycleStatus, int version)
 {
   switch (cycleStatus[preset.Name]) {
     case CycleStatus::InProgress:
@@ -781,7 +108,7 @@
       return ReadFileResult::USER_PRESET_INHERITANCE;
     }
 
-    auto result = VisitPreset(parentPreset, presets, cycleStatus);
+    auto result = VisitPreset(parentPreset, presets, cycleStatus, version);
     if (result != ReadFileResult::READ_OK) {
       return result;
     }
@@ -791,9 +118,17 @@
     for (auto const& v : parentPreset.Environment) {
       preset.Environment.insert(v);
     }
+
+    if (!preset.ConditionEvaluator) {
+      preset.ConditionEvaluator = parentPreset.ConditionEvaluator;
+    }
   }
 
-  CHECK_OK(preset.VisitPresetAfterInherit())
+  if (preset.ConditionEvaluator && preset.ConditionEvaluator->IsNull()) {
+    preset.ConditionEvaluator.reset();
+  }
+
+  CHECK_OK(preset.VisitPresetAfterInherit(version))
 
   cycleStatus[preset.Name] = CycleStatus::Verified;
   return ReadFileResult::READ_OK;
@@ -801,7 +136,8 @@
 
 template <class T>
 ReadFileResult ComputePresetInheritance(
-  std::map<std::string, cmCMakePresetsFile::PresetPair<T>>& presets)
+  std::map<std::string, cmCMakePresetsFile::PresetPair<T>>& presets,
+  const cmCMakePresetsFile& file)
 {
   std::map<std::string, CycleStatus> cycleStatus;
   for (auto const& it : presets) {
@@ -809,7 +145,9 @@
   }
 
   for (auto& it : presets) {
-    auto result = VisitPreset<T>(it.second.Unexpanded, presets, cycleStatus);
+    auto& preset = it.second.Unexpanded;
+    auto result =
+      VisitPreset<T>(preset, presets, cycleStatus, file.GetVersion(preset));
     if (result != ReadFileResult::READ_OK) {
       return result;
     }
@@ -839,24 +177,17 @@
     [&str](const char* prefix) -> bool { return str == prefix; });
 }
 
-enum class ExpandMacroResult
-{
-  Ok,
-  Ignore,
-  Error,
-};
-
-using MacroExpander = std::function<ExpandMacroResult(
-  const std::string&, const std::string&, std::string&)>;
-
 ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status,
-                           const std::vector<MacroExpander>& macroExpanders);
+                           const std::vector<MacroExpander>& macroExpanders,
+                           int version);
 ExpandMacroResult ExpandMacros(
-  std::string& out, const std::vector<MacroExpander>& macroExpanders);
-ExpandMacroResult ExpandMacro(
-  std::string& out, const std::string& macroNamespace,
-  const std::string& macroName,
-  const std::vector<MacroExpander>& macroExpanders);
+  std::string& out, const std::vector<MacroExpander>& macroExpanders,
+  int version);
+ExpandMacroResult ExpandMacro(std::string& out,
+                              const std::string& macroNamespace,
+                              const std::string& macroName,
+                              const std::vector<MacroExpander>& macroExpanders,
+                              int version);
 
 bool ExpandMacros(const cmCMakePresetsFile& file,
                   const ConfigurePreset& preset,
@@ -864,7 +195,7 @@
                   const std::vector<MacroExpander>& macroExpanders)
 {
   std::string binaryDir = preset.BinaryDir;
-  CHECK_EXPAND(out, binaryDir, macroExpanders)
+  CHECK_EXPAND(out, binaryDir, macroExpanders, file.GetVersion(preset))
 
   if (!cmSystemTools::FileIsFullPath(binaryDir)) {
     binaryDir = cmStrCat(file.SourceDir, '/', binaryDir);
@@ -872,69 +203,89 @@
   out->BinaryDir = cmSystemTools::CollapseFullPath(binaryDir);
   cmSystemTools::ConvertToUnixSlashes(out->BinaryDir);
 
+  if (!preset.InstallDir.empty()) {
+    std::string installDir = preset.InstallDir;
+    CHECK_EXPAND(out, installDir, macroExpanders, file.GetVersion(preset))
+
+    if (!cmSystemTools::FileIsFullPath(installDir)) {
+      installDir = cmStrCat(file.SourceDir, '/', installDir);
+    }
+    out->InstallDir = cmSystemTools::CollapseFullPath(installDir);
+    cmSystemTools::ConvertToUnixSlashes(out->InstallDir);
+  }
+
   for (auto& variable : out->CacheVariables) {
     if (variable.second) {
-      CHECK_EXPAND(out, variable.second->Value, macroExpanders)
+      CHECK_EXPAND(out, variable.second->Value, macroExpanders,
+                   file.GetVersion(preset))
     }
   }
 
   return true;
 }
 
-bool ExpandMacros(const cmCMakePresetsFile&, const BuildPreset&,
+bool ExpandMacros(const cmCMakePresetsFile& file, const BuildPreset& preset,
                   cm::optional<BuildPreset>& out,
                   const std::vector<MacroExpander>& macroExpanders)
 {
   for (auto& target : out->Targets) {
-    CHECK_EXPAND(out, target, macroExpanders)
+    CHECK_EXPAND(out, target, macroExpanders, file.GetVersion(preset))
   }
 
   for (auto& nativeToolOption : out->NativeToolOptions) {
-    CHECK_EXPAND(out, nativeToolOption, macroExpanders)
+    CHECK_EXPAND(out, nativeToolOption, macroExpanders,
+                 file.GetVersion(preset))
   }
 
   return true;
 }
 
-bool ExpandMacros(const cmCMakePresetsFile&, const TestPreset&,
+bool ExpandMacros(const cmCMakePresetsFile& file, const TestPreset& preset,
                   cm::optional<TestPreset>& out,
                   const std::vector<MacroExpander>& macroExpanders)
 {
   for (auto& overwrite : out->OverwriteConfigurationFile) {
-    CHECK_EXPAND(out, overwrite, macroExpanders);
+    CHECK_EXPAND(out, overwrite, macroExpanders, file.GetVersion(preset));
   }
 
   if (out->Output) {
-    CHECK_EXPAND(out, out->Output->OutputLogFile, macroExpanders)
+    CHECK_EXPAND(out, out->Output->OutputLogFile, macroExpanders,
+                 file.GetVersion(preset))
   }
 
   if (out->Filter) {
     if (out->Filter->Include) {
-      CHECK_EXPAND(out, out->Filter->Include->Name, macroExpanders)
-      CHECK_EXPAND(out, out->Filter->Include->Label, macroExpanders)
+      CHECK_EXPAND(out, out->Filter->Include->Name, macroExpanders,
+                   file.GetVersion(preset))
+      CHECK_EXPAND(out, out->Filter->Include->Label, macroExpanders,
+                   file.GetVersion(preset))
 
       if (out->Filter->Include->Index) {
         CHECK_EXPAND(out, out->Filter->Include->Index->IndexFile,
-                     macroExpanders);
+                     macroExpanders, file.GetVersion(preset));
       }
     }
 
     if (out->Filter->Exclude) {
-      CHECK_EXPAND(out, out->Filter->Exclude->Name, macroExpanders)
-      CHECK_EXPAND(out, out->Filter->Exclude->Label, macroExpanders)
+      CHECK_EXPAND(out, out->Filter->Exclude->Name, macroExpanders,
+                   file.GetVersion(preset))
+      CHECK_EXPAND(out, out->Filter->Exclude->Label, macroExpanders,
+                   file.GetVersion(preset))
 
       if (out->Filter->Exclude->Fixtures) {
-        CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Any, macroExpanders)
+        CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Any, macroExpanders,
+                     file.GetVersion(preset))
         CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Setup,
-                     macroExpanders)
+                     macroExpanders, file.GetVersion(preset))
         CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Cleanup,
-                     macroExpanders)
+                     macroExpanders, file.GetVersion(preset))
       }
     }
   }
 
   if (out->Execution) {
-    CHECK_EXPAND(out, out->Execution->ResourceSpecFile, macroExpanders)
+    CHECK_EXPAND(out, out->Execution->ResourceSpecFile, macroExpanders,
+                 file.GetVersion(preset))
   }
 
   return true;
@@ -955,8 +306,8 @@
 
   MacroExpander defaultMacroExpander =
     [&file, &preset](const std::string& macroNamespace,
-                     const std::string& macroName,
-                     std::string& macroOut) -> ExpandMacroResult {
+                     const std::string& macroName, std::string& macroOut,
+                     int version) -> ExpandMacroResult {
     if (macroNamespace.empty()) {
       if (macroName == "sourceDir") {
         macroOut += file.SourceDir;
@@ -985,6 +336,13 @@
         macroOut += '$';
         return ExpandMacroResult::Ok;
       }
+      if (macroName == "hostSystemName") {
+        if (version < 3) {
+          return ExpandMacroResult::Error;
+        }
+        macroOut += cmSystemTools::GetSystemName();
+        return ExpandMacroResult::Ok;
+      }
     }
 
     return ExpandMacroResult::Ignore;
@@ -993,11 +351,12 @@
   MacroExpander environmentMacroExpander =
     [&macroExpanders, &out, &envCycles](
       const std::string& macroNamespace, const std::string& macroName,
-      std::string& result) -> ExpandMacroResult {
+      std::string& result, int version) -> ExpandMacroResult {
     if (macroNamespace == "env" && !macroName.empty() && out) {
       auto v = out->Environment.find(macroName);
       if (v != out->Environment.end() && v->second) {
-        auto e = VisitEnv(*v->second, envCycles[macroName], macroExpanders);
+        auto e =
+          VisitEnv(*v->second, envCycles[macroName], macroExpanders, version);
         if (e != ExpandMacroResult::Ok) {
           return e;
         }
@@ -1025,7 +384,8 @@
 
   for (auto& v : out->Environment) {
     if (v.second) {
-      switch (VisitEnv(*v.second, envCycles[v.first], macroExpanders)) {
+      switch (VisitEnv(*v.second, envCycles[v.first], macroExpanders,
+                       file.GetVersion(preset))) {
         case ExpandMacroResult::Error:
           return false;
         case ExpandMacroResult::Ignore:
@@ -1037,11 +397,25 @@
     }
   }
 
+  if (preset.ConditionEvaluator) {
+    cm::optional<bool> result;
+    if (!preset.ConditionEvaluator->Evaluate(
+          macroExpanders, file.GetVersion(preset), result)) {
+      return false;
+    }
+    if (!result) {
+      out.reset();
+      return true;
+    }
+    out->ConditionResult = *result;
+  }
+
   return ExpandMacros(file, preset, out, macroExpanders);
 }
 
 ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status,
-                           const std::vector<MacroExpander>& macroExpanders)
+                           const std::vector<MacroExpander>& macroExpanders,
+                           int version)
 {
   if (status == CycleStatus::Verified) {
     return ExpandMacroResult::Ok;
@@ -1051,7 +425,7 @@
   }
 
   status = CycleStatus::InProgress;
-  auto e = ExpandMacros(value, macroExpanders);
+  auto e = ExpandMacros(value, macroExpanders, version);
   if (e != ExpandMacroResult::Ok) {
     return e;
   }
@@ -1060,7 +434,8 @@
 }
 
 ExpandMacroResult ExpandMacros(
-  std::string& out, const std::vector<MacroExpander>& macroExpanders)
+  std::string& out, const std::vector<MacroExpander>& macroExpanders,
+  int version)
 {
   std::string result;
   std::string macroNamespace;
@@ -1107,8 +482,8 @@
 
       case State::MacroName:
         if (c == '}') {
-          auto e =
-            ExpandMacro(result, macroNamespace, macroName, macroExpanders);
+          auto e = ExpandMacro(result, macroNamespace, macroName,
+                               macroExpanders, version);
           if (e != ExpandMacroResult::Ok) {
             return e;
           }
@@ -1140,10 +515,11 @@
 ExpandMacroResult ExpandMacro(std::string& out,
                               const std::string& macroNamespace,
                               const std::string& macroName,
-                              const std::vector<MacroExpander>& macroExpanders)
+                              const std::vector<MacroExpander>& macroExpanders,
+                              int version)
 {
   for (auto const& macroExpander : macroExpanders) {
-    auto result = macroExpander(macroNamespace, macroName, out);
+    auto result = macroExpander(macroNamespace, macroName, out, version);
     if (result != ExpandMacroResult::Ignore) {
       return result;
     }
@@ -1157,6 +533,98 @@
 }
 }
 
+bool cmCMakePresetsFileInternal::EqualsCondition::Evaluate(
+  const std::vector<MacroExpander>& expanders, int version,
+  cm::optional<bool>& out) const
+{
+  std::string lhs = this->Lhs;
+  CHECK_EXPAND(out, lhs, expanders, version);
+
+  std::string rhs = this->Rhs;
+  CHECK_EXPAND(out, rhs, expanders, version);
+
+  out = (lhs == rhs);
+  return true;
+}
+
+bool cmCMakePresetsFileInternal::InListCondition::Evaluate(
+  const std::vector<MacroExpander>& expanders, int version,
+  cm::optional<bool>& out) const
+{
+  std::string str = this->String;
+  CHECK_EXPAND(out, str, expanders, version);
+
+  for (auto item : this->List) {
+    CHECK_EXPAND(out, item, expanders, version);
+    if (str == item) {
+      out = true;
+      return true;
+    }
+  }
+
+  out = false;
+  return true;
+}
+
+bool cmCMakePresetsFileInternal::MatchesCondition::Evaluate(
+  const std::vector<MacroExpander>& expanders, int version,
+  cm::optional<bool>& out) const
+{
+  std::string str = this->String;
+  CHECK_EXPAND(out, str, expanders, version);
+  std::string regexStr = this->Regex;
+  CHECK_EXPAND(out, regexStr, expanders, version);
+
+  cmsys::RegularExpression regex;
+  if (!regex.compile(regexStr)) {
+    return false;
+  }
+
+  out = regex.find(str);
+  return true;
+}
+
+bool cmCMakePresetsFileInternal::AnyAllOfCondition::Evaluate(
+  const std::vector<MacroExpander>& expanders, int version,
+  cm::optional<bool>& out) const
+{
+  for (auto const& condition : this->Conditions) {
+    cm::optional<bool> result;
+    if (!condition->Evaluate(expanders, version, result)) {
+      out.reset();
+      return false;
+    }
+
+    if (!result) {
+      out.reset();
+      return true;
+    }
+
+    if (result == this->StopValue) {
+      out = result;
+      return true;
+    }
+  }
+
+  out = !this->StopValue;
+  return true;
+}
+
+bool cmCMakePresetsFileInternal::NotCondition::Evaluate(
+  const std::vector<MacroExpander>& expanders, int version,
+  cm::optional<bool>& out) const
+{
+  out.reset();
+  if (!this->SubCondition->Evaluate(expanders, version, out)) {
+    out.reset();
+    return false;
+  }
+  if (out) {
+    *out = !*out;
+  }
+  return true;
+}
+
 cmCMakePresetsFile::ReadFileResult
 cmCMakePresetsFile::ConfigurePreset::VisitPresetInherit(
   const cmCMakePresetsFile::Preset& parentPreset)
@@ -1174,6 +642,7 @@
     preset.ToolsetStrategy = parent.ToolsetStrategy;
   }
   InheritString(preset.BinaryDir, parent.BinaryDir);
+  InheritString(preset.InstallDir, parent.InstallDir);
   InheritOptionalValue(preset.WarnDev, parent.WarnDev);
   InheritOptionalValue(preset.ErrorDev, parent.ErrorDev);
   InheritOptionalValue(preset.WarnDeprecated, parent.WarnDeprecated);
@@ -1201,16 +670,19 @@
 }
 
 cmCMakePresetsFile::ReadFileResult
-cmCMakePresetsFile::ConfigurePreset::VisitPresetAfterInherit()
+cmCMakePresetsFile::ConfigurePreset::VisitPresetAfterInherit(int version)
 {
   auto& preset = *this;
   if (!preset.Hidden) {
-    if (preset.Generator.empty()) {
-      return ReadFileResult::INVALID_PRESET;
+    if (version < 3) {
+      if (preset.Generator.empty()) {
+        return ReadFileResult::INVALID_PRESET;
+      }
+      if (preset.BinaryDir.empty()) {
+        return ReadFileResult::INVALID_PRESET;
+      }
     }
-    if (preset.BinaryDir.empty()) {
-      return ReadFileResult::INVALID_PRESET;
-    }
+
     if (preset.WarnDev == false && preset.ErrorDev == true) {
       return ReadFileResult::INVALID_PRESET;
     }
@@ -1246,7 +718,7 @@
 }
 
 cmCMakePresetsFile::ReadFileResult
-cmCMakePresetsFile::BuildPreset::VisitPresetAfterInherit()
+cmCMakePresetsFile::BuildPreset::VisitPresetAfterInherit(int /* version */)
 {
   auto& preset = *this;
   if (!preset.Hidden && preset.ConfigurePreset.empty()) {
@@ -1356,7 +828,7 @@
 }
 
 cmCMakePresetsFile::ReadFileResult
-cmCMakePresetsFile::TestPreset::VisitPresetAfterInherit()
+cmCMakePresetsFile::TestPreset::VisitPresetAfterInherit(int /* version */)
 {
   auto& preset = *this;
   if (!preset.Hidden && preset.ConfigurePreset.empty()) {
@@ -1417,9 +889,9 @@
                         : ReadFileResult::FILE_NOT_FOUND;
   }
 
-  CHECK_OK(ComputePresetInheritance(this->ConfigurePresets))
-  CHECK_OK(ComputePresetInheritance(this->BuildPresets))
-  CHECK_OK(ComputePresetInheritance(this->TestPresets))
+  CHECK_OK(ComputePresetInheritance(this->ConfigurePresets, *this))
+  CHECK_OK(ComputePresetInheritance(this->BuildPresets, *this))
+  CHECK_OK(ComputePresetInheritance(this->TestPresets, *this))
 
   for (auto& it : this->ConfigurePresets) {
     if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) {
@@ -1510,111 +982,18 @@
              "support.";
     case ReadFileResult::INVALID_CONFIGURE_PRESET:
       return "Invalid \"configurePreset\" field";
+    case ReadFileResult::INSTALL_PREFIX_UNSUPPORTED:
+      return "File version must be 3 or higher for installDir preset "
+             "support.";
+    case ReadFileResult::INVALID_CONDITION:
+      return "Invalid preset condition";
+    case ReadFileResult::CONDITION_UNSUPPORTED:
+      return "File version must be 3 or higher for condition support";
   }
 
   return "Unknown error";
 }
 
-cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadJSONFile(
-  const std::string& filename, bool user)
-{
-  cmsys::ifstream fin(filename.c_str());
-  if (!fin) {
-    return ReadFileResult::FILE_NOT_FOUND;
-  }
-  // If there's a BOM, toss it.
-  cmsys::FStream::ReadBOM(fin);
-
-  Json::Value root;
-  Json::CharReaderBuilder builder;
-  Json::CharReaderBuilder::strictMode(&builder.settings_);
-  if (!Json::parseFromStream(builder, fin, &root, nullptr)) {
-    return ReadFileResult::JSON_PARSE_ERROR;
-  }
-
-  int v = 0;
-  auto result = RootVersionHelper(v, &root);
-  if (result != ReadFileResult::READ_OK) {
-    return result;
-  }
-  if (v < MIN_VERSION || v > MAX_VERSION) {
-    return ReadFileResult::UNRECOGNIZED_VERSION;
-  }
-
-  // Support for build and test presets added in version 2.
-  if (v < 2 &&
-      (root.isMember("buildPresets") || root.isMember("testPresets"))) {
-    return ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED;
-  }
-
-  RootPresets presets;
-  if ((result = RootPresetsHelper(presets, &root)) !=
-      ReadFileResult::READ_OK) {
-    return result;
-  }
-
-  unsigned int currentMajor = cmVersion::GetMajorVersion();
-  unsigned int currentMinor = cmVersion::GetMinorVersion();
-  unsigned int currentPatch = cmVersion::GetPatchVersion();
-  auto const& required = presets.CMakeMinimumRequired;
-  if (required.Major > currentMajor ||
-      (required.Major == currentMajor &&
-       (required.Minor > currentMinor ||
-        (required.Minor == currentMinor &&
-         (required.Patch > currentPatch))))) {
-    return ReadFileResult::UNRECOGNIZED_CMAKE_VERSION;
-  }
-
-  for (auto& preset : presets.ConfigurePresets) {
-    preset.User = user;
-    if (preset.Name.empty()) {
-      return ReadFileResult::INVALID_PRESET;
-    }
-
-    PresetPair<ConfigurePreset> presetPair;
-    presetPair.Unexpanded = preset;
-    presetPair.Expanded = cm::nullopt;
-    if (!this->ConfigurePresets
-           .emplace(std::make_pair(preset.Name, presetPair))
-           .second) {
-      return ReadFileResult::DUPLICATE_PRESETS;
-    }
-    this->ConfigurePresetOrder.push_back(preset.Name);
-  }
-
-  for (auto& preset : presets.BuildPresets) {
-    preset.User = user;
-    if (preset.Name.empty()) {
-      return ReadFileResult::INVALID_PRESET;
-    }
-
-    PresetPair<BuildPreset> presetPair;
-    presetPair.Unexpanded = preset;
-    presetPair.Expanded = cm::nullopt;
-    if (!this->BuildPresets.emplace(preset.Name, presetPair).second) {
-      return ReadFileResult::DUPLICATE_PRESETS;
-    }
-    this->BuildPresetOrder.push_back(preset.Name);
-  }
-
-  for (auto& preset : presets.TestPresets) {
-    preset.User = user;
-    if (preset.Name.empty()) {
-      return ReadFileResult::INVALID_PRESET;
-    }
-
-    PresetPair<TestPreset> presetPair;
-    presetPair.Unexpanded = preset;
-    presetPair.Expanded = cm::nullopt;
-    if (!this->TestPresets.emplace(preset.Name, presetPair).second) {
-      return ReadFileResult::DUPLICATE_PRESETS;
-    }
-    this->TestPresetOrder.push_back(preset.Name);
-  }
-
-  return ReadFileResult::READ_OK;
-}
-
 void cmCMakePresetsFile::ClearPresets()
 {
   this->ConfigurePresets.clear();
@@ -1666,7 +1045,7 @@
   for (auto const& p : this->ConfigurePresetOrder) {
     auto const& preset = this->ConfigurePresets.at(p);
     if (!preset.Unexpanded.Hidden && preset.Expanded &&
-        filter(preset.Unexpanded)) {
+        preset.Expanded->ConditionResult && filter(preset.Unexpanded)) {
       presets.push_back(
         static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
     }
@@ -1683,7 +1062,8 @@
   std::vector<const cmCMakePresetsFile::Preset*> presets;
   for (auto const& p : this->BuildPresetOrder) {
     auto const& preset = this->BuildPresets.at(p);
-    if (!preset.Unexpanded.Hidden && preset.Expanded) {
+    if (!preset.Unexpanded.Hidden && preset.Expanded &&
+        preset.Expanded->ConditionResult) {
       presets.push_back(
         static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
     }
@@ -1700,7 +1080,8 @@
   std::vector<const cmCMakePresetsFile::Preset*> presets;
   for (auto const& p : this->TestPresetOrder) {
     auto const& preset = this->TestPresets.at(p);
-    if (!preset.Unexpanded.Hidden && preset.Expanded) {
+    if (!preset.Unexpanded.Hidden && preset.Expanded &&
+        preset.Expanded->ConditionResult) {
       presets.push_back(
         static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded));
     }
diff --git a/Source/cmCMakePresetsFile.h b/Source/cmCMakePresetsFile.h
index 3067d5e..fc14830 100644
--- a/Source/cmCMakePresetsFile.h
+++ b/Source/cmCMakePresetsFile.h
@@ -2,8 +2,11 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #pragma once
 
+#include "cmConfigure.h" // IWYU pragma: keep
+
 #include <functional>
 #include <map>
+#include <memory>
 #include <string>
 #include <utility>
 #include <vector>
@@ -33,6 +36,9 @@
     INVALID_MACRO_EXPANSION,
     BUILD_TEST_PRESETS_UNSUPPORTED,
     INVALID_CONFIGURE_PRESET,
+    INSTALL_PREFIX_UNSUPPORTED,
+    INVALID_CONDITION,
+    CONDITION_UNSUPPORTED,
   };
 
   enum class ArchToolsetStrategy
@@ -48,6 +54,8 @@
     std::string Value;
   };
 
+  class Condition;
+
   class Preset
   {
   public:
@@ -70,6 +78,9 @@
     std::string DisplayName;
     std::string Description;
 
+    std::shared_ptr<Condition> ConditionEvaluator;
+    bool ConditionResult = true;
+
     std::map<std::string, cm::optional<std::string>> Environment;
 
     virtual ReadFileResult VisitPresetInherit(const Preset& parent) = 0;
@@ -78,7 +89,7 @@
       return ReadFileResult::READ_OK;
     }
 
-    virtual ReadFileResult VisitPresetAfterInherit()
+    virtual ReadFileResult VisitPresetAfterInherit(int /* version */)
     {
       return ReadFileResult::READ_OK;
     }
@@ -103,6 +114,7 @@
     std::string Toolset;
     cm::optional<ArchToolsetStrategy> ToolsetStrategy;
     std::string BinaryDir;
+    std::string InstallDir;
 
     std::map<std::string, cm::optional<CacheVariable>> CacheVariables;
 
@@ -120,7 +132,7 @@
 
     ReadFileResult VisitPresetInherit(const Preset& parent) override;
     ReadFileResult VisitPresetBeforeInherit() override;
-    ReadFileResult VisitPresetAfterInherit() override;
+    ReadFileResult VisitPresetAfterInherit(int version) override;
   };
 
   class BuildPreset : public Preset
@@ -146,7 +158,7 @@
     std::vector<std::string> NativeToolOptions;
 
     ReadFileResult VisitPresetInherit(const Preset& parent) override;
-    ReadFileResult VisitPresetAfterInherit() override;
+    ReadFileResult VisitPresetAfterInherit(int /* version */) override;
   };
 
   class TestPreset : public Preset
@@ -273,7 +285,7 @@
     cm::optional<ExecutionOptions> Execution;
 
     ReadFileResult VisitPresetInherit(const Preset& parent) override;
-    ReadFileResult VisitPresetAfterInherit() override;
+    ReadFileResult VisitPresetAfterInherit(int /* version */) override;
   };
 
   template <class T>
@@ -293,6 +305,13 @@
   std::vector<std::string> TestPresetOrder;
 
   std::string SourceDir;
+  int Version;
+  int UserVersion;
+
+  int GetVersion(const Preset& preset) const
+  {
+    return preset.User ? this->UserVersion : this->Version;
+  }
 
   static std::string GetFilename(const std::string& sourceDir);
   static std::string GetUserFilename(const std::string& sourceDir);
diff --git a/Source/cmCMakePresetsFileInternal.h b/Source/cmCMakePresetsFileInternal.h
new file mode 100644
index 0000000..3269276
--- /dev/null
+++ b/Source/cmCMakePresetsFileInternal.h
@@ -0,0 +1,112 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include <memory>
+
+#include "cmCMakePresetsFile.h"
+
+#define CHECK_OK(expr)                                                        \
+  {                                                                           \
+    auto _result = expr;                                                      \
+    if (_result != ReadFileResult::READ_OK)                                   \
+      return _result;                                                         \
+  }
+
+namespace cmCMakePresetsFileInternal {
+enum class ExpandMacroResult
+{
+  Ok,
+  Ignore,
+  Error,
+};
+
+using MacroExpander = std::function<ExpandMacroResult(
+  const std::string&, const std::string&, std::string&, int version)>;
+}
+
+class cmCMakePresetsFile::Condition
+{
+public:
+  virtual ~Condition() = default;
+
+  virtual bool Evaluate(
+    const std::vector<cmCMakePresetsFileInternal::MacroExpander>& expanders,
+    int version, cm::optional<bool>& out) const = 0;
+  virtual bool IsNull() const { return false; }
+};
+
+namespace cmCMakePresetsFileInternal {
+
+class NullCondition : public cmCMakePresetsFile::Condition
+{
+  bool Evaluate(const std::vector<MacroExpander>& /*expanders*/,
+                int /*version*/, cm::optional<bool>& out) const override
+  {
+    out = true;
+    return true;
+  }
+
+  bool IsNull() const override { return true; }
+};
+
+class ConstCondition : public cmCMakePresetsFile::Condition
+{
+public:
+  bool Evaluate(const std::vector<MacroExpander>& /*expanders*/,
+                int /*version*/, cm::optional<bool>& out) const override
+  {
+    out = this->Value;
+    return true;
+  }
+
+  bool Value;
+};
+
+class EqualsCondition : public cmCMakePresetsFile::Condition
+{
+public:
+  bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
+                cm::optional<bool>& out) const override;
+
+  std::string Lhs;
+  std::string Rhs;
+};
+
+class InListCondition : public cmCMakePresetsFile::Condition
+{
+public:
+  bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
+                cm::optional<bool>& out) const override;
+
+  std::string String;
+  std::vector<std::string> List;
+};
+
+class MatchesCondition : public cmCMakePresetsFile::Condition
+{
+public:
+  bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
+                cm::optional<bool>& out) const override;
+
+  std::string String;
+  std::string Regex;
+};
+
+class AnyAllOfCondition : public cmCMakePresetsFile::Condition
+{
+public:
+  bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
+                cm::optional<bool>& out) const override;
+
+  std::vector<std::unique_ptr<Condition>> Conditions;
+  bool StopValue;
+};
+
+class NotCondition : public cmCMakePresetsFile::Condition
+{
+public:
+  bool Evaluate(const std::vector<MacroExpander>& expanders, int version,
+                cm::optional<bool>& out) const override;
+
+  std::unique_ptr<Condition> SubCondition;
+};
+}
diff --git a/Source/cmCMakePresetsFileReadJSON.cxx b/Source/cmCMakePresetsFileReadJSON.cxx
new file mode 100644
index 0000000..403fac6
--- /dev/null
+++ b/Source/cmCMakePresetsFileReadJSON.cxx
@@ -0,0 +1,1022 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include <functional>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/memory>
+#include <cm/optional>
+#include <cmext/string_view>
+
+#include <cm3p/json/reader.h>
+#include <cm3p/json/value.h>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmCMakePresetsFile.h"
+#include "cmCMakePresetsFileInternal.h"
+#include "cmJSONHelpers.h"
+#include "cmVersion.h"
+
+namespace {
+using ReadFileResult = cmCMakePresetsFile::ReadFileResult;
+using CacheVariable = cmCMakePresetsFile::CacheVariable;
+using ConfigurePreset = cmCMakePresetsFile::ConfigurePreset;
+using BuildPreset = cmCMakePresetsFile::BuildPreset;
+using TestPreset = cmCMakePresetsFile::TestPreset;
+using ArchToolsetStrategy = cmCMakePresetsFile::ArchToolsetStrategy;
+
+constexpr int MIN_VERSION = 1;
+constexpr int MAX_VERSION = 3;
+
+struct CMakeVersion
+{
+  unsigned int Major = 0;
+  unsigned int Minor = 0;
+  unsigned int Patch = 0;
+};
+
+struct RootPresets
+{
+  CMakeVersion CMakeMinimumRequired;
+  std::vector<cmCMakePresetsFile::ConfigurePreset> ConfigurePresets;
+  std::vector<cmCMakePresetsFile::BuildPreset> BuildPresets;
+  std::vector<cmCMakePresetsFile::TestPreset> TestPresets;
+};
+
+std::unique_ptr<cmCMakePresetsFileInternal::NotCondition> InvertCondition(
+  std::unique_ptr<cmCMakePresetsFile::Condition> condition)
+{
+  auto retval = cm::make_unique<cmCMakePresetsFileInternal::NotCondition>();
+  retval->SubCondition = std::move(condition);
+  return retval;
+}
+
+auto const ConditionStringHelper = cmJSONStringHelper<ReadFileResult>(
+  ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION);
+
+auto const ConditionBoolHelper = cmJSONBoolHelper<ReadFileResult>(
+  ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION);
+
+auto const ConditionStringListHelper =
+  cmJSONVectorHelper<std::string, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION,
+    ConditionStringHelper);
+
+auto const ConstConditionHelper =
+  cmJSONObjectHelper<cmCMakePresetsFileInternal::ConstCondition,
+                     ReadFileResult>(ReadFileResult::READ_OK,
+                                     ReadFileResult::INVALID_CONDITION, false)
+    .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
+    .Bind("value"_s, &cmCMakePresetsFileInternal::ConstCondition::Value,
+          ConditionBoolHelper, true);
+
+auto const EqualsConditionHelper =
+  cmJSONObjectHelper<cmCMakePresetsFileInternal::EqualsCondition,
+                     ReadFileResult>(ReadFileResult::READ_OK,
+                                     ReadFileResult::INVALID_CONDITION, false)
+    .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
+    .Bind("lhs"_s, &cmCMakePresetsFileInternal::EqualsCondition::Lhs,
+          ConditionStringHelper, true)
+    .Bind("rhs"_s, &cmCMakePresetsFileInternal::EqualsCondition::Rhs,
+          ConditionStringHelper, true);
+
+auto const InListConditionHelper =
+  cmJSONObjectHelper<cmCMakePresetsFileInternal::InListCondition,
+                     ReadFileResult>(ReadFileResult::READ_OK,
+                                     ReadFileResult::INVALID_CONDITION, false)
+    .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
+    .Bind("string"_s, &cmCMakePresetsFileInternal::InListCondition::String,
+          ConditionStringHelper, true)
+    .Bind("list"_s, &cmCMakePresetsFileInternal::InListCondition::List,
+          ConditionStringListHelper, true);
+
+auto const MatchesConditionHelper =
+  cmJSONObjectHelper<cmCMakePresetsFileInternal::MatchesCondition,
+                     ReadFileResult>(ReadFileResult::READ_OK,
+                                     ReadFileResult::INVALID_CONDITION, false)
+    .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
+    .Bind("string"_s, &cmCMakePresetsFileInternal::MatchesCondition::String,
+          ConditionStringHelper, true)
+    .Bind("regex"_s, &cmCMakePresetsFileInternal::MatchesCondition::Regex,
+          ConditionStringHelper, true);
+
+ReadFileResult SubConditionHelper(
+  std::unique_ptr<cmCMakePresetsFile::Condition>& out,
+  const Json::Value* value);
+
+auto const ListConditionVectorHelper =
+  cmJSONVectorHelper<std::unique_ptr<cmCMakePresetsFile::Condition>,
+                     ReadFileResult>(ReadFileResult::READ_OK,
+                                     ReadFileResult::INVALID_CONDITION,
+                                     SubConditionHelper);
+auto const AnyAllOfConditionHelper =
+  cmJSONObjectHelper<cmCMakePresetsFileInternal::AnyAllOfCondition,
+                     ReadFileResult>(ReadFileResult::READ_OK,
+                                     ReadFileResult::INVALID_CONDITION, false)
+    .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
+    .Bind("conditions"_s,
+          &cmCMakePresetsFileInternal::AnyAllOfCondition::Conditions,
+          ListConditionVectorHelper);
+
+auto const NotConditionHelper =
+  cmJSONObjectHelper<cmCMakePresetsFileInternal::NotCondition, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false)
+    .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true)
+    .Bind("condition"_s,
+          &cmCMakePresetsFileInternal::NotCondition::SubCondition,
+          SubConditionHelper);
+
+ReadFileResult ConditionHelper(
+  std::unique_ptr<cmCMakePresetsFile::Condition>& out,
+  const Json::Value* value)
+{
+  if (!value) {
+    out.reset();
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->isBool()) {
+    auto c = cm::make_unique<cmCMakePresetsFileInternal::ConstCondition>();
+    c->Value = value->asBool();
+    out = std::move(c);
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->isNull()) {
+    out = cm::make_unique<cmCMakePresetsFileInternal::NullCondition>();
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->isObject()) {
+    if (!value->isMember("type")) {
+      return ReadFileResult::INVALID_CONDITION;
+    }
+
+    if (!(*value)["type"].isString()) {
+      return ReadFileResult::INVALID_CONDITION;
+    }
+    auto type = (*value)["type"].asString();
+
+    if (type == "const") {
+      auto c = cm::make_unique<cmCMakePresetsFileInternal::ConstCondition>();
+      CHECK_OK(ConstConditionHelper(*c, value));
+      out = std::move(c);
+      return ReadFileResult::READ_OK;
+    }
+
+    if (type == "equals" || type == "notEquals") {
+      auto c = cm::make_unique<cmCMakePresetsFileInternal::EqualsCondition>();
+      CHECK_OK(EqualsConditionHelper(*c, value));
+      out = std::move(c);
+      if (type == "notEquals") {
+        out = InvertCondition(std::move(out));
+      }
+      return ReadFileResult::READ_OK;
+    }
+
+    if (type == "inList" || type == "notInList") {
+      auto c = cm::make_unique<cmCMakePresetsFileInternal::InListCondition>();
+      CHECK_OK(InListConditionHelper(*c, value));
+      out = std::move(c);
+      if (type == "notInList") {
+        out = InvertCondition(std::move(out));
+      }
+      return ReadFileResult::READ_OK;
+    }
+
+    if (type == "matches" || type == "notMatches") {
+      auto c = cm::make_unique<cmCMakePresetsFileInternal::MatchesCondition>();
+      CHECK_OK(MatchesConditionHelper(*c, value));
+      out = std::move(c);
+      if (type == "notMatches") {
+        out = InvertCondition(std::move(out));
+      }
+      return ReadFileResult::READ_OK;
+    }
+
+    if (type == "anyOf" || type == "allOf") {
+      auto c =
+        cm::make_unique<cmCMakePresetsFileInternal::AnyAllOfCondition>();
+      c->StopValue = (type == "anyOf");
+      CHECK_OK(AnyAllOfConditionHelper(*c, value));
+      out = std::move(c);
+      return ReadFileResult::READ_OK;
+    }
+
+    if (type == "not") {
+      auto c = cm::make_unique<cmCMakePresetsFileInternal::NotCondition>();
+      CHECK_OK(NotConditionHelper(*c, value));
+      out = std::move(c);
+      return ReadFileResult::READ_OK;
+    }
+  }
+
+  return ReadFileResult::INVALID_CONDITION;
+}
+
+ReadFileResult PresetConditionHelper(
+  std::shared_ptr<cmCMakePresetsFile::Condition>& out,
+  const Json::Value* value)
+{
+  std::unique_ptr<cmCMakePresetsFile::Condition> ptr;
+  auto result = ConditionHelper(ptr, value);
+  out = std::move(ptr);
+  return result;
+}
+
+ReadFileResult SubConditionHelper(
+  std::unique_ptr<cmCMakePresetsFile::Condition>& out,
+  const Json::Value* value)
+{
+  std::unique_ptr<cmCMakePresetsFile::Condition> ptr;
+  auto result = ConditionHelper(ptr, value);
+  if (ptr && ptr->IsNull()) {
+    return ReadFileResult::INVALID_CONDITION;
+  }
+  out = std::move(ptr);
+  return result;
+}
+
+cmJSONHelper<std::nullptr_t, ReadFileResult> VendorHelper(ReadFileResult error)
+{
+  return [error](std::nullptr_t& /*out*/,
+                 const Json::Value* value) -> ReadFileResult {
+    if (!value) {
+      return ReadFileResult::READ_OK;
+    }
+
+    if (!value->isObject()) {
+      return error;
+    }
+
+    return ReadFileResult::READ_OK;
+  };
+}
+
+auto const VersionIntHelper = cmJSONIntHelper<ReadFileResult>(
+  ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION);
+
+auto const VersionHelper = cmJSONRequiredHelper<int, ReadFileResult>(
+  ReadFileResult::NO_VERSION, VersionIntHelper);
+
+auto const RootVersionHelper =
+  cmJSONObjectHelper<int, ReadFileResult>(ReadFileResult::READ_OK,
+                                          ReadFileResult::INVALID_ROOT)
+    .Bind("version"_s, VersionHelper, false);
+
+auto const VariableStringHelper = cmJSONStringHelper<ReadFileResult>(
+  ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE);
+
+ReadFileResult VariableValueHelper(std::string& out, const Json::Value* value)
+{
+  if (!value) {
+    out.clear();
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->isBool()) {
+    out = value->asBool() ? "TRUE" : "FALSE";
+    return ReadFileResult::READ_OK;
+  }
+
+  return VariableStringHelper(out, value);
+}
+
+auto const VariableObjectHelper =
+  cmJSONObjectHelper<CacheVariable, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE, false)
+    .Bind("type"_s, &CacheVariable::Type, VariableStringHelper, false)
+    .Bind("value"_s, &CacheVariable::Value, VariableValueHelper);
+
+ReadFileResult VariableHelper(cm::optional<CacheVariable>& out,
+                              const Json::Value* value)
+{
+  if (value->isBool()) {
+    out = CacheVariable{
+      /*Type=*/"BOOL",
+      /*Value=*/value->asBool() ? "TRUE" : "FALSE",
+    };
+    return ReadFileResult::READ_OK;
+  }
+  if (value->isString()) {
+    out = CacheVariable{
+      /*Type=*/"",
+      /*Value=*/value->asString(),
+    };
+    return ReadFileResult::READ_OK;
+  }
+  if (value->isObject()) {
+    out.emplace();
+    return VariableObjectHelper(*out, value);
+  }
+  if (value->isNull()) {
+    out = cm::nullopt;
+    return ReadFileResult::READ_OK;
+  }
+  return ReadFileResult::INVALID_VARIABLE;
+}
+
+auto const VariablesHelper =
+  cmJSONMapHelper<cm::optional<CacheVariable>, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, VariableHelper);
+
+auto const PresetStringHelper = cmJSONStringHelper<ReadFileResult>(
+  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
+
+ReadFileResult EnvironmentHelper(cm::optional<std::string>& out,
+                                 const Json::Value* value)
+{
+  if (!value || value->isNull()) {
+    out = cm::nullopt;
+    return ReadFileResult::READ_OK;
+  }
+  if (value->isString()) {
+    out = value->asString();
+    return ReadFileResult::READ_OK;
+  }
+  return ReadFileResult::INVALID_PRESET;
+}
+
+auto const EnvironmentMapHelper =
+  cmJSONMapHelper<cm::optional<std::string>, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
+    EnvironmentHelper);
+
+auto const PresetVectorStringHelper =
+  cmJSONVectorHelper<std::string, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET,
+    PresetStringHelper);
+
+ReadFileResult PresetInheritsHelper(std::vector<std::string>& out,
+                                    const Json::Value* value)
+{
+  out.clear();
+  if (!value) {
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->isString()) {
+    out.push_back(value->asString());
+    return ReadFileResult::READ_OK;
+  }
+
+  return PresetVectorStringHelper(out, value);
+}
+
+auto const PresetBoolHelper = cmJSONBoolHelper<ReadFileResult>(
+  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
+
+auto const PresetOptionalBoolHelper =
+  cmJSONOptionalHelper<bool, ReadFileResult>(ReadFileResult::READ_OK,
+                                             PresetBoolHelper);
+
+auto const PresetIntHelper = cmJSONIntHelper<ReadFileResult>(
+  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET);
+
+auto const PresetOptionalIntHelper = cmJSONOptionalHelper<int, ReadFileResult>(
+  ReadFileResult::READ_OK, PresetIntHelper);
+
+auto const PresetVectorIntHelper = cmJSONVectorHelper<int, ReadFileResult>(
+  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, PresetIntHelper);
+
+auto const PresetWarningsHelper =
+  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+    .Bind("dev"_s, &ConfigurePreset::WarnDev, PresetOptionalBoolHelper, false)
+    .Bind("deprecated"_s, &ConfigurePreset::WarnDeprecated,
+          PresetOptionalBoolHelper, false)
+    .Bind("uninitialized"_s, &ConfigurePreset::WarnUninitialized,
+          PresetOptionalBoolHelper, false)
+    .Bind("unusedCli"_s, &ConfigurePreset::WarnUnusedCli,
+          PresetOptionalBoolHelper, false)
+    .Bind("systemVars"_s, &ConfigurePreset::WarnSystemVars,
+          PresetOptionalBoolHelper, false);
+
+auto const PresetErrorsHelper =
+  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+    .Bind("dev"_s, &ConfigurePreset::ErrorDev, PresetOptionalBoolHelper, false)
+    .Bind("deprecated"_s, &ConfigurePreset::ErrorDeprecated,
+          PresetOptionalBoolHelper, false);
+
+auto const PresetDebugHelper =
+  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+    .Bind("output"_s, &ConfigurePreset::DebugOutput, PresetOptionalBoolHelper,
+          false)
+    .Bind("tryCompile"_s, &ConfigurePreset::DebugTryCompile,
+          PresetOptionalBoolHelper, false)
+    .Bind("find"_s, &ConfigurePreset::DebugFind, PresetOptionalBoolHelper,
+          false);
+
+ReadFileResult ArchToolsetStrategyHelper(
+  cm::optional<ArchToolsetStrategy>& out, const Json::Value* value)
+{
+  if (!value) {
+    out = cm::nullopt;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (!value->isString()) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
+  if (value->asString() == "set") {
+    out = ArchToolsetStrategy::Set;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "external") {
+    out = ArchToolsetStrategy::External;
+    return ReadFileResult::READ_OK;
+  }
+
+  return ReadFileResult::INVALID_PRESET;
+}
+
+std::function<ReadFileResult(ConfigurePreset&, const Json::Value*)>
+ArchToolsetHelper(
+  std::string ConfigurePreset::*valueField,
+  cm::optional<ArchToolsetStrategy> ConfigurePreset::*strategyField)
+{
+  auto const objectHelper =
+    cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+      .Bind("value", valueField, PresetStringHelper, false)
+      .Bind("strategy", strategyField, ArchToolsetStrategyHelper, false);
+  return [valueField, strategyField, objectHelper](
+           ConfigurePreset& out, const Json::Value* value) -> ReadFileResult {
+    if (!value) {
+      (out.*valueField).clear();
+      out.*strategyField = cm::nullopt;
+      return ReadFileResult::READ_OK;
+    }
+
+    if (value->isString()) {
+      out.*valueField = value->asString();
+      out.*strategyField = cm::nullopt;
+      return ReadFileResult::READ_OK;
+    }
+
+    if (value->isObject()) {
+      return objectHelper(out, value);
+    }
+
+    return ReadFileResult::INVALID_PRESET;
+  };
+}
+
+auto const ArchitectureHelper = ArchToolsetHelper(
+  &ConfigurePreset::Architecture, &ConfigurePreset::ArchitectureStrategy);
+auto const ToolsetHelper = ArchToolsetHelper(
+  &ConfigurePreset::Toolset, &ConfigurePreset::ToolsetStrategy);
+
+auto const ConfigurePresetHelper =
+  cmJSONObjectHelper<ConfigurePreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+    .Bind("name"_s, &ConfigurePreset::Name, PresetStringHelper)
+    .Bind("inherits"_s, &ConfigurePreset::Inherits, PresetInheritsHelper,
+          false)
+    .Bind("hidden"_s, &ConfigurePreset::Hidden, PresetBoolHelper, false)
+    .Bind<std::nullptr_t>("vendor"_s, nullptr,
+                          VendorHelper(ReadFileResult::INVALID_PRESET), false)
+    .Bind("displayName"_s, &ConfigurePreset::DisplayName, PresetStringHelper,
+          false)
+    .Bind("description"_s, &ConfigurePreset::Description, PresetStringHelper,
+          false)
+    .Bind("generator"_s, &ConfigurePreset::Generator, PresetStringHelper,
+          false)
+    .Bind("architecture"_s, ArchitectureHelper, false)
+    .Bind("toolset"_s, ToolsetHelper, false)
+    .Bind("binaryDir"_s, &ConfigurePreset::BinaryDir, PresetStringHelper,
+          false)
+    .Bind("installDir"_s, &ConfigurePreset::InstallDir, PresetStringHelper,
+          false)
+    .Bind<std::string>("cmakeExecutable"_s, nullptr, PresetStringHelper, false)
+    .Bind("cacheVariables"_s, &ConfigurePreset::CacheVariables,
+          VariablesHelper, false)
+    .Bind("environment"_s, &ConfigurePreset::Environment, EnvironmentMapHelper,
+          false)
+    .Bind("warnings"_s, PresetWarningsHelper, false)
+    .Bind("errors"_s, PresetErrorsHelper, false)
+    .Bind("debug"_s, PresetDebugHelper, false)
+    .Bind("condition"_s, &ConfigurePreset::ConditionEvaluator,
+          PresetConditionHelper, false);
+
+auto const BuildPresetHelper =
+  cmJSONObjectHelper<BuildPreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+    .Bind("name"_s, &BuildPreset::Name, PresetStringHelper)
+    .Bind("inherits"_s, &BuildPreset::Inherits, PresetInheritsHelper, false)
+    .Bind("hidden"_s, &BuildPreset::Hidden, PresetBoolHelper, false)
+    .Bind<std::nullptr_t>("vendor"_s, nullptr,
+                          VendorHelper(ReadFileResult::INVALID_PRESET), false)
+    .Bind("displayName"_s, &BuildPreset::DisplayName, PresetStringHelper,
+          false)
+    .Bind("description"_s, &BuildPreset::Description, PresetStringHelper,
+          false)
+    .Bind("environment"_s, &BuildPreset::Environment, EnvironmentMapHelper,
+          false)
+    .Bind("configurePreset"_s, &BuildPreset::ConfigurePreset,
+          PresetStringHelper, false)
+    .Bind("inheritConfigureEnvironment"_s,
+          &BuildPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper,
+          false)
+    .Bind("jobs"_s, &BuildPreset::Jobs, PresetOptionalIntHelper, false)
+    .Bind("targets"_s, &BuildPreset::Targets, PresetVectorStringHelper, false)
+    .Bind("configuration"_s, &BuildPreset::Configuration, PresetStringHelper,
+          false)
+    .Bind("cleanFirst"_s, &BuildPreset::CleanFirst, PresetOptionalBoolHelper,
+          false)
+    .Bind("verbose"_s, &BuildPreset::Verbose, PresetOptionalBoolHelper, false)
+    .Bind("nativeToolOptions"_s, &BuildPreset::NativeToolOptions,
+          PresetVectorStringHelper, false)
+    .Bind("condition"_s, &BuildPreset::ConditionEvaluator,
+          PresetConditionHelper, false);
+
+ReadFileResult TestPresetOutputVerbosityHelper(
+  TestPreset::OutputOptions::VerbosityEnum& out, const Json::Value* value)
+{
+  if (!value) {
+    out = TestPreset::OutputOptions::VerbosityEnum::Default;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (!value->isString()) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
+  if (value->asString() == "default") {
+    out = TestPreset::OutputOptions::VerbosityEnum::Default;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "verbose") {
+    out = TestPreset::OutputOptions::VerbosityEnum::Verbose;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "extra") {
+    out = TestPreset::OutputOptions::VerbosityEnum::Extra;
+    return ReadFileResult::READ_OK;
+  }
+
+  return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalOutputVerbosityHelper =
+  cmJSONOptionalHelper<TestPreset::OutputOptions::VerbosityEnum,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       TestPresetOutputVerbosityHelper);
+
+auto const TestPresetOptionalOutputHelper =
+  cmJSONOptionalHelper<TestPreset::OutputOptions, ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::OutputOptions, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+      .Bind("shortProgress"_s, &TestPreset::OutputOptions::ShortProgress,
+            PresetOptionalBoolHelper, false)
+      .Bind("verbosity"_s, &TestPreset::OutputOptions::Verbosity,
+            TestPresetOptionalOutputVerbosityHelper, false)
+      .Bind("debug"_s, &TestPreset::OutputOptions::Debug,
+            PresetOptionalBoolHelper, false)
+      .Bind("outputOnFailure"_s, &TestPreset::OutputOptions::OutputOnFailure,
+            PresetOptionalBoolHelper, false)
+      .Bind("quiet"_s, &TestPreset::OutputOptions::Quiet,
+            PresetOptionalBoolHelper, false)
+      .Bind("outputLogFile"_s, &TestPreset::OutputOptions::OutputLogFile,
+            PresetStringHelper, false)
+      .Bind("labelSummary"_s, &TestPreset::OutputOptions::LabelSummary,
+            PresetOptionalBoolHelper, false)
+      .Bind("subprojectSummary"_s,
+            &TestPreset::OutputOptions::SubprojectSummary,
+            PresetOptionalBoolHelper, false)
+      .Bind("maxPassedTestOutputSize"_s,
+            &TestPreset::OutputOptions::MaxPassedTestOutputSize,
+            PresetOptionalIntHelper, false)
+      .Bind("maxFailedTestOutputSize"_s,
+            &TestPreset::OutputOptions::MaxFailedTestOutputSize,
+            PresetOptionalIntHelper, false)
+      .Bind("maxTestNameWidth"_s, &TestPreset::OutputOptions::MaxTestNameWidth,
+            PresetOptionalIntHelper, false));
+
+auto const TestPresetOptionalFilterIncludeIndexObjectHelper =
+  cmJSONOptionalHelper<TestPreset::IncludeOptions::IndexOptions,
+                       ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::IncludeOptions::IndexOptions,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       ReadFileResult::INVALID_PRESET)
+      .Bind("start"_s, &TestPreset::IncludeOptions::IndexOptions::Start,
+            PresetOptionalIntHelper, false)
+      .Bind("end"_s, &TestPreset::IncludeOptions::IndexOptions::End,
+            PresetOptionalIntHelper, false)
+      .Bind("stride"_s, &TestPreset::IncludeOptions::IndexOptions::Stride,
+            PresetOptionalIntHelper, false)
+      .Bind("specificTests"_s,
+            &TestPreset::IncludeOptions::IndexOptions::SpecificTests,
+            PresetVectorIntHelper, false));
+
+ReadFileResult TestPresetOptionalFilterIncludeIndexHelper(
+  cm::optional<TestPreset::IncludeOptions::IndexOptions>& out,
+  const Json::Value* value)
+{
+  if (!value) {
+    out = cm::nullopt;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->isString()) {
+    out.emplace();
+    out->IndexFile = value->asString();
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->isObject()) {
+    return TestPresetOptionalFilterIncludeIndexObjectHelper(out, value);
+  }
+
+  return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalFilterIncludeHelper =
+  cmJSONOptionalHelper<TestPreset::IncludeOptions, ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::IncludeOptions, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
+      .Bind("name"_s, &TestPreset::IncludeOptions::Name, PresetStringHelper,
+            false)
+      .Bind("label"_s, &TestPreset::IncludeOptions::Label, PresetStringHelper,
+            false)
+      .Bind("index"_s, &TestPreset::IncludeOptions::Index,
+            TestPresetOptionalFilterIncludeIndexHelper, false)
+      .Bind("useUnion"_s, &TestPreset::IncludeOptions::UseUnion,
+            PresetOptionalBoolHelper, false));
+
+auto const TestPresetOptionalFilterExcludeFixturesHelper =
+  cmJSONOptionalHelper<TestPreset::ExcludeOptions::FixturesOptions,
+                       ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::ExcludeOptions::FixturesOptions,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       ReadFileResult::INVALID_PRESET)
+      .Bind("any"_s, &TestPreset::ExcludeOptions::FixturesOptions::Any,
+            PresetStringHelper, false)
+      .Bind("setup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Setup,
+            PresetStringHelper, false)
+      .Bind("cleanup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Cleanup,
+            PresetStringHelper, false));
+
+auto const TestPresetOptionalFilterExcludeHelper =
+  cmJSONOptionalHelper<TestPreset::ExcludeOptions, ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::ExcludeOptions, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
+      .Bind("name"_s, &TestPreset::ExcludeOptions::Name, PresetStringHelper,
+            false)
+      .Bind("label"_s, &TestPreset::ExcludeOptions::Label, PresetStringHelper,
+            false)
+      .Bind("fixtures"_s, &TestPreset::ExcludeOptions::Fixtures,
+            TestPresetOptionalFilterExcludeFixturesHelper, false));
+
+ReadFileResult TestPresetExecutionShowOnlyHelper(
+  TestPreset::ExecutionOptions::ShowOnlyEnum& out, const Json::Value* value)
+{
+  if (!value || !value->isString()) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
+  if (value->asString() == "human") {
+    out = TestPreset::ExecutionOptions::ShowOnlyEnum::Human;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "json-v1") {
+    out = TestPreset::ExecutionOptions::ShowOnlyEnum::JsonV1;
+    return ReadFileResult::READ_OK;
+  }
+
+  return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalExecutionShowOnlyHelper =
+  cmJSONOptionalHelper<TestPreset::ExecutionOptions::ShowOnlyEnum,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       TestPresetExecutionShowOnlyHelper);
+
+ReadFileResult TestPresetExecutionModeHelper(
+  TestPreset::ExecutionOptions::RepeatOptions::ModeEnum& out,
+  const Json::Value* value)
+{
+  if (!value) {
+    return ReadFileResult::READ_OK;
+  }
+
+  if (!value->isString()) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
+  if (value->asString() == "until-fail") {
+    out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilFail;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "until-pass") {
+    out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilPass;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "after-timeout") {
+    out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::AfterTimeout;
+    return ReadFileResult::READ_OK;
+  }
+
+  return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalExecutionRepeatHelper =
+  cmJSONOptionalHelper<TestPreset::ExecutionOptions::RepeatOptions,
+                       ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::ExecutionOptions::RepeatOptions,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       ReadFileResult::INVALID_PRESET)
+      .Bind("mode"_s, &TestPreset::ExecutionOptions::RepeatOptions::Mode,
+            TestPresetExecutionModeHelper, true)
+      .Bind("count"_s, &TestPreset::ExecutionOptions::RepeatOptions::Count,
+            PresetIntHelper, true));
+
+ReadFileResult TestPresetExecutionNoTestsActionHelper(
+  TestPreset::ExecutionOptions::NoTestsActionEnum& out,
+  const Json::Value* value)
+{
+  if (!value) {
+    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (!value->isString()) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
+  if (value->asString() == "default") {
+    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "error") {
+    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Error;
+    return ReadFileResult::READ_OK;
+  }
+
+  if (value->asString() == "ignore") {
+    out = TestPreset::ExecutionOptions::NoTestsActionEnum::Ignore;
+    return ReadFileResult::READ_OK;
+  }
+
+  return ReadFileResult::INVALID_PRESET;
+}
+
+auto const TestPresetOptionalExecutionNoTestsActionHelper =
+  cmJSONOptionalHelper<TestPreset::ExecutionOptions::NoTestsActionEnum,
+                       ReadFileResult>(ReadFileResult::READ_OK,
+                                       TestPresetExecutionNoTestsActionHelper);
+
+auto const TestPresetExecutionHelper =
+  cmJSONOptionalHelper<TestPreset::ExecutionOptions, ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::ExecutionOptions, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
+      .Bind("stopOnFailure"_s, &TestPreset::ExecutionOptions::StopOnFailure,
+            PresetOptionalBoolHelper, false)
+      .Bind("enableFailover"_s, &TestPreset::ExecutionOptions::EnableFailover,
+            PresetOptionalBoolHelper, false)
+      .Bind("jobs"_s, &TestPreset::ExecutionOptions::Jobs,
+            PresetOptionalIntHelper, false)
+      .Bind("resourceSpecFile"_s,
+            &TestPreset::ExecutionOptions::ResourceSpecFile,
+            PresetStringHelper, false)
+      .Bind("testLoad"_s, &TestPreset::ExecutionOptions::TestLoad,
+            PresetOptionalIntHelper, false)
+      .Bind("showOnly"_s, &TestPreset::ExecutionOptions::ShowOnly,
+            TestPresetOptionalExecutionShowOnlyHelper, false)
+      .Bind("repeat"_s, &TestPreset::ExecutionOptions::Repeat,
+            TestPresetOptionalExecutionRepeatHelper, false)
+      .Bind("interactiveDebugging"_s,
+            &TestPreset::ExecutionOptions::InteractiveDebugging,
+            PresetOptionalBoolHelper, false)
+      .Bind("scheduleRandom"_s, &TestPreset::ExecutionOptions::ScheduleRandom,
+            PresetOptionalBoolHelper, false)
+      .Bind("timeout"_s, &TestPreset::ExecutionOptions::Timeout,
+            PresetOptionalIntHelper, false)
+      .Bind("noTestsAction"_s, &TestPreset::ExecutionOptions::NoTestsAction,
+            TestPresetOptionalExecutionNoTestsActionHelper, false));
+
+auto const TestPresetFilterHelper =
+  cmJSONOptionalHelper<TestPreset::FilterOptions, ReadFileResult>(
+    ReadFileResult::READ_OK,
+    cmJSONObjectHelper<TestPreset::FilterOptions, ReadFileResult>(
+      ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET)
+      .Bind("include"_s, &TestPreset::FilterOptions::Include,
+            TestPresetOptionalFilterIncludeHelper, false)
+      .Bind("exclude"_s, &TestPreset::FilterOptions::Exclude,
+            TestPresetOptionalFilterExcludeHelper, false));
+
+auto const TestPresetHelper =
+  cmJSONObjectHelper<TestPreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false)
+    .Bind("name"_s, &TestPreset::Name, PresetStringHelper)
+    .Bind("inherits"_s, &TestPreset::Inherits, PresetInheritsHelper, false)
+    .Bind("hidden"_s, &TestPreset::Hidden, PresetBoolHelper, false)
+    .Bind<std::nullptr_t>("vendor"_s, nullptr,
+                          VendorHelper(ReadFileResult::INVALID_PRESET), false)
+    .Bind("displayName"_s, &TestPreset::DisplayName, PresetStringHelper, false)
+    .Bind("description"_s, &TestPreset::Description, PresetStringHelper, false)
+    .Bind("environment"_s, &TestPreset::Environment, EnvironmentMapHelper,
+          false)
+    .Bind("configurePreset"_s, &TestPreset::ConfigurePreset,
+          PresetStringHelper, false)
+    .Bind("inheritConfigureEnvironment"_s,
+          &TestPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper,
+          false)
+    .Bind("configuration"_s, &TestPreset::Configuration, PresetStringHelper,
+          false)
+    .Bind("overwriteConfigurationFile"_s,
+          &TestPreset::OverwriteConfigurationFile, PresetVectorStringHelper,
+          false)
+    .Bind("output"_s, &TestPreset::Output, TestPresetOptionalOutputHelper,
+          false)
+    .Bind("filter"_s, &TestPreset::Filter, TestPresetFilterHelper, false)
+    .Bind("execution"_s, &TestPreset::Execution, TestPresetExecutionHelper,
+          false)
+    .Bind("condition"_s, &TestPreset::ConditionEvaluator,
+          PresetConditionHelper, false);
+
+auto const ConfigurePresetsHelper =
+  cmJSONVectorHelper<ConfigurePreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
+    ConfigurePresetHelper);
+
+auto const BuildPresetsHelper =
+  cmJSONVectorHelper<BuildPreset, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS,
+    BuildPresetHelper);
+
+auto const TestPresetsHelper = cmJSONVectorHelper<TestPreset, ReadFileResult>(
+  ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, TestPresetHelper);
+
+auto const CMakeVersionUIntHelper = cmJSONUIntHelper<ReadFileResult>(
+  ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION);
+
+auto const CMakeVersionHelper =
+  cmJSONObjectHelper<CMakeVersion, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_CMAKE_VERSION, false)
+    .Bind("major"_s, &CMakeVersion::Major, CMakeVersionUIntHelper, false)
+    .Bind("minor"_s, &CMakeVersion::Minor, CMakeVersionUIntHelper, false)
+    .Bind("patch"_s, &CMakeVersion::Patch, CMakeVersionUIntHelper, false);
+
+auto const RootPresetsHelper =
+  cmJSONObjectHelper<RootPresets, ReadFileResult>(
+    ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false)
+    .Bind<int>("version"_s, nullptr, VersionHelper)
+    .Bind("configurePresets"_s, &RootPresets::ConfigurePresets,
+          ConfigurePresetsHelper, false)
+    .Bind("buildPresets"_s, &RootPresets::BuildPresets, BuildPresetsHelper,
+          false)
+    .Bind("testPresets"_s, &RootPresets::TestPresets, TestPresetsHelper, false)
+    .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired,
+          CMakeVersionHelper, false)
+    .Bind<std::nullptr_t>("vendor"_s, nullptr,
+                          VendorHelper(ReadFileResult::INVALID_ROOT), false);
+}
+
+cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadJSONFile(
+  const std::string& filename, bool user)
+{
+  cmsys::ifstream fin(filename.c_str());
+  if (!fin) {
+    return ReadFileResult::FILE_NOT_FOUND;
+  }
+  // If there's a BOM, toss it.
+  cmsys::FStream::ReadBOM(fin);
+
+  Json::Value root;
+  Json::CharReaderBuilder builder;
+  Json::CharReaderBuilder::strictMode(&builder.settings_);
+  if (!Json::parseFromStream(builder, fin, &root, nullptr)) {
+    return ReadFileResult::JSON_PARSE_ERROR;
+  }
+
+  int v = 0;
+  auto result = RootVersionHelper(v, &root);
+  if (result != ReadFileResult::READ_OK) {
+    return result;
+  }
+  if (v < MIN_VERSION || v > MAX_VERSION) {
+    return ReadFileResult::UNRECOGNIZED_VERSION;
+  }
+  if (user) {
+    this->UserVersion = v;
+  } else {
+    this->Version = v;
+  }
+
+  // Support for build and test presets added in version 2.
+  if (v < 2 &&
+      (root.isMember("buildPresets") || root.isMember("testPresets"))) {
+    return ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED;
+  }
+
+  RootPresets presets;
+  if ((result = RootPresetsHelper(presets, &root)) !=
+      ReadFileResult::READ_OK) {
+    return result;
+  }
+
+  unsigned int currentMajor = cmVersion::GetMajorVersion();
+  unsigned int currentMinor = cmVersion::GetMinorVersion();
+  unsigned int currentPatch = cmVersion::GetPatchVersion();
+  auto const& required = presets.CMakeMinimumRequired;
+  if (required.Major > currentMajor ||
+      (required.Major == currentMajor &&
+       (required.Minor > currentMinor ||
+        (required.Minor == currentMinor &&
+         (required.Patch > currentPatch))))) {
+    return ReadFileResult::UNRECOGNIZED_CMAKE_VERSION;
+  }
+
+  for (auto& preset : presets.ConfigurePresets) {
+    preset.User = user;
+    if (preset.Name.empty()) {
+      return ReadFileResult::INVALID_PRESET;
+    }
+
+    PresetPair<ConfigurePreset> presetPair;
+    presetPair.Unexpanded = preset;
+    presetPair.Expanded = cm::nullopt;
+    if (!this->ConfigurePresets
+           .emplace(std::make_pair(preset.Name, presetPair))
+           .second) {
+      return ReadFileResult::DUPLICATE_PRESETS;
+    }
+
+    // Support for installDir presets added in version 3.
+    if (v < 3 && !preset.InstallDir.empty()) {
+      return ReadFileResult::INSTALL_PREFIX_UNSUPPORTED;
+    }
+
+    // Support for conditions added in version 3.
+    if (v < 3 && preset.ConditionEvaluator) {
+      return ReadFileResult::CONDITION_UNSUPPORTED;
+    }
+
+    this->ConfigurePresetOrder.push_back(preset.Name);
+  }
+
+  for (auto& preset : presets.BuildPresets) {
+    preset.User = user;
+    if (preset.Name.empty()) {
+      return ReadFileResult::INVALID_PRESET;
+    }
+
+    PresetPair<BuildPreset> presetPair;
+    presetPair.Unexpanded = preset;
+    presetPair.Expanded = cm::nullopt;
+    if (!this->BuildPresets.emplace(preset.Name, presetPair).second) {
+      return ReadFileResult::DUPLICATE_PRESETS;
+    }
+
+    // Support for conditions added in version 3.
+    if (v < 3 && preset.ConditionEvaluator) {
+      return ReadFileResult::CONDITION_UNSUPPORTED;
+    }
+
+    this->BuildPresetOrder.push_back(preset.Name);
+  }
+
+  for (auto& preset : presets.TestPresets) {
+    preset.User = user;
+    if (preset.Name.empty()) {
+      return ReadFileResult::INVALID_PRESET;
+    }
+
+    PresetPair<TestPreset> presetPair;
+    presetPair.Unexpanded = preset;
+    presetPair.Expanded = cm::nullopt;
+    if (!this->TestPresets.emplace(preset.Name, presetPair).second) {
+      return ReadFileResult::DUPLICATE_PRESETS;
+    }
+
+    // Support for conditions added in version 3.
+    if (v < 3 && preset.ConditionEvaluator) {
+      return ReadFileResult::CONDITION_UNSUPPORTED;
+    }
+
+    this->TestPresetOrder.push_back(preset.Name);
+  }
+
+  return ReadFileResult::READ_OK;
+}
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index 620ba19..643b43f 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -4,7 +4,6 @@
 
 #include <algorithm>
 #include <cctype>
-#include <cerrno>
 #include <chrono>
 #include <cstdio>
 #include <cstdlib>
@@ -2108,17 +2107,17 @@
   } else if (this->CheckArgument(arg, "-L"_s, "--label-regex") &&
              i < args.size() - 1) {
     i++;
-    this->GetTestHandler()->SetPersistentOption("LabelRegularExpression",
-                                                args[i].c_str());
-    this->GetMemCheckHandler()->SetPersistentOption("LabelRegularExpression",
-                                                    args[i].c_str());
+    this->GetTestHandler()->AddPersistentMultiOption("LabelRegularExpression",
+                                                     args[i]);
+    this->GetMemCheckHandler()->AddPersistentMultiOption(
+      "LabelRegularExpression", args[i]);
   } else if (this->CheckArgument(arg, "-LE"_s, "--label-exclude") &&
              i < args.size() - 1) {
     i++;
-    this->GetTestHandler()->SetPersistentOption(
-      "ExcludeLabelRegularExpression", args[i].c_str());
-    this->GetMemCheckHandler()->SetPersistentOption(
-      "ExcludeLabelRegularExpression", args[i].c_str());
+    this->GetTestHandler()->AddPersistentMultiOption(
+      "ExcludeLabelRegularExpression", args[i]);
+    this->GetMemCheckHandler()->AddPersistentMultiOption(
+      "ExcludeLabelRegularExpression", args[i]);
   }
 
   else if (this->CheckArgument(arg, "-E"_s, "--exclude-regex") &&
@@ -2221,7 +2220,7 @@
     cmCTestScriptHandler* ch = this->GetScriptHandler();
     // -SR is an internal argument, -SP should be ignored when it is passed
     if (!SRArgumentSpecified) {
-      ch->AddConfigurationScript(args[i].c_str(), false);
+      ch->AddConfigurationScript(args[i], false);
     }
   }
 
@@ -2231,7 +2230,7 @@
     this->Impl->RunConfigurationScript = true;
     i++;
     cmCTestScriptHandler* ch = this->GetScriptHandler();
-    ch->AddConfigurationScript(args[i].c_str(), true);
+    ch->AddConfigurationScript(args[i], true);
   }
 
   if (this->CheckArgument(arg, "-S"_s, "--script") && i < args.size() - 1) {
@@ -2240,7 +2239,7 @@
     cmCTestScriptHandler* ch = this->GetScriptHandler();
     // -SR is an internal argument, -S should be ignored when it is passed
     if (!SRArgumentSpecified) {
-      ch->AddConfigurationScript(args[i].c_str(), true);
+      ch->AddConfigurationScript(args[i], true);
     }
   }
 }
@@ -2268,6 +2267,15 @@
   }
 }
 
+void cmCTest::AddPersistentMultiOptionIfNotEmpty(const std::string& value,
+                                                 const std::string& optionName)
+{
+  if (!value.empty()) {
+    this->GetTestHandler()->AddPersistentMultiOption(optionName, value);
+    this->GetMemCheckHandler()->AddPersistentMultiOption(optionName, value);
+  }
+}
+
 bool cmCTest::SetArgsFromPreset(const std::string& presetName,
                                 bool listPresets)
 {
@@ -2310,6 +2318,13 @@
     return false;
   }
 
+  if (!expandedPreset->ConditionResult) {
+    cmSystemTools::Error(cmStrCat("Cannot use disabled test preset in ",
+                                  workingDirectory, ": \"", presetName, '"'));
+    settingsFile.PrintTestPresetList();
+    return false;
+  }
+
   auto configurePresetPair =
     settingsFile.ConfigurePresets.find(expandedPreset->ConfigurePreset);
   if (configurePresetPair == settingsFile.ConfigurePresets.end()) {
@@ -2412,7 +2427,7 @@
     if (expandedPreset->Filter->Include) {
       this->SetPersistentOptionIfNotEmpty(
         expandedPreset->Filter->Include->Name, "IncludeRegularExpression");
-      this->SetPersistentOptionIfNotEmpty(
+      this->AddPersistentMultiOptionIfNotEmpty(
         expandedPreset->Filter->Include->Label, "LabelRegularExpression");
 
       if (expandedPreset->Filter->Include->Index) {
@@ -2445,7 +2460,7 @@
     if (expandedPreset->Filter->Exclude) {
       this->SetPersistentOptionIfNotEmpty(
         expandedPreset->Filter->Exclude->Name, "ExcludeRegularExpression");
-      this->SetPersistentOptionIfNotEmpty(
+      this->AddPersistentMultiOptionIfNotEmpty(
         expandedPreset->Filter->Exclude->Label,
         "ExcludeLabelRegularExpression");
 
@@ -2826,9 +2841,10 @@
       cmCTestLog(this, OUTPUT,
                  "Internal ctest changing into directory: " << workDir
                                                             << std::endl);
-      if (cmSystemTools::ChangeDirectory(workDir) != 0) {
+      cmsys::Status status = cmSystemTools::ChangeDirectory(workDir);
+      if (!status) {
         auto msg = "Failed to change working directory to \"" + workDir +
-          "\" : " + std::strerror(errno) + "\n";
+          "\" : " + status.GetString() + "\n";
         cmCTestLog(this, ERROR_MESSAGE, msg);
         return 1;
       }
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
index 4669a1c..392eb1c 100644
--- a/Source/cmCTest.h
+++ b/Source/cmCTest.h
@@ -463,6 +463,8 @@
 private:
   void SetPersistentOptionIfNotEmpty(const std::string& value,
                                      const std::string& optionName);
+  void AddPersistentMultiOptionIfNotEmpty(const std::string& value,
+                                          const std::string& optionName);
 
   int GenerateNotesFile(const std::string& files);
 
diff --git a/Source/cmCommandLineArgument.h b/Source/cmCommandLineArgument.h
index 495dc69..b14cfc2 100644
--- a/Source/cmCommandLineArgument.h
+++ b/Source/cmCommandLineArgument.h
@@ -112,6 +112,10 @@
           }
         }
         if (parseState == ParseMode::Valid) {
+          if (possible_value[0] == ' ') {
+            possible_value.remove_prefix(1);
+          }
+
           parseState = this->StoreCall(std::string(possible_value),
                                        std::forward<CallState>(state)...)
             ? ParseMode::Valid
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index 6225a4a..5473316 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -701,6 +701,10 @@
 
       this->AddTargetItem(lib, tgt);
       this->AddLibraryRuntimeInfo(lib.Value, tgt);
+      if (tgt && tgt->GetType() == cmStateEnums::SHARED_LIBRARY &&
+          this->Target->IsDLLPlatform()) {
+        this->AddRuntimeDLL(tgt);
+      }
     }
   } else {
     // This is not a CMake target.  Use the name given.
@@ -728,6 +732,13 @@
 void cmComputeLinkInformation::AddSharedDepItem(BT<std::string> const& item,
                                                 const cmGeneratorTarget* tgt)
 {
+  // Record dependencies on DLLs.
+  if (tgt && tgt->GetType() == cmStateEnums::SHARED_LIBRARY &&
+      this->Target->IsDLLPlatform() &&
+      this->SharedDependencyMode != SharedDepModeLink) {
+    this->AddRuntimeDLL(tgt);
+  }
+
   // If dropping shared library dependencies, ignore them.
   if (this->SharedDependencyMode == SharedDepModeNone) {
     return;
@@ -799,6 +810,14 @@
   }
 }
 
+void cmComputeLinkInformation::AddRuntimeDLL(cmGeneratorTarget const* tgt)
+{
+  if (std::find(this->RuntimeDLLs.begin(), this->RuntimeDLLs.end(), tgt) ==
+      this->RuntimeDLLs.end()) {
+    this->RuntimeDLLs.emplace_back(tgt);
+  }
+}
+
 void cmComputeLinkInformation::ComputeLinkTypeInfo()
 {
   // Check whether archives may actually be shared libraries.
diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h
index 9fec702..4acb99f 100644
--- a/Source/cmComputeLinkInformation.h
+++ b/Source/cmComputeLinkInformation.h
@@ -64,6 +64,10 @@
   std::string GetRPathString(bool for_install) const;
   std::string GetChrpathString() const;
   std::set<cmGeneratorTarget const*> const& GetSharedLibrariesLinked() const;
+  std::vector<cmGeneratorTarget const*> const& GetRuntimeDLLs() const
+  {
+    return this->RuntimeDLLs;
+  }
 
   std::string const& GetLibLinkFileFlag() const
   {
@@ -81,6 +85,7 @@
   void AddItem(BT<std::string> const& item, const cmGeneratorTarget* tgt);
   void AddSharedDepItem(BT<std::string> const& item,
                         cmGeneratorTarget const* tgt);
+  void AddRuntimeDLL(cmGeneratorTarget const* tgt);
 
   // Output information.
   ItemVector Items;
@@ -89,6 +94,7 @@
   std::vector<std::string> FrameworkPaths;
   std::vector<std::string> RuntimeSearchPath;
   std::set<cmGeneratorTarget const*> SharedLibrariesLinked;
+  std::vector<cmGeneratorTarget const*> RuntimeDLLs;
 
   // Context information.
   cmGeneratorTarget const* const Target;
diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx
index 62bc526..f99592c 100644
--- a/Source/cmConditionEvaluator.cxx
+++ b/Source/cmConditionEvaluator.cxx
@@ -654,10 +654,10 @@
       if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
           this->IsKeyword(keyIS_NEWER_THAN, *argP1)) {
         int fileIsNewer = 0;
-        bool success = cmSystemTools::FileTimeCompare(
+        cmsys::Status ftcStatus = cmSystemTools::FileTimeCompare(
           arg->GetValue(), (argP2)->GetValue(), &fileIsNewer);
         this->HandleBinaryOp(
-          (!success || fileIsNewer == 1 || fileIsNewer == 0), reducible, arg,
+          (!ftcStatus || fileIsNewer == 1 || fileIsNewer == 0), reducible, arg,
           newArgs, argP1, argP2);
       }
 
diff --git a/Source/cmCreateTestSourceList.cxx b/Source/cmCreateTestSourceList.cxx
index 3001ae0..a2fac73 100644
--- a/Source/cmCreateTestSourceList.cxx
+++ b/Source/cmCreateTestSourceList.cxx
@@ -90,10 +90,15 @@
     std::replace(func_name.begin(), func_name.end(), ' ', '_');
     std::replace(func_name.begin(), func_name.end(), '/', '_');
     std::replace(func_name.begin(), func_name.end(), ':', '_');
+    bool already_declared =
+      std::find(tests_func_name.begin(), tests_func_name.end(), func_name) !=
+      tests_func_name.end();
     tests_func_name.push_back(func_name);
-    forwardDeclareCode += "int ";
-    forwardDeclareCode += func_name;
-    forwardDeclareCode += "(int, char*[]);\n";
+    if (!already_declared) {
+      forwardDeclareCode += "int ";
+      forwardDeclareCode += func_name;
+      forwardDeclareCode += "(int, char*[]);\n";
+    }
   }
 
   std::string functionMapCode;
diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx
index 4329caf..4705443 100644
--- a/Source/cmCustomCommandGenerator.cxx
+++ b/Source/cmCustomCommandGenerator.cxx
@@ -139,6 +139,14 @@
   }
   return outputs;
 }
+
+std::string EvaluateDepfile(std::string const& path,
+                            cmGeneratorExpression const& ge,
+                            cmLocalGenerator* lg, std::string const& config)
+{
+  std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(path);
+  return cge->Evaluate(lg, config);
+}
 }
 
 cmCustomCommandGenerator::cmCustomCommandGenerator(
@@ -381,9 +389,20 @@
   }
 }
 
+std::string cmCustomCommandGenerator::GetDepfile() const
+{
+  const auto& depfile = this->CC->GetDepfile();
+  if (depfile.empty()) {
+    return "";
+  }
+
+  cmGeneratorExpression ge(this->CC->GetBacktrace());
+  return EvaluateDepfile(depfile, ge, this->LG, this->OutputConfig);
+}
+
 std::string cmCustomCommandGenerator::GetFullDepfile() const
 {
-  std::string depfile = this->CC->GetDepfile();
+  std::string depfile = this->GetDepfile();
   if (depfile.empty()) {
     return "";
   }
diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h
index 4be5b3f..53e5573 100644
--- a/Source/cmCustomCommandGenerator.h
+++ b/Source/cmCustomCommandGenerator.h
@@ -57,6 +57,7 @@
   std::vector<std::string> const& GetDepends() const;
   std::set<BT<std::pair<std::string, bool>>> const& GetUtilities() const;
   bool HasOnlyEmptyCommandLines() const;
+  std::string GetDepfile() const;
   std::string GetFullDepfile() const;
   std::string GetInternalDepfile() const;
 
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 7015a01..0409f97 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -924,13 +924,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.18 (this upper limit may be reviewed
+  // policy settings for up to CMake 3.19 (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.6...3.18)\n";
+     << "cmake_policy(VERSION 2.6...3.19)\n";
   /* clang-format on */
 }
 
diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx
index a92f6e3..52965bb 100644
--- a/Source/cmExtraSublimeTextGenerator.cxx
+++ b/Source/cmExtraSublimeTextGenerator.cxx
@@ -435,7 +435,8 @@
   lg->GetIncludeDirectories(includes, target, language, config);
 
   std::string includesString =
-    lg->GetIncludeFlags(includes, target, language, true, false, config);
+    lg->GetIncludeFlags(includes, target, language, config, false,
+                        cmLocalGenerator::IncludePathStyle::Absolute);
 
   return includesString;
 }
diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx
index d2a9bec..d529f52 100644
--- a/Source/cmFileAPI.cxx
+++ b/Source/cmFileAPI.cxx
@@ -686,7 +686,7 @@
 
 // The "codemodel" object kind.
 
-static unsigned int const CodeModelV2Minor = 2;
+static unsigned int const CodeModelV2Minor = 3;
 
 void cmFileAPI::BuildClientRequestCodeModel(
   ClientRequest& r, std::vector<RequestVersion> const& versions)
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index 9061109..6b8757c 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -20,11 +20,16 @@
 #include <cm3p/json/value.h>
 
 #include "cmCryptoHash.h"
+#include "cmExportSet.h"
 #include "cmFileAPI.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmInstallDirectoryGenerator.h"
+#include "cmInstallExportGenerator.h"
+#include "cmInstallFilesGenerator.h"
 #include "cmInstallGenerator.h"
+#include "cmInstallScriptGenerator.h"
 #include "cmInstallSubdirectoryGenerator.h"
 #include "cmInstallTargetGenerator.h"
 #include "cmLinkLineComputer.h"
@@ -42,81 +47,13 @@
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmTargetDepend.h"
+#include "cmTargetExport.h"
 #include "cmake.h"
 
 namespace {
 
-class Codemodel
-{
-  cmFileAPI& FileAPI;
-  unsigned long Version;
-
-  Json::Value DumpPaths();
-  Json::Value DumpConfigurations();
-  Json::Value DumpConfiguration(std::string const& config);
-
-public:
-  Codemodel(cmFileAPI& fileAPI, unsigned long version);
-  Json::Value Dump();
-};
-
-class CodemodelConfig
-{
-  cmFileAPI& FileAPI;
-  unsigned long Version;
-  std::string const& Config;
-  std::string TopSource;
-  std::string TopBuild;
-
-  struct Directory
-  {
-    cmStateSnapshot Snapshot;
-    cmLocalGenerator const* LocalGenerator = nullptr;
-    Json::Value TargetIndexes = Json::arrayValue;
-    Json::ArrayIndex ProjectIndex;
-    bool HasInstallRule = false;
-  };
-  std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
-    DirectoryMap;
-  std::vector<Directory> Directories;
-
-  struct Project
-  {
-    cmStateSnapshot Snapshot;
-    static const Json::ArrayIndex NoParentIndex =
-      static_cast<Json::ArrayIndex>(-1);
-    Json::ArrayIndex ParentIndex = NoParentIndex;
-    Json::Value ChildIndexes = Json::arrayValue;
-    Json::Value DirectoryIndexes = Json::arrayValue;
-    Json::Value TargetIndexes = Json::arrayValue;
-  };
-  std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
-    ProjectMap;
-  std::vector<Project> Projects;
-
-  void ProcessDirectories();
-
-  Json::ArrayIndex GetDirectoryIndex(cmLocalGenerator const* lg);
-  Json::ArrayIndex GetDirectoryIndex(cmStateSnapshot s);
-
-  Json::ArrayIndex AddProject(cmStateSnapshot s);
-
-  Json::Value DumpTargets();
-  Json::Value DumpTarget(cmGeneratorTarget* gt, Json::ArrayIndex ti);
-
-  Json::Value DumpDirectories();
-  Json::Value DumpDirectory(Directory& d);
-
-  Json::Value DumpProjects();
-  Json::Value DumpProject(Project& p);
-
-  Json::Value DumpMinimumCMakeVersion(cmStateSnapshot s);
-
-public:
-  CodemodelConfig(cmFileAPI& fileAPI, unsigned long version,
-                  std::string const& config);
-  Json::Value Dump();
-};
+using TargetIndexMapType =
+  std::unordered_map<cmGeneratorTarget const*, Json::ArrayIndex>;
 
 std::string RelativeIfUnder(std::string const& top, std::string const& in)
 {
@@ -131,16 +68,6 @@
   return out;
 }
 
-std::string TargetId(cmGeneratorTarget const* gt, std::string const& topBuild)
-{
-  cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_256);
-  std::string path = RelativeIfUnder(
-    topBuild, gt->GetLocalGenerator()->GetCurrentBinaryDirectory());
-  std::string hash = hasher.HashString(path);
-  hash.resize(20, '0');
-  return gt->GetName() + CMAKE_DIRECTORY_ID_SEP + hash;
-}
-
 class JBTIndex
 {
 public:
@@ -290,6 +217,91 @@
   return backtraceGraph;
 }
 
+class Codemodel
+{
+  cmFileAPI& FileAPI;
+  unsigned long Version;
+
+  Json::Value DumpPaths();
+  Json::Value DumpConfigurations();
+  Json::Value DumpConfiguration(std::string const& config);
+
+public:
+  Codemodel(cmFileAPI& fileAPI, unsigned long version);
+  Json::Value Dump();
+};
+
+class CodemodelConfig
+{
+  cmFileAPI& FileAPI;
+  unsigned long Version;
+  std::string const& Config;
+  std::string TopSource;
+  std::string TopBuild;
+
+  struct Directory
+  {
+    cmStateSnapshot Snapshot;
+    cmLocalGenerator const* LocalGenerator = nullptr;
+    Json::Value TargetIndexes = Json::arrayValue;
+    Json::ArrayIndex ProjectIndex;
+    bool HasInstallRule = false;
+  };
+  std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
+    DirectoryMap;
+  std::vector<Directory> Directories;
+
+  struct Project
+  {
+    cmStateSnapshot Snapshot;
+    static const Json::ArrayIndex NoParentIndex =
+      static_cast<Json::ArrayIndex>(-1);
+    Json::ArrayIndex ParentIndex = NoParentIndex;
+    Json::Value ChildIndexes = Json::arrayValue;
+    Json::Value DirectoryIndexes = Json::arrayValue;
+    Json::Value TargetIndexes = Json::arrayValue;
+  };
+  std::map<cmStateSnapshot, Json::ArrayIndex, cmStateSnapshot::StrictWeakOrder>
+    ProjectMap;
+  std::vector<Project> Projects;
+
+  TargetIndexMapType TargetIndexMap;
+
+  void ProcessDirectories();
+
+  Json::ArrayIndex GetDirectoryIndex(cmLocalGenerator const* lg);
+  Json::ArrayIndex GetDirectoryIndex(cmStateSnapshot s);
+
+  Json::ArrayIndex AddProject(cmStateSnapshot s);
+
+  Json::Value DumpTargets();
+  Json::Value DumpTarget(cmGeneratorTarget* gt, Json::ArrayIndex ti);
+
+  Json::Value DumpDirectories();
+  Json::Value DumpDirectory(Directory& d);
+  Json::Value DumpDirectoryObject(Directory& d);
+
+  Json::Value DumpProjects();
+  Json::Value DumpProject(Project& p);
+
+  Json::Value DumpMinimumCMakeVersion(cmStateSnapshot s);
+
+public:
+  CodemodelConfig(cmFileAPI& fileAPI, unsigned long version,
+                  std::string const& config);
+  Json::Value Dump();
+};
+
+std::string TargetId(cmGeneratorTarget const* gt, std::string const& topBuild)
+{
+  cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_256);
+  std::string path = RelativeIfUnder(
+    topBuild, gt->GetLocalGenerator()->GetCurrentBinaryDirectory());
+  std::string hash = hasher.HashString(path);
+  hash.resize(20, '0');
+  return gt->GetName() + CMAKE_DIRECTORY_ID_SEP + hash;
+}
+
 struct CompileData
 {
   struct IncludeEntry
@@ -367,6 +379,31 @@
 } // namespace std
 
 namespace {
+class DirectoryObject
+{
+  cmLocalGenerator const* LG = nullptr;
+  std::string const& Config;
+  TargetIndexMapType& TargetIndexMap;
+  std::string TopSource;
+  std::string TopBuild;
+  BacktraceData Backtraces;
+
+  void AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt);
+
+  Json::Value DumpPaths();
+  Json::Value DumpInstallers();
+  Json::Value DumpInstaller(cmInstallGenerator* gen);
+  Json::Value DumpInstallerExportTargets(cmExportSet* exp);
+  Json::Value DumpInstallerPath(std::string const& top,
+                                std::string const& fromPathIn,
+                                std::string const& toPath);
+
+public:
+  DirectoryObject(cmLocalGenerator const* lg, std::string const& config,
+                  TargetIndexMapType& targetIndexMap);
+  Json::Value Dump();
+};
+
 class Target
 {
   cmGeneratorTarget* GT;
@@ -663,6 +700,8 @@
   target["projectIndex"] = pi;
   this->Projects[pi].TargetIndexes.append(ti);
 
+  this->TargetIndexMap[gt] = ti;
+
   return target;
 }
 
@@ -677,7 +716,7 @@
 
 Json::Value CodemodelConfig::DumpDirectory(Directory& d)
 {
-  Json::Value directory = Json::objectValue;
+  Json::Value directory = this->DumpDirectoryObject(d);
 
   std::string sourceDir = d.Snapshot.GetDirectory().GetCurrentSource();
   directory["source"] = RelativeIfUnder(this->TopSource, sourceDir);
@@ -717,6 +756,31 @@
   return directory;
 }
 
+Json::Value CodemodelConfig::DumpDirectoryObject(Directory& d)
+{
+  std::string prefix = "directory";
+  std::string sourceDirRel = RelativeIfUnder(
+    this->TopSource, d.Snapshot.GetDirectory().GetCurrentSource());
+  std::string buildDirRel = RelativeIfUnder(
+    this->TopBuild, d.Snapshot.GetDirectory().GetCurrentBinary());
+  if (!cmSystemTools::FileIsFullPath(buildDirRel)) {
+    prefix = cmStrCat(prefix, '-', buildDirRel);
+  } else if (!cmSystemTools::FileIsFullPath(sourceDirRel)) {
+    prefix = cmStrCat(prefix, '-', sourceDirRel);
+  }
+  for (char& c : prefix) {
+    if (c == '/' || c == '\\') {
+      c = '.';
+    }
+  }
+  if (!this->Config.empty()) {
+    prefix += "-" + this->Config;
+  }
+
+  DirectoryObject dir(d.LocalGenerator, this->Config, this->TargetIndexMap);
+  return this->FileAPI.MaybeJsonFile(dir.Dump(), prefix);
+}
+
 Json::Value CodemodelConfig::DumpProjects()
 {
   Json::Value projects = Json::arrayValue;
@@ -760,6 +824,246 @@
   return minimumCMakeVersion;
 }
 
+DirectoryObject::DirectoryObject(cmLocalGenerator const* lg,
+                                 std::string const& config,
+                                 TargetIndexMapType& targetIndexMap)
+  : LG(lg)
+  , Config(config)
+  , TargetIndexMap(targetIndexMap)
+  , TopSource(lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
+  , TopBuild(
+      lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeOutputDirectory())
+  , Backtraces(this->TopSource)
+{
+}
+
+Json::Value DirectoryObject::Dump()
+{
+  Json::Value directoryObject = Json::objectValue;
+  directoryObject["paths"] = this->DumpPaths();
+  directoryObject["installers"] = this->DumpInstallers();
+  directoryObject["backtraceGraph"] = this->Backtraces.Dump();
+  return directoryObject;
+}
+
+void DirectoryObject::AddBacktrace(Json::Value& object,
+                                   cmListFileBacktrace const& bt)
+{
+  if (JBTIndex backtrace = this->Backtraces.Add(bt)) {
+    object["backtrace"] = backtrace.Index;
+  }
+}
+
+Json::Value DirectoryObject::DumpPaths()
+{
+  Json::Value paths = Json::objectValue;
+
+  std::string const& sourceDir = this->LG->GetCurrentSourceDirectory();
+  paths["source"] = RelativeIfUnder(this->TopSource, sourceDir);
+
+  std::string const& buildDir = this->LG->GetCurrentBinaryDirectory();
+  paths["build"] = RelativeIfUnder(this->TopBuild, buildDir);
+
+  return paths;
+}
+
+Json::Value DirectoryObject::DumpInstallers()
+{
+  Json::Value installers = Json::arrayValue;
+  for (const auto& gen : this->LG->GetMakefile()->GetInstallGenerators()) {
+    Json::Value installer = this->DumpInstaller(gen.get());
+    if (!installer.empty()) {
+      installers.append(std::move(installer)); // NOLINT(*)
+    }
+  }
+  return installers;
+}
+
+Json::Value DirectoryObject::DumpInstaller(cmInstallGenerator* gen)
+{
+  Json::Value installer = Json::objectValue;
+
+  // Exclude subdirectory installers.  They are implementation details.
+  if (dynamic_cast<cmInstallSubdirectoryGenerator*>(gen)) {
+    return installer;
+  }
+
+  // Exclude installers not used in this configuration.
+  if (!gen->InstallsForConfig(this->Config)) {
+    return installer;
+  }
+
+  // Add fields specific to each kind of install generator.
+  if (auto* installTarget = dynamic_cast<cmInstallTargetGenerator*>(gen)) {
+    cmInstallTargetGenerator::Files const& files =
+      installTarget->GetFiles(this->Config);
+    if (files.From.empty()) {
+      return installer;
+    }
+
+    installer["type"] = "target";
+    installer["destination"] = installTarget->GetDestination(this->Config);
+    installer["targetId"] =
+      TargetId(installTarget->GetTarget(), this->TopBuild);
+    installer["targetIndex"] =
+      this->TargetIndexMap[installTarget->GetTarget()];
+
+    std::string fromDir = files.FromDir;
+    if (!fromDir.empty()) {
+      fromDir.push_back('/');
+    }
+
+    std::string toDir = files.ToDir;
+    if (!toDir.empty()) {
+      toDir.push_back('/');
+    }
+
+    Json::Value paths = Json::arrayValue;
+    for (size_t i = 0; i < files.From.size(); ++i) {
+      std::string const& fromPath = cmStrCat(fromDir, files.From[i]);
+      std::string const& toPath = cmStrCat(toDir, files.To[i]);
+      paths.append(this->DumpInstallerPath(this->TopBuild, fromPath, toPath));
+    }
+    installer["paths"] = std::move(paths);
+
+    if (installTarget->GetOptional()) {
+      installer["isOptional"] = true;
+    }
+
+    if (installTarget->IsImportLibrary()) {
+      installer["targetIsImportLibrary"] = true;
+    }
+
+    switch (files.NamelinkMode) {
+      case cmInstallTargetGenerator::NamelinkModeNone:
+        break;
+      case cmInstallTargetGenerator::NamelinkModeOnly:
+        installer["targetInstallNamelink"] = "only";
+        break;
+      case cmInstallTargetGenerator::NamelinkModeSkip:
+        installer["targetInstallNamelink"] = "skip";
+        break;
+    }
+
+    // FIXME: Parse FilePermissions to provide structured information.
+    // FIXME: Thread EXPORT name through from install() call.
+  } else if (auto* installFiles =
+               dynamic_cast<cmInstallFilesGenerator*>(gen)) {
+    std::vector<std::string> const& files =
+      installFiles->GetFiles(this->Config);
+    if (files.empty()) {
+      return installer;
+    }
+
+    installer["type"] = "file";
+    installer["destination"] = installFiles->GetDestination(this->Config);
+    Json::Value paths = Json::arrayValue;
+    std::string const& rename = installFiles->GetRename(this->Config);
+    if (!rename.empty() && files.size() == 1) {
+      paths.append(this->DumpInstallerPath(this->TopSource, files[0], rename));
+    } else {
+      for (std::string const& file : installFiles->GetFiles(this->Config)) {
+        paths.append(RelativeIfUnder(this->TopSource, file));
+      }
+    }
+    installer["paths"] = std::move(paths);
+    if (installFiles->GetOptional()) {
+      installer["isOptional"] = true;
+    }
+    // FIXME: Parse FilePermissions to provide structured information.
+  } else if (auto* installDir =
+               dynamic_cast<cmInstallDirectoryGenerator*>(gen)) {
+    std::vector<std::string> const& dirs =
+      installDir->GetDirectories(this->Config);
+    if (dirs.empty()) {
+      return installer;
+    }
+
+    installer["type"] = "directory";
+    installer["destination"] = installDir->GetDestination(this->Config);
+    Json::Value paths = Json::arrayValue;
+    for (std::string const& dir : dirs) {
+      if (cmHasLiteralSuffix(dir, "/")) {
+        paths.append(this->DumpInstallerPath(
+          this->TopSource, dir.substr(0, dir.size() - 1), "."));
+      } else {
+        paths.append(this->DumpInstallerPath(
+          this->TopSource, dir, cmSystemTools::GetFilenameName(dir)));
+      }
+    }
+    installer["paths"] = std::move(paths);
+    if (installDir->GetOptional()) {
+      installer["isOptional"] = true;
+    }
+    // FIXME: Parse FilePermissions, DirPermissions, and LiteralArguments.
+    // to provide structured information.
+  } else if (auto* installExport =
+               dynamic_cast<cmInstallExportGenerator*>(gen)) {
+    installer["type"] = "export";
+    installer["destination"] = installExport->GetDestination();
+    cmExportSet* exportSet = installExport->GetExportSet();
+    installer["exportName"] = exportSet->GetName();
+    installer["exportTargets"] = this->DumpInstallerExportTargets(exportSet);
+    Json::Value paths = Json::arrayValue;
+    paths.append(
+      RelativeIfUnder(this->TopBuild, installExport->GetMainImportFile()));
+    installer["paths"] = std::move(paths);
+  } else if (auto* installScript =
+               dynamic_cast<cmInstallScriptGenerator*>(gen)) {
+    if (installScript->IsCode()) {
+      installer["type"] = "code";
+    } else {
+      installer["type"] = "script";
+      installer["scriptFile"] = RelativeIfUnder(
+        this->TopSource, installScript->GetScript(this->Config));
+    }
+  }
+
+  // Add fields common to all install generators.
+  installer["component"] = gen->GetComponent();
+  if (gen->GetExcludeFromAll()) {
+    installer["isExcludeFromAll"] = true;
+  }
+  this->AddBacktrace(installer, gen->GetBacktrace());
+
+  return installer;
+}
+
+Json::Value DirectoryObject::DumpInstallerExportTargets(cmExportSet* exp)
+{
+  Json::Value targets = Json::arrayValue;
+  for (auto const& targetExport : exp->GetTargetExports()) {
+    Json::Value target = Json::objectValue;
+    target["id"] = TargetId(targetExport->Target, this->TopBuild);
+    target["index"] = this->TargetIndexMap[targetExport->Target];
+    targets.append(std::move(target)); // NOLINT(*)
+  }
+  return targets;
+}
+
+Json::Value DirectoryObject::DumpInstallerPath(std::string const& top,
+                                               std::string const& fromPathIn,
+                                               std::string const& toPath)
+{
+  Json::Value installPath;
+
+  std::string fromPath = RelativeIfUnder(top, fromPathIn);
+
+  // If toPath is the last component of fromPath, use just fromPath.
+  if (toPath.find_first_of('/') == std::string::npos &&
+      cmHasSuffix(fromPath, toPath) &&
+      (fromPath.size() == toPath.size() ||
+       fromPath[fromPath.size() - toPath.size() - 1] == '/')) {
+    installPath = fromPath;
+  } else {
+    installPath = Json::objectValue;
+    installPath["from"] = fromPath;
+    installPath["to"] = toPath;
+  }
+
+  return installPath;
+}
+
 Target::Target(cmGeneratorTarget* gt, std::string const& config)
   : GT(gt)
   , Config(config)
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 4a28238..26bdedf 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -1313,8 +1313,9 @@
 bool HandleRename(std::vector<std::string> const& args,
                   cmExecutionStatus& status)
 {
-  if (args.size() != 3) {
-    status.SetError("RENAME given incorrect number of arguments.");
+  if (args.size() < 3) {
+    status.SetError("RENAME must be called with at least two additional "
+                    "arguments");
     return false;
   }
 
@@ -1330,13 +1331,143 @@
       cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', args[2]);
   }
 
-  if (!cmSystemTools::RenameFile(oldname, newname)) {
-    std::string err = cmSystemTools::GetLastSystemError();
-    status.SetError(cmStrCat("RENAME failed to rename\n  ", oldname,
-                             "\nto\n  ", newname, "\nbecause: ", err, "\n"));
+  struct Arguments
+  {
+    bool NoReplace = false;
+    std::string Result;
+  };
+
+  static auto const parser = cmArgumentParser<Arguments>{}
+                               .Bind("NO_REPLACE"_s, &Arguments::NoReplace)
+                               .Bind("RESULT"_s, &Arguments::Result);
+
+  std::vector<std::string> unconsumedArgs;
+  Arguments const arguments =
+    parser.Parse(cmMakeRange(args).advance(3), &unconsumedArgs);
+  if (!unconsumedArgs.empty()) {
+    status.SetError("RENAME unknown argument:\n  " + unconsumedArgs.front());
     return false;
   }
-  return true;
+
+  std::string err;
+  switch (cmSystemTools::RenameFile(oldname, newname,
+                                    arguments.NoReplace
+                                      ? cmSystemTools::Replace::No
+                                      : cmSystemTools::Replace::Yes,
+                                    &err)) {
+    case cmSystemTools::RenameResult::Success:
+      if (!arguments.Result.empty()) {
+        status.GetMakefile().AddDefinition(arguments.Result, "0");
+      }
+      return true;
+    case cmSystemTools::RenameResult::NoReplace:
+      if (!arguments.Result.empty()) {
+        err = "NO_REPLACE";
+      } else {
+        err = "path not replaced";
+      }
+      CM_FALLTHROUGH;
+    case cmSystemTools::RenameResult::Failure:
+      if (!arguments.Result.empty()) {
+        status.GetMakefile().AddDefinition(arguments.Result, err);
+        return true;
+      }
+      break;
+  }
+  status.SetError(cmStrCat("RENAME failed to rename\n  ", oldname, "\nto\n  ",
+                           newname, "\nbecause: ", err, "\n"));
+  return false;
+}
+
+bool HandleCopyFile(std::vector<std::string> const& args,
+                    cmExecutionStatus& status)
+{
+  if (args.size() < 3) {
+    status.SetError("COPY_FILE must be called with at least two additional "
+                    "arguments");
+    return false;
+  }
+
+  // Compute full path for old and new names.
+  std::string oldname = args[1];
+  if (!cmsys::SystemTools::FileIsFullPath(oldname)) {
+    oldname =
+      cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', args[1]);
+  }
+  std::string newname = args[2];
+  if (!cmsys::SystemTools::FileIsFullPath(newname)) {
+    newname =
+      cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', args[2]);
+  }
+
+  struct Arguments
+  {
+    bool OnlyIfDifferent = false;
+    std::string Result;
+  };
+
+  static auto const parser =
+    cmArgumentParser<Arguments>{}
+      .Bind("ONLY_IF_DIFFERENT"_s, &Arguments::OnlyIfDifferent)
+      .Bind("RESULT"_s, &Arguments::Result);
+
+  std::vector<std::string> unconsumedArgs;
+  Arguments const arguments =
+    parser.Parse(cmMakeRange(args).advance(3), &unconsumedArgs);
+  if (!unconsumedArgs.empty()) {
+    status.SetError("COPY_FILE unknown argument:\n  " +
+                    unconsumedArgs.front());
+    return false;
+  }
+
+  bool result = true;
+  if (cmsys::SystemTools::FileIsDirectory(oldname)) {
+    if (!arguments.Result.empty()) {
+      status.GetMakefile().AddDefinition(arguments.Result,
+                                         "cannot copy a directory");
+    } else {
+      status.SetError(
+        cmStrCat("COPY_FILE cannot copy a directory\n  ", oldname));
+      result = false;
+    }
+    return result;
+  }
+  if (cmsys::SystemTools::FileIsDirectory(newname)) {
+    if (!arguments.Result.empty()) {
+      status.GetMakefile().AddDefinition(arguments.Result,
+                                         "cannot copy to a directory");
+    } else {
+      status.SetError(
+        cmStrCat("COPY_FILE cannot copy to a directory\n  ", newname));
+      result = false;
+    }
+    return result;
+  }
+
+  cmSystemTools::CopyWhen when;
+  if (arguments.OnlyIfDifferent) {
+    when = cmSystemTools::CopyWhen::OnlyIfDifferent;
+  } else {
+    when = cmSystemTools::CopyWhen::Always;
+  }
+
+  std::string err;
+  if (cmSystemTools::CopySingleFile(oldname, newname, when, &err) ==
+      cmSystemTools::CopyResult::Success) {
+    if (!arguments.Result.empty()) {
+      status.GetMakefile().AddDefinition(arguments.Result, "0");
+    }
+  } else {
+    if (!arguments.Result.empty()) {
+      status.GetMakefile().AddDefinition(arguments.Result, err);
+    } else {
+      status.SetError(cmStrCat("COPY_FILE failed to copy\n  ", oldname,
+                               "\nto\n  ", newname, "\nbecause: ", err, "\n"));
+      result = false;
+    }
+  }
+
+  return result;
 }
 
 bool HandleRemoveImpl(std::vector<std::string> const& args, bool recurse,
@@ -2825,9 +2956,12 @@
 
   // Check if copy-on-error is enabled in the arguments.
   if (!completed && arguments.CopyOnError) {
-    completed = cmsys::SystemTools::CopyFileAlways(fileName, newFileName);
-    if (!completed) {
-      result = "Copy failed: " + cmSystemTools::GetLastSystemError();
+    cmsys::Status copied =
+      cmsys::SystemTools::CopyFileAlways(fileName, newFileName);
+    if (copied) {
+      completed = true;
+    } else {
+      result = "Copy failed: " + copied.GetString();
     }
   }
 
@@ -3569,6 +3703,7 @@
     { "GLOB_RECURSE"_s, HandleGlobRecurseCommand },
     { "MAKE_DIRECTORY"_s, HandleMakeDirectoryCommand },
     { "RENAME"_s, HandleRename },
+    { "COPY_FILE"_s, HandleCopyFile },
     { "REMOVE"_s, HandleRemove },
     { "REMOVE_RECURSE"_s, HandleRemoveRecurse },
     { "COPY"_s, HandleCopyCommand },
diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx
index 49b1bd7..d85ba8f 100644
--- a/Source/cmFindLibraryCommand.cxx
+++ b/Source/cmFindLibraryCommand.cxx
@@ -374,7 +374,7 @@
     regex += "(\\.[0-9]+\\.[0-9]+)?";
   }
   regex += "$";
-  entry.Regex.compile(regex.c_str());
+  entry.Regex.compile(regex);
   this->Names.push_back(std::move(entry));
 }
 
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index e40316e..7125170 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -14,6 +14,7 @@
 #include <utility>
 
 #include <cm/iterator>
+#include <cm/optional>
 #include <cm/string_view>
 #include <cm/vector>
 #include <cmext/algorithm>
@@ -23,6 +24,7 @@
 #include "cmsys/String.h"
 
 #include "cmAlgorithms.h"
+#include "cmComputeLinkInformation.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorExpressionContext.h"
 #include "cmGeneratorExpressionDAGChecker.h"
@@ -1627,8 +1629,8 @@
         type != cmStateEnums::OBJECT_LIBRARY) {
       std::ostringstream e;
       e << "Objects of target \"" << tgtName
-        << "\" referenced but is not an allowed library types (EXECUTABLE, "
-        << "STATIC, SHARED, MODULE, OBJECT).";
+        << "\" referenced but is not one of the allowed target types "
+        << "(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT).";
       reportError(context, content->GetOriginalExpression(), e.str());
       return std::string();
     }
@@ -1687,6 +1689,54 @@
   }
 } targetObjectsNode;
 
+static const struct TargetRuntimeDllsNode : public cmGeneratorExpressionNode
+{
+  TargetRuntimeDllsNode() {} // NOLINT(modernize-use-equals-default)
+
+  std::string Evaluate(
+    const std::vector<std::string>& parameters,
+    cmGeneratorExpressionContext* context,
+    const GeneratorExpressionContent* content,
+    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+  {
+    std::string tgtName = parameters.front();
+    cmGeneratorTarget* gt = context->LG->FindGeneratorTargetToUse(tgtName);
+    if (!gt) {
+      std::ostringstream e;
+      e << "Objects of target \"" << tgtName
+        << "\" referenced but no such target exists.";
+      reportError(context, content->GetOriginalExpression(), e.str());
+      return std::string();
+    }
+    cmStateEnums::TargetType type = gt->GetType();
+    if (type != cmStateEnums::EXECUTABLE &&
+        type != cmStateEnums::SHARED_LIBRARY &&
+        type != cmStateEnums::MODULE_LIBRARY) {
+      std::ostringstream e;
+      e << "Objects of target \"" << tgtName
+        << "\" referenced but is not one of the allowed target types "
+        << "(EXECUTABLE, SHARED, MODULE).";
+      reportError(context, content->GetOriginalExpression(), e.str());
+      return std::string();
+    }
+
+    if (auto* cli = gt->GetLinkInformation(context->Config)) {
+      std::vector<std::string> dllPaths;
+      auto const& dlls = cli->GetRuntimeDLLs();
+
+      for (auto const& dll : dlls) {
+        if (auto loc = dll->MaybeGetLocation(context->Config)) {
+          dllPaths.emplace_back(*loc);
+        }
+      }
+
+      return cmJoin(dllPaths, ";");
+    }
+
+    return "";
+  }
+} targetRuntimeDllsNode;
+
 static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
 {
   CompileFeaturesNode() {} // NOLINT(modernize-use-equals-default)
@@ -2603,6 +2653,7 @@
     { "TARGET_EXISTS", &targetExistsNode },
     { "TARGET_NAME_IF_EXISTS", &targetNameIfExistsNode },
     { "TARGET_GENEX_EVAL", &targetGenexEvalNode },
+    { "TARGET_RUNTIME_DLLS", &targetRuntimeDllsNode },
     { "GENEX_EVAL", &genexEvalNode },
     { "BUILD_INTERFACE", &buildInterfaceNode },
     { "INSTALL_INTERFACE", &installInterfaceNode },
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index efac06a..365f8b8 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -1062,6 +1062,20 @@
   return location;
 }
 
+cm::optional<std::string> cmGeneratorTarget::MaybeGetLocation(
+  std::string const& config) const
+{
+  cm::optional<std::string> location;
+  if (cmGeneratorTarget::ImportInfo const* imp = this->GetImportInfo(config)) {
+    if (!imp->Location.empty()) {
+      location = imp->Location;
+    }
+  } else {
+    location = this->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact);
+  }
+  return location;
+}
+
 std::vector<cmCustomCommand> const& cmGeneratorTarget::GetPreBuildCommands()
   const
 {
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 8fe70ab..2935e0b 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -14,6 +14,8 @@
 #include <utility>
 #include <vector>
 
+#include <cm/optional>
+
 #include "cmLinkItem.h"
 #include "cmListFileCache.h"
 #include "cmPolicies.h"
@@ -50,6 +52,9 @@
   bool CanCompileSources() const;
   const std::string& GetLocation(const std::string& config) const;
 
+  /** Get the full path to the target's main artifact, if known.  */
+  cm::optional<std::string> MaybeGetLocation(std::string const& config) const;
+
   std::vector<cmCustomCommand> const& GetPreBuildCommands() const;
   std::vector<cmCustomCommand> const& GetPreLinkCommands() const;
   std::vector<cmCustomCommand> const& GetPostBuildCommands() const;
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index c502fb8..6937639 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -9,6 +9,7 @@
 
 #include <cm/iterator>
 #include <cm/memory>
+#include <cm/string_view>
 #include <cmext/algorithm>
 #include <cmext/memory>
 
@@ -503,14 +504,7 @@
 
 codecvt::Encoding cmGlobalNinjaGenerator::GetMakefileEncoding() const
 {
-#ifdef _WIN32
-  // Ninja on Windows does not support non-ANSI characters.
-  // https://github.com/ninja-build/ninja/issues/1195
-  return codecvt::ANSI;
-#else
-  // No encoding conversion needed on other platforms.
-  return codecvt::None;
-#endif
+  return this->NinjaExpectedEncoding;
 }
 
 void cmGlobalNinjaGenerator::GetDocumentation(cmDocumentationEntry& entry)
@@ -732,6 +726,61 @@
   this->NinjaSupportsMetadataOnRegeneration = !cmSystemTools::VersionCompare(
     cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
     RequiredNinjaVersionForMetadataOnRegeneration().c_str());
+#ifdef _WIN32
+  this->NinjaSupportsCodePage = !cmSystemTools::VersionCompare(
+    cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+    RequiredNinjaVersionForCodePage().c_str());
+  if (this->NinjaSupportsCodePage) {
+    this->CheckNinjaCodePage();
+  } else {
+    this->NinjaExpectedEncoding = codecvt::ANSI;
+  }
+#endif
+}
+
+void cmGlobalNinjaGenerator::CheckNinjaCodePage()
+{
+  std::vector<std::string> command{ this->NinjaCommand, "-t", "wincodepage" };
+  std::string output;
+  std::string error;
+  int result;
+  if (!cmSystemTools::RunSingleCommand(command, &output, &error, &result,
+                                       nullptr, cmSystemTools::OUTPUT_NONE)) {
+    this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+                                           cmStrCat("Running\n '",
+                                                    cmJoin(command, "' '"),
+                                                    "'\n"
+                                                    "failed with:\n ",
+                                                    error));
+    cmSystemTools::SetFatalErrorOccured();
+  } else if (result == 0) {
+    std::istringstream outputStream(output);
+    std::string line;
+    bool found = false;
+    while (cmSystemTools::GetLineFromStream(outputStream, line)) {
+      if (cmHasLiteralPrefix(line, "Build file encoding: ")) {
+        cm::string_view lineView(line);
+        cm::string_view encoding =
+          lineView.substr(cmStrLen("Build file encoding: "));
+        if (encoding == "UTF-8") {
+          // Ninja expects UTF-8. We use that internally. No conversion needed.
+          this->NinjaExpectedEncoding = codecvt::None;
+        } else {
+          this->NinjaExpectedEncoding = codecvt::ANSI;
+        }
+        found = true;
+        break;
+      }
+    }
+    if (!found) {
+      this->GetCMakeInstance()->IssueMessage(
+        MessageType::WARNING,
+        "Could not determine Ninja's code page, defaulting to UTF-8");
+      this->NinjaExpectedEncoding = codecvt::None;
+    }
+  } else {
+    this->NinjaExpectedEncoding = codecvt::ANSI;
+  }
 }
 
 bool cmGlobalNinjaGenerator::CheckLanguages(
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 0c919ef..9f31708 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -388,6 +388,7 @@
   {
     return "1.10.2";
   }
+  static std::string RequiredNinjaVersionForCodePage() { return "1.11"; }
   bool SupportsConsolePool() const;
   bool SupportsImplicitOuts() const;
   bool SupportsManifestRestat() const;
@@ -474,6 +475,7 @@
   std::string GetEditCacheCommand() const override;
   bool FindMakeProgram(cmMakefile* mf) override;
   void CheckNinjaFeatures();
+  void CheckNinjaCodePage();
   bool CheckLanguages(std::vector<std::string> const& languages,
                       cmMakefile* mf) const override;
   bool CheckFortran(cmMakefile* mf) const;
@@ -568,6 +570,9 @@
   bool NinjaSupportsUnconditionalRecompactTool = false;
   bool NinjaSupportsMultipleOutputs = false;
   bool NinjaSupportsMetadataOnRegeneration = false;
+  bool NinjaSupportsCodePage = false;
+
+  codecvt::Encoding NinjaExpectedEncoding = codecvt::None;
 
   bool DiagnosedCxxModuleSupport = false;
 
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index badce2e..93fbe37 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -231,6 +231,23 @@
     return false;
   }
 
+  if (!this->CustomFlagTableDir.empty() &&
+      !(cmSystemTools::FileIsFullPath(this->CustomFlagTableDir) &&
+        cmSystemTools::FileIsDirectory(this->CustomFlagTableDir))) {
+    std::ostringstream e;
+    /* clang-format off */
+    e <<
+      "Generator\n"
+      "  " << this->GetName() << "\n"
+      "given toolset\n"
+      "  customFlagTableDir=" << this->CustomFlagTableDir << "\n"
+      "that is not an absolute path to an existing directory.";
+    /* clang-format on */
+    mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    cmSystemTools::SetFatalErrorOccured();
+    return false;
+  }
+
   if (cmHasLiteralPrefix(this->GetPlatformToolsetString(), "v140")) {
     // The GenerateDebugInformation link setting for the v140 toolset
     // in VS 2015 was originally an enum with "No" and "Debug" values,
@@ -263,8 +280,8 @@
       bcDir = this->VCTargetsPath + "/BuildCustomizations";
     } else {
       bcDir = this->GetPlatformToolsetCudaCustomDirString() +
-        "CUDAVisualStudioIntegration\\extras\\"
-        "visual_studio_integration\\MSBuildExtensions";
+        this->GetPlatformToolsetCudaVSIntegrationSubdirString() +
+        "extras\\visual_studio_integration\\MSBuildExtensions";
       cmSystemTools::ConvertToUnixSlashes(bcDir);
     }
     cmsys::Glob gl;
@@ -470,11 +487,27 @@
       if (this->GeneratorToolsetCudaCustomDir.back() != '\\') {
         this->GeneratorToolsetCudaCustomDir.push_back('\\');
       }
+      /* check for legacy toolkit folder structure */
+      if (cmsys::SystemTools::FileIsDirectory(
+            cmStrCat(this->GeneratorToolsetCudaCustomDir, "nvcc"))) {
+        this->GeneratorToolsetCudaNvccSubdir = "nvcc\\";
+      }
+      if (cmsys::SystemTools::FileIsDirectory(
+            cmStrCat(this->GeneratorToolsetCudaCustomDir,
+                     "CUDAVisualStudioIntegration"))) {
+        this->GeneratorToolsetCudaVSIntegrationSubdir =
+          "CUDAVisualStudioIntegration\\";
+      }
     } else {
       this->GeneratorToolsetCuda = value;
     }
     return true;
   }
+  if (key == "customFlagTableDir") {
+    this->CustomFlagTableDir = value;
+    cmSystemTools::ConvertToUnixSlashes(this->CustomFlagTableDir);
+    return true;
+  }
   if (key == "version") {
     this->GeneratorToolsetVersion = value;
     return true;
@@ -787,6 +820,18 @@
   return this->GeneratorToolsetCudaCustomDir;
 }
 
+std::string const&
+cmGlobalVisualStudio10Generator::GetPlatformToolsetCudaNvccSubdirString() const
+{
+  return this->GeneratorToolsetCudaNvccSubdir;
+}
+
+std::string const& cmGlobalVisualStudio10Generator::
+  GetPlatformToolsetCudaVSIntegrationSubdirString() const
+{
+  return this->GeneratorToolsetCudaVSIntegrationSubdir;
+}
+
 cmGlobalVisualStudio10Generator::AuxToolset
 cmGlobalVisualStudio10Generator::FindAuxToolset(std::string&,
                                                 std::string&) const
@@ -1349,137 +1394,262 @@
   return ret;
 }
 
-static std::string cmGetFlagTableName(std::string const& toolsetName,
-                                      std::string const& table)
+cm::optional<std::string> cmGlobalVisualStudio10Generator::FindFlagTable(
+  cm::string_view toolsetName, cm::string_view table) const
 {
-  return cmSystemTools::GetCMakeRoot() + "/Templates/MSBuild/FlagTables/" +
-    toolsetName + "_" + table + ".json";
+  if (!this->CustomFlagTableDir.empty()) {
+    std::string customFlagTableFile =
+      cmStrCat(this->CustomFlagTableDir, '/', this->GetPlatformName(), '_',
+               toolsetName, '_', table, ".json");
+    if (cmSystemTools::FileExists(customFlagTableFile)) {
+      return customFlagTableFile;
+    }
+    customFlagTableFile =
+      cmStrCat(this->CustomFlagTableDir, '/', this->GetPlatformName(), '_',
+               table, ".json");
+    if (cmSystemTools::FileExists(customFlagTableFile)) {
+      return customFlagTableFile;
+    }
+  }
+  std::string fullPath =
+    cmStrCat(cmSystemTools::GetCMakeRoot(), "/Templates/MSBuild/FlagTables/",
+             toolsetName, '_', table, ".json");
+  if (cmSystemTools::FileExists(fullPath)) {
+    return fullPath;
+  }
+  return {};
 }
 
 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::LoadFlagTable(
-  std::string const& optionsName, std::string const& toolsetName,
-  std::string const& defaultName, std::string const& table) const
+  std::string const& toolSpecificName, std::string const& defaultName,
+  std::string const& table) const
 {
-  cmIDEFlagTable const* ret = nullptr;
+  cmMakefile* mf = this->GetCurrentMakefile();
 
   std::string filename;
-  if (!optionsName.empty()) {
-    filename = cmGetFlagTableName(optionsName, table);
-    ret = cmLoadFlagTableJson(filename);
-  } else {
-    filename = cmGetFlagTableName(toolsetName, table);
-    if (cmSystemTools::FileExists(filename)) {
-      ret = cmLoadFlagTableJson(filename);
+  if (!toolSpecificName.empty()) {
+    if (cm::optional<std::string> found =
+          this->FindFlagTable(toolSpecificName, table)) {
+      filename = std::move(*found);
     } else {
-      filename = cmGetFlagTableName(defaultName, table);
-      ret = cmLoadFlagTableJson(filename);
+      mf->IssueMessage(MessageType::FATAL_ERROR,
+                       cmStrCat("JSON flag table for ", table,
+                                " not found for toolset ", toolSpecificName));
+      return nullptr;
+    }
+  } else {
+    std::string const& genericName =
+      this->CanonicalToolsetName(this->GetPlatformToolsetString());
+    cm::optional<std::string> found = this->FindFlagTable(genericName, table);
+    if (!found) {
+      found = this->FindFlagTable(defaultName, table);
+    }
+    if (found) {
+      filename = std::move(*found);
+    } else {
+      mf->IssueMessage(MessageType::FATAL_ERROR,
+                       cmStrCat("JSON flag table for ", table,
+                                " not found for toolset ", genericName, " ",
+                                defaultName));
+      return nullptr;
     }
   }
 
-  if (!ret) {
-    cmMakefile* mf = this->GetCurrentMakefile();
-
-    std::ostringstream e;
-    /* clang-format off */
-    e << "JSON flag table \"" << filename <<
-      "\" could not be loaded.\n";
-    /* clang-format on */
-    mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+  if (cmIDEFlagTable const* ret = cmLoadFlagTableJson(filename)) {
+    return ret;
   }
-  return ret;
+
+  mf->IssueMessage(
+    MessageType::FATAL_ERROR,
+    cmStrCat("JSON flag table could not be loaded:\n  ", filename));
+  return nullptr;
 }
 
 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetClFlagTable() const
 {
-  std::string optionsName = this->ToolsetOptions.GetClFlagTableName(
-    this->GetPlatformName(), this->GetPlatformToolsetString());
-  std::string toolsetName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->GetPlatformToolsetString());
-  std::string defaultName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->DefaultCLFlagTableName);
-  return LoadFlagTable(optionsName, toolsetName, defaultName, "CL");
+  return LoadFlagTable(this->GetClFlagTableName(),
+                       this->DefaultCLFlagTableName, "CL");
 }
 
 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCSharpFlagTable()
   const
 {
-  std::string optionsName = this->ToolsetOptions.GetCSharpFlagTableName(
-    this->GetPlatformName(), this->GetPlatformToolsetString());
-  std::string toolsetName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->GetPlatformToolsetString());
-  std::string defaultName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->DefaultCSharpFlagTableName);
-  return LoadFlagTable(optionsName, toolsetName, defaultName, "CSharp");
+  return LoadFlagTable(this->GetCSharpFlagTableName(),
+                       this->DefaultCSharpFlagTableName, "CSharp");
 }
 
 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetRcFlagTable() const
 {
-  std::string optionsName = this->ToolsetOptions.GetRcFlagTableName(
-    this->GetPlatformName(), this->GetPlatformToolsetString());
-  std::string toolsetName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->GetPlatformToolsetString());
-  std::string defaultName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->DefaultRCFlagTableName);
-  return LoadFlagTable(optionsName, toolsetName, defaultName, "RC");
+  return LoadFlagTable(this->GetRcFlagTableName(),
+                       this->DefaultRCFlagTableName, "RC");
 }
 
 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetLibFlagTable() const
 {
-  std::string optionsName = this->ToolsetOptions.GetLibFlagTableName(
-    this->GetPlatformName(), this->GetPlatformToolsetString());
-  std::string toolsetName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->GetPlatformToolsetString());
-  std::string defaultName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->DefaultLibFlagTableName);
-  return LoadFlagTable(optionsName, toolsetName, defaultName, "LIB");
+  return LoadFlagTable(this->GetLibFlagTableName(),
+                       this->DefaultLibFlagTableName, "LIB");
 }
 
 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetLinkFlagTable() const
 {
-  std::string optionsName = this->ToolsetOptions.GetLinkFlagTableName(
-    this->GetPlatformName(), this->GetPlatformToolsetString());
-  std::string toolsetName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->GetPlatformToolsetString());
-  std::string defaultName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->DefaultLinkFlagTableName);
-  return LoadFlagTable(optionsName, toolsetName, defaultName, "Link");
+  return LoadFlagTable(this->GetLinkFlagTableName(),
+                       this->DefaultLinkFlagTableName, "Link");
 }
 
 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCudaFlagTable() const
 {
-  std::string toolsetName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->GetPlatformToolsetString());
-  std::string defaultName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->DefaultCudaFlagTableName);
-  return LoadFlagTable("", toolsetName, defaultName, "Cuda");
+  return LoadFlagTable(std::string(), this->DefaultCudaFlagTableName, "Cuda");
 }
 
 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCudaHostFlagTable()
   const
 {
-  std::string toolsetName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->GetPlatformToolsetString());
-  std::string defaultName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->DefaultCudaHostFlagTableName);
-  return LoadFlagTable("", toolsetName, defaultName, "CudaHost");
+  return LoadFlagTable(std::string(), this->DefaultCudaHostFlagTableName,
+                       "CudaHost");
 }
 
 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetMasmFlagTable() const
 {
-  std::string optionsName = this->ToolsetOptions.GetMasmFlagTableName(
-    this->GetPlatformName(), this->GetPlatformToolsetString());
-  std::string toolsetName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->GetPlatformToolsetString());
-  std::string defaultName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->DefaultMasmFlagTableName);
-  return LoadFlagTable(optionsName, toolsetName, defaultName, "MASM");
+  return LoadFlagTable(this->GetMasmFlagTableName(),
+                       this->DefaultMasmFlagTableName, "MASM");
 }
 
 cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetNasmFlagTable() const
 {
-  std::string toolsetName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->GetPlatformToolsetString());
-  std::string defaultName = this->ToolsetOptions.GetToolsetName(
-    this->GetPlatformName(), this->DefaultNasmFlagTableName);
-  return LoadFlagTable("", toolsetName, defaultName, "NASM");
+  return LoadFlagTable(std::string(), this->DefaultNasmFlagTableName, "NASM");
+}
+
+std::string cmGlobalVisualStudio10Generator::GetClFlagTableName() const
+{
+  std::string const& toolset = this->GetPlatformToolsetString();
+  std::string const useToolset = this->CanonicalToolsetName(toolset);
+
+  if (toolset == "v142") {
+    return "v142";
+  } else if (toolset == "v141") {
+    return "v141";
+  } else if (useToolset == "v140") {
+    return "v140";
+  } else if (useToolset == "v120") {
+    return "v12";
+  } else if (useToolset == "v110") {
+    return "v11";
+  } else if (useToolset == "v100") {
+    return "v10";
+  } else {
+    return "";
+  }
+}
+
+std::string cmGlobalVisualStudio10Generator::GetCSharpFlagTableName() const
+{
+  std::string const& toolset = this->GetPlatformToolsetString();
+  std::string const useToolset = this->CanonicalToolsetName(toolset);
+
+  if (useToolset == "v142") {
+    return "v142";
+  } else if (useToolset == "v141") {
+    return "v141";
+  } else if (useToolset == "v140") {
+    return "v140";
+  } else if (useToolset == "v120") {
+    return "v12";
+  } else if (useToolset == "v110") {
+    return "v11";
+  } else if (useToolset == "v100") {
+    return "v10";
+  } else {
+    return "";
+  }
+}
+
+std::string cmGlobalVisualStudio10Generator::GetRcFlagTableName() const
+{
+  std::string const& toolset = this->GetPlatformToolsetString();
+  std::string const useToolset = this->CanonicalToolsetName(toolset);
+
+  if ((useToolset == "v140") || (useToolset == "v141") ||
+      (useToolset == "v142")) {
+    return "v14";
+  } else if (useToolset == "v120") {
+    return "v12";
+  } else if (useToolset == "v110") {
+    return "v11";
+  } else if (useToolset == "v100") {
+    return "v10";
+  } else {
+    return "";
+  }
+}
+
+std::string cmGlobalVisualStudio10Generator::GetLibFlagTableName() const
+{
+  std::string const& toolset = this->GetPlatformToolsetString();
+  std::string const useToolset = this->CanonicalToolsetName(toolset);
+
+  if ((useToolset == "v140") || (useToolset == "v141") ||
+      (useToolset == "v142")) {
+    return "v14";
+  } else if (useToolset == "v120") {
+    return "v12";
+  } else if (useToolset == "v110") {
+    return "v11";
+  } else if (useToolset == "v100") {
+    return "v10";
+  } else {
+    return "";
+  }
+}
+
+std::string cmGlobalVisualStudio10Generator::GetLinkFlagTableName() const
+{
+  std::string const& toolset = this->GetPlatformToolsetString();
+  std::string const useToolset = this->CanonicalToolsetName(toolset);
+
+  if (useToolset == "v142") {
+    return "v142";
+  } else if (useToolset == "v141") {
+    return "v141";
+  } else if (useToolset == "v140") {
+    return "v140";
+  } else if (useToolset == "v120") {
+    return "v12";
+  } else if (useToolset == "v110") {
+    return "v11";
+  } else if (useToolset == "v100") {
+    return "v10";
+  } else {
+    return "";
+  }
+}
+
+std::string cmGlobalVisualStudio10Generator::GetMasmFlagTableName() const
+{
+  std::string const& toolset = this->GetPlatformToolsetString();
+  std::string const useToolset = this->CanonicalToolsetName(toolset);
+
+  if ((useToolset == "v140") || (useToolset == "v141") ||
+      (useToolset == "v142")) {
+    return "v14";
+  } else if (useToolset == "v120") {
+    return "v12";
+  } else if (useToolset == "v110") {
+    return "v11";
+  } else if (useToolset == "v100") {
+    return "v10";
+  } else {
+    return "";
+  }
+}
+
+std::string cmGlobalVisualStudio10Generator::CanonicalToolsetName(
+  std::string const& toolset) const
+{
+  std::size_t length = toolset.length();
+
+  if (cmHasLiteralSuffix(toolset, "_xp")) {
+    length -= 3;
+  }
+
+  return toolset.substr(0, length);
 }
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index 8d30ef8..2596720 100644
--- a/Source/cmGlobalVisualStudio10Generator.h
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -5,8 +5,10 @@
 #include <memory>
 #include <set>
 
+#include <cm/optional>
+#include <cm/string_view>
+
 #include "cmGlobalVisualStudio8Generator.h"
-#include "cmVisualStudio10ToolsetOptions.h"
 
 /** \class cmGlobalVisualStudio10Generator
  * \brief Write a Unix makefiles.
@@ -76,6 +78,13 @@
   const char* GetPlatformToolsetCudaCustomDir() const;
   std::string const& GetPlatformToolsetCudaCustomDirString() const;
 
+  /** The nvcc subdirectory of a custom cuda install directory */
+  std::string const& GetPlatformToolsetCudaNvccSubdirString() const;
+
+  /** The visual studio integration subdirectory of a custom cuda install
+   * directory */
+  std::string const& GetPlatformToolsetCudaVSIntegrationSubdirString() const;
+
   /** Return whether we need to use No/Debug instead of false/true
       for GenerateDebugInformation.  */
   bool GetPlatformToolsetNeedsDebugEnum() const
@@ -176,8 +185,7 @@
 
   std::string const& GetMSBuildCommand();
 
-  cmIDEFlagTable const* LoadFlagTable(std::string const& optionsName,
-                                      std::string const& toolsetName,
+  cmIDEFlagTable const* LoadFlagTable(std::string const& toolSpecificName,
                                       std::string const& defaultName,
                                       std::string const& table) const;
 
@@ -187,6 +195,8 @@
   std::string GeneratorToolsetCustomVCTargetsDir;
   std::string GeneratorToolsetCuda;
   std::string GeneratorToolsetCudaCustomDir;
+  std::string GeneratorToolsetCudaNvccSubdir;
+  std::string GeneratorToolsetCudaVSIntegrationSubdir;
   std::string DefaultPlatformToolset;
   std::string DefaultPlatformToolsetHostArchitecture;
   std::string DefaultAndroidToolset;
@@ -230,7 +240,6 @@
 
   std::string MSBuildCommand;
   bool MSBuildCommandInitialized;
-  cmVisualStudio10ToolsetOptions ToolsetOptions;
   std::set<std::string> AndroidExecutableWarnings;
   virtual std::string FindMSBuildCommand();
   std::string FindDevEnvCommand() override;
@@ -242,6 +251,19 @@
 
   bool ParseGeneratorToolset(std::string const& ts, cmMakefile* mf);
 
+  std::string GetClFlagTableName() const;
+  std::string GetCSharpFlagTableName() const;
+  std::string GetRcFlagTableName() const;
+  std::string GetLibFlagTableName() const;
+  std::string GetLinkFlagTableName() const;
+  std::string GetMasmFlagTableName() const;
+  std::string CanonicalToolsetName(std::string const& toolset) const;
+
+  cm::optional<std::string> FindFlagTable(cm::string_view toolsetName,
+                                          cm::string_view table) const;
+
+  std::string CustomFlagTableDir;
+
   std::string CustomVCTargetsPath;
   std::string VCTargetsPath;
   bool FindVCTargetsPath(cmMakefile* mf);
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index d6cc423..7dd1704 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -991,7 +991,8 @@
       includes, genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES),
       *sf);
   }
-  lg->AppendFlags(flags, lg->GetIncludeFlags(includes, gtgt, lang, true));
+  lg->AppendFlags(flags,
+                  lg->GetIncludeFlags(includes, gtgt, lang, std::string()));
 
   cmXCodeObject* buildFile =
     this->CreateXCodeBuildFileFromPath(sf->ResolveFullPath(), gtgt, lang, sf);
@@ -2695,7 +2696,7 @@
     // GNU assembly files (#16449)
     for (auto const& language : languages) {
       std::string includeFlags = this->CurrentLocalGenerator->GetIncludeFlags(
-        includes, gtgt, language, true, false, configName);
+        includes, gtgt, language, configName);
 
       if (!includeFlags.empty()) {
         cflags[language] += " " + includeFlags;
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index bef785d..eb214fa 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -338,6 +338,7 @@
 
       // Add the names based on the current namelink mode.
       if (haveNamelink) {
+        files.NamelinkMode = this->NamelinkMode;
         // With a namelink we need to check the mode.
         if (this->NamelinkMode == NamelinkModeOnly) {
           // Install the namelink only.
diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h
index 8c5d444..84fce42 100644
--- a/Source/cmInstallTargetGenerator.h
+++ b/Source/cmInstallTargetGenerator.h
@@ -39,7 +39,6 @@
     NamelinkModeSkip
   };
   void SetNamelinkMode(NamelinkModeType mode) { this->NamelinkMode = mode; }
-  NamelinkModeType GetNamelinkMode() const { return this->NamelinkMode; }
 
   std::string GetInstallFilename(const std::string& config) const;
 
@@ -82,6 +81,7 @@
     // Prefix for all files in To.
     std::string ToDir;
 
+    NamelinkModeType NamelinkMode = NamelinkModeNone;
     bool NoTweak = false;
     bool UseSourcePermissions = false;
     cmInstallType Type = cmInstallType();
diff --git a/Source/cmJSONHelpers.h b/Source/cmJSONHelpers.h
index a63347d..6690aef 100644
--- a/Source/cmJSONHelpers.h
+++ b/Source/cmJSONHelpers.h
@@ -239,7 +239,7 @@
       if (!filter(t)) {
         continue;
       }
-      out.push_back(t);
+      out.push_back(std::move(t));
     }
     return success;
   };
diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx
index fdddb45..09cd88e 100644
--- a/Source/cmListCommand.cxx
+++ b/Source/cmListCommand.cxx
@@ -4,9 +4,7 @@
 
 #include <algorithm>
 #include <cassert>
-#include <cstddef>
 #include <cstdio>
-#include <cstdlib> // required for atoi
 #include <functional>
 #include <iterator>
 #include <set>
@@ -36,6 +34,42 @@
 
 namespace {
 
+bool GetIndexArg(const std::string& arg, int* idx, cmMakefile& mf)
+{
+  long value;
+  if (!cmStrToLong(arg, &value)) {
+    switch (mf.GetPolicyStatus(cmPolicies::CMP0121)) {
+      case cmPolicies::WARN: {
+        // Default is to warn and use old behavior OLD behavior is to allow
+        // compatibility, so issue a warning and use the previous behavior.
+        std::string warn =
+          cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0121),
+                   " Invalid list index \"", arg, "\".");
+        mf.IssueMessage(MessageType::AUTHOR_WARNING, warn);
+        break;
+      }
+      case cmPolicies::OLD:
+        // OLD behavior is to allow compatibility, so just ignore the
+        // situation.
+        break;
+      case cmPolicies::NEW:
+        return false;
+      case cmPolicies::REQUIRED_IF_USED:
+      case cmPolicies::REQUIRED_ALWAYS:
+        std::string msg =
+          cmStrCat(cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0121),
+                   " Invalid list index \"", arg, "\".");
+        mf.IssueMessage(MessageType::FATAL_ERROR, msg);
+        break;
+    }
+  }
+
+  // Truncation is happening here, but it had always been happening here.
+  *idx = static_cast<int>(value);
+
+  return true;
+}
+
 bool FilterRegex(std::vector<std::string> const& args, bool includeMatches,
                  std::string const& listName,
                  std::vector<std::string>& varArgsExpanded,
@@ -154,7 +188,11 @@
   const char* sep = "";
   size_t nitem = varArgsExpanded.size();
   for (cc = 2; cc < args.size() - 1; cc++) {
-    int item = atoi(args[cc].c_str());
+    int item;
+    if (!GetIndexArg(args[cc], &item, status.GetMakefile())) {
+      status.SetError(cmStrCat("index: ", args[cc], " is not a valid index"));
+      return false;
+    }
     value += sep;
     sep = ";";
     if (item < 0) {
@@ -362,7 +400,11 @@
   const std::string& listName = args[1];
 
   // expand the variable
-  int item = atoi(args[2].c_str());
+  int item;
+  if (!GetIndexArg(args[2], &item, status.GetMakefile())) {
+    status.SetError(cmStrCat("index: ", args[2], " is not a valid index"));
+    return false;
+  }
   std::vector<std::string> varArgsExpanded;
   if ((!GetList(varArgsExpanded, listName, status.GetMakefile()) ||
        varArgsExpanded.empty()) &&
@@ -1282,8 +1324,16 @@
     return true;
   }
 
-  const int start = atoi(args[2].c_str());
-  const int length = atoi(args[3].c_str());
+  int start;
+  int length;
+  if (!GetIndexArg(args[2], &start, status.GetMakefile())) {
+    status.SetError(cmStrCat("index: ", args[2], " is not a valid index"));
+    return false;
+  }
+  if (!GetIndexArg(args[3], &length, status.GetMakefile())) {
+    status.SetError(cmStrCat("index: ", args[3], " is not a valid index"));
+    return false;
+  }
 
   using size_type = decltype(varArgsExpanded)::size_type;
 
@@ -1338,7 +1388,11 @@
   std::vector<size_t> removed;
   size_t nitem = varArgsExpanded.size();
   for (cc = 2; cc < args.size(); ++cc) {
-    int item = atoi(args[cc].c_str());
+    int item;
+    if (!GetIndexArg(args[cc], &item, status.GetMakefile())) {
+      status.SetError(cmStrCat("index: ", args[cc], " is not a valid index"));
+      return false;
+    }
     if (item < 0) {
       item = static_cast<int>(nitem) + item;
     }
diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx
index 1464a14..5c3a034 100644
--- a/Source/cmListFileCache.cxx
+++ b/Source/cmListFileCache.cxx
@@ -7,6 +7,10 @@
 #include <sstream>
 #include <utility>
 
+#ifdef _WIN32
+#  include <cmsys/Encoding.hxx>
+#endif
+
 #include "cmListFileLexer.h"
 #include "cmMessageType.h"
 #include "cmMessenger.h"
@@ -83,9 +87,15 @@
 {
   this->FileName = filename;
 
+#ifdef _WIN32
+  std::string expandedFileName = cmsys::Encoding::ToNarrow(
+    cmSystemTools::ConvertToWindowsExtendedPath(filename));
+  filename = expandedFileName.c_str();
+#endif
+
   // Open the file.
   cmListFileLexer_BOM bom;
-  if (!cmListFileLexer_SetFileName(this->Lexer, this->FileName, &bom)) {
+  if (!cmListFileLexer_SetFileName(this->Lexer, filename, &bom)) {
     this->IssueFileOpenError("cmListFileCache: error can not open file.");
     return false;
   }
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 73b6fbc..b301c6e 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -838,16 +838,16 @@
 }
 
 std::string cmLocalGenerator::ConvertToIncludeReference(
-  std::string const& path, OutputFormat format, bool forceFullPaths)
+  std::string const& path, IncludePathStyle pathStyle, OutputFormat format)
 {
-  static_cast<void>(forceFullPaths);
+  static_cast<void>(pathStyle);
   return this->ConvertToOutputForExisting(path, format);
 }
 
 std::string cmLocalGenerator::GetIncludeFlags(
-  const std::vector<std::string>& includeDirs, cmGeneratorTarget* target,
-  const std::string& lang, bool forceFullPaths, bool forResponseFile,
-  const std::string& config)
+  std::vector<std::string> const& includeDirs, cmGeneratorTarget* target,
+  std::string const& lang, std::string const& config, bool forResponseFile,
+  IncludePathStyle pathStyle)
 {
   if (lang.empty()) {
     return "";
@@ -923,7 +923,7 @@
       flagUsed = true;
     }
     std::string includePath =
-      this->ConvertToIncludeReference(i, shellFormat, forceFullPaths);
+      this->ConvertToIncludeReference(i, pathStyle, shellFormat);
     if (quotePaths && !includePath.empty() && includePath.front() != '\"') {
       includeFlags << "\"";
     }
@@ -1527,12 +1527,12 @@
         }
 
         if (target->IsWin32Executable(config)) {
-          exeFlags +=
-            this->Makefile->GetSafeDefinition("CMAKE_CREATE_WIN32_EXE");
+          exeFlags += this->Makefile->GetSafeDefinition(
+            cmStrCat("CMAKE_", linkLanguage, "_CREATE_WIN32_EXE"));
           exeFlags += " ";
         } else {
-          exeFlags +=
-            this->Makefile->GetSafeDefinition("CMAKE_CREATE_CONSOLE_EXE");
+          exeFlags += this->Makefile->GetSafeDefinition(
+            cmStrCat("CMAKE_", linkLanguage, "_CREATE_CONSOLE_EXE"));
           exeFlags += " ";
         }
 
@@ -2701,8 +2701,9 @@
     }
 
     file << "foreach(retry RANGE 1 30)\n";
-    file << "  if (EXISTS \"" << from_file << "\" AND \"" << from_file
-         << "  \" IS_NEWER_THAN \"" << dest_file << "\")\n";
+    file << "  if (EXISTS \"" << from_file << "\" AND (NOT EXISTS \""
+         << dest_file << "\" OR NOT \"" << dest_file << "  \" IS_NEWER_THAN \""
+         << from_file << "\"))\n";
     file << "    execute_process(COMMAND ${CMAKE_COMMAND} -E copy";
     file << " \"" << from_file << "\""
          << " \"" << to_dir << "\" RESULT_VARIABLE result "
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index e48849a..f597120 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -171,13 +171,19 @@
                                             cmGeneratorTarget* target,
                                             const std::string& config,
                                             const std::string& lang);
+
+  enum class IncludePathStyle
+  {
+    Default,
+    Absolute,
+  };
+
   //! Get the include flags for the current makefile and language
-  std::string GetIncludeFlags(const std::vector<std::string>& includes,
-                              cmGeneratorTarget* target,
-                              const std::string& lang,
-                              bool forceFullPaths = false,
-                              bool forResponseFile = false,
-                              const std::string& config = "");
+  std::string GetIncludeFlags(
+    std::vector<std::string> const& includes, cmGeneratorTarget* target,
+    std::string const& lang, std::string const& config,
+    bool forResponseFile = false,
+    IncludePathStyle pathStyle = IncludePathStyle::Default);
 
   using GeneratorTargetVector =
     std::vector<std::unique_ptr<cmGeneratorTarget>>;
@@ -256,11 +262,6 @@
   bool GetRealDependency(const std::string& name, const std::string& config,
                          std::string& dep);
 
-  virtual std::string ConvertToIncludeReference(
-    std::string const& path,
-    cmOutputConverter::OutputFormat format = cmOutputConverter::SHELL,
-    bool forceFullPaths = false);
-
   /** Called from command-line hook to clear dependencies.  */
   virtual void ClearDependencies(cmMakefile* /* mf */, bool /* verbose */) {}
 
@@ -557,6 +558,13 @@
   cmProp GetRuleLauncher(cmGeneratorTarget* target, const std::string& prop);
 
 protected:
+  // The default implementation ignores the IncludePathStyle and always
+  // uses absolute paths.  A generator may override this to use relative
+  // paths in some cases.
+  virtual std::string ConvertToIncludeReference(
+    std::string const& path, IncludePathStyle pathStyle,
+    cmOutputConverter::OutputFormat format);
+
   //! put all the libraries for a target on into the given stream
   void OutputLinkLibraries(cmComputeLinkInformation* pcli,
                            cmLinkLineComputer* linkLineComputer,
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index 51ad993..c2a6410 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -97,9 +97,12 @@
       // contains any non-ASCII characters and dependency checking will fail.
       // As a workaround, leave the msvc_deps_prefix UTF-8 encoded even though
       // the rest of the file is ANSI encoded.
-      if (GetConsoleOutputCP() == CP_UTF8 && GetACP() != CP_UTF8) {
+      if (GetConsoleOutputCP() == CP_UTF8 && GetACP() != CP_UTF8 &&
+          this->GetGlobalGenerator()->GetMakefileEncoding() != codecvt::None) {
         this->GetRulesFileStream().WriteRaw(showIncludesPrefix);
       } else {
+        // Ninja 1.11 and above uses the UTF-8 code page if it's supported, so
+        // in that case we can write it normally without using raw bytes.
         this->GetRulesFileStream() << showIncludesPrefix;
       }
 #else
@@ -202,10 +205,10 @@
 // Virtual protected methods.
 
 std::string cmLocalNinjaGenerator::ConvertToIncludeReference(
-  std::string const& path, cmOutputConverter::OutputFormat format,
-  bool forceFullPaths)
+  std::string const& path, IncludePathStyle pathStyle,
+  cmOutputConverter::OutputFormat format)
 {
-  if (forceFullPaths) {
+  if (pathStyle == IncludePathStyle::Absolute) {
     return this->ConvertToOutputFormat(
       cmSystemTools::CollapseFullPath(path, this->GetCurrentBinaryDirectory()),
       format);
@@ -667,7 +670,7 @@
       cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
       customStep += hash.HashString(ninjaOutputs[0]).substr(0, 7);
 
-      std::string depfile = cc->GetDepfile();
+      std::string depfile = ccg.GetDepfile();
       if (!depfile.empty()) {
         switch (cc->GetCMP0116Status()) {
           case cmPolicies::WARN:
diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h
index 5b850f3..8b6824f 100644
--- a/Source/cmLocalNinjaGenerator.h
+++ b/Source/cmLocalNinjaGenerator.h
@@ -12,6 +12,7 @@
 
 #include "cmListFileCache.h"
 #include "cmLocalCommonGenerator.h"
+#include "cmLocalGenerator.h"
 #include "cmNinjaTypes.h"
 #include "cmOutputConverter.h"
 
@@ -91,9 +92,8 @@
 
 protected:
   std::string ConvertToIncludeReference(
-    std::string const& path,
-    cmOutputConverter::OutputFormat format = cmOutputConverter::SHELL,
-    bool forceFullPaths = false) override;
+    std::string const& path, IncludePathStyle pathStyle,
+    cmOutputConverter::OutputFormat format) override;
 
 private:
   cmGeneratedFileStream& GetImplFileStream(const std::string& config) const;
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 78cae0e..40a67a3 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -1222,7 +1222,7 @@
 
   // Each output must get its own copy of this rule.
   cmsys::RegularExpression sourceFiles(
-    "\\.(C|M|c|c\\+\\+|cc|cpp|cxx|mpp|cu|m|mm|"
+    "\\.(C|M|c|c\\+\\+|cc|cpp|cxx|mpp|ixx|cppm|cu|m|mm|"
     "rc|def|r|odl|idl|hpj|bat|h|h\\+\\+|"
     "hm|hpp|hxx|in|txx|inl)$");
 
@@ -4393,7 +4393,7 @@
 
   // Deprecate old policies, especially those that require a lot
   // of code to maintain the old behavior.
-  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0075 &&
+  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0081 &&
       !(this->GetCMakeInstance()->GetIsInTryCompile() &&
         (
           // Policies set by cmCoreTryCompile::TryCompileCode.
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index 1750e37..6783341 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -384,11 +384,14 @@
   if (this->GeneratorTarget->IsWin32Executable(
         this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"))) {
     this->LocalGenerator->AppendFlags(
-      linkFlags, this->Makefile->GetSafeDefinition("CMAKE_CREATE_WIN32_EXE"));
+      linkFlags,
+      this->Makefile->GetSafeDefinition(
+        cmStrCat("CMAKE_", linkLanguage, "_CREATE_WIN32_EXE")));
   } else {
     this->LocalGenerator->AppendFlags(
       linkFlags,
-      this->Makefile->GetSafeDefinition("CMAKE_CREATE_CONSOLE_EXE"));
+      this->Makefile->GetSafeDefinition(
+        cmStrCat("CMAKE_", linkLanguage, "_CREATE_CONSOLE_EXE")));
   }
 
   // Add symbol export flags if necessary.
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index ce64e2c..5e4f03d 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -780,9 +780,12 @@
     vars.Target = target.c_str();
     vars.LinkLibraries = linkLibs.c_str();
     vars.ObjectsQuoted = buildObjs.c_str();
+    std::string targetOutSOName;
     if (this->GeneratorTarget->HasSOName(this->GetConfigName())) {
       vars.SONameFlag = this->Makefile->GetSONameFlag(linkLanguage);
-      vars.TargetSOName = this->TargetNames.SharedObject.c_str();
+      targetOutSOName = this->LocalGenerator->ConvertToOutputFormat(
+        this->TargetNames.SharedObject.c_str(), cmOutputConverter::SHELL);
+      vars.TargetSOName = targetOutSOName.c_str();
     }
     vars.LinkFlags = linkFlags.c_str();
 
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 4918bf6..fa469ed 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -854,7 +854,7 @@
   vars.Defines = definesString.c_str();
 
   std::string includesString = this->LocalGenerator->GetIncludeFlags(
-    includes, this->GeneratorTarget, lang, true, false, config);
+    includes, this->GeneratorTarget, lang, config);
   this->LocalGenerator->AppendFlags(includesString,
                                     "$(" + lang + "_INCLUDES)");
   vars.Includes = includesString.c_str();
@@ -2195,8 +2195,8 @@
                                               lang, this->GetConfigName());
 
   std::string includeFlags = this->LocalGenerator->GetIncludeFlags(
-    includes, this->GeneratorTarget, lang, false, useResponseFile,
-    this->GetConfigName());
+    includes, this->GeneratorTarget, lang, this->GetConfigName(),
+    useResponseFile);
   if (includeFlags.empty()) {
     return;
   }
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index 49e5e4c..1d511f2 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -868,7 +868,8 @@
   if (genTarget->HasSOName(config)) {
     vars["SONAME_FLAG"] =
       this->GetMakefile()->GetSONameFlag(this->TargetLinkLanguage(config));
-    vars["SONAME"] = tgtNames.SharedObject;
+    vars["SONAME"] = localGen.ConvertToOutputFormat(tgtNames.SharedObject,
+                                                    cmOutputConverter::SHELL);
     if (genTarget->GetType() == cmStateEnums::SHARED_LIBRARY) {
       std::string install_dir =
         this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(config);
@@ -1176,7 +1177,8 @@
   }
   if (gt->HasSOName(config)) {
     vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage(config));
-    vars["SONAME"] = tgtNames.SharedObject;
+    vars["SONAME"] = localGen.ConvertToOutputFormat(tgtNames.SharedObject,
+                                                    cmOutputConverter::SHELL);
     if (targetType == cmStateEnums::SHARED_LIBRARY) {
       std::string install_dir = gt->GetInstallNameDirForBuildTree(config);
       if (!install_dir.empty()) {
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 672b579..2e0ffdb 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -263,9 +263,10 @@
                                               language, config);
   // Add include directory flags.
   std::string includeFlags = this->LocalGenerator->GetIncludeFlags(
-    includes, this->GeneratorTarget, language,
-    language == "RC", // full include paths for RC needed by cmcldeps
-    false, config);
+    includes, this->GeneratorTarget, language, config, false,
+    // full include paths for RC needed by cmcldeps
+    language == "RC" ? cmLocalGenerator::IncludePathStyle::Absolute
+                     : cmLocalGenerator::IncludePathStyle::Default);
   if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
     std::replace(includeFlags.begin(), includeFlags.end(), '\\', '/');
   }
@@ -324,7 +325,8 @@
   }
 
   std::string includesString = this->LocalGenerator->GetIncludeFlags(
-    includes, this->GeneratorTarget, language, true, false, config);
+    includes, this->GeneratorTarget, language, config, false,
+    cmLocalGenerator::IncludePathStyle::Absolute);
   this->LocalGenerator->AppendFlags(includesString,
                                     this->GetIncludes(language, config));
 
@@ -1379,8 +1381,8 @@
         cmSystemTools::GetParentDirectory(source->GetFullPath()));
 
       std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags(
-        sourceDirectory, this->GeneratorTarget, language, false, false,
-        config);
+        sourceDirectory, this->GeneratorTarget, language, config, false,
+        cmLocalGenerator::IncludePathStyle::Default);
 
       vars["INCLUDES"] = cmStrCat(sourceDirectoryFlag, ' ', vars["INCLUDES"]);
     }
diff --git a/Source/cmOrderDirectories.cxx b/Source/cmOrderDirectories.cxx
index 0369af0..68f40a9 100644
--- a/Source/cmOrderDirectories.cxx
+++ b/Source/cmOrderDirectories.cxx
@@ -359,7 +359,7 @@
   std::string const& removeExtRegex)
 {
   this->LinkExtensions = linkExtensions;
-  this->RemoveLibraryExtension.compile(removeExtRegex.c_str());
+  this->RemoveLibraryExtension.compile(removeExtRegex);
 }
 
 void cmOrderDirectories::CollectOriginalDirectories()
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 2194b0f..d546b6e 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -359,7 +359,14 @@
          3, 20, 0, cmPolicies::WARN)                                          \
   SELECT(POLICY, CMP0120,                                                     \
          "The WriteCompilerDetectionHeader module is removed.", 3, 20, 0,     \
-         cmPolicies::WARN)
+         cmPolicies::WARN)                                                    \
+  SELECT(POLICY, CMP0121,                                                     \
+         "The list() command now validates parsing of index arguments.", 3,   \
+         21, 0, cmPolicies::WARN)                                             \
+  SELECT(                                                                     \
+    POLICY, CMP0122,                                                          \
+    "UseSWIG use standard library name conventions for csharp language.", 3,  \
+    21, 0, cmPolicies::WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \
diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx
index ed32de9..acdb09f 100644
--- a/Source/cmProjectCommand.cxx
+++ b/Source/cmProjectCommand.cxx
@@ -59,6 +59,11 @@
 
   mf.AddDefinition("PROJECT_NAME", projectName);
 
+  mf.AddDefinitionBool("PROJECT_IS_TOP_LEVEL", mf.IsRootMakefile());
+  mf.AddCacheDefinition(projectName + "_IS_TOP_LEVEL",
+                        mf.IsRootMakefile() ? "ON" : "OFF",
+                        "Value Computed by CMake", cmStateEnums::STATIC);
+
   // Set the CMAKE_PROJECT_NAME variable to be the highest-level
   // project name in the tree. If there are two project commands
   // in the same CMakeLists.txt file, and it is the top level
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index a1816f1..3adeb1a 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -294,6 +294,17 @@
   return fileStream.Close();
 }
 
+void AddAutogenExecutableToDependencies(
+  cmQtAutoGenInitializer::GenVarsT const& genVars,
+  std::vector<std::string>& dependencies)
+{
+  if (genVars.ExecutableTarget != nullptr) {
+    dependencies.push_back(genVars.ExecutableTarget->Target->GetName());
+  } else if (!genVars.Executable.empty()) {
+    dependencies.push_back(genVars.Executable);
+  }
+}
+
 } // End of unnamed namespace
 
 cmQtAutoGenInitializer::cmQtAutoGenInitializer(
@@ -419,12 +430,8 @@
     cmSystemTools::ConvertToUnixSlashes(this->Dir.Work);
 
     // Include directory
-    this->ConfigFileNames(this->Dir.Include,
-                          cmStrCat(this->Dir.Build, "/include"), "");
-    this->Dir.IncludeGenExp = this->Dir.Include.Default;
-    if (this->MultiConfig) {
-      this->Dir.IncludeGenExp += "_$<CONFIG>";
-    }
+    this->ConfigFileNamesAndGenex(this->Dir.Include, this->Dir.IncludeGenExp,
+                                  cmStrCat(this->Dir.Build, "/include"), "");
   }
 
   // Moc, Uic and _autogen target settings
@@ -575,15 +582,9 @@
       cmStrCat(this->Dir.Build, "/mocs_compilation.cpp");
     this->Moc.CompilationFileGenex = this->Moc.CompilationFile.Default;
   } else {
-    this->ConfigFileNames(this->Moc.CompilationFile,
-                          cmStrCat(this->Dir.Build, "/mocs_compilation"),
-                          ".cpp");
-    if (this->MultiConfig) {
-      this->Moc.CompilationFileGenex =
-        cmStrCat(this->Dir.Build, "/mocs_compilation_$<CONFIG>.cpp"_s);
-    } else {
-      this->Moc.CompilationFileGenex = this->Moc.CompilationFile.Default;
-    }
+    this->ConfigFileNamesAndGenex(
+      this->Moc.CompilationFile, this->Moc.CompilationFileGenex,
+      cmStrCat(this->Dir.Build, "/mocs_compilation"_s), ".cpp"_s);
   }
 
   // Moc predefs
@@ -935,9 +936,35 @@
         if (!skipUic) {
           // Check if the .ui file has uic options
           std::string const uicOpts = sf->GetSafeProperty(kw.AUTOUIC_OPTIONS);
-          if (!uicOpts.empty()) {
-            this->Uic.UiFiles.emplace_back(fullPath, cmExpandedList(uicOpts));
+          if (uicOpts.empty()) {
+            this->Uic.UiFilesNoOptions.emplace_back(fullPath);
+          } else {
+            this->Uic.UiFilesWithOptions.emplace_back(fullPath,
+                                                      cmExpandedList(uicOpts));
           }
+
+          auto uiHeaderRelativePath = cmSystemTools::RelativePath(
+            this->LocalGen->GetCurrentSourceDirectory(),
+            cmSystemTools::GetFilenamePath(fullPath));
+
+          // Avoid creating a path containing adjacent slashes
+          if (!uiHeaderRelativePath.empty() &&
+              uiHeaderRelativePath.back() != '/') {
+            uiHeaderRelativePath += '/';
+          }
+
+          auto uiHeaderFilePath = cmStrCat(
+            '/', uiHeaderRelativePath, "ui_"_s,
+            cmSystemTools::GetFilenameWithoutLastExtension(fullPath), ".h"_s);
+
+          ConfigString uiHeader;
+          std::string uiHeaderGenex;
+          this->ConfigFileNamesAndGenex(
+            uiHeader, uiHeaderGenex, cmStrCat(this->Dir.Build, "/include"_s),
+            uiHeaderFilePath);
+
+          this->Uic.UiHeaders.emplace_back(
+            std::make_pair(uiHeader, uiHeaderGenex));
         } else {
           // Register skipped .ui file
           this->Uic.SkipUi.insert(fullPath);
@@ -1091,6 +1118,13 @@
     autogenByproducts.push_back(this->Moc.CompilationFileGenex);
   }
 
+  if (this->Uic.Enabled) {
+    for (const auto& file : this->Uic.UiHeaders) {
+      this->AddGeneratedSource(file.first, this->Uic);
+      autogenByproducts.push_back(file.second);
+    }
+  }
+
   // Compose target comment
   std::string autogenComment;
   {
@@ -1149,6 +1183,42 @@
                                           this->Makefile);
     }
 
+    if (!this->Uic.UiFilesNoOptions.empty() ||
+        !this->Uic.UiFilesWithOptions.empty()) {
+      // Add a generated timestamp file
+      ConfigString timestampFile;
+      std::string timestampFileGenex;
+      ConfigFileNamesAndGenex(timestampFile, timestampFileGenex,
+                              cmStrCat(this->Dir.Build, "/autouic"_s),
+                              ".stamp"_s);
+      this->AddGeneratedSource(timestampFile, this->Uic);
+
+      // Add a step in the pre-build command to touch the timestamp file
+      commandLines.push_back(
+        cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E", "touch",
+                            timestampFileGenex }));
+
+      // UIC needs to be re-run if any of the known UI files change or the
+      // executable itself has been updated
+      auto uicDependencies = this->Uic.UiFilesNoOptions;
+      for (auto const& uiFile : this->Uic.UiFilesWithOptions) {
+        uicDependencies.push_back(uiFile.first);
+      }
+      AddAutogenExecutableToDependencies(this->Uic, uicDependencies);
+
+      // Add a rule file to cause the target to build if a dependency has
+      // changed, which will trigger the pre-build command to run autogen
+      std::string no_main_dependency;
+      cmCustomCommandLines no_command_lines;
+      this->LocalGen->AddCustomCommandToOutput(
+        timestampFileGenex, uicDependencies, no_main_dependency,
+        no_command_lines, /*comment=*/"", this->Dir.Work.c_str(),
+        /*cmp0116=*/cmPolicies::NEW, /*replace=*/false,
+        /*escapeOldStyle=*/false, /*uses_terminal=*/false,
+        /*command_expand_lists=*/false, /*depfile=*/"", /*job_pool=*/"",
+        stdPipesUTF8);
+    }
+
     // Add the pre-build command directly to bypass the OBJECT_LIBRARY
     // rejection in cmMakefile::AddCustomCommandToTarget because we know
     // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case.
@@ -1241,16 +1311,8 @@
       dependencies.clear();
       dependencies.push_back(timestampTargetName);
 
-      if (this->Moc.ExecutableTarget != nullptr) {
-        dependencies.push_back(this->Moc.ExecutableTarget->Target->GetName());
-      } else if (!this->Moc.Executable.empty()) {
-        dependencies.push_back(this->Moc.Executable);
-      }
-      if (this->Uic.ExecutableTarget != nullptr) {
-        dependencies.push_back(this->Uic.ExecutableTarget->Target->GetName());
-      } else if (!this->Uic.Executable.empty()) {
-        dependencies.push_back(this->Uic.Executable);
-      }
+      AddAutogenExecutableToDependencies(this->Moc, dependencies);
+      AddAutogenExecutableToDependencies(this->Uic, dependencies);
 
       // Create the custom command that outputs the timestamp file.
       const char timestampFileName[] = "timestamp";
@@ -1589,7 +1651,7 @@
     uic_skip.insert(this->Uic.SkipUi.begin(), this->Uic.SkipUi.end());
 
     info.SetArray("UIC_SKIP", uic_skip);
-    info.SetArrayArray("UIC_UI_FILES", this->Uic.UiFiles,
+    info.SetArrayArray("UIC_UI_FILES", this->Uic.UiFilesWithOptions,
                        [](Json::Value& jval, UicT::UiFileT const& uiFile) {
                          jval.resize(2u);
                          jval[0u] = uiFile.first;
@@ -1749,6 +1811,18 @@
   }
 }
 
+void cmQtAutoGenInitializer::ConfigFileNamesAndGenex(
+  ConfigString& configString, std::string& genex, cm::string_view const prefix,
+  cm::string_view const suffix)
+{
+  this->ConfigFileNames(configString, prefix, suffix);
+  if (this->MultiConfig) {
+    genex = cmStrCat(prefix, "_$<CONFIG>"_s, suffix);
+  } else {
+    genex = configString.Default;
+  }
+}
+
 void cmQtAutoGenInitializer::ConfigFileClean(ConfigString& configString)
 {
   this->AddCleanFile(configString.Default);
diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h
index f7e126d..8a6d8f9 100644
--- a/Source/cmQtAutoGenInitializer.h
+++ b/Source/cmQtAutoGenInitializer.h
@@ -141,6 +141,8 @@
 
   void ConfigFileNames(ConfigString& configString, cm::string_view prefix,
                        cm::string_view suffix);
+  void ConfigFileNamesAndGenex(ConfigString& configString, std::string& genex,
+                               cm::string_view prefix, cm::string_view suffix);
   void ConfigFileClean(ConfigString& configString);
 
   std::string GetMocBuildPath(MUFile const& muf);
@@ -236,9 +238,12 @@
       : GenVarsT(GenT::UIC){};
 
     std::set<std::string> SkipUi;
-    std::vector<UiFileT> UiFiles;
+    std::vector<std::string> UiFilesNoOptions;
+    std::vector<UiFileT> UiFilesWithOptions;
     ConfigStrings<std::vector<std::string>> Options;
     std::vector<std::string> SearchPaths;
+    std::vector<std::pair<ConfigString /*ui header*/, std::string /*genex*/>>
+      UiHeaders;
   } Uic;
 
   /** rcc variables.  */
diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx
index 6e88e26..568926e 100644
--- a/Source/cmQtAutoGenerator.cxx
+++ b/Source/cmQtAutoGenerator.cxx
@@ -116,7 +116,7 @@
   bool success = true;
   std::string const dirName = cmSystemTools::GetFilenamePath(filename);
   if (!dirName.empty()) {
-    success = cmSystemTools::MakeDirectory(dirName);
+    success = static_cast<bool>(cmSystemTools::MakeDirectory(dirName));
   }
   return success;
 }
diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx
index f583162..e2b1ae1 100644
--- a/Source/cmQtAutoMocUic.cxx
+++ b/Source/cmQtAutoMocUic.cxx
@@ -1588,14 +1588,14 @@
   };
 
   // Vicinity of the source
-  if (findUi(cmStrCat(sourceDirPrefix, this->UiName))) {
-    return true;
-  }
   if (!includePrefix.empty()) {
     if (findUi(cmStrCat(sourceDirPrefix, includePrefix, this->UiName))) {
       return true;
     }
   }
+  if (findUi(cmStrCat(sourceDirPrefix, this->UiName))) {
+    return true;
+  }
   // Additional AUTOUIC search paths
   auto const& searchPaths = this->UicConst().SearchPaths;
   if (!searchPaths.empty()) {
diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h
index 76a5ded..32ed687 100644
--- a/Source/cmSourceFile.h
+++ b/Source/cmSourceFile.h
@@ -175,7 +175,7 @@
 #define CM_HEADER_REGEX "\\.(h|hh|h\\+\\+|hm|hpp|hxx|in|txx|inl)$"
 
 #define CM_SOURCE_REGEX                                                       \
-  "\\.(C|F|M|c|c\\+\\+|cc|cpp|mpp|cxx|cu|f|f90|for|fpp|ftn|m|mm|"             \
+  "\\.(C|F|M|c|c\\+\\+|cc|cpp|mpp|cxx|ixx|cppm|cu|f|f90|for|fpp|ftn|m|mm|"    \
   "rc|def|r|odl|idl|hpj|bat)$"
 
 #define CM_PCH_REGEX "cmake_pch(_[^.]+)?\\.(h|hxx)$"
diff --git a/Source/cmStandardLevelResolver.cxx b/Source/cmStandardLevelResolver.cxx
index bf6925e..280e508 100644
--- a/Source/cmStandardLevelResolver.cxx
+++ b/Source/cmStandardLevelResolver.cxx
@@ -308,8 +308,9 @@
 std::unordered_map<std::string, StanardLevelComputer> StandardComputerMapping =
   {
     { "C",
-      StanardLevelComputer{ "C", std::vector<int>{ 90, 99, 11 },
-                            std::vector<std::string>{ "90", "99", "11" } } },
+      StanardLevelComputer{
+        "C", std::vector<int>{ 90, 99, 11, 17, 23 },
+        std::vector<std::string>{ "90", "99", "11", "17", "23" } } },
     { "CXX",
       StanardLevelComputer{
         "CXX", std::vector<int>{ 98, 11, 14, 17, 20, 23 },
diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx
index 1e20abb..fbf47ef 100644
--- a/Source/cmStateSnapshot.cxx
+++ b/Source/cmStateSnapshot.cxx
@@ -16,16 +16,9 @@
 #include "cmState.h"
 #include "cmStateDirectory.h"
 #include "cmStatePrivate.h"
+#include "cmSystemTools.h"
 #include "cmVersion.h"
 
-#if !defined(_WIN32)
-#  include <sys/utsname.h>
-#endif
-
-#if defined(__CYGWIN__)
-#  include "cmSystemTools.h"
-#endif
-
 cmStateSnapshot::cmStateSnapshot(cmState* state)
   : State(state)
 {
@@ -292,34 +285,26 @@
 
 void cmStateSnapshot::SetDefaultDefinitions()
 {
-/* Up to CMake 2.4 here only WIN32, UNIX and APPLE were set.
-  With CMake must separate between target and host platform. In most cases
-  the tests for WIN32, UNIX and APPLE will be for the target system, so an
-  additional set of variables for the host system is required ->
-  CMAKE_HOST_WIN32, CMAKE_HOST_UNIX, CMAKE_HOST_APPLE.
-  WIN32, UNIX and APPLE are now set in the platform files in
-  Modules/Platforms/.
-  To keep cmake scripts (-P) and custom language and compiler modules
-  working, these variables are still also set here in this place, but they
-  will be reset in CMakeSystemSpecificInformation.cmake before the platform
-  files are executed. */
-#if defined(_WIN32)
-  this->SetDefinition("WIN32", "1");
-  this->SetDefinition("CMAKE_HOST_WIN32", "1");
-  this->SetDefinition("CMAKE_HOST_SYSTEM_NAME", "Windows");
-#else
-  this->SetDefinition("UNIX", "1");
-  this->SetDefinition("CMAKE_HOST_UNIX", "1");
-
-#  if defined(__ANDROID__)
-  this->SetDefinition("CMAKE_HOST_SYSTEM_NAME", "Android");
-#  else
-  struct utsname uts_name;
-  if (uname(&uts_name) >= 0) {
-    this->SetDefinition("CMAKE_HOST_SYSTEM_NAME", uts_name.sysname);
+  /* Up to CMake 2.4 here only WIN32, UNIX and APPLE were set.
+    With CMake must separate between target and host platform. In most cases
+    the tests for WIN32, UNIX and APPLE will be for the target system, so an
+    additional set of variables for the host system is required ->
+    CMAKE_HOST_WIN32, CMAKE_HOST_UNIX, CMAKE_HOST_APPLE.
+    WIN32, UNIX and APPLE are now set in the platform files in
+    Modules/Platforms/.
+    To keep cmake scripts (-P) and custom language and compiler modules
+    working, these variables are still also set here in this place, but they
+    will be reset in CMakeSystemSpecificInformation.cmake before the platform
+    files are executed. */
+  cm::string_view hostSystemName = cmSystemTools::GetSystemName();
+  this->SetDefinition("CMAKE_HOST_SYSTEM_NAME", hostSystemName);
+  if (hostSystemName == "Windows") {
+    this->SetDefinition("WIN32", "1");
+    this->SetDefinition("CMAKE_HOST_WIN32", "1");
+  } else {
+    this->SetDefinition("UNIX", "1");
+    this->SetDefinition("CMAKE_HOST_UNIX", "1");
   }
-#  endif
-#endif
 #if defined(__CYGWIN__)
   std::string legacy;
   if (cmSystemTools::GetEnv("CMAKE_LEGACY_CYGWIN_WIN32", legacy) &&
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index 23fc3e0..5fa309d 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -241,7 +241,7 @@
   status.GetMakefile().ClearMatches();
   // Compile the regular expression.
   cmsys::RegularExpression re;
-  if (!re.compile(regex.c_str())) {
+  if (!re.compile(regex)) {
     std::string e =
       "sub-command REGEX, mode MATCH failed to compile regex \"" + regex +
       "\".";
@@ -283,7 +283,7 @@
   status.GetMakefile().ClearMatches();
   // Compile the regular expression.
   cmsys::RegularExpression re;
-  if (!re.compile(regex.c_str())) {
+  if (!re.compile(regex)) {
     std::string e =
       "sub-command REGEX, mode MATCHALL failed to compile regex \"" + regex +
       "\".";
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index c1ce7ec..2b3266d 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -86,6 +86,7 @@
 #  include <unistd.h>
 
 #  include <sys/time.h>
+#  include <sys/types.h>
 #endif
 
 #if defined(_WIN32) &&                                                        \
@@ -101,6 +102,10 @@
 #  include <malloc.h> /* for malloc/free on QNX */
 #endif
 
+#if !defined(_WIN32) && !defined(__ANDROID__)
+#  include <sys/utsname.h>
+#endif
+
 namespace {
 
 cmSystemTools::InterruptCallback s_InterruptCallback;
@@ -951,21 +956,87 @@
 
 #ifdef _WIN32
 namespace {
-bool cmMoveFile(std::wstring const& oldname, std::wstring const& newname)
+bool cmMoveFile(std::wstring const& oldname, std::wstring const& newname,
+                cmSystemTools::Replace replace)
 {
   // Not only ignore any previous error, but clear any memory of it.
   SetLastError(0);
 
-  // Use MOVEFILE_REPLACE_EXISTING to replace an existing destination file.
-  return MoveFileExW(oldname.c_str(), newname.c_str(),
-                     MOVEFILE_REPLACE_EXISTING);
+  DWORD flags = 0;
+  if (replace == cmSystemTools::Replace::Yes) {
+    // Use MOVEFILE_REPLACE_EXISTING to replace an existing destination file.
+    flags = flags | MOVEFILE_REPLACE_EXISTING;
+  }
+
+  return MoveFileExW(oldname.c_str(), newname.c_str(), flags);
 }
 }
 #endif
 
+bool cmSystemTools::CopySingleFile(const std::string& oldname,
+                                   const std::string& newname)
+{
+  return cmSystemTools::CopySingleFile(oldname, newname, CopyWhen::Always) ==
+    CopyResult::Success;
+}
+
+cmSystemTools::CopyResult cmSystemTools::CopySingleFile(
+  std::string const& oldname, std::string const& newname, CopyWhen when,
+  std::string* err)
+{
+  switch (when) {
+    case CopyWhen::Always:
+      break;
+    case CopyWhen::OnlyIfDifferent:
+      if (!FilesDiffer(oldname, newname)) {
+        return CopyResult::Success;
+      }
+      break;
+  }
+
+  mode_t perm = 0;
+  cmsys::Status perms = SystemTools::GetPermissions(oldname, perm);
+
+  // If files are the same do not copy
+  if (SystemTools::SameFile(oldname, newname)) {
+    return CopyResult::Success;
+  }
+
+  cmsys::Status status;
+  status = cmsys::SystemTools::CloneFileContent(oldname, newname);
+  if (!status) {
+    // if cloning did not succeed, fall back to blockwise copy
+    status = cmsys::SystemTools::CopyFileContentBlockwise(oldname, newname);
+  }
+  if (!status) {
+    if (err) {
+      *err = status.GetString();
+    }
+    return CopyResult::Failure;
+  }
+  if (perms) {
+    status = SystemTools::SetPermissions(newname, perm);
+    if (!status) {
+      if (err) {
+        *err = status.GetString();
+      }
+      return CopyResult::Failure;
+    }
+  }
+  return CopyResult::Success;
+}
+
 bool cmSystemTools::RenameFile(const std::string& oldname,
                                const std::string& newname)
 {
+  return cmSystemTools::RenameFile(oldname, newname, Replace::Yes) ==
+    RenameResult::Success;
+}
+
+cmSystemTools::RenameResult cmSystemTools::RenameFile(
+  std::string const& oldname, std::string const& newname, Replace replace,
+  std::string* err)
+{
 #ifdef _WIN32
 #  ifndef INVALID_FILE_ATTRIBUTES
 #    define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
@@ -987,7 +1058,7 @@
     oldname_wstr, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
 
   DWORD move_last_error = 0;
-  while (!cmMoveFile(oldname_wstr, newname_wstr) && --retry.Count) {
+  while (!cmMoveFile(oldname_wstr, newname_wstr, replace) && --retry.Count) {
     move_last_error = GetLastError();
 
     // There was no error ==> the operation is not yet complete.
@@ -1003,7 +1074,13 @@
     // 3) Windows Explorer has an associated directory already opened.
     if (move_last_error != ERROR_ACCESS_DENIED &&
         move_last_error != ERROR_SHARING_VIOLATION) {
-      return false;
+      if (replace == Replace::No && move_last_error == ERROR_ALREADY_EXISTS) {
+        return RenameResult::NoReplace;
+      }
+      if (err) {
+        *err = cmsys::Status::Windows(move_last_error).GetString();
+      }
+      return RenameResult::Failure;
     }
 
     DWORD const attrs = GetFileAttributesW(newname_wstr.c_str());
@@ -1027,10 +1104,37 @@
     save_restore_file_attributes.SetPath(newname_wstr);
   }
   SetLastError(move_last_error);
-  return retry.Count > 0;
+  if (retry.Count > 0) {
+    return RenameResult::Success;
+  }
+  if (replace == Replace::No && GetLastError() == ERROR_ALREADY_EXISTS) {
+    return RenameResult::NoReplace;
+  }
+  if (err) {
+    *err = cmsys::Status::Windows_GetLastError().GetString();
+  }
+  return RenameResult::Failure;
 #else
-  /* On UNIX we have an OS-provided call to do this atomically.  */
-  return rename(oldname.c_str(), newname.c_str()) == 0;
+  // On UNIX we have OS-provided calls to create 'newname' atomically.
+  if (replace == Replace::No) {
+    if (link(oldname.c_str(), newname.c_str()) == 0) {
+      return RenameResult::Success;
+    }
+    if (errno == EEXIST) {
+      return RenameResult::NoReplace;
+    }
+    if (err) {
+      *err = cmsys::Status::POSIX_errno().GetString();
+    }
+    return RenameResult::Failure;
+  }
+  if (rename(oldname.c_str(), newname.c_str()) == 0) {
+    return RenameResult::Success;
+  }
+  if (err) {
+    *err = cmsys::Status::POSIX_errno().GetString();
+  }
+  return RenameResult::Failure;
 #endif
 }
 
@@ -3021,7 +3125,7 @@
   }
   return false;
 #else
-  return cmSystemTools::RemoveADirectory(dir);
+  return static_cast<bool>(cmSystemTools::RemoveADirectory(dir));
 #endif
 }
 
@@ -3101,3 +3205,46 @@
 
   return true;
 }
+
+cm::string_view cmSystemTools::GetSystemName()
+{
+#if defined(_WIN32)
+  return "Windows";
+#elif defined(__ANDROID__)
+  return "Android";
+#else
+  static struct utsname uts_name;
+  static bool initialized = false;
+  static cm::string_view systemName;
+  if (initialized) {
+    return systemName;
+  }
+  if (uname(&uts_name) >= 0) {
+    initialized = true;
+    systemName = uts_name.sysname;
+
+    if (cmIsOff(systemName)) {
+      systemName = "UnknownOS";
+    }
+
+    // fix for BSD/OS, remove the /
+    static const cmsys::RegularExpression bsdOsRegex("BSD.OS");
+    cmsys::RegularExpressionMatch match;
+    if (bsdOsRegex.find(uts_name.sysname, match)) {
+      systemName = "BSDOS";
+    }
+
+    // fix for GNU/kFreeBSD, remove the GNU/
+    if (systemName.find("kFreeBSD") != cm::string_view::npos) {
+      systemName = "kFreeBSD";
+    }
+
+    // fix for CYGWIN which has windows version in it
+    if (systemName.find("CYGWIN") != cm::string_view::npos) {
+      systemName = "CYGWIN";
+    }
+    return systemName;
+  }
+  return "";
+#endif
+}
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 5bbbb0c..99f20e0 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -12,6 +12,7 @@
 #include <cm/string_view>
 
 #include "cmsys/Process.h"
+#include "cmsys/Status.hxx"      // IWYU pragma: export
 #include "cmsys/SystemTools.hxx" // IWYU pragma: export
 
 #include "cmCryptoHash.h"
@@ -128,10 +129,43 @@
   static bool SimpleGlob(const std::string& glob,
                          std::vector<std::string>& files, int type = 0);
 
+  enum class CopyWhen
+  {
+    Always,
+    OnlyIfDifferent,
+  };
+  enum class CopyResult
+  {
+    Success,
+    Failure,
+  };
+
+  /** Copy a file. */
+  static bool CopySingleFile(const std::string& oldname,
+                             const std::string& newname);
+  static CopyResult CopySingleFile(std::string const& oldname,
+                                   std::string const& newname, CopyWhen when,
+                                   std::string* err = nullptr);
+
+  enum class Replace
+  {
+    Yes,
+    No,
+  };
+  enum class RenameResult
+  {
+    Success,
+    NoReplace,
+    Failure,
+  };
+
   /** Rename a file or directory within a single disk volume (atomic
       if possible).  */
   static bool RenameFile(const std::string& oldname,
                          const std::string& newname);
+  static RenameResult RenameFile(std::string const& oldname,
+                                 std::string const& newname, Replace replace,
+                                 std::string* err = nullptr);
 
   //! Rename a file if contents are different, delete the source otherwise
   static void MoveFileIfDifferent(const std::string& source,
@@ -465,6 +499,9 @@
                          const std::string& newName,
                          std::string* errorMessage = nullptr);
 
+  /** Get the system name. */
+  static cm::string_view GetSystemName();
+
 private:
   static bool s_ForceUnixPaths;
   static bool s_RunCommandHideConsole;
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 965ac3e..0255d60 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -545,7 +545,7 @@
           e1.Element(
             "CudaToolkitCustomDir",
             this->GlobalGenerator->GetPlatformToolsetCudaCustomDirString() +
-              "nvcc");
+              this->GlobalGenerator->GetPlatformToolsetCudaNvccSubdirString());
         }
       }
 
@@ -654,8 +654,9 @@
         std::string cudaPath = customDir.empty()
           ? "$(VCTargetsPath)\\BuildCustomizations\\"
           : customDir +
-            "CUDAVisualStudioIntegration\\extras\\"
-            "visual_studio_integration\\MSBuildExtensions\\";
+            this->GlobalGenerator
+              ->GetPlatformToolsetCudaVSIntegrationSubdirString() +
+            "extras\\visual_studio_integration\\MSBuildExtensions\\";
         Elem(e1, "Import")
           .Attribute("Project",
                      std::move(cudaPath) + "CUDA " +
@@ -747,8 +748,9 @@
         std::string cudaPath = customDir.empty()
           ? "$(VCTargetsPath)\\BuildCustomizations\\"
           : customDir +
-            "CUDAVisualStudioIntegration\\extras\\"
-            "visual_studio_integration\\MSBuildExtensions\\";
+            this->GlobalGenerator
+              ->GetPlatformToolsetCudaVSIntegrationSubdirString() +
+            "extras\\visual_studio_integration\\MSBuildExtensions\\";
         Elem(e1, "Import")
           .Attribute("Project",
                      std::move(cudaPath) + "CUDA " +
diff --git a/Source/cmVisualStudio10ToolsetOptions.cxx b/Source/cmVisualStudio10ToolsetOptions.cxx
deleted file mode 100644
index 7fc33e6..0000000
--- a/Source/cmVisualStudio10ToolsetOptions.cxx
+++ /dev/null
@@ -1,143 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#include "cmVisualStudio10ToolsetOptions.h"
-
-#include "cmAlgorithms.h"
-#include "cmIDEFlagTable.h"
-#include "cmVisualStudioGeneratorOptions.h"
-
-std::string cmVisualStudio10ToolsetOptions::GetClFlagTableName(
-  std::string const& name, std::string const& toolset) const
-{
-  std::string const useToolset = this->GetToolsetName(name, toolset);
-
-  if (toolset == "v142") {
-    return "v142";
-  } else if (toolset == "v141") {
-    return "v141";
-  } else if (useToolset == "v140") {
-    return "v140";
-  } else if (useToolset == "v120") {
-    return "v12";
-  } else if (useToolset == "v110") {
-    return "v11";
-  } else if (useToolset == "v100") {
-    return "v10";
-  } else {
-    return "";
-  }
-}
-
-std::string cmVisualStudio10ToolsetOptions::GetCSharpFlagTableName(
-  std::string const& name, std::string const& toolset) const
-{
-  std::string const useToolset = this->GetToolsetName(name, toolset);
-
-  if (useToolset == "v142") {
-    return "v142";
-  } else if (useToolset == "v141") {
-    return "v141";
-  } else if (useToolset == "v140") {
-    return "v140";
-  } else if (useToolset == "v120") {
-    return "v12";
-  } else if (useToolset == "v110") {
-    return "v11";
-  } else if (useToolset == "v100") {
-    return "v10";
-  } else {
-    return "";
-  }
-}
-
-std::string cmVisualStudio10ToolsetOptions::GetRcFlagTableName(
-  std::string const& name, std::string const& toolset) const
-{
-  std::string const useToolset = this->GetToolsetName(name, toolset);
-
-  if ((useToolset == "v140") || (useToolset == "v141") ||
-      (useToolset == "v142")) {
-    return "v14";
-  } else if (useToolset == "v120") {
-    return "v12";
-  } else if (useToolset == "v110") {
-    return "v11";
-  } else if (useToolset == "v100") {
-    return "v10";
-  } else {
-    return "";
-  }
-}
-
-std::string cmVisualStudio10ToolsetOptions::GetLibFlagTableName(
-  std::string const& name, std::string const& toolset) const
-{
-  std::string const useToolset = this->GetToolsetName(name, toolset);
-
-  if ((useToolset == "v140") || (useToolset == "v141") ||
-      (useToolset == "v142")) {
-    return "v14";
-  } else if (useToolset == "v120") {
-    return "v12";
-  } else if (useToolset == "v110") {
-    return "v11";
-  } else if (useToolset == "v100") {
-    return "v10";
-  } else {
-    return "";
-  }
-}
-
-std::string cmVisualStudio10ToolsetOptions::GetLinkFlagTableName(
-  std::string const& name, std::string const& toolset) const
-{
-  std::string const useToolset = this->GetToolsetName(name, toolset);
-
-  if (useToolset == "v142") {
-    return "v142";
-  } else if (useToolset == "v141") {
-    return "v141";
-  } else if (useToolset == "v140") {
-    return "v140";
-  } else if (useToolset == "v120") {
-    return "v12";
-  } else if (useToolset == "v110") {
-    return "v11";
-  } else if (useToolset == "v100") {
-    return "v10";
-  } else {
-    return "";
-  }
-}
-
-std::string cmVisualStudio10ToolsetOptions::GetMasmFlagTableName(
-  std::string const& name, std::string const& toolset) const
-{
-  std::string const useToolset = this->GetToolsetName(name, toolset);
-
-  if ((useToolset == "v140") || (useToolset == "v141") ||
-      (useToolset == "v142")) {
-    return "v14";
-  } else if (useToolset == "v120") {
-    return "v12";
-  } else if (useToolset == "v110") {
-    return "v11";
-  } else if (useToolset == "v100") {
-    return "v10";
-  } else {
-    return "";
-  }
-}
-
-std::string cmVisualStudio10ToolsetOptions::GetToolsetName(
-  std::string const& name, std::string const& toolset) const
-{
-  static_cast<void>(name);
-  std::size_t length = toolset.length();
-
-  if (cmHasLiteralSuffix(toolset, "_xp")) {
-    length -= 3;
-  }
-
-  return toolset.substr(0, length);
-}
diff --git a/Source/cmVisualStudio10ToolsetOptions.h b/Source/cmVisualStudio10ToolsetOptions.h
deleted file mode 100644
index 85cc2b6..0000000
--- a/Source/cmVisualStudio10ToolsetOptions.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* 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 <string>
-
-/** \class cmVisualStudio10ToolsetOptions
- * \brief Retrieves toolset options for MSBuild.
- *
- * cmVisualStudio10ToolsetOptions manages toolsets within MSBuild
- */
-class cmVisualStudio10ToolsetOptions
-{
-public:
-  std::string GetClFlagTableName(std::string const& name,
-                                 std::string const& toolset) const;
-  std::string GetCSharpFlagTableName(std::string const& name,
-                                     std::string const& toolset) const;
-  std::string GetRcFlagTableName(std::string const& name,
-                                 std::string const& toolset) const;
-  std::string GetLibFlagTableName(std::string const& name,
-                                  std::string const& toolset) const;
-  std::string GetLinkFlagTableName(std::string const& name,
-                                   std::string const& toolset) const;
-  std::string GetMasmFlagTableName(std::string const& name,
-                                   std::string const& toolset) const;
-  std::string GetToolsetName(std::string const& name,
-                             std::string const& toolset) const;
-};
diff --git a/Source/cmWorkingDirectory.cxx b/Source/cmWorkingDirectory.cxx
index 5700b1c..12fae12 100644
--- a/Source/cmWorkingDirectory.cxx
+++ b/Source/cmWorkingDirectory.cxx
@@ -19,7 +19,7 @@
 
 bool cmWorkingDirectory::SetDirectory(std::string const& newdir)
 {
-  if (cmSystemTools::ChangeDirectory(newdir) == 0) {
+  if (cmSystemTools::ChangeDirectory(newdir)) {
     this->ResultCode = 0;
     return true;
   }
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 4b57395..1d4bbf4 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -28,6 +28,7 @@
 
 #include "cm_sys_stat.h"
 
+#include "cmCMakePath.h"
 #include "cmCMakePresetsFile.h"
 #include "cmCommandLineArgument.h"
 #include "cmCommands.h"
@@ -208,9 +209,9 @@
     };
 
     // The "c" extension MUST precede the "C" extension.
-    setupExts(
-      this->CLikeSourceFileExtensions,
-      { "c", "C", "c++", "cc", "cpp", "cxx", "cu", "mpp", "m", "M", "mm" });
+    setupExts(this->CLikeSourceFileExtensions,
+              { "c", "C", "c++", "cc", "cpp", "cxx", "cu", "mpp", "m", "M",
+                "mm", "ixx", "cppm" });
     setupExts(this->HeaderFileExtensions,
               { "h", "hh", "h++", "hm", "hpp", "hxx", "in", "txx" });
     setupExts(this->CudaFileExtensions, { "cu" });
@@ -493,6 +494,21 @@
     return true;
   };
 
+  auto PrefixLambda = [&](std::string const& path, cmake* state) -> bool {
+    const std::string var = "CMAKE_INSTALL_PREFIX";
+    cmStateEnums::CacheEntryType type = cmStateEnums::PATH;
+    cmCMakePath absolutePath(path);
+    if (absolutePath.IsAbsolute()) {
+#ifndef CMAKE_BOOTSTRAP
+      state->UnprocessedPresetVariables.erase(var);
+#endif
+      state->ProcessCacheArg(var, path, type);
+      return true;
+    }
+    cmSystemTools::Error("Absolute paths are required for --install-prefix");
+    return false;
+  };
+
   std::vector<CommandArgument> arguments = {
     CommandArgument{ "-D", "-D must be followed with VAR=VALUE.",
                      CommandArgument::Values::One, DefineLambda },
@@ -511,8 +527,12 @@
                        state->ReadListFile(args, path);
                        return true;
                      } },
+
     CommandArgument{ "-P", "-P must be followed by a file name.",
                      CommandArgument::Values::One, ScriptLambda },
+    CommandArgument{ "--install-prefix",
+                     "No install directory specified for --install-prefix",
+                     CommandArgument::Values::One, PrefixLambda },
     CommandArgument{ "--find-package", CommandArgument::Values::Zero,
                      [&](std::string const&, cmake*) -> bool {
                        findPackageMode = true;
@@ -649,7 +669,7 @@
     this->GlobalGenerator->CreateGenerationObjects();
     const auto& lg = this->GlobalGenerator->LocalGenerators[0];
     std::string includeFlags =
-      lg->GetIncludeFlags(includeDirs, nullptr, language);
+      lg->GetIncludeFlags(includeDirs, nullptr, language, std::string());
 
     std::string definitions = mf->GetSafeDefinition("PACKAGE_DEFINITIONS");
     printf("%s %s\n", includeFlags.c_str(), definitions.c_str());
@@ -815,6 +835,9 @@
                      CommandArgument::Values::One, PlatformLambda },
     CommandArgument{ "-T", "No toolset specified for -T",
                      CommandArgument::Values::One, ToolsetLamda },
+    CommandArgument{ "--install-prefix",
+                     "No install directory specified for --install-prefix",
+                     CommandArgument::Values::One, IgnoreAndTrueLambda },
 
     CommandArgument{ "--check-build-system", CommandArgument::Values::Two,
                      [](std::string const& value, cmake* state) -> bool {
@@ -1194,11 +1217,17 @@
                                     "\": Invalid macro expansion"));
       return;
     }
+    if (!expandedPreset->ConditionResult) {
+      cmSystemTools::Error(cmStrCat("Could not use disabled preset \"",
+                                    preset->second.Unexpanded.Name, "\""));
+      return;
+    }
 
-    if (!this->State->IsCacheLoaded() && !haveBArg) {
+    if (!this->State->IsCacheLoaded() && !haveBArg &&
+        !expandedPreset->BinaryDir.empty()) {
       this->SetHomeOutputDirectory(expandedPreset->BinaryDir);
     }
-    if (!this->GlobalGenerator) {
+    if (!this->GlobalGenerator && !expandedPreset->Generator.empty()) {
       if (!this->CreateAndSetGlobalGenerator(expandedPreset->Generator,
                                              false)) {
         return;
@@ -1207,6 +1236,14 @@
     this->UnprocessedPresetVariables = expandedPreset->CacheVariables;
     this->UnprocessedPresetEnvironment = expandedPreset->Environment;
 
+    if (!expandedPreset->InstallDir.empty() &&
+        this->State->GetInitializedCacheValue("CMAKE_INSTALL_PREFIX") ==
+          nullptr) {
+      this->UnprocessedPresetVariables["CMAKE_INSTALL_PREFIX"] = {
+        "PATH", expandedPreset->InstallDir
+      };
+    }
+
     if (!expandedPreset->ArchitectureStrategy ||
         expandedPreset->ArchitectureStrategy ==
           cmCMakePresetsFile::ArchToolsetStrategy::Set) {
@@ -3133,6 +3170,14 @@
       return 1;
     }
 
+    if (!expandedPreset->ConditionResult) {
+      cmSystemTools::Error(cmStrCat("Cannot use disabled build preset in ",
+                                    this->GetHomeDirectory(), ": \"",
+                                    presetName, '"'));
+      settingsFile.PrintBuildPresetList();
+      return 1;
+    }
+
     auto configurePresetPair =
       settingsFile.ConfigurePresets.find(expandedPreset->ConfigurePreset);
     if (configurePresetPair == settingsFile.ConfigurePresets.end()) {
@@ -3159,7 +3204,9 @@
       return 1;
     }
 
-    dir = expandedConfigurePreset->BinaryDir;
+    if (!expandedConfigurePreset->BinaryDir.empty()) {
+      dir = expandedConfigurePreset->BinaryDir;
+    }
 
     this->UnprocessedPresetEnvironment = expandedPreset->Environment;
     this->ProcessPresetEnvironment();
diff --git a/Source/cmake.h b/Source/cmake.h
index 82e028c..ab2ed21 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -712,6 +712,8 @@
       "Specify toolset name if supported by generator." },                    \
     { "-A <platform-name>",                                                   \
       "Specify platform name if supported by generator." },                   \
+    { "--install-prefix <directory>",                                         \
+      "Specify install directory [CMAKE_INSTALL_PREFIX]." },                  \
     { "-Wdev", "Enable developer warnings." },                                \
     { "-Wno-dev", "Suppress developer warnings." },                           \
     { "-Werror=dev", "Make developer warnings errors." },                     \
@@ -739,6 +741,8 @@
   F(c_std_90)                                                                 \
   F(c_std_99)                                                                 \
   F(c_std_11)                                                                 \
+  F(c_std_17)                                                                 \
+  F(c_std_23)                                                                 \
   FOR_EACH_C90_FEATURE(F)                                                     \
   FOR_EACH_C99_FEATURE(F)                                                     \
   FOR_EACH_C11_FEATURE(F)
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 6713cc3..a47eccd 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -74,7 +74,7 @@
                              std::vector<std::string>::const_iterator argEnd);
 
 namespace {
-void CMakeCommandUsage(const char* program)
+void CMakeCommandUsage(std::string const& program)
 {
   std::ostringstream errorStream;
 
@@ -704,7 +704,7 @@
       } else if (args[2] == "--ignore-eol") {
         filesDiffer = cmsys::SystemTools::TextFilesDiffer(args[3], args[4]);
       } else {
-        CMakeCommandUsage(args[0].c_str());
+        CMakeCommandUsage(args[0]);
         return 2;
       }
 
@@ -1085,7 +1085,7 @@
       std::string const& directory = args[2];
       if (!cmSystemTools::FileExists(directory)) {
         cmSystemTools::Error("Directory does not exist for chdir command: " +
-                             args[2]);
+                             directory);
         return 1;
       }
 
@@ -1152,7 +1152,7 @@
                   << "\n";
         return 1;
       }
-      if (!cmSystemTools::CreateSymlink(args[2], args[3])) {
+      if (!cmSystemTools::CreateSymlink(args[2], destinationFileName)) {
         return 1;
       }
       return 0;
@@ -1161,12 +1161,12 @@
     // Command to create a hard link.  Fails on platforms not
     // supporting them.
     if (args[1] == "create_hardlink" && args.size() == 4) {
-      const char* SouceFileName = args[2].c_str();
-      const char* destinationFileName = args[3].c_str();
+      std::string const& sourceFileName = args[2];
+      std::string const& destinationFileName = args[3];
 
-      if (!cmSystemTools::FileExists(SouceFileName)) {
+      if (!cmSystemTools::FileExists(sourceFileName)) {
         std::cerr << "failed to create hard link because source path '"
-                  << SouceFileName << "' does not exist \n";
+                  << sourceFileName << "' does not exist \n";
         return 1;
       }
 
@@ -1180,7 +1180,7 @@
         return 1;
       }
 
-      if (!cmSystemTools::CreateLink(args[2], args[3])) {
+      if (!cmSystemTools::CreateLink(sourceFileName, destinationFileName)) {
         return 1;
       }
       return 0;
@@ -1560,7 +1560,7 @@
     }
   }
 
-  CMakeCommandUsage(args[0].c_str());
+  CMakeCommandUsage(args[0]);
   return 1;
 }
 
@@ -1635,7 +1635,7 @@
     cmSystemTools::RemoveFile(link);
   }
 #if defined(_WIN32) && !defined(__CYGWIN__)
-  return cmSystemTools::CopyFileAlways(file, link);
+  return static_cast<bool>(cmSystemTools::CopyFileAlways(file, link));
 #else
   std::string linktext = cmSystemTools::GetFilenameName(file);
   return cmSystemTools::CreateSymlink(linktext, link);
diff --git a/Source/ctest.cxx b/Source/ctest.cxx
index 3c331d3..a4b85ae 100644
--- a/Source/ctest.cxx
+++ b/Source/ctest.cxx
@@ -55,8 +55,9 @@
     "format of the test information and can be 'human' for the current text "
     "format or 'json-v1' for json format. Defaults to 'human'." },
   { "-L <regex>, --label-regex <regex>",
-    "Run tests with labels matching "
-    "regular expression." },
+    "Run tests with labels matching regular expression. "
+    "With multiple -L, run tests where each "
+    "regular expression matches at least one label." },
   { "-R <regex>, --tests-regex <regex>",
     "Run tests matching regular "
     "expression." },
@@ -64,8 +65,9 @@
     "Exclude tests matching regular "
     "expression." },
   { "-LE <regex>, --label-exclude <regex>",
-    "Exclude tests with labels "
-    "matching regular expression." },
+    "Exclude tests with labels matching regular expression. "
+    "With multiple -LE, exclude tests where each "
+    "regular expression matches at least one label." },
   { "-FA <regex>, --fixture-exclude-any <regex>",
     "Do not automatically "
     "add any tests for "
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt
index b0a8542..bf8543e 100644
--- a/Source/kwsys/CMakeLists.txt
+++ b/Source/kwsys/CMakeLists.txt
@@ -142,6 +142,7 @@
   set(KWSYS_USE_MD5 1)
   set(KWSYS_USE_Process 1)
   set(KWSYS_USE_RegularExpression 1)
+  set(KWSYS_USE_Status 1)
   set(KWSYS_USE_System 1)
   set(KWSYS_USE_SystemTools 1)
   set(KWSYS_USE_CommandLineArguments 1)
@@ -157,6 +158,7 @@
   set(KWSYS_USE_Directory 1)
   set(KWSYS_USE_FStream 1)
   set(KWSYS_USE_Encoding 1)
+  set(KWSYS_USE_Status 1)
 endif()
 if(KWSYS_USE_Glob)
   set(KWSYS_USE_Directory 1)
@@ -177,6 +179,7 @@
 endif()
 if(KWSYS_USE_Directory)
   set(KWSYS_USE_Encoding 1)
+  set(KWSYS_USE_Status 1)
 endif()
 if(KWSYS_USE_DynamicLoader)
   set(KWSYS_USE_Encoding 1)
@@ -630,7 +633,7 @@
 # Add selected C++ classes.
 set(cppclasses
   Directory DynamicLoader Encoding Glob RegularExpression SystemTools
-  CommandLineArguments FStream SystemInformation ConsoleBuf
+  CommandLineArguments FStream SystemInformation ConsoleBuf Status
   )
 foreach(cpp ${cppclasses})
   if(KWSYS_USE_${cpp})
@@ -963,6 +966,7 @@
     # C++ tests
     set(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS}
       testConfigure.cxx
+      testStatus.cxx
       testSystemTools.cxx
       testCommandLineArguments.cxx
       testCommandLineArguments1.cxx
diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx
index 0c2190a..2e8aa83 100644
--- a/Source/kwsys/Directory.cxx
+++ b/Source/kwsys/Directory.cxx
@@ -94,7 +94,7 @@
 
 namespace KWSYS_NAMESPACE {
 
-bool Directory::Load(const std::string& name, std::string* errorMessage)
+Status Directory::Load(std::string const& name, std::string* errorMessage)
 {
   this->Clear();
   intptr_t srchHandle;
@@ -121,7 +121,11 @@
   delete[] buf;
 
   if (srchHandle == -1) {
-    return 0;
+    Status status = Status::POSIX_errno();
+    if (errorMessage) {
+      *errorMessage = status.GetString();
+    }
+    return status;
   }
 
   // Loop through names
@@ -129,7 +133,14 @@
     this->Internal->Files.push_back(Encoding::ToNarrow(data.name));
   } while (_wfindnext(srchHandle, &data) != -1);
   this->Internal->Path = name;
-  return _findclose(srchHandle) != -1;
+  if (_findclose(srchHandle) == -1) {
+    Status status = Status::POSIX_errno();
+    if (errorMessage) {
+      *errorMessage = status.GetString();
+    }
+    return status;
+  }
+  return Status::Success();
 }
 
 unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name,
@@ -152,6 +163,20 @@
   delete[] buf;
 
   if (srchHandle == -1) {
+    if (errorMessage) {
+      if (unsigned int errorId = GetLastError()) {
+        LPSTR message = nullptr;
+        DWORD size = FormatMessageA(
+          FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+            FORMAT_MESSAGE_IGNORE_INSERTS,
+          nullptr, errorId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+          (LPSTR)&message, 0, nullptr);
+        *errorMessage = std::string(message, size);
+        LocalFree(message);
+      } else {
+        *errorMessage = "Unknown error.";
+      }
+    }
     return 0;
   }
 
@@ -192,7 +217,7 @@
 
 namespace KWSYS_NAMESPACE {
 
-bool Directory::Load(const std::string& name, std::string* errorMessage)
+Status Directory::Load(std::string const& name, std::string* errorMessage)
 {
   this->Clear();
 
@@ -203,7 +228,7 @@
     if (errorMessage != nullptr) {
       *errorMessage = std::string(strerror(errno));
     }
-    return false;
+    return Status::POSIX_errno();
   }
 
   errno = 0;
@@ -214,12 +239,12 @@
     if (errorMessage != nullptr) {
       *errorMessage = std::string(strerror(errno));
     }
-    return false;
+    return Status::POSIX_errno();
   }
 
   this->Internal->Path = name;
   closedir(dir);
-  return true;
+  return Status::Success();
 }
 
 unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name,
diff --git a/Source/kwsys/Directory.hxx.in b/Source/kwsys/Directory.hxx.in
index 7bc9db0..d501116 100644
--- a/Source/kwsys/Directory.hxx.in
+++ b/Source/kwsys/Directory.hxx.in
@@ -4,6 +4,7 @@
 #define @KWSYS_NAMESPACE@_Directory_hxx
 
 #include <@KWSYS_NAMESPACE@/Configure.h>
+#include <@KWSYS_NAMESPACE@/Status.hxx>
 
 #include <string>
 
@@ -32,10 +33,9 @@
 
   /**
    * Load the specified directory and load the names of the files
-   * in that directory. 0 is returned if the directory can not be
-   * opened, 1 if it is opened.
+   * in that directory.
    */
-  bool Load(const std::string&, std::string* errorMessage = nullptr);
+  Status Load(std::string const&, std::string* errorMessage = nullptr);
 
   /**
    * Return the number of files in the current directory.
diff --git a/Source/kwsys/Glob.hxx.in b/Source/kwsys/Glob.hxx.in
index e8474e2..fd39775 100644
--- a/Source/kwsys/Glob.hxx.in
+++ b/Source/kwsys/Glob.hxx.in
@@ -54,6 +54,9 @@
   Glob();
   ~Glob();
 
+  Glob(const Glob&) = delete;
+  void operator=(const Glob&) = delete;
+
   //! Find all files that match the pattern.
   bool FindFiles(const std::string& inexpr, GlobMessages* messages = nullptr);
 
@@ -124,10 +127,6 @@
   std::vector<std::string> VisitedSymlinks;
   bool ListDirs;
   bool RecurseListDirs;
-
-private:
-  Glob(const Glob&) = delete;
-  void operator=(const Glob&) = delete;
 };
 
 } // namespace @KWSYS_NAMESPACE@
diff --git a/Source/kwsys/Status.cxx b/Source/kwsys/Status.cxx
new file mode 100644
index 0000000..503d1e1
--- /dev/null
+++ b/Source/kwsys/Status.cxx
@@ -0,0 +1,60 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Status.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#  include "Status.hxx.in"
+#endif
+
+#include <cerrno>
+#include <cstring>
+#include <string>
+
+#if defined(_WIN32)
+#  include <windows.h>
+#endif
+
+namespace KWSYS_NAMESPACE {
+
+Status Status::POSIX_errno()
+{
+  return Status::POSIX(errno);
+}
+
+#ifdef _WIN32
+Status Status::Windows_GetLastError()
+{
+  return Status::Windows(GetLastError());
+}
+#endif
+
+std::string Status::GetString() const
+{
+  std::string err;
+  switch (this->Kind_) {
+    case Kind::Success:
+      err = "Success";
+      break;
+    case Kind::POSIX:
+      err = strerror(this->POSIX_);
+      break;
+#ifdef _WIN32
+    case Kind::Windows: {
+      LPSTR message = NULL;
+      DWORD size = FormatMessageA(
+        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+          FORMAT_MESSAGE_IGNORE_INSERTS,
+        NULL, this->Windows_, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+        (LPSTR)&message, 0, NULL);
+      err = std::string(message, size);
+      LocalFree(message);
+    } break;
+#endif
+  };
+  return err;
+}
+
+} // namespace KWSYS_NAMESPACE
diff --git a/Source/kwsys/Status.hxx.in b/Source/kwsys/Status.hxx.in
new file mode 100644
index 0000000..feb5b84
--- /dev/null
+++ b/Source/kwsys/Status.hxx.in
@@ -0,0 +1,101 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifndef @KWSYS_NAMESPACE@_Status_hxx
+#define @KWSYS_NAMESPACE@_Status_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#include <string>
+
+namespace @KWSYS_NAMESPACE@ {
+
+/** \class Status
+ * \brief OS-specific status of a system operation.
+ */
+class @KWSYS_NAMESPACE@_EXPORT Status
+{
+public:
+  enum class Kind
+  {
+    Success,
+    POSIX,
+#ifdef _WIN32
+    Windows,
+#endif
+  };
+
+  /** Construct with kind "Success".  */
+  Status() = default;
+
+  /** Construct with kind "Success".  */
+  static Status Success() { return Status(); }
+
+  /** Construct with kind "POSIX" using given errno-style value.  */
+  static Status POSIX(int e)
+  {
+    Status s(Kind::POSIX);
+    s.POSIX_ = e;
+    return s;
+  }
+
+  /** Construct with kind "POSIX" using errno.  */
+  static Status POSIX_errno();
+
+#ifdef _WIN32
+  /** Construct with kind "Windows" using given GetLastError()-style value.  */
+  static Status Windows(unsigned int e)
+  {
+    Status s(Kind::Windows);
+    s.Windows_ = e;
+    return s;
+  }
+
+  /** Construct with kind "Windows" using GetLastError().  */
+  static Status Windows_GetLastError();
+#endif
+
+  /** Return true on "Success", false otherwise.  */
+  explicit operator bool() const { return this->Kind_ == Kind::Success; }
+
+  /** Return the kind of status.  */
+  Kind GetKind() const { return this->Kind_; }
+
+  /** If the kind is "POSIX", returns the errno-style value.
+      Otherwise, returns 0.  */
+  int GetPOSIX() const
+  {
+    return this->Kind_ == Kind::POSIX ? this->POSIX_ : 0;
+  }
+
+#ifdef _WIN32
+  /** If the kind is "Windows", returns the GetLastError()-style value.
+      Otherwise, returns 0.  */
+  int GetWindows() const
+  {
+    return this->Kind_ == Kind::Windows ? this->Windows_ : 0;
+  }
+#endif
+
+  /** Return a human-readable description of the status.  */
+  std::string GetString() const;
+
+private:
+  Status(Kind kind)
+    : Kind_(kind)
+  {
+  }
+
+  Kind Kind_ = Kind::Success;
+
+  union
+  {
+    int POSIX_;
+#ifdef _WIN32
+    unsigned int Windows_;
+#endif
+  };
+};
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index 6144d9c..2518845 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -244,7 +244,7 @@
   return _wchdir(KWSYS_NAMESPACE::Encoding::ToWide(dir).c_str());
 }
 inline void Realpath(const std::string& path, std::string& resolved_path,
-                     std::string* errorMessage = 0)
+                     std::string* errorMessage = nullptr)
 {
   std::wstring tmp = KWSYS_NAMESPACE::Encoding::ToWide(path);
   wchar_t* ptemp;
@@ -882,21 +882,24 @@
 #endif
 }
 
-bool SystemTools::MakeDirectory(const char* path, const mode_t* mode)
+Status SystemTools::MakeDirectory(const char* path, const mode_t* mode)
 {
   if (!path) {
-    return false;
+    return Status::POSIX(EINVAL);
   }
   return SystemTools::MakeDirectory(std::string(path), mode);
 }
 
-bool SystemTools::MakeDirectory(const std::string& path, const mode_t* mode)
+Status SystemTools::MakeDirectory(std::string const& path, const mode_t* mode)
 {
-  if (SystemTools::PathExists(path)) {
-    return SystemTools::FileIsDirectory(path);
-  }
   if (path.empty()) {
-    return false;
+    return Status::POSIX(EINVAL);
+  }
+  if (SystemTools::PathExists(path)) {
+    if (SystemTools::FileIsDirectory(path)) {
+      return Status::Success();
+    }
+    return Status::POSIX(EEXIST);
   }
   std::string dir = path;
   SystemTools::ConvertToUnixSlashes(dir);
@@ -914,15 +917,11 @@
     ++pos;
   }
   topdir = dir;
-  if (Mkdir(topdir, mode) != 0) {
-    // if it is some other error besides directory exists
-    // then return false
-    if (errno != EEXIST) {
-      return false;
-    }
+  if (Mkdir(topdir, mode) != 0 && errno != EEXIST) {
+    return Status::POSIX_errno();
   }
 
-  return true;
+  return Status::Success();
 }
 
 // replace replace with with as many times as it shows up in source.
@@ -1411,18 +1410,18 @@
 #endif
 }
 
-bool SystemTools::Touch(const std::string& filename, bool create)
+Status SystemTools::Touch(std::string const& filename, bool create)
 {
   if (!SystemTools::FileExists(filename)) {
     if (create) {
       FILE* file = Fopen(filename, "a+b");
       if (file) {
         fclose(file);
-        return true;
+        return Status::Success();
       }
-      return false;
+      return Status::POSIX_errno();
     } else {
-      return true;
+      return Status::Success();
     }
   }
 #if defined(_WIN32) && !defined(__CYGWIN__)
@@ -1430,31 +1429,32 @@
                          FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, 0,
                          OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
   if (!h) {
-    return false;
+    return Status::Windows_GetLastError();
   }
   FILETIME mtime;
   GetSystemTimeAsFileTime(&mtime);
   if (!SetFileTime(h, 0, 0, &mtime)) {
+    Status status = Status::Windows_GetLastError();
     CloseHandle(h);
-    return false;
+    return status;
   }
   CloseHandle(h);
 #elif KWSYS_CXX_HAS_UTIMENSAT
   // utimensat is only available on newer Unixes and macOS 10.13+
   if (utimensat(AT_FDCWD, filename.c_str(), nullptr, 0) < 0) {
-    return false;
+    return Status::POSIX_errno();
   }
 #else
   // fall back to utimes
   if (utimes(filename.c_str(), nullptr) < 0) {
-    return false;
+    return Status::POSIX_errno();
   }
 #endif
-  return true;
+  return Status::Success();
 }
 
-bool SystemTools::FileTimeCompare(const std::string& f1, const std::string& f2,
-                                  int* result)
+Status SystemTools::FileTimeCompare(std::string const& f1,
+                                    std::string const& f2, int* result)
 {
   // Default to same time.
   *result = 0;
@@ -1462,11 +1462,11 @@
   // POSIX version.  Use stat function to get file modification time.
   struct stat s1;
   if (stat(f1.c_str(), &s1) != 0) {
-    return false;
+    return Status::POSIX_errno();
   }
   struct stat s2;
   if (stat(f2.c_str(), &s2) != 0) {
-    return false;
+    return Status::POSIX_errno();
   }
 #  if KWSYS_CXX_STAT_HAS_ST_MTIM
   // Compare using nanosecond resolution.
@@ -1504,17 +1504,17 @@
   WIN32_FILE_ATTRIBUTE_DATA f2d;
   if (!GetFileAttributesExW(Encoding::ToWindowsExtendedPath(f1).c_str(),
                             GetFileExInfoStandard, &f1d)) {
-    return false;
+    return Status::Windows_GetLastError();
   }
   if (!GetFileAttributesExW(Encoding::ToWindowsExtendedPath(f2).c_str(),
                             GetFileExInfoStandard, &f2d)) {
-    return false;
+    return Status::Windows_GetLastError();
   }
 
   // Compare the file times using resolution provided by system call.
   *result = (int)CompareFileTime(&f1d.ftLastWriteTime, &f2d.ftLastWriteTime);
 #endif
-  return true;
+  return Status::Success();
 }
 
 // Return a capitalized string (i.e the first letter is uppercased, all other
@@ -2129,8 +2129,8 @@
   return new_destination + '/' + SystemTools::GetFilenameName(source);
 }
 
-bool SystemTools::CopyFileIfDifferent(const std::string& source,
-                                      const std::string& destination)
+Status SystemTools::CopyFileIfDifferent(std::string const& source,
+                                        std::string const& destination)
 {
   // special check for a destination that is a directory
   // FilesDiffer does not handle file to directory compare
@@ -2147,7 +2147,7 @@
     }
   }
   // at this point the files must be the same so return true
-  return true;
+  return Status::Success();
 }
 
 #define KWSYS_ST_BUFFER 4096
@@ -2273,16 +2273,13 @@
   return false;
 }
 
-/**
- * Blockwise copy source to destination file
- */
-static bool CopyFileContentBlockwise(const std::string& source,
-                                     const std::string& destination)
+Status SystemTools::CopyFileContentBlockwise(std::string const& source,
+                                             std::string const& destination)
 {
   // Open files
   kwsys::ifstream fin(source.c_str(), std::ios::in | std::ios::binary);
   if (!fin) {
-    return false;
+    return Status::POSIX_errno();
   }
 
   // try and remove the destination file so that read only destination files
@@ -2294,7 +2291,7 @@
   kwsys::ofstream fout(destination.c_str(),
                        std::ios::out | std::ios::trunc | std::ios::binary);
   if (!fout) {
-    return false;
+    return Status::POSIX_errno();
   }
 
   // This copy loop is very sensitive on certain platforms with
@@ -2323,10 +2320,10 @@
   fout.close();
 
   if (!fout) {
-    return false;
+    return Status::POSIX_errno();
   }
 
-  return true;
+  return Status::Success();
 }
 
 /**
@@ -2341,13 +2338,13 @@
  * - The underlying filesystem does not support file cloning
  * - An unspecified error occurred
  */
-static bool CloneFileContent(const std::string& source,
-                             const std::string& destination)
+Status SystemTools::CloneFileContent(std::string const& source,
+                                     std::string const& destination)
 {
 #if defined(__linux) && defined(FICLONE)
   int in = open(source.c_str(), O_RDONLY);
   if (in < 0) {
-    return false;
+    return Status::POSIX_errno();
   }
 
   SystemTools::RemoveFile(destination);
@@ -2355,38 +2352,42 @@
   int out =
     open(destination.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
   if (out < 0) {
+    Status status = Status::POSIX_errno();
     close(in);
-    return false;
+    return status;
   }
 
-  int result = ioctl(out, FICLONE, in);
+  Status status = Status::Success();
+  if (ioctl(out, FICLONE, in) < 0) {
+    status = Status::POSIX_errno();
+  }
   close(in);
   close(out);
 
-  if (result < 0) {
-    return false;
-  }
-
-  return true;
+  return status;
 #else
   (void)source;
   (void)destination;
-  return false;
+  return Status::POSIX(ENOSYS);
 #endif
 }
 
 /**
  * Copy a file named by "source" to the file named by "destination".
  */
-bool SystemTools::CopyFileAlways(const std::string& source,
-                                 const std::string& destination)
+Status SystemTools::CopyFileAlways(std::string const& source,
+                                   std::string const& destination)
 {
+  Status status;
   mode_t perm = 0;
-  bool perms = SystemTools::GetPermissions(source, perm);
+  Status perms = SystemTools::GetPermissions(source, perm);
   std::string real_destination = destination;
 
   if (SystemTools::FileIsDirectory(source)) {
-    SystemTools::MakeDirectory(destination);
+    status = SystemTools::MakeDirectory(destination);
+    if (!status) {
+      return status;
+    }
   } else {
     // If destination is a directory, try to create a file with the same
     // name as the source in that directory.
@@ -2403,30 +2404,34 @@
     }
     // If files are the same do not copy
     if (SystemTools::SameFile(source, real_destination)) {
-      return true;
+      return status;
     }
 
     // Create destination directory
-
-    SystemTools::MakeDirectory(destination_dir);
-
-    if (!CloneFileContent(source, real_destination)) {
-      // if cloning did not succeed, fall back to blockwise copy
-      if (!CopyFileContentBlockwise(source, real_destination)) {
-        return false;
+    if (!destination_dir.empty()) {
+      status = SystemTools::MakeDirectory(destination_dir);
+      if (!status) {
+        return status;
       }
     }
+
+    status = SystemTools::CloneFileContent(source, real_destination);
+    // if cloning did not succeed, fall back to blockwise copy
+    if (!status) {
+      status = SystemTools::CopyFileContentBlockwise(source, real_destination);
+    }
+    if (!status) {
+      return status;
+    }
   }
   if (perms) {
-    if (!SystemTools::SetPermissions(real_destination, perm)) {
-      return false;
-    }
+    status = SystemTools::SetPermissions(real_destination, perm);
   }
-  return true;
+  return status;
 }
 
-bool SystemTools::CopyAFile(const std::string& source,
-                            const std::string& destination, bool always)
+Status SystemTools::CopyAFile(std::string const& source,
+                              std::string const& destination, bool always)
 {
   if (always) {
     return SystemTools::CopyFileAlways(source, destination);
@@ -2439,18 +2444,21 @@
  * Copy a directory content from "source" directory to the directory named by
  * "destination".
  */
-bool SystemTools::CopyADirectory(const std::string& source,
-                                 const std::string& destination, bool always)
+Status SystemTools::CopyADirectory(std::string const& source,
+                                   std::string const& destination, bool always)
 {
+  Status status;
   Directory dir;
-  if (dir.Load(source) == 0) {
-    return false;
+  status = dir.Load(source);
+  if (!status) {
+    return status;
   }
-  size_t fileNum;
-  if (!SystemTools::MakeDirectory(destination)) {
-    return false;
+  status = SystemTools::MakeDirectory(destination);
+  if (!status) {
+    return status;
   }
-  for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) {
+
+  for (size_t fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) {
     if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") != 0 &&
         strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), "..") != 0) {
       std::string fullPath = source;
@@ -2460,18 +2468,20 @@
         std::string fullDestPath = destination;
         fullDestPath += "/";
         fullDestPath += dir.GetFile(static_cast<unsigned long>(fileNum));
-        if (!SystemTools::CopyADirectory(fullPath, fullDestPath, always)) {
-          return false;
+        status = SystemTools::CopyADirectory(fullPath, fullDestPath, always);
+        if (!status) {
+          return status;
         }
       } else {
-        if (!SystemTools::CopyAFile(fullPath, destination, always)) {
-          return false;
+        status = SystemTools::CopyAFile(fullPath, destination, always);
+        if (!status) {
+          return status;
         }
       }
     }
   }
 
-  return true;
+  return status;
 }
 
 // return size of file; also returns zero if no file exists
@@ -2553,26 +2563,26 @@
   return strerror(e);
 }
 
-bool SystemTools::RemoveFile(const std::string& source)
+Status SystemTools::RemoveFile(std::string const& source)
 {
 #ifdef _WIN32
   std::wstring const& ws = Encoding::ToWindowsExtendedPath(source);
   if (DeleteFileW(ws.c_str())) {
-    return true;
+    return Status::Success();
   }
   DWORD err = GetLastError();
   if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
-    return true;
+    return Status::Success();
   }
   if (err != ERROR_ACCESS_DENIED) {
-    return false;
+    return Status::Windows(err);
   }
   /* The file may be read-only.  Try adding write permission.  */
   mode_t mode;
   if (!SystemTools::GetPermissions(source, mode) ||
       !SystemTools::SetPermissions(source, S_IWRITE)) {
     SetLastError(err);
-    return false;
+    return Status::Windows(err);
   }
 
   const DWORD DIRECTORY_SOFT_LINK_ATTRS =
@@ -2581,26 +2591,29 @@
   if (attrs != INVALID_FILE_ATTRIBUTES &&
       (attrs & DIRECTORY_SOFT_LINK_ATTRS) == DIRECTORY_SOFT_LINK_ATTRS &&
       RemoveDirectoryW(ws.c_str())) {
-    return true;
+    return Status::Success();
   }
   if (DeleteFileW(ws.c_str()) || GetLastError() == ERROR_FILE_NOT_FOUND ||
       GetLastError() == ERROR_PATH_NOT_FOUND) {
-    return true;
+    return Status::Success();
   }
   /* Try to restore the original permissions.  */
   SystemTools::SetPermissions(source, mode);
   SetLastError(err);
-  return false;
+  return Status::Windows(err);
 #else
-  return unlink(source.c_str()) == 0 || errno == ENOENT;
+  if (unlink(source.c_str()) != 0 && errno != ENOENT) {
+    return Status::POSIX_errno();
+  }
+  return Status::Success();
 #endif
 }
 
-bool SystemTools::RemoveADirectory(const std::string& source)
+Status SystemTools::RemoveADirectory(std::string const& source)
 {
   // Add write permission to the directory so we can modify its
   // content to remove files and directories from it.
-  mode_t mode;
+  mode_t mode = 0;
   if (SystemTools::GetPermissions(source, mode)) {
 #if defined(_WIN32) && !defined(__CYGWIN__)
     mode |= S_IWRITE;
@@ -2610,8 +2623,13 @@
     SystemTools::SetPermissions(source, mode);
   }
 
+  Status status;
   Directory dir;
-  dir.Load(source);
+  status = dir.Load(source);
+  if (!status) {
+    return status;
+  }
+
   size_t fileNum;
   for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) {
     if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") != 0 &&
@@ -2621,18 +2639,23 @@
       fullPath += dir.GetFile(static_cast<unsigned long>(fileNum));
       if (SystemTools::FileIsDirectory(fullPath) &&
           !SystemTools::FileIsSymlink(fullPath)) {
-        if (!SystemTools::RemoveADirectory(fullPath)) {
-          return false;
+        status = SystemTools::RemoveADirectory(fullPath);
+        if (!status) {
+          return status;
         }
       } else {
-        if (!SystemTools::RemoveFile(fullPath)) {
-          return false;
+        status = SystemTools::RemoveFile(fullPath);
+        if (!status) {
+          return status;
         }
       }
     }
   }
 
-  return (Rmdir(source) == 0);
+  if (Rmdir(source) != 0) {
+    status = Status::POSIX_errno();
+  }
+  return status;
 }
 
 /**
@@ -3026,44 +3049,49 @@
 }
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
-bool SystemTools::CreateSymlink(const std::string&, const std::string&)
+Status SystemTools::CreateSymlink(std::string const&, std::string const&)
 {
-  return false;
+  return Status::Windows(ERROR_NOT_SUPPORTED);
 }
 #else
-bool SystemTools::CreateSymlink(const std::string& origName,
-                                const std::string& newName)
+Status SystemTools::CreateSymlink(std::string const& origName,
+                                  std::string const& newName)
 {
-  return symlink(origName.c_str(), newName.c_str()) >= 0;
+  if (symlink(origName.c_str(), newName.c_str()) < 0) {
+    return Status::POSIX_errno();
+  }
+  return Status::Success();
 }
 #endif
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
-bool SystemTools::ReadSymlink(const std::string&, std::string&)
+Status SystemTools::ReadSymlink(std::string const&, std::string&)
 {
-  return false;
+  return Status::Windows(ERROR_NOT_SUPPORTED);
 }
 #else
-bool SystemTools::ReadSymlink(const std::string& newName,
-                              std::string& origName)
+Status SystemTools::ReadSymlink(std::string const& newName,
+                                std::string& origName)
 {
   char buf[KWSYS_SYSTEMTOOLS_MAXPATH + 1];
   int count = static_cast<int>(
     readlink(newName.c_str(), buf, KWSYS_SYSTEMTOOLS_MAXPATH));
-  if (count >= 0) {
-    // Add null-terminator.
-    buf[count] = 0;
-    origName = buf;
-    return true;
-  } else {
-    return false;
+  if (count < 0) {
+    return Status::POSIX_errno();
   }
+  // Add null-terminator.
+  buf[count] = 0;
+  origName = buf;
+  return Status::Success();
 }
 #endif
 
-int SystemTools::ChangeDirectory(const std::string& dir)
+Status SystemTools::ChangeDirectory(std::string const& dir)
 {
-  return Chdir(dir);
+  if (Chdir(dir) < 0) {
+    return Status::POSIX_errno();
+  }
+  return Status::Success();
 }
 
 std::string SystemTools::GetCurrentWorkingDirectory()
@@ -3929,7 +3957,7 @@
 
 bool SystemToolsStatic::FileIsFullPath(const char* in_name, size_t len)
 {
-#if defined(_WIN32) || defined(__CYGWIN__)
+#if defined(_WIN32) && !defined(__CYGWIN__)
   // On Windows, the name must be at least two characters long.
   if (len < 2) {
     return false;
@@ -3960,7 +3988,8 @@
   return false;
 }
 
-bool SystemTools::GetShortPath(const std::string& path, std::string& shortPath)
+Status SystemTools::GetShortPath(std::string const& path,
+                                 std::string& shortPath)
 {
 #if defined(_WIN32) && !defined(__CYGWIN__)
   std::string tempPath = path; // create a buffer
@@ -3980,14 +4009,14 @@
   }
 
   if (ret == 0) {
-    return false;
+    return Status::Windows_GetLastError();
   } else {
     shortPath = Encoding::ToNarrow(&buffer[0]);
-    return true;
+    return Status::Success();
   }
 #else
   shortPath = path;
-  return true;
+  return Status::Success();
 #endif
 }
 
@@ -4088,21 +4117,21 @@
   return width;
 }
 
-bool SystemTools::GetPermissions(const char* file, mode_t& mode)
+Status SystemTools::GetPermissions(const char* file, mode_t& mode)
 {
   if (!file) {
-    return false;
+    return Status::POSIX(EINVAL);
   }
   return SystemTools::GetPermissions(std::string(file), mode);
 }
 
-bool SystemTools::GetPermissions(const std::string& file, mode_t& mode)
+Status SystemTools::GetPermissions(std::string const& file, mode_t& mode)
 {
 #if defined(_WIN32)
   DWORD attr =
     GetFileAttributesW(Encoding::ToWindowsExtendedPath(file).c_str());
   if (attr == INVALID_FILE_ATTRIBUTES) {
-    return false;
+    return Status::Windows_GetLastError();
   }
   if ((attr & FILE_ATTRIBUTE_READONLY) != 0) {
     mode = (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6));
@@ -4125,27 +4154,27 @@
 #else
   struct stat st;
   if (stat(file.c_str(), &st) < 0) {
-    return false;
+    return Status::POSIX_errno();
   }
   mode = st.st_mode;
 #endif
-  return true;
+  return Status::Success();
 }
 
-bool SystemTools::SetPermissions(const char* file, mode_t mode,
-                                 bool honor_umask)
+Status SystemTools::SetPermissions(const char* file, mode_t mode,
+                                   bool honor_umask)
 {
   if (!file) {
-    return false;
+    return Status::POSIX(EINVAL);
   }
   return SystemTools::SetPermissions(std::string(file), mode, honor_umask);
 }
 
-bool SystemTools::SetPermissions(const std::string& file, mode_t mode,
-                                 bool honor_umask)
+Status SystemTools::SetPermissions(std::string const& file, mode_t mode,
+                                   bool honor_umask)
 {
   if (!SystemTools::PathExists(file)) {
-    return false;
+    return Status::POSIX(ENOENT);
   }
   if (honor_umask) {
     mode_t currentMask = umask(0);
@@ -4158,10 +4187,10 @@
   if (chmod(file.c_str(), mode) < 0)
 #endif
   {
-    return false;
+    return Status::POSIX_errno();
   }
 
-  return true;
+  return Status::Success();
 }
 
 std::string SystemTools::GetParentDirectory(const std::string& fileOrDir)
diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in
index 74dc176..e5d115e 100644
--- a/Source/kwsys/SystemTools.hxx.in
+++ b/Source/kwsys/SystemTools.hxx.in
@@ -4,6 +4,7 @@
 #define @KWSYS_NAMESPACE@_SystemTools_hxx
 
 #include <@KWSYS_NAMESPACE@/Configure.hxx>
+#include <@KWSYS_NAMESPACE@/Status.hxx>
 
 #include <iosfwd>
 #include <map>
@@ -339,7 +340,7 @@
   /**
      Change the modification time or create a file
   */
-  static bool Touch(const std::string& filename, bool create);
+  static Status Touch(std::string const& filename, bool create);
 
   /**
    *  Compare file modification times.
@@ -347,8 +348,8 @@
    *  When true is returned, result has -1, 0, +1 for
    *  f1 older, same, or newer than f2.
    */
-  static bool FileTimeCompare(const std::string& f1, const std::string& f2,
-                              int* result);
+  static Status FileTimeCompare(std::string const& f1, std::string const& f2,
+                                int* result);
 
   /**
    *  Get the file extension (including ".") needed for an executable
@@ -507,7 +508,7 @@
    * For windows return the short path for the given path,
    * Unix just a pass through
    */
-  static bool GetShortPath(const std::string& path, std::string& result);
+  static Status GetShortPath(std::string const& path, std::string& result);
 
   /**
    * Read line from file. Make sure to read a full line and truncates it if
@@ -553,16 +554,16 @@
    * can make a full path even if none of the directories existed
    * prior to calling this function.
    */
-  static bool MakeDirectory(const char* path, const mode_t* mode = nullptr);
-  static bool MakeDirectory(const std::string& path,
-                            const mode_t* mode = nullptr);
+  static Status MakeDirectory(const char* path, const mode_t* mode = nullptr);
+  static Status MakeDirectory(std::string const& path,
+                              const mode_t* mode = nullptr);
 
   /**
    * Copy the source file to the destination file only
    * if the two files differ.
    */
-  static bool CopyFileIfDifferent(const std::string& source,
-                                  const std::string& destination);
+  static Status CopyFileIfDifferent(std::string const& source,
+                                    std::string const& destination);
 
   /**
    * Compare the contents of two files.  Return true if different
@@ -578,6 +579,17 @@
                               const std::string& path2);
 
   /**
+   * Blockwise copy source to destination file
+   */
+  static Status CopyFileContentBlockwise(std::string const& source,
+                                         std::string const& destination);
+  /**
+   * Clone the source file to the destination file
+   */
+  static Status CloneFileContent(std::string const& source,
+                                 std::string const& destination);
+
+  /**
    * Return true if the two files are the same file
    */
   static bool SameFile(const std::string& file1, const std::string& file2);
@@ -585,16 +597,16 @@
   /**
    * Copy a file.
    */
-  static bool CopyFileAlways(const std::string& source,
-                             const std::string& destination);
+  static Status CopyFileAlways(std::string const& source,
+                               std::string const& destination);
 
   /**
    * Copy a file.  If the "always" argument is true the file is always
    * copied.  If it is false, the file is copied only if it is new or
    * has changed.
    */
-  static bool CopyAFile(const std::string& source,
-                        const std::string& destination, bool always = true);
+  static Status CopyAFile(std::string const& source,
+                          std::string const& destination, bool always = true);
 
   /**
    * Copy content directory to another directory with all files and
@@ -602,19 +614,19 @@
    * always copied.  If it is false, only files that have changed or
    * are new are copied.
    */
-  static bool CopyADirectory(const std::string& source,
-                             const std::string& destination,
-                             bool always = true);
+  static Status CopyADirectory(std::string const& source,
+                               std::string const& destination,
+                               bool always = true);
 
   /**
    * Remove a file
    */
-  static bool RemoveFile(const std::string& source);
+  static Status RemoveFile(std::string const& source);
 
   /**
    * Remove a directory
    */
-  static bool RemoveADirectory(const std::string& source);
+  static Status RemoveADirectory(std::string const& source);
 
   /**
    * Get the maximum full file path length
@@ -708,14 +720,14 @@
    * Create a symbolic link if the platform supports it.  Returns whether
    * creation succeeded.
    */
-  static bool CreateSymlink(const std::string& origName,
-                            const std::string& newName);
+  static Status CreateSymlink(std::string const& origName,
+                              std::string const& newName);
 
   /**
    * Read the contents of a symbolic link.  Returns whether reading
    * succeeded.
    */
-  static bool ReadSymlink(const std::string& newName, std::string& origName);
+  static Status ReadSymlink(std::string const& newName, std::string& origName);
 
   /**
    * Try to locate the file 'filename' in the directory 'dir'.
@@ -765,12 +777,12 @@
    * WARNING:  A non-thread-safe method is currently used to get the umask
    * if a honor_umask parameter is set to true.
    */
-  static bool GetPermissions(const char* file, mode_t& mode);
-  static bool GetPermissions(const std::string& file, mode_t& mode);
-  static bool SetPermissions(const char* file, mode_t mode,
-                             bool honor_umask = false);
-  static bool SetPermissions(const std::string& file, mode_t mode,
-                             bool honor_umask = false);
+  static Status GetPermissions(const char* file, mode_t& mode);
+  static Status GetPermissions(std::string const& file, mode_t& mode);
+  static Status SetPermissions(const char* file, mode_t mode,
+                               bool honor_umask = false);
+  static Status SetPermissions(std::string const& file, mode_t mode,
+                               bool honor_umask = false);
 
   /** -----------------------------------------------------------------
    *               Time Manipulation Routines
@@ -867,7 +879,7 @@
   /**
    * Change directory to the directory specified
    */
-  static int ChangeDirectory(const std::string& dir);
+  static Status ChangeDirectory(std::string const& dir);
 
   /**
    * Get the result of strerror(errno)
diff --git a/Source/kwsys/Terminal.c b/Source/kwsys/Terminal.c
index 4d1b46c..9409d1b 100644
--- a/Source/kwsys/Terminal.c
+++ b/Source/kwsys/Terminal.c
@@ -10,7 +10,7 @@
 #endif
 
 /* Configure support for this platform.  */
-#if defined(_WIN32) || defined(__CYGWIN__)
+#if defined(_WIN32)
 #  define KWSYS_TERMINAL_SUPPORT_CONSOLE
 #endif
 #if !defined(_WIN32)
diff --git a/Source/kwsys/testDirectory.cxx b/Source/kwsys/testDirectory.cxx
index eb3ca32..06a22dc 100644
--- a/Source/kwsys/testDirectory.cxx
+++ b/Source/kwsys/testDirectory.cxx
@@ -88,7 +88,7 @@
 
   errorMessage = "foo";
   // Increment res failure if directory lists
-  res += testdir.Load(testdirpath, &errorMessage);
+  res += testdir.Load(testdirpath, &errorMessage) ? 1 : 0;
 #if !defined(_WIN32) || defined(__CYGWIN__)
   // Increment res failure if errorMessage is unmodified
   res += (errorMessage == "foo");
@@ -120,7 +120,7 @@
     std::cerr << destination << " shouldn't exist before test" << std::endl;
     return 2;
   }
-  const bool copysuccess = SystemTools::CopyADirectory(source, destination);
+  const Status copysuccess = SystemTools::CopyADirectory(source, destination);
   const bool destinationexists = SystemTools::PathExists(destination);
   if (copysuccess) {
     std::cerr << "CopyADirectory should have returned false" << std::endl;
diff --git a/Source/kwsys/testStatus.cxx b/Source/kwsys/testStatus.cxx
new file mode 100644
index 0000000..f85ef42
--- /dev/null
+++ b/Source/kwsys/testStatus.cxx
@@ -0,0 +1,117 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Status.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+#  include "Status.hxx.in"
+#endif
+
+#include <cerrno>
+#include <iostream>
+
+#ifdef _WIN32
+#  include <windows.h>
+#endif
+
+int testStatus(int, char* [])
+{
+  bool res = true;
+  {
+    kwsys::Status status;
+    if (status.GetKind() != kwsys::Status::Kind::Success) {
+      std::cerr << "Status default constructor does not produce Success\n";
+      res = false;
+    }
+
+    status = kwsys::Status::Success();
+    if (status.GetKind() != kwsys::Status::Kind::Success) {
+      std::cerr << "Status Success constructor does not produce Success\n";
+      res = false;
+    }
+    if (!status) {
+      std::cerr << "Status Success kind is not true\n";
+      res = false;
+    }
+    if (status.GetPOSIX() != 0) {
+      std::cerr << "Status Success kind does not return POSIX 0\n";
+      res = false;
+    }
+#ifdef _WIN32
+    if (status.GetWindows() != 0) {
+      std::cerr << "Status Success kind does not return Windows 0\n";
+      res = false;
+    }
+#endif
+    if (status.GetString() != "Success") {
+      std::cerr << "Status Success kind does not return \"Success\" string\n";
+      res = false;
+    }
+
+    status = kwsys::Status::POSIX(EINVAL);
+    if (status.GetKind() != kwsys::Status::Kind::POSIX) {
+      std::cerr << "Status POSIX constructor does not produce POSIX\n";
+      res = false;
+    }
+    if (status) {
+      std::cerr << "Status POSIX kind is not false\n";
+      res = false;
+    }
+    if (status.GetPOSIX() != EINVAL) {
+      std::cerr << "Status POSIX kind does not preserve POSIX value\n";
+      res = false;
+    }
+#ifdef _WIN32
+    if (status.GetWindows() != 0) {
+      std::cerr << "Status POSIX kind does not return Windows 0\n";
+      res = false;
+    }
+#endif
+    if (status.GetString().empty()) {
+      std::cerr << "Status POSIX kind returns empty string\n";
+      res = false;
+    }
+    errno = ENOENT;
+    status = kwsys::Status::POSIX_errno();
+    if (status.GetPOSIX() != ENOENT) {
+      std::cerr << "Status POSIX_errno did not use errno\n";
+      res = false;
+    }
+    errno = 0;
+
+#ifdef _WIN32
+    status = kwsys::Status::Windows(ERROR_INVALID_PARAMETER);
+    if (status.GetKind() != kwsys::Status::Kind::Windows) {
+      std::cerr << "Status Windows constructor does not produce Windows\n";
+      res = false;
+    }
+    if (status) {
+      std::cerr << "Status Windows kind is not false\n";
+      res = false;
+    }
+    if (status.GetWindows() != ERROR_INVALID_PARAMETER) {
+      std::cerr << "Status Windows kind does not preserve Windows value\n";
+      res = false;
+    }
+    if (status.GetPOSIX() != 0) {
+      std::cerr << "Status Windows kind does not return POSIX 0\n";
+      res = false;
+    }
+    if (status.GetString().empty()) {
+      std::cerr << "Status Windows kind returns empty string\n";
+      res = false;
+    }
+
+    SetLastError(ERROR_FILE_NOT_FOUND);
+    status = kwsys::Status::Windows_GetLastError();
+    if (status.GetWindows() != ERROR_FILE_NOT_FOUND) {
+      std::cerr << "Status Windows_GetLastError did not use GetLastError()\n";
+      res = false;
+    }
+    SetLastError(ERROR_SUCCESS);
+#endif
+  }
+  return res ? 0 : 1;
+}
diff --git a/Tests/BundleGeneratorTest/CMakeLists.txt b/Tests/BundleGeneratorTest/CMakeLists.txt
index 037df09..cf7e2ce 100644
--- a/Tests/BundleGeneratorTest/CMakeLists.txt
+++ b/Tests/BundleGeneratorTest/CMakeLists.txt
@@ -1,6 +1,6 @@
 project(BundleGeneratorTest)
 
-cmake_minimum_required(VERSION 2.7)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Build a shared library and install it in lib/
 add_library(Library SHARED Library.cxx)
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 8e7c04f..d6a20bc 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -25,14 +25,14 @@
 include(${CMAKE_CURRENT_SOURCE_DIR}/CheckSwift.cmake)
 
 # Fake a user home directory to avoid polluting the real one.
-if(DEFINED ENV{HOME} AND NOT CTEST_NO_TEST_HOME)
+if(NOT CTEST_NO_TEST_HOME AND (NOT WIN32 OR DEFINED ENV{HOME}))
   set(TEST_HOME "${CMake_BINARY_DIR}/Tests/CMakeFiles/TestHome")
   file(MAKE_DIRECTORY "${TEST_HOME}")
   file(WRITE "${TEST_HOME}/.cvspass" ":pserver:anoncvs@www.cmake.org:/cvsroot/KWSys A\n")
   set(TEST_HOME_ENV_CODE "# Fake a user home directory to avoid polluting the real one.
 # But provide original ENV{HOME} value in ENV{CTEST_REAL_HOME} for tests that
 # need access to the real HOME directory.
-if(NOT DEFINED ENV{CTEST_REAL_HOME})
+if(DEFINED ENV{HOME} AND NOT DEFINED ENV{CTEST_REAL_HOME})
   set(ENV{CTEST_REAL_HOME} \"\$ENV{HOME}\")
 endif()
 set(ENV{HOME} \"${TEST_HOME}\")
@@ -96,7 +96,7 @@
   # some old versions of make simply cannot handle spaces in paths
   if (MAKE_IS_GNU OR
       CMAKE_MAKE_PROGRAM MATCHES "nmake|gmake|wmake" OR
-      CMAKE_GENERATOR MATCHES "Visual Studio|Xcode|Borland")
+      CMAKE_GENERATOR MATCHES "Visual Studio|Xcode|Borland|Ninja")
     set(MAKE_SUPPORTS_SPACES 1)
   else()
     set(MAKE_SUPPORTS_SPACES 0)
@@ -804,6 +804,7 @@
     ${build_generator_args}
     --build-project Framework
     --build-options
+      -DMAKE_SUPPORTS_SPACES=${MAKE_SUPPORTS_SPACES}
     "-DCMAKE_INSTALL_PREFIX:PATH=${CMake_BINARY_DIR}/Tests/Framework/Install"
     --test-command bar)
   list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Framework")
@@ -828,6 +829,8 @@
     ${build_generator_args}
     --build-project LibName
     --build-exe-dir "${CMake_BINARY_DIR}/Tests/LibName/lib"
+    --build-options
+      -DMAKE_SUPPORTS_SPACES=${MAKE_SUPPORTS_SPACES}
     --test-command foobar
     )
   list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/LibName")
@@ -1421,6 +1424,7 @@
             CURL
             Cups
             Doxygen
+            DevIL
             EnvModules
             EXPAT
             Fontconfig
@@ -1693,7 +1697,7 @@
       ${build_generator_args}
       --build-project ${import_name}
       --build-options
-      "-DCMAKE_PREFIX_PATH:PATH=${install_dir}/lib/cmake")
+      "-DCMAKE_PREFIX_PATH:PATH=${install_dir}")
     set_tests_properties(${import_test_name} PROPERTIES DEPENDS ${export_test_name})
     list(APPEND TEST_BUILD_DIRS "${import_build_dir}")
   endfunction()
diff --git a/Tests/CMakeOnly/CheckCXXSymbolExists/CMakeLists.txt b/Tests/CMakeOnly/CheckCXXSymbolExists/CMakeLists.txt
index 2028a13..2784e3b 100644
--- a/Tests/CMakeOnly/CheckCXXSymbolExists/CMakeLists.txt
+++ b/Tests/CMakeOnly/CheckCXXSymbolExists/CMakeLists.txt
@@ -9,7 +9,7 @@
 
 project(CheckCXXSymbolExists CXX)
 
-cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
+cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR)
 
 set(CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/../CheckSymbolExists")
 
diff --git a/Tests/CMakeOnly/CheckLanguage/CMakeLists.txt b/Tests/CMakeOnly/CheckLanguage/CMakeLists.txt
index 1570c37..2e5d8d3 100644
--- a/Tests/CMakeOnly/CheckLanguage/CMakeLists.txt
+++ b/Tests/CMakeOnly/CheckLanguage/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.8)
+cmake_minimum_required (VERSION 2.8.12)
 project(CheckLanguage NONE)
 include(CheckLanguage)
 
diff --git a/Tests/CMakeOnly/CheckSymbolExists/CMakeLists.txt b/Tests/CMakeOnly/CheckSymbolExists/CMakeLists.txt
index 7f01463..9a9bb2a 100644
--- a/Tests/CMakeOnly/CheckSymbolExists/CMakeLists.txt
+++ b/Tests/CMakeOnly/CheckSymbolExists/CMakeLists.txt
@@ -9,7 +9,7 @@
 
 project(CheckSymbolExists C)
 
-cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
+cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR)
 
 set(CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}")
 
diff --git a/Tests/CMakeOnly/LinkInterfaceLoop/CMakeLists.txt b/Tests/CMakeOnly/LinkInterfaceLoop/CMakeLists.txt
index 56e449a..d66eb06 100644
--- a/Tests/CMakeOnly/LinkInterfaceLoop/CMakeLists.txt
+++ b/Tests/CMakeOnly/LinkInterfaceLoop/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.8)
+cmake_minimum_required (VERSION 2.8.12)
 project(LinkInterfaceLoop C)
 
 # Add a shared library that incorrectly names itself as a
diff --git a/Tests/CMakeOnly/TargetScope/CMakeLists.txt b/Tests/CMakeOnly/TargetScope/CMakeLists.txt
index fa5d8e2..faf2250 100644
--- a/Tests/CMakeOnly/TargetScope/CMakeLists.txt
+++ b/Tests/CMakeOnly/TargetScope/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.8)
+cmake_minimum_required (VERSION 2.8.12)
 project(TargetScope NONE)
 
 add_subdirectory(Sub)
diff --git a/Tests/CMakeTests/CMakeLists.txt b/Tests/CMakeTests/CMakeLists.txt
index 6bbbe7d..52959e6 100644
--- a/Tests/CMakeTests/CMakeLists.txt
+++ b/Tests/CMakeTests/CMakeLists.txt
@@ -7,6 +7,7 @@
   add_test(NAME CMake.${TestName}
     COMMAND ${CMAKE_EXECUTABLE} ${PreArgs}
     -P "${CMAKE_CURRENT_BINARY_DIR}/${TestName}Test.cmake" ${ARGN})
+  set_tests_properties("CMake.${TestName}" PROPERTIES LABELS "CMake;command")
 endmacro()
 
 
diff --git a/Tests/CPackComponents/CMakeLists.txt b/Tests/CPackComponents/CMakeLists.txt
index 5b03c9e..c1b348e 100644
--- a/Tests/CPackComponents/CMakeLists.txt
+++ b/Tests/CPackComponents/CMakeLists.txt
@@ -4,7 +4,7 @@
 # application (mylibapp). We create a binary installer that allows
 # users to select which pieces will be installed: the example
 # application, the library binaries, and/or the header file.
-cmake_minimum_required(VERSION 2.6)
+cmake_minimum_required(VERSION 2.8.12)
 project(CPackComponents)
 
 # Create the mylib library
diff --git a/Tests/CTestTest2/test.cmake.in b/Tests/CTestTest2/test.cmake.in
index a9bbc52..d5d4d2f 100644
--- a/Tests/CTestTest2/test.cmake.in
+++ b/Tests/CTestTest2/test.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestBadExe/test.cmake.in b/Tests/CTestTestBadExe/test.cmake.in
index 43a8572..dd180f0 100644
--- a/Tests/CTestTestBadExe/test.cmake.in
+++ b/Tests/CTestTestBadExe/test.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestChecksum/test.cmake.in b/Tests/CTestTestChecksum/test.cmake.in
index 2a435d2..3bac0e0 100644
--- a/Tests/CTestTestChecksum/test.cmake.in
+++ b/Tests/CTestTestChecksum/test.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestCostSerial/test.cmake.in b/Tests/CTestTestCostSerial/test.cmake.in
index 9b32a46..1c46d4c 100644
--- a/Tests/CTestTestCostSerial/test.cmake.in
+++ b/Tests/CTestTestCostSerial/test.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestCrash/CMakeLists.txt b/Tests/CTestTestCrash/CMakeLists.txt
index 77986df..663d2e4 100644
--- a/Tests/CTestTestCrash/CMakeLists.txt
+++ b/Tests/CTestTestCrash/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(CTestTestCrash)
 include(CTest)
 
diff --git a/Tests/CTestTestCrash/test.cmake.in b/Tests/CTestTestCrash/test.cmake.in
index 3641cb0..916d4e9 100644
--- a/Tests/CTestTestCrash/test.cmake.in
+++ b/Tests/CTestTestCrash/test.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestCycle/CMakeLists.txt b/Tests/CTestTestCycle/CMakeLists.txt
index 6ba6b8c..19f4dd7 100644
--- a/Tests/CTestTestCycle/CMakeLists.txt
+++ b/Tests/CTestTestCycle/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(CTestTestCycle)
 include(CTest)
 
diff --git a/Tests/CTestTestCycle/test.cmake.in b/Tests/CTestTestCycle/test.cmake.in
index 4a63dd6..507d46b 100644
--- a/Tests/CTestTestCycle/test.cmake.in
+++ b/Tests/CTestTestCycle/test.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestDepends/CMakeLists.txt b/Tests/CTestTestDepends/CMakeLists.txt
index 5cd6d66..462ad8c 100644
--- a/Tests/CTestTestDepends/CMakeLists.txt
+++ b/Tests/CTestTestDepends/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(CTestTestDepends)
 include(CTest)
 
diff --git a/Tests/CTestTestDepends/test.cmake.in b/Tests/CTestTestDepends/test.cmake.in
index 74fddb3..11bc92a 100644
--- a/Tests/CTestTestDepends/test.cmake.in
+++ b/Tests/CTestTestDepends/test.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestFailure/CMakeLists.txt b/Tests/CTestTestFailure/CMakeLists.txt
index 01fbb2c..db14b3d 100644
--- a/Tests/CTestTestFailure/CMakeLists.txt
+++ b/Tests/CTestTestFailure/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(CTestTestFailure)
 include(CTest)
 
diff --git a/Tests/CTestTestFailure/testNoBuild.cmake.in b/Tests/CTestTestFailure/testNoBuild.cmake.in
index 86333af..47d254f 100644
--- a/Tests/CTestTestFailure/testNoBuild.cmake.in
+++ b/Tests/CTestTestFailure/testNoBuild.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestFailure/testNoExe.cmake.in b/Tests/CTestTestFailure/testNoExe.cmake.in
index 8875cee..8496c80 100644
--- a/Tests/CTestTestFailure/testNoExe.cmake.in
+++ b/Tests/CTestTestFailure/testNoExe.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestLabelRegExp/test.cmake.in b/Tests/CTestTestLabelRegExp/test.cmake.in
index 5c0c9d7..dd40c3b 100644
--- a/Tests/CTestTestLabelRegExp/test.cmake.in
+++ b/Tests/CTestTestLabelRegExp/test.cmake.in
@@ -27,11 +27,15 @@
 expect_test_list("test2.*test3.*Total Tests: 2" --label-regex bar)
 expect_test_list("test1.*test2.*test3.*Total Tests: 3" --label-regex foo|bar)
 expect_test_list("Total Tests: 0" --label-regex baz)
+expect_test_list("Total Tests: 0" --label-regex foo --label-regex baz)
+expect_test_list("test3.*Total Tests: 1" --label-regex foo --label-regex bar)
 
 expect_test_list("test2.*Total Tests: 1" --label-exclude foo)
 expect_test_list("test1.*Total Tests: 1" --label-exclude bar)
 expect_test_list("Total Tests: 0" --label-exclude foo|bar)
 expect_test_list("test1.*test2.*test3.*Total Tests: 3" --label-exclude baz)
+expect_test_list("test1.*test2.*Total Tests: 2" --label-exclude foo --label-exclude bar)
+expect_test_list("test1.*test2.*test3.*Total Tests: 3" --label-exclude foo --label-exclude baz)
 
 expect_test_list("test1.*Total Tests: 1" --label-regex foo --label-exclude bar)
 expect_test_list("test2.*Total Tests: 1" --label-regex bar --label-exclude foo)
diff --git a/Tests/CTestTestParallel/CMakeLists.txt b/Tests/CTestTestParallel/CMakeLists.txt
index e47085a..819fee4 100644
--- a/Tests/CTestTestParallel/CMakeLists.txt
+++ b/Tests/CTestTestParallel/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(CTestTestParallel)
 include(CTest)
 
diff --git a/Tests/CTestTestParallel/test.cmake.in b/Tests/CTestTestParallel/test.cmake.in
index 045a4ca..517db72 100644
--- a/Tests/CTestTestParallel/test.cmake.in
+++ b/Tests/CTestTestParallel/test.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestResourceLock/CMakeLists.txt b/Tests/CTestTestResourceLock/CMakeLists.txt
index 4001643..4bc4366 100644
--- a/Tests/CTestTestResourceLock/CMakeLists.txt
+++ b/Tests/CTestTestResourceLock/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(CTestTestResourceLock)
 include(CTest)
 
diff --git a/Tests/CTestTestResourceLock/test.cmake.in b/Tests/CTestTestResourceLock/test.cmake.in
index 67dde18..826226d 100644
--- a/Tests/CTestTestResourceLock/test.cmake.in
+++ b/Tests/CTestTestResourceLock/test.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestScheduler/CMakeLists.txt b/Tests/CTestTestScheduler/CMakeLists.txt
index ccd7b2c..a3f0f27 100644
--- a/Tests/CTestTestScheduler/CMakeLists.txt
+++ b/Tests/CTestTestScheduler/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project (CTestTestScheduler)
 include (CTest)
 
diff --git a/Tests/CTestTestScheduler/test.cmake.in b/Tests/CTestTestScheduler/test.cmake.in
index f8c8ab7..5dcfb63 100644
--- a/Tests/CTestTestScheduler/test.cmake.in
+++ b/Tests/CTestTestScheduler/test.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestSkipReturnCode/test.cmake.in b/Tests/CTestTestSkipReturnCode/test.cmake.in
index 112b0cd..2988d2f 100644
--- a/Tests/CTestTestSkipReturnCode/test.cmake.in
+++ b/Tests/CTestTestSkipReturnCode/test.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestStopTime/CMakeLists.txt b/Tests/CTestTestStopTime/CMakeLists.txt
index bd8bebd..08116e2 100644
--- a/Tests/CTestTestStopTime/CMakeLists.txt
+++ b/Tests/CTestTestStopTime/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(CTestTestStopTime)
 include(CTest)
 
diff --git a/Tests/CTestTestStopTime/test.cmake.in b/Tests/CTestTestStopTime/test.cmake.in
index d3a9a4a..3797d40 100644
--- a/Tests/CTestTestStopTime/test.cmake.in
+++ b/Tests/CTestTestStopTime/test.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestSubdir/CMakeLists.txt b/Tests/CTestTestSubdir/CMakeLists.txt
index b7cc7e2..87c4604 100644
--- a/Tests/CTestTestSubdir/CMakeLists.txt
+++ b/Tests/CTestTestSubdir/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(CTestTestSubdir)
 include(CTest)
 
diff --git a/Tests/CTestTestSubdir/test.cmake.in b/Tests/CTestTestSubdir/test.cmake.in
index 8b3957b..3b1fb5f 100644
--- a/Tests/CTestTestSubdir/test.cmake.in
+++ b/Tests/CTestTestSubdir/test.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestTimeout/test.cmake.in b/Tests/CTestTestTimeout/test.cmake.in
index 4b5157e..ce9c497 100644
--- a/Tests/CTestTestTimeout/test.cmake.in
+++ b/Tests/CTestTestTimeout/test.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestUpload/CMakeLists.txt b/Tests/CTestTestUpload/CMakeLists.txt
index 90d811c..5e02b2f 100644
--- a/Tests/CTestTestUpload/CMakeLists.txt
+++ b/Tests/CTestTestUpload/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(CTestTestUpload)
 
 add_executable (Sleep sleep.c)
diff --git a/Tests/CTestTestUpload/test.cmake.in b/Tests/CTestTestUpload/test.cmake.in
index 701439d..74fd1ec 100644
--- a/Tests/CTestTestUpload/test.cmake.in
+++ b/Tests/CTestTestUpload/test.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestVerboseOutput/CMakeLists.txt b/Tests/CTestTestVerboseOutput/CMakeLists.txt
index 4cdd29c..3792385 100644
--- a/Tests/CTestTestVerboseOutput/CMakeLists.txt
+++ b/Tests/CTestTestVerboseOutput/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(CTestTestVerboseOutput)
 include(CTest)
 
diff --git a/Tests/CTestTestVerboseOutput/test.cmake.in b/Tests/CTestTestVerboseOutput/test.cmake.in
index 7f49548..9c9a4dc 100644
--- a/Tests/CTestTestVerboseOutput/test.cmake.in
+++ b/Tests/CTestTestVerboseOutput/test.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CTestTestZeroTimeout/CMakeLists.txt b/Tests/CTestTestZeroTimeout/CMakeLists.txt
index 4d2b79d..2d404c8 100644
--- a/Tests/CTestTestZeroTimeout/CMakeLists.txt
+++ b/Tests/CTestTestZeroTimeout/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project (CTestTestZeroTimeout)
 include (CTest)
 
diff --git a/Tests/CTestTestZeroTimeout/test.cmake.in b/Tests/CTestTestZeroTimeout/test.cmake.in
index b829fef..50dbba0 100644
--- a/Tests/CTestTestZeroTimeout/test.cmake.in
+++ b/Tests/CTestTestZeroTimeout/test.cmake.in
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.4)
+cmake_minimum_required(VERSION 2.8.12)
 
 # Settings:
 set(CTEST_DASHBOARD_ROOT                "@CMake_BINARY_DIR@/Tests/CTestTest")
diff --git a/Tests/CheckFortran.cmake b/Tests/CheckFortran.cmake
index 33e1bfb..36293f5 100644
--- a/Tests/CheckFortran.cmake
+++ b/Tests/CheckFortran.cmake
@@ -7,7 +7,7 @@
   message(STATUS ${_desc})
   file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CheckFortran)
   file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CheckFortran/CMakeLists.txt"
-    "cmake_minimum_required(VERSION 2.4)
+    "cmake_minimum_required(VERSION 2.8.12)
 project(CheckFortran Fortran)
 file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\"
   \"set(CMAKE_Fortran_COMPILER \\\"\${CMAKE_Fortran_COMPILER}\\\")\\n\"
diff --git a/Tests/CompileFeatures/CMakeLists.txt b/Tests/CompileFeatures/CMakeLists.txt
index cff98e3..20988ac 100644
--- a/Tests/CompileFeatures/CMakeLists.txt
+++ b/Tests/CompileFeatures/CMakeLists.txt
@@ -18,7 +18,7 @@
   endif()
 endmacro()
 
-if(NOT CMAKE_C_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IntelLLVM)$")
+if(NOT CMAKE_C_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IntelLLVM|Fujitsu|FujitsuClang)$")
   get_property(c_features GLOBAL PROPERTY CMAKE_C_KNOWN_FEATURES)
   list(FILTER c_features EXCLUDE REGEX "^c_std_[0-9][0-9]")
   foreach(feature ${c_features})
@@ -26,7 +26,7 @@
   endforeach()
 endif()
 
-if(NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IntelLLVM)$")
+if(NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IntelLLVM|Fujitsu|FujitsuClang)$")
   get_property(cxx_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
   list(FILTER cxx_features EXCLUDE REGEX "^cxx_std_[0-9][0-9]")
   foreach(feature ${cxx_features})
@@ -237,6 +237,8 @@
     if (std_flag_idx EQUAL -1)
       add_executable(default_dialect_C default_dialect.c)
       target_compile_definitions(default_dialect_C PRIVATE
+        DEFAULT_C23=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},23>
+        DEFAULT_C17=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},17>
         DEFAULT_C11=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},11>
         DEFAULT_C99=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},99>
         DEFAULT_C90=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},90>
diff --git a/Tests/CompileFeatures/default_dialect.c b/Tests/CompileFeatures/default_dialect.c
index 6160c2f..b990e53 100644
--- a/Tests/CompileFeatures/default_dialect.c
+++ b/Tests/CompileFeatures/default_dialect.c
@@ -1,5 +1,13 @@
 
-#if DEFAULT_C11
+#if DEFAULT_C23
+#  if __STDC_VERSION__ <= 201710L
+#    error Unexpected value for __STDC_VERSION__.
+#  endif
+#elif DEFAULT_C17
+#  if __STDC_VERSION__ < 201710L
+#    error Unexpected value for __STDC_VERSION__.
+#  endif
+#elif DEFAULT_C11
 #  if __STDC_VERSION__ < 201112L
 #    error Unexpected value for __STDC_VERSION__.
 #  endif
diff --git a/Tests/ConfigSources/CMakeLists.txt b/Tests/ConfigSources/CMakeLists.txt
index a3d98f6..38475f8 100644
--- a/Tests/ConfigSources/CMakeLists.txt
+++ b/Tests/ConfigSources/CMakeLists.txt
@@ -1,5 +1,6 @@
 cmake_minimum_required(VERSION 3.0)
 get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+
 if(NOT _isMultiConfig AND NOT CMAKE_BUILD_TYPE)
   set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build" FORCE)
 endif()
@@ -74,10 +75,10 @@
   VERBATIM
   )
 foreach(n RANGE 1 5)
-  set_property(SOURCE custom${n}_Debug.cpp PROPERTY COMPILE_DEFINITIONS CUSTOM_CFG_DEBUG)
-  foreach(other Release RelWithDebInfo MinSizeRel)
+  foreach(other ${CMAKE_BUILD_TYPE} Release RelWithDebInfo MinSizeRel)
     set_property(SOURCE custom${n}_${other}.cpp PROPERTY COMPILE_DEFINITIONS CUSTOM_CFG_OTHER)
   endforeach()
+  set_property(SOURCE custom${n}_Debug.cpp PROPERTY COMPILE_DEFINITIONS CUSTOM_CFG_DEBUG)
 endforeach()
 add_library(Custom STATIC
   custom1_$<CONFIG>.cpp
diff --git a/Tests/CustomCommand/CMakeLists.txt b/Tests/CustomCommand/CMakeLists.txt
index 80545c4..11d005f 100644
--- a/Tests/CustomCommand/CMakeLists.txt
+++ b/Tests/CustomCommand/CMakeLists.txt
@@ -1,7 +1,7 @@
 #
 # Wrapping
 #
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project (CustomCommand)
 
 add_subdirectory(GeneratedHeader)
diff --git a/Tests/CustomCommandWorkingDirectory/CMakeLists.txt b/Tests/CustomCommandWorkingDirectory/CMakeLists.txt
index 3bab1fe..7697a9b 100644
--- a/Tests/CustomCommandWorkingDirectory/CMakeLists.txt
+++ b/Tests/CustomCommandWorkingDirectory/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(TestWorkingDir)
 
 add_custom_command(
diff --git a/Tests/Dependency/CMakeLists.txt b/Tests/Dependency/CMakeLists.txt
index ebc2d10..58d3fb7 100644
--- a/Tests/Dependency/CMakeLists.txt
+++ b/Tests/Dependency/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project( Dependency )
 
 # to test directories with only one character One was changed to 1
diff --git a/Tests/ExportImport/Import/Interface/pch_iface_test.cpp b/Tests/ExportImport/Import/Interface/pch_iface_test.cpp
index a18bbde..d676a5b 100644
--- a/Tests/ExportImport/Import/Interface/pch_iface_test.cpp
+++ b/Tests/ExportImport/Import/Interface/pch_iface_test.cpp
@@ -3,7 +3,8 @@
 #  ifndef PCH_PCH_H_INCLUDED
 #    error "Expected PCH_PCH_H_INCLUDED."
 #  endif
-#elif defined(__PGIC__) || defined(__ibmxl__) || defined(_CRAYC)
+#elif defined(__PGIC__) || defined(__ibmxl__) || defined(_CRAYC) ||           \
+  defined(__FUJITSU)
 // No PCH expected but these compilers define macros below.
 #elif defined(__GNUC__) || defined(__clang__) || defined(_INTEL_COMPILER) ||  \
   defined(_MSC_VER)
diff --git a/Tests/ExternalProjectLocal/CMakeLists.txt b/Tests/ExternalProjectLocal/CMakeLists.txt
index 9a0241c..57e8105 100644
--- a/Tests/ExternalProjectLocal/CMakeLists.txt
+++ b/Tests/ExternalProjectLocal/CMakeLists.txt
@@ -41,7 +41,7 @@
 set(proj TutorialStep5-Local-TestAfterInstall)
 ExternalProject_Add(${proj}
 URL "${CMAKE_CURRENT_SOURCE_DIR}/Step5"
-CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -G ${CMAKE_GENERATOR} <SOURCE_DIR>
+CMAKE_ARGS --install-prefix=<INSTALL_DIR> -G ${CMAKE_GENERATOR} <SOURCE_DIR>
 CMAKE_CACHE_DEFAULT_ARGS -DUSE_MYMATH:BOOL=OFF
 TEST_AFTER_INSTALL 1
 LOG_TEST 1
@@ -51,7 +51,7 @@
 set(proj TutorialStep5-Local-TestExcludeFromMainBefore)
 ExternalProject_Add(${proj}
 URL "${CMAKE_CURRENT_SOURCE_DIR}/Step5"
-CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>  -G ${CMAKE_GENERATOR} <SOURCE_DIR>
+CMAKE_ARGS --install-prefix=<INSTALL_DIR>  -G ${CMAKE_GENERATOR} <SOURCE_DIR>
 CMAKE_CACHE_DEFAULT_ARGS -DUSE_MYMATH:BOOL=OFF
 TEST_BEFORE_INSTALL 1
 TEST_EXCLUDE_FROM_MAIN 1
@@ -63,7 +63,7 @@
 set(proj TutorialStep5-Local-TestExcludeFromMainAfter)
 ExternalProject_Add(${proj}
 URL "${CMAKE_CURRENT_SOURCE_DIR}/Step5"
-CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>  -G ${CMAKE_GENERATOR} <SOURCE_DIR>
+CMAKE_ARGS --install-prefix=<INSTALL_DIR>  -G ${CMAKE_GENERATOR} <SOURCE_DIR>
 CMAKE_CACHE_DEFAULT_ARGS -DUSE_MYMATH:BOOL=OFF
 TEST_AFTER_INSTALL 1
 TEST_EXCLUDE_FROM_MAIN 1
diff --git a/Tests/FindBLAS/CMakeLists.txt b/Tests/FindBLAS/CMakeLists.txt
index 667195d..47ec568 100644
--- a/Tests/FindBLAS/CMakeLists.txt
+++ b/Tests/FindBLAS/CMakeLists.txt
@@ -1,10 +1,12 @@
-add_test(NAME FindBLAS.Test COMMAND
-  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-  --build-and-test
-  "${CMake_SOURCE_DIR}/Tests/FindBLAS/Test"
-  "${CMake_BINARY_DIR}/Tests/FindBLAS/Test"
-  ${build_generator_args}
-  --build-project TestFindBLAS
-  --build-options ${build_options}
-  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-  )
+foreach(vendor IN LISTS CMake_TEST_FindBLAS)
+  add_test(NAME FindBLAS.Test_${vendor} COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindBLAS/Test"
+    "${CMake_BINARY_DIR}/Tests/FindBLAS/Test_${vendor}"
+    ${build_generator_args}
+    --build-project TestFindBLAS
+    --build-options ${build_options} -DBLA_VENDOR=${vendor}
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+endforeach()
diff --git a/Tests/FindBLAS/Test/CMakeLists.txt b/Tests/FindBLAS/Test/CMakeLists.txt
index 59418f3..1bebf8e 100644
--- a/Tests/FindBLAS/Test/CMakeLists.txt
+++ b/Tests/FindBLAS/Test/CMakeLists.txt
@@ -11,3 +11,9 @@
 add_executable(test_var main.c)
 target_link_libraries(test_var PRIVATE ${BLAS_LIBRARIES})
 add_test(NAME test_var COMMAND test_var)
+
+if(BLA_VENDOR STREQUAL "Intel10_64lp")
+  if(NOT BLAS_LIBRARIES MATCHES "^[^;]*mkl_intel_lp64")
+    message(FATAL_ERROR "BLAS_LIBRARIES does not start in mkl_intel_lp64:\n ${BLAS_LIBRARIES}")
+  endif()
+endif()
diff --git a/Tests/FindDevIL/CMakeLists.txt b/Tests/FindDevIL/CMakeLists.txt
new file mode 100644
index 0000000..d37d50f
--- /dev/null
+++ b/Tests/FindDevIL/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_test(NAME FindDevIL.Test COMMAND
+  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+  --build-and-test
+  "${CMake_SOURCE_DIR}/Tests/FindDevIL/Test"
+  "${CMake_BINARY_DIR}/Tests/FindDevIL/Test"
+  ${build_generator_args}
+  --build-project TestFindDevIL
+  --build-options ${build_options}
+  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+  )
diff --git a/Tests/FindDevIL/Test/CMakeLists.txt b/Tests/FindDevIL/Test/CMakeLists.txt
new file mode 100644
index 0000000..c2c1322
--- /dev/null
+++ b/Tests/FindDevIL/Test/CMakeLists.txt
@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 3.1)
+project(TestFindDevIL C)
+include(CTest)
+
+find_package(DevIL)
+
+#FIXME: check version too.
+# add_definitions(
+#  -DCMAKE_EXPECTED_SDL_VERSION_MAJOR=${SDL_VERSION_MAJOR}
+#  -DCMAKE_EXPECTED_SDL_VERSION_MINOR=${SDL_VERSION_MINOR}
+#  -DCMAKE_EXPECTED_SDL_VERSION_PATCH=${SDL_VERSION_PATCH})
+
+add_executable(test_devil_var main.c)
+target_include_directories(test_devil_var PRIVATE ${IL_INCLUDE_DIRS})
+target_link_libraries(test_devil_var PRIVATE ${IL_LIBRARIES})
+add_test(NAME test_devil_var COMMAND test_devil_var)
+
+add_executable(test_devil_il_tgt main.c)
+target_link_libraries(test_devil_il_tgt DevIL::IL)
+add_test(NAME test_devil_il_tgt COMMAND test_devil_il_tgt)
+
+add_executable(test_devil_ilu_tgt main_ilu.c)
+target_link_libraries(test_devil_ilu_tgt DevIL::ILU)
+
+add_executable(test_devil_ilu_var main_ilu.c)
+target_include_directories(test_devil_ilu_var PRIVATE ${IL_INCLUDE_DIRS} ${ILU_INCLUDE_DIRS})
+target_link_libraries(test_devil_ilu_var ${IL_LIBRARIES} ${ILU_LIBRARIES})
+
+#FIXME: Check DevIL::ILUT target
diff --git a/Tests/FindDevIL/Test/main.c b/Tests/FindDevIL/Test/main.c
new file mode 100644
index 0000000..4a07087
--- /dev/null
+++ b/Tests/FindDevIL/Test/main.c
@@ -0,0 +1,10 @@
+#include <IL/il.h>
+
+int main()
+{
+  // Test 1 requires to link to the library.
+  ilInit();
+
+  ilShutDown();
+  return 0;
+}
diff --git a/Tests/FindDevIL/Test/main_ilu.c b/Tests/FindDevIL/Test/main_ilu.c
new file mode 100644
index 0000000..a9e7819
--- /dev/null
+++ b/Tests/FindDevIL/Test/main_ilu.c
@@ -0,0 +1,8 @@
+#include <IL/ilu.h>
+
+int main()
+{
+  // IL Utilities requires only initialization.
+  // Unlike main DevIL there are no shutdown function.
+  iluInit();
+}
diff --git a/Tests/FindLAPACK/CMakeLists.txt b/Tests/FindLAPACK/CMakeLists.txt
index 2081d59..5e2ea7a 100644
--- a/Tests/FindLAPACK/CMakeLists.txt
+++ b/Tests/FindLAPACK/CMakeLists.txt
@@ -1,10 +1,12 @@
-add_test(NAME FindLAPACK.Test COMMAND
-  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-  --build-and-test
-  "${CMake_SOURCE_DIR}/Tests/FindLAPACK/Test"
-  "${CMake_BINARY_DIR}/Tests/FindLAPACK/Test"
-  ${build_generator_args}
-  --build-project TestFindLAPACK
-  --build-options ${build_options}
-  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-  )
+foreach(vendor IN LISTS CMake_TEST_FindLAPACK)
+  add_test(NAME FindLAPACK.Test_${vendor} COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindLAPACK/Test"
+    "${CMake_BINARY_DIR}/Tests/FindLAPACK/Test_${vendor}"
+    ${build_generator_args}
+    --build-project TestFindLAPACK
+    --build-options ${build_options} -DBLA_VENDOR=${vendor}
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+endforeach()
diff --git a/Tests/FindLAPACK/Test/CMakeLists.txt b/Tests/FindLAPACK/Test/CMakeLists.txt
index 8afa36a..67fb9bd 100644
--- a/Tests/FindLAPACK/Test/CMakeLists.txt
+++ b/Tests/FindLAPACK/Test/CMakeLists.txt
@@ -11,3 +11,9 @@
 add_executable(test_var main.c)
 target_link_libraries(test_var PRIVATE ${LAPACK_LIBRARIES})
 add_test(NAME test_var COMMAND test_var)
+
+if(BLA_VENDOR STREQUAL "Intel10_64lp")
+  if(NOT LAPACK_LIBRARIES MATCHES "^[^;]*mkl_intel_lp64")
+    message(FATAL_ERROR "LAPACK_LIBRARIES does not start in mkl_intel_lp64:\n ${LAPACK_LIBRARIES}")
+  endif()
+endif()
diff --git a/Tests/FindPackageModeMakefileTest/CMakeLists.txt b/Tests/FindPackageModeMakefileTest/CMakeLists.txt
index 8a87a8c..0b15be8 100644
--- a/Tests/FindPackageModeMakefileTest/CMakeLists.txt
+++ b/Tests/FindPackageModeMakefileTest/CMakeLists.txt
@@ -19,12 +19,16 @@
     # configure a FindFoo.cmake so it knows where the library can be found
     configure_file(FindFoo.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FindFoo.cmake @ONLY)
 
-    # Need the -isysroot flag on recentish macOS after command line tools
-    # no longer provide headers in /usr/include
-    if(APPLE AND CMAKE_OSX_SYSROOT)
-      set(__EXTRA_OSX_SYSROOT_FLAGS "-isysroot ${CMAKE_OSX_SYSROOT}")
-    else()
-      set(__EXTRA_OSX_SYSROOT_FLAGS "")
+    set(EXTRA_FLAGS "")
+    if(APPLE)
+      # Need the -isysroot flag on recentish macOS after command line tools
+      # no longer provide headers in /usr/include
+      if(CMAKE_OSX_SYSROOT)
+        string(APPEND EXTRA_FLAGS " -isysroot ${CMAKE_OSX_SYSROOT}")
+      endif()
+      foreach(arch ${CMAKE_OSX_ARCHITECTURES})
+        string(APPEND EXTRA_FLAGS " -arch ${arch}")
+      endforeach()
     endif()
 
     # now set up the test:
diff --git a/Tests/FindPackageModeMakefileTest/Makefile.in b/Tests/FindPackageModeMakefileTest/Makefile.in
index af9fa96..695c64f 100644
--- a/Tests/FindPackageModeMakefileTest/Makefile.in
+++ b/Tests/FindPackageModeMakefileTest/Makefile.in
@@ -5,7 +5,7 @@
 CMAKE_CXX_COMPILER = "@CMAKE_CXX_COMPILER@"
 CMAKE_CXX_COMPILER_ID = "@CMAKE_CXX_COMPILER_ID@"
 CMAKE_CXX_FLAGS = @CMAKE_CXX_FLAGS@
-__EXTRA_OSX_SYSROOT_FLAGS = @__EXTRA_OSX_SYSROOT_FLAGS@
+EXTRA_FLAGS = @EXTRA_FLAGS@
 
 CMAKE_FOO = $(CMAKE) --find-package -DCMAKE_MODULE_PATH=$(CMAKE_CURRENT_BINARY_DIR) -DNAME=Foo -DLANGUAGE=CXX -DCOMPILER_ID=$(CMAKE_CXX_COMPILER_ID)
 
@@ -16,7 +16,7 @@
 main.o: clean main.cpp
 	@$(CMAKE_FOO) -DMODE=COMPILE >$(tmp)
 	@foo="`cat $(tmp)`"; \
-	 printf '"%s" %s %s %s -c main.cpp\n' $(CMAKE_CXX_COMPILER) "$(CMAKE_CXX_FLAGS)" "$(__EXTRA_OSX_SYSROOT_FLAGS)" "$$foo" >$(tmp)
+	 printf '"%s" %s %s %s -c main.cpp\n' $(CMAKE_CXX_COMPILER) "$(CMAKE_CXX_FLAGS)" "$(EXTRA_FLAGS)" "$$foo" >$(tmp)
 	@cat $(tmp)
 	@sh $(tmp)
 	@rm -f $(tmp)
@@ -24,7 +24,7 @@
 pngtest: main.o
 	@$(CMAKE_FOO) -DMODE=LINK >$(tmp)
 	@foo="`cat $(tmp)`"; \
-	 printf '"%s" %s %s %s -o pngtest main.o %s\n' $(CMAKE_CXX_COMPILER) "$(CMAKE_CXX_FLAGS)" "$(__EXTRA_OSX_SYSROOT_FLAGS)" "$(LDFLAGS)" "$$foo" >$(tmp)
+	 printf '"%s" %s %s %s -o pngtest main.o %s\n' $(CMAKE_CXX_COMPILER) "$(CMAKE_CXX_FLAGS)" "$(EXTRA_FLAGS)" "$(LDFLAGS)" "$$foo" >$(tmp)
 	@cat $(tmp)
 	@sh $(tmp)
 	@rm -f $(tmp)
diff --git a/Tests/Fortran/CMakeLists.txt b/Tests/Fortran/CMakeLists.txt
index 1868892..2fc47a5 100644
--- a/Tests/Fortran/CMakeLists.txt
+++ b/Tests/Fortran/CMakeLists.txt
@@ -46,7 +46,7 @@
   FortranCInterface_VERIFY()
   FortranCInterface_VERIFY(CXX)
   if(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
-    if(NOT CMAKE_Fortran_COMPILER_ID MATCHES "SunPro|PathScale|Absoft")
+    if(NOT CMAKE_Fortran_COMPILER_ID MATCHES "SunPro|PathScale|Absoft|Fujitsu")
       set(module_expected 1)
     endif()
     if(FortranCInterface_MODULE_FOUND OR module_expected)
@@ -131,7 +131,7 @@
   # as a language, cmake needs language specific versions
   # of these variables....
   if(WIN32 AND CMAKE_Fortran_COMPILER_ID MATCHES "GNU")
-    set(CMAKE_CREATE_CONSOLE_EXE )
+    set(CMAKE_Fortran_CREATE_CONSOLE_EXE )
     set(CMAKE_LIBRARY_PATH_FLAG "-L")
     set(CMAKE_LINK_LIBRARY_FLAG "-l")
     set(CMAKE_LINK_LIBRARY_SUFFIX )
diff --git a/Tests/FortranModules/CMakeLists.txt b/Tests/FortranModules/CMakeLists.txt
index b7a6f68..94f5939 100644
--- a/Tests/FortranModules/CMakeLists.txt
+++ b/Tests/FortranModules/CMakeLists.txt
@@ -1,6 +1,11 @@
 cmake_minimum_required (VERSION 3.9)
 project(FortranModules Fortran)
 
+if("${CMAKE_Fortran_COMPILER_ID};${CMAKE_Fortran_SIMULATE_ID}" MATCHES "^Intel(LLVM)?;MSVC$")
+  string(APPEND CMAKE_Fortran_FLAGS_DEBUG " -Z7")
+  string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO " -Z7")
+endif()
+
 if(NOT DEFINED CMake_TEST_NESTED_MAKE_PROGRAM AND NOT CMAKE_GENERATOR MATCHES "Visual Studio")
   set(CMake_TEST_NESTED_MAKE_PROGRAM "${CMAKE_MAKE_PROGRAM}")
 endif()
diff --git a/Tests/FortranOnly/CMakeLists.txt b/Tests/FortranOnly/CMakeLists.txt
index b5b5e56..cdf8ed6 100644
--- a/Tests/FortranOnly/CMakeLists.txt
+++ b/Tests/FortranOnly/CMakeLists.txt
@@ -117,15 +117,9 @@
   target_compile_definitions(IntelIfDef PRIVATE SOME_DEF)
 endif()
 
-# Skip these tests if compiler/version doesn't have preprocessing flags
-if((CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 4.4)
-  OR (CMAKE_Fortran_COMPILER_ID STREQUAL "XL" AND CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 15.1.6))
-  set(test_pp_flags 0)
-else()
-  set(test_pp_flags 1)
-endif()
-
-if(test_pp_flags)
+# Skip these tests if compiler/version does enable and disable preprocessing
+if(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON AND
+   CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF)
   # Test that we can always preprocess a target
   add_executable(preprocess_target preprocess2.f)
   set_property(TARGET preprocess_target PROPERTY Fortran_PREPROCESS ON)
@@ -145,17 +139,22 @@
 
 # Test that we can explicitly not preprocess a target or source.
 # This will not work on certain compilers due to either missing a
-# "don't preprocess" flag, or due to choice of file extension.
-if(test_pp_flags AND NOT CMAKE_Fortran_COMPILER_ID MATCHES "(Flang|NAG|PGI|NVHPC|SunPro|XL)")
+# "don't preprocess" flag, or due to the flags being ignored for
+# extensions like '.F' and '.fpp'.
+if(CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF AND
+    NOT CMAKE_Fortran_COMPILER_ID MATCHES "(Flang|NAG|PGI|NVHPC|SunPro|XL)")
   add_library(no_preprocess_target STATIC no_preprocess_target_upper.F)
   target_compile_options(no_preprocess_target PRIVATE -DINTEGER=nonsense)
+
   add_library(no_preprocess_source STATIC no_preprocess_source_upper.F)
   target_compile_options(no_preprocess_source PRIVATE -DINTEGER=nonsense)
+
   if(NOT CMAKE_Fortran_COMPILER_ID STREQUAL "Cray"
       AND NOT "${CMAKE_Fortran_COMPILER_ID};${CMAKE_Fortran_SIMULATE_ID}" MATCHES "Intel(LLVM)?;MSVC")
     target_sources(no_preprocess_target PRIVATE no_preprocess_target_fpp.fpp)
     target_sources(no_preprocess_source PRIVATE no_preprocess_source_fpp.fpp)
   endif()
+
   set_property(TARGET no_preprocess_target PROPERTY Fortran_PREPROCESS OFF)
   set_property(SOURCE no_preprocess_source_upper.F no_preprocess_source_fpp.fpp PROPERTY Fortran_PREPROCESS OFF)
 endif()
diff --git a/Tests/Framework/CMakeLists.txt b/Tests/Framework/CMakeLists.txt
index aabf6b4..287be94 100644
--- a/Tests/Framework/CMakeLists.txt
+++ b/Tests/Framework/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(Framework)
 
 add_library(foo SHARED
@@ -83,7 +83,7 @@
   target_link_libraries(barStatic fooStatic)
 endif()
 
-if(XCODE)
+if(MAKE_SUPPORTS_SPACES AND NOT CMAKE_GENERATOR STREQUAL "Watcom WMake")
   add_library(space SHARED space.c)
   set_target_properties(space PROPERTIES
     FRAMEWORK TRUE
diff --git a/Tests/FunctionTest/CMakeLists.txt b/Tests/FunctionTest/CMakeLists.txt
index 68da972..6450447 100644
--- a/Tests/FunctionTest/CMakeLists.txt
+++ b/Tests/FunctionTest/CMakeLists.txt
@@ -1,5 +1,5 @@
 # a simple C only test case
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project (FunctionTest)
 
 function(FAILED testname)
diff --git a/Tests/JCTest/CMakeLists.txt b/Tests/JCTest/CMakeLists.txt
index 31dcc3a..b120640 100644
--- a/Tests/JCTest/CMakeLists.txt
+++ b/Tests/JCTest/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.6)
+cmake_minimum_required(VERSION 2.8.12)
 project(TestTime)
 enable_testing()
 add_executable(TestTime TestTime.cxx)
diff --git a/Tests/Java/CMakeLists.txt b/Tests/Java/CMakeLists.txt
index aea4282..e4f2821 100644
--- a/Tests/Java/CMakeLists.txt
+++ b/Tests/Java/CMakeLists.txt
@@ -1,6 +1,6 @@
 project(hello Java)
 
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 set(CMAKE_VERBOSE_MAKEFILE 1)
 
 include(CTest)
diff --git a/Tests/JavaJavah/CMakeLists.txt b/Tests/JavaJavah/CMakeLists.txt
index 77c292a..b56cc21 100644
--- a/Tests/JavaJavah/CMakeLists.txt
+++ b/Tests/JavaJavah/CMakeLists.txt
@@ -1,6 +1,6 @@
 project(helloJavah Java CXX)
 
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 set(CMAKE_VERBOSE_MAKEFILE 1)
 
 include(CTest)
diff --git a/Tests/JavaNativeHeaders/CMakeLists.txt b/Tests/JavaNativeHeaders/CMakeLists.txt
index f3cc89d..2471e01 100644
--- a/Tests/JavaNativeHeaders/CMakeLists.txt
+++ b/Tests/JavaNativeHeaders/CMakeLists.txt
@@ -1,6 +1,6 @@
 project(helloJavaNativeHeaders Java CXX)
 
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 set(CMAKE_VERBOSE_MAKEFILE 1)
 
 include (CTest)
diff --git a/Tests/LibName/CMakeLists.txt b/Tests/LibName/CMakeLists.txt
index 3ac125f..b8f0890 100644
--- a/Tests/LibName/CMakeLists.txt
+++ b/Tests/LibName/CMakeLists.txt
@@ -24,3 +24,11 @@
 
 add_executable(verFoobar foobar.c)
 target_link_libraries(verFoobar verFoo)
+
+if(MAKE_SUPPORTS_SPACES AND NOT CMAKE_GENERATOR STREQUAL "Watcom WMake")
+  # check with lib version and space
+  add_library(ver_space SHARED ver_space.c)
+  set_target_properties(ver_space PROPERTIES VERSION 3.1.4 SOVERSION 3 OUTPUT_NAME "ver space")
+  add_executable(use_ver_space use_ver_space.c)
+  target_link_libraries(use_ver_space ver_space)
+endif()
diff --git a/Tests/LibName/use_ver_space.c b/Tests/LibName/use_ver_space.c
new file mode 100644
index 0000000..a6a733d
--- /dev/null
+++ b/Tests/LibName/use_ver_space.c
@@ -0,0 +1,9 @@
+#ifdef _WIN32
+__declspec(dllimport)
+#endif
+  int ver_space(void);
+
+int main(void)
+{
+  return ver_space();
+}
diff --git a/Tests/LibName/ver_space.c b/Tests/LibName/ver_space.c
new file mode 100644
index 0000000..669a3b5
--- /dev/null
+++ b/Tests/LibName/ver_space.c
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+  int ver_space(void)
+{
+  return 0;
+}
diff --git a/Tests/LoadCommand/CMakeCommands/CMakeLists.txt b/Tests/LoadCommand/CMakeCommands/CMakeLists.txt
index 99b1aba..cafa99b 100644
--- a/Tests/LoadCommand/CMakeCommands/CMakeLists.txt
+++ b/Tests/LoadCommand/CMakeCommands/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(CMAKE_LOADED_COMMANDS)
 
 if (MUDSLIDE_TYPE MATCHES MUCHO)
diff --git a/Tests/LoadCommand/CMakeLists.txt b/Tests/LoadCommand/CMakeLists.txt
index cfaebad..e1c4998 100644
--- a/Tests/LoadCommand/CMakeLists.txt
+++ b/Tests/LoadCommand/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(LoadCommand)
 
 # set a definition
diff --git a/Tests/LoadCommandOneConfig/CMakeCommands/CMakeLists.txt b/Tests/LoadCommandOneConfig/CMakeCommands/CMakeLists.txt
index 5ee2ed0..dc029a4 100644
--- a/Tests/LoadCommandOneConfig/CMakeCommands/CMakeLists.txt
+++ b/Tests/LoadCommandOneConfig/CMakeCommands/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(CMAKE_LOADED_COMMANDS)
 
 if (MUDSLIDE_TYPE MATCHES MUCHO)
diff --git a/Tests/LoadCommandOneConfig/CMakeLists.txt b/Tests/LoadCommandOneConfig/CMakeLists.txt
index 65de042..fef4bb7 100644
--- a/Tests/LoadCommandOneConfig/CMakeLists.txt
+++ b/Tests/LoadCommandOneConfig/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(LoadCommand)
 
 # set a definition
diff --git a/Tests/MakeClean/CMakeLists.txt b/Tests/MakeClean/CMakeLists.txt
index fbd4995..809d65b 100644
--- a/Tests/MakeClean/CMakeLists.txt
+++ b/Tests/MakeClean/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(MakeClean)
 
 # Build the to-clean project.
diff --git a/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt b/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt
index 0cf74bf..e406758 100644
--- a/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt
+++ b/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt
@@ -52,7 +52,7 @@
 # detailed features tables, not just meta-features
 
 if (CMAKE_C_COMPILE_FEATURES)
-  if(NOT CMAKE_C_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IntelLLVM)$")
+  if (NOT CMAKE_C_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IntelLLVM|Fujitsu|FujitsuClang)$")
     set(C_expected_features ${CMAKE_C_COMPILE_FEATURES})
     list(FILTER C_expected_features EXCLUDE REGEX "^c_std_[0-9][0-9]")
   endif()
@@ -95,7 +95,7 @@
 endif()
 
 if (CMAKE_CXX_COMPILE_FEATURES)
-  if(NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IntelLLVM)$")
+  if (NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|IntelLLVM|Fujitsu|FujitsuClang)$")
     set(CXX_expected_features ${CMAKE_CXX_COMPILE_FEATURES})
     list(FILTER CXX_expected_features EXCLUDE REGEX "^cxx_std_[0-9][0-9]")
   endif()
diff --git a/Tests/ModuleDefinition/CMakeLists.txt b/Tests/ModuleDefinition/CMakeLists.txt
index e49ebea..567fb4b 100644
--- a/Tests/ModuleDefinition/CMakeLists.txt
+++ b/Tests/ModuleDefinition/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.6)
+cmake_minimum_required(VERSION 2.8.12)
 project(ModuleDefinition C)
 
 # Test .def file source recognition for DLLs.
diff --git a/Tests/NewlineArgs/CMakeLists.txt b/Tests/NewlineArgs/CMakeLists.txt
index 7551601..3e4b436 100644
--- a/Tests/NewlineArgs/CMakeLists.txt
+++ b/Tests/NewlineArgs/CMakeLists.txt
@@ -1,5 +1,5 @@
 # a simple CXX only test case
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project (NewlineArgs CXX)
 
 add_definitions("-DTEST_FLAG_1
diff --git a/Tests/Plugin/CMakeLists.txt b/Tests/Plugin/CMakeLists.txt
index 729bba3..ec22bf4 100644
--- a/Tests/Plugin/CMakeLists.txt
+++ b/Tests/Plugin/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 cmake_policy(SET CMP0054 NEW)
 project(Plugin)
 
@@ -46,7 +46,7 @@
 if(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG AND
     "${CMAKE_C_CREATE_SHARED_MODULE}" MATCHES "SONAME_FLAG")
   # Verify that targets export with proper IMPORTED SONAME properties.
-  export(TARGETS example_mod_1 NAMESPACE exp_
+  export(TARGETS example_mod_1 example_exe NAMESPACE exp_
     FILE ${CMAKE_CURRENT_BINARY_DIR}/mods.cmake)
 
   include(ExternalProject)
diff --git a/Tests/Preprocess/CMakeLists.txt b/Tests/Preprocess/CMakeLists.txt
index bf2af64..4347459 100644
--- a/Tests/Preprocess/CMakeLists.txt
+++ b/Tests/Preprocess/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.6)
+cmake_minimum_required(VERSION 2.8.12)
 project(Preprocess)
 
 # This test is meant both as a test and as a reference for supported
diff --git a/Tests/QtAutogen/RerunUicOnFileChange/CMakeLists.txt b/Tests/QtAutogen/RerunUicOnFileChange/CMakeLists.txt
new file mode 100644
index 0000000..1f636af
--- /dev/null
+++ b/Tests/QtAutogen/RerunUicOnFileChange/CMakeLists.txt
@@ -0,0 +1,102 @@
+cmake_minimum_required(VERSION 3.17)
+project(RerunUicOnFileChange)
+include("../AutogenGuiTest.cmake")
+
+# Utility variables
+set(testProjectTemplateDir "${CMAKE_CURRENT_SOURCE_DIR}/UicOnFileChange")
+set(testProjectSrc "${CMAKE_CURRENT_BINARY_DIR}/UicOnFileChange")
+set(testProjectBinDir "${CMAKE_CURRENT_BINARY_DIR}/UicOnFileChange-build")
+
+set(TEST_CONFIG "Release")
+
+macro(sleep)
+  message(STATUS "Sleeping for a few seconds.")
+  execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1)
+endmacro()
+macro(rebuild buildName)
+  message(STATUS "Starting build ${buildName}.")
+  execute_process(COMMAND "${CMAKE_COMMAND}" --build . --config "${TEST_CONFIG}"
+    WORKING_DIRECTORY "${testProjectBinDir}" RESULT_VARIABLE result
+  )
+  if (result)
+    message(FATAL_ERROR "Build ${buildName} failed.")
+  else()
+    message(STATUS "Build ${buildName} finished.")
+  endif()
+endmacro()
+
+configure_file("${testProjectTemplateDir}/mocwidget.h" "${testProjectSrc}/mocwidget.h" COPYONLY)
+configure_file("${testProjectTemplateDir}/main.cpp" "${testProjectSrc}/main.cpp" COPYONLY)
+configure_file("${testProjectTemplateDir}/CMakeLists.txt.in" "${testProjectSrc}/CMakeLists.txt" @ONLY)
+
+set(Num 1)
+configure_file("${testProjectTemplateDir}/mainwindow.ui.in" "${testProjectSrc}/mainwindow.ui" @ONLY)
+
+if(CMAKE_GENERATOR_INSTANCE)
+    set(_D_CMAKE_GENERATOR_INSTANCE "-DCMAKE_GENERATOR_INSTANCE=${CMAKE_GENERATOR_INSTANCE}")
+else()
+    set(_D_CMAKE_GENERATOR_INSTANCE "")
+endif()
+
+get_property(is_multi GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(is_multi)
+  set(build_type_extra "-DCMAKE_CONFIGURATION_TYPES=${TEST_CONFIG}")
+  set(extra_bin_path "${TEST_CONFIG}/")
+else()
+  set(build_type_extra "-DCMAKE_BUILD_TYPE=${TEST_CONFIG}")
+endif()
+
+# Set the environment PATH/LD_LIBRARY_PATH variables to run the resulting executable
+if(WIN32 AND TARGET ${QT_QTCORE_TARGET})
+  get_target_property(qtcore_path ${QT_QTCORE_TARGET} LOCATION)
+  if(NOT qtcore_path)
+    get_target_property(qtcore_path ${QT_QTCORE_TARGET} IMPORTED_LOCATION)
+  endif()
+  get_filename_component(qtcore_path "${qtcore_path}" DIRECTORY)
+  set(ENV{PATH} "${qtcore_path};$ENV{PATH}")
+endif()
+
+execute_process(
+  COMMAND "${CMAKE_COMMAND}" -B "${testProjectBinDir}" -S "${testProjectSrc}"
+          -G "${CMAKE_GENERATOR}"
+          -A "${CMAKE_GENERATOR_PLATFORM}"
+          -T "${CMAKE_GENERATOR_TOOLSET}"
+          ${_D_CMAKE_GENERATOR_INSTANCE}
+          "${build_type_extra}"
+          "-DQT_TEST_VERSION=${QT_TEST_VERSION}"
+          "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
+          "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+  RESULT_VARIABLE exit_code
+  OUTPUT_VARIABLE output
+  ERROR_VARIABLE output
+)
+if(NOT exit_code EQUAL 0)
+  message(FATAL_ERROR "Initial configuration of UicOnFileChange failed. Output: ${output}")
+endif()
+
+# Initial build
+execute_process(
+    COMMAND "${CMAKE_COMMAND}" --build "${testProjectBinDir}" --config "${TEST_CONFIG}"
+    RESULT_VARIABLE exit_code
+    OUTPUT_VARIABLE output
+    ERROR_VARIABLE output
+)
+if(NOT exit_code EQUAL 0)
+    message(FATAL_ERROR "Initial build of UicOnFileChange failed. Output: ${output}")
+endif()
+
+execute_process(COMMAND "${testProjectBinDir}/${extra_bin_path}UicOnFileChange" RESULT_VARIABLE result)
+if(NOT result EQUAL "1")
+  message(FATAL_ERROR "Initial build of UicOnFileChange test result is: ${result}")
+endif()
+
+sleep()
+
+set(Num 2)
+configure_file("${testProjectTemplateDir}/mainwindow.ui.in" "${testProjectSrc}/mainwindow.ui" @ONLY)
+rebuild(2)
+
+execute_process(COMMAND "${testProjectBinDir}/${extra_bin_path}UicOnFileChange" RESULT_VARIABLE result)
+if(NOT result EQUAL "0")
+  message(FATAL_ERROR "Rebuild of UicOnFileChange test result is: ${result}")
+endif()
diff --git a/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/CMakeLists.txt.in b/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/CMakeLists.txt.in
new file mode 100644
index 0000000..fa9dd6b
--- /dev/null
+++ b/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/CMakeLists.txt.in
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.10)
+
+project(UicOnFileChange)
+include("@CMAKE_CURRENT_LIST_DIR@/../AutogenGuiTest.cmake")
+
+# Enable CMAKE_AUTOUIC for all targets
+set(CMAKE_AUTOUIC ON)
+
+add_executable(UicOnFileChange main.cpp mainwindow.ui)
+target_include_directories(UicOnFileChange PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+target_link_libraries(UicOnFileChange ${QT_QTCORE_TARGET} ${QT_LIBRARIES})
diff --git a/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/main.cpp b/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/main.cpp
new file mode 100644
index 0000000..fd810fa
--- /dev/null
+++ b/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/main.cpp
@@ -0,0 +1,9 @@
+#include "ui_mainwindow.h"
+
+int main(int argc, char* argv[])
+{
+  MocWidget mw;
+  Ui::Widget mwUi;
+  mwUi.setupUi(&mw);
+  return mw.objectName() == "Widget2" ? 0 : 1;
+}
diff --git a/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/mainwindow.ui.in b/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/mainwindow.ui.in
new file mode 100644
index 0000000..8f39e55
--- /dev/null
+++ b/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/mainwindow.ui.in
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Widget</class>
+ <widget class="MocWidget" name="Widget@Num@"/>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/mocwidget.h b/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/mocwidget.h
new file mode 100644
index 0000000..87fc177
--- /dev/null
+++ b/Tests/QtAutogen/RerunUicOnFileChange/UicOnFileChange/mocwidget.h
@@ -0,0 +1,5 @@
+#include <QtCore/QObject>
+
+class MocWidget : public QObject
+{
+};
diff --git a/Tests/QtAutogen/TestMacros.cmake b/Tests/QtAutogen/TestMacros.cmake
index 1024996..9dcf31f 100644
--- a/Tests/QtAutogen/TestMacros.cmake
+++ b/Tests/QtAutogen/TestMacros.cmake
@@ -43,6 +43,7 @@
     --build-options ${build_options} ${Autogen_BUILD_OPTIONS}
     ${_TestCommand}
   )
+  set_tests_properties("${_QtXAutogen}.${NAME}" PROPERTIES LABELS "Qt${QT_TEST_VERSION}")
   list(APPEND TEST_BUILD_DIRS "${_BuildDir}")
   unset(_TestCommand)
   unset(_QtXAutogen)
diff --git a/Tests/QtAutogen/Tests.cmake b/Tests/QtAutogen/Tests.cmake
index b1337d6..ab5686a 100644
--- a/Tests/QtAutogen/Tests.cmake
+++ b/Tests/QtAutogen/Tests.cmake
@@ -24,6 +24,7 @@
 ADD_AUTOGEN_TEST(RerunMocOnMissingDependency)
 ADD_AUTOGEN_TEST(RerunRccConfigChange)
 ADD_AUTOGEN_TEST(RerunRccDepends)
+ADD_AUTOGEN_TEST(RerunUicOnFileChange)
 ADD_AUTOGEN_TEST(SameName sameName)
 ADD_AUTOGEN_TEST(StaticLibraryCycle slc)
 ADD_AUTOGEN_TEST(UicInclude uicInclude)
@@ -35,7 +36,9 @@
 
 if(QT_TEST_ALLOW_QT_MACROS)
   ADD_AUTOGEN_TEST(MocCMP0071)
+  set_property(TEST "Qt${QT_TEST_VERSION}Autogen.MocCMP0071" APPEND PROPERTY LABELS "policy")
   ADD_AUTOGEN_TEST(MocCMP0100)
+  set_property(TEST "Qt${QT_TEST_VERSION}Autogen.MocCMP0100" APPEND PROPERTY LABELS "policy")
   ADD_AUTOGEN_TEST(MocInclude)
   ADD_AUTOGEN_TEST(MocIncludeSymlink)
   ADD_AUTOGEN_TEST(MocSkipSource)
diff --git a/Tests/ReturnTest/CMakeLists.txt b/Tests/ReturnTest/CMakeLists.txt
index c4c606c..78e3fc1 100644
--- a/Tests/ReturnTest/CMakeLists.txt
+++ b/Tests/ReturnTest/CMakeLists.txt
@@ -1,5 +1,5 @@
 # a simple C only test case
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project (ReturnTest)
 
 function (FAILED testname)
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake
index 01eac91..e4fdb4a 100644
--- a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake
@@ -3,15 +3,15 @@
 
 add_custom_command(
   OUTPUT topcc.c
-  DEPFILE topcc.c.d
-  COMMAND ${CMAKE_COMMAND} -DOUTFILE=${CMAKE_CURRENT_BINARY_DIR}/topcc.c -DINFILE=topccdep.txt -DDEPFILE=topcc.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile.cmake"
+  DEPFILE topcc_$<CONFIG>.c.d
+  COMMAND ${CMAKE_COMMAND} -DOUTFILE=${CMAKE_CURRENT_BINARY_DIR}/topcc.c -DINFILE=topccdep.txt -DDEPFILE=topcc_$<CONFIG>.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile.cmake"
   )
 add_custom_target(topcc ALL DEPENDS topcc.c)
 
 add_custom_command(
   OUTPUT topexe.c
-  DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/topexe.c.d
-  COMMAND ${CMAKE_COMMAND} -DOUTFILE=topexe.c "-DINFILE=${CMAKE_CURRENT_BINARY_DIR}/topexedep.txt" -DDEPFILE=topexe.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile.cmake"
+  DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/topexe_$<CONFIG>.c.d
+  COMMAND ${CMAKE_COMMAND} -DOUTFILE=topexe.c "-DINFILE=${CMAKE_CURRENT_BINARY_DIR}/topexedep.txt" -DDEPFILE=topexe_$<CONFIG>.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile.cmake"
   )
 add_executable(topexe "${CMAKE_CURRENT_BINARY_DIR}/topexe.c")
 
diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-COMMAND-OLD-stderr.txt b/Tests/RunCMake/BundleUtilities/CMP0080-COMMAND-OLD-stderr.txt
new file mode 100644
index 0000000..31a0207
--- /dev/null
+++ b/Tests/RunCMake/BundleUtilities/CMP0080-COMMAND-OLD-stderr.txt
@@ -0,0 +1,9 @@
+^CMake Deprecation Warning at [^
+]*/Tests/RunCMake/BundleUtilities/CMP0080-COMMAND.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0080 will be removed from a future version
+  of CMake.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD.$
diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-OLD-stderr.txt b/Tests/RunCMake/BundleUtilities/CMP0080-OLD-stderr.txt
new file mode 100644
index 0000000..2ff5d60
--- /dev/null
+++ b/Tests/RunCMake/BundleUtilities/CMP0080-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0080-OLD.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0080 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/CMP0041/RunCMakeTest.cmake b/Tests/RunCMake/CMP0041/RunCMakeTest.cmake
index e7f27a1..f47bb2e 100644
--- a/Tests/RunCMake/CMP0041/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMP0041/RunCMakeTest.cmake
@@ -6,6 +6,10 @@
 run_cmake(CMP0041-OLD)
 run_cmake(CMP0041-NEW)
 run_cmake(CMP0041-WARN)
+
+# Protect tests from running inside the default install prefix.
+set(RunCMake_TEST_OPTIONS "--install-prefix ${RunCMake_BINARY_DIR}/NotDefaultPrefix")
+
 run_cmake(CMP0041-tid-OLD)
 run_cmake(CMP0041-tid-NEW)
 run_cmake(CMP0041-tid-WARN)
diff --git a/Tests/RunCMake/CMP0081/CMP0081-OLD-result.txt b/Tests/RunCMake/CMP0081/CMP0081-OLD-result.txt
deleted file mode 100644
index 573541a..0000000
--- a/Tests/RunCMake/CMP0081/CMP0081-OLD-result.txt
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/Tests/RunCMake/CMP0081/CMP0081-OLD-stderr.txt b/Tests/RunCMake/CMP0081/CMP0081-OLD-stderr.txt
new file mode 100644
index 0000000..ff339fa
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0081-OLD.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0081 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/CMP0121/CMP0121-ERANGE-Common.cmake b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-Common.cmake
new file mode 100644
index 0000000..5594be8
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-Common.cmake
@@ -0,0 +1,8 @@
+set(listvar a b c d e)
+
+list(GET listvar
+  18446744073709551616 # 2^64
+  2147483648 # 2^31
+  4294967296 # 2^32; errors out-of-range as -2147483643 due to underflow
+  out)
+message("ERANGE: -->${out}<--")
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW-result.txt b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW-stderr.txt
new file mode 100644
index 0000000..0166e14
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at CMP0121-ERANGE-Common.cmake:3 \(list\):
+  list index: 18446744073709551616 is not a valid index
+Call Stack \(most recent call first\):
+  CMP0121-ERANGE-NEW.cmake:2 \(include\)
+  CMakeLists.txt:3 \(include\)
+
+
+ERANGE: --><--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW.cmake b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW.cmake
new file mode 100644
index 0000000..68e564d
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 NEW)
+include(CMP0121-ERANGE-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-result.txt b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-stderr.txt
new file mode 100644
index 0000000..5a03559
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at CMP0121-ERANGE-Common.cmake:3 \(list\):
+  list index: (-2147483643|2147483647) out of range \(-5, 4\)
+Call Stack \(most recent call first\):
+  CMP0121-ERANGE-OLD.cmake:2 \(include\)
+  CMakeLists.txt:3 \(include\)
+
+
+ERANGE: --><--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD.cmake b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD.cmake
new file mode 100644
index 0000000..32f0b56
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 OLD)
+include(CMP0121-ERANGE-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-result.txt b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-stderr.txt
new file mode 100644
index 0000000..1e7b127
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN-stderr.txt
@@ -0,0 +1,18 @@
+CMake Warning \(dev\) at CMP0121-ERANGE-Common.cmake:3 \(list\):
+  Policy CMP0121 is not set: The list\(\) command now validates parsing of
+  index arguments.  Run "cmake --help-policy CMP0121" for policy details.
+  Use the cmake_policy command to set the policy and suppress this warning.
+  Invalid list index "18446744073709551616".
+Call Stack \(most recent call first\):
+  CMP0121-ERANGE-WARN.cmake:2 \(include\)
+  CMakeLists.txt:3 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Error at CMP0121-ERANGE-Common.cmake:3 \(list\):
+  list index: (-2147483643|2147483647) out of range \(-5, 4\)
+Call Stack \(most recent call first\):
+  CMP0121-ERANGE-WARN.cmake:2 \(include\)
+  CMakeLists.txt:3 \(include\)
+
+
+ERANGE: --><--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN.cmake b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN.cmake
new file mode 100644
index 0000000..9655290
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-ERANGE-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0121-ERANGE-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-GET-Common.cmake b/Tests/RunCMake/CMP0121/CMP0121-GET-Common.cmake
new file mode 100644
index 0000000..e4986f0
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-GET-Common.cmake
@@ -0,0 +1,4 @@
+set(listvar a b c d e)
+
+list(GET listvar 0 2junk out)
+message("GET: -->${out}<--")
diff --git a/Tests/RunCMake/CMP0121/CMP0121-GET-NEW-result.txt b/Tests/RunCMake/CMP0121/CMP0121-GET-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-GET-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0121/CMP0121-GET-NEW-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-GET-NEW-stderr.txt
new file mode 100644
index 0000000..d502b86
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-GET-NEW-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at CMP0121-GET-Common.cmake:3 \(list\):
+  list index: 2junk is not a valid index
+Call Stack \(most recent call first\):
+  CMP0121-GET-NEW.cmake:2 \(include\)
+  CMakeLists.txt:3 \(include\)
+
+
+GET: --><--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-GET-NEW.cmake b/Tests/RunCMake/CMP0121/CMP0121-GET-NEW.cmake
new file mode 100644
index 0000000..1ab054d
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-GET-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 NEW)
+include(CMP0121-GET-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-GET-OLD-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-GET-OLD-stderr.txt
new file mode 100644
index 0000000..96375e9
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-GET-OLD-stderr.txt
@@ -0,0 +1 @@
+GET: -->a;c<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-GET-OLD.cmake b/Tests/RunCMake/CMP0121/CMP0121-GET-OLD.cmake
new file mode 100644
index 0000000..ef4526f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-GET-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 OLD)
+include(CMP0121-GET-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-GET-WARN-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-GET-WARN-stderr.txt
new file mode 100644
index 0000000..ecfad2c
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-GET-WARN-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at CMP0121-GET-Common.cmake:3 \(list\):
+  Policy CMP0121 is not set: The list\(\) command now validates parsing of
+  index arguments.  Run "cmake --help-policy CMP0121" for policy details.
+  Use the cmake_policy command to set the policy and suppress this warning.
+  Invalid list index "2junk".
+Call Stack \(most recent call first\):
+  CMP0121-GET-WARN.cmake:2 \(include\)
+  CMakeLists.txt:3 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+GET: -->a;c<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-GET-WARN.cmake b/Tests/RunCMake/CMP0121/CMP0121-GET-WARN.cmake
new file mode 100644
index 0000000..b08620b
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-GET-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0121-GET-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-INSERT-Common.cmake b/Tests/RunCMake/CMP0121/CMP0121-INSERT-Common.cmake
new file mode 100644
index 0000000..4950881
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-INSERT-Common.cmake
@@ -0,0 +1,4 @@
+set(listvar a b c d e)
+
+list(INSERT listvar junk2 new)
+message("INSERT: -->${listvar}<--")
diff --git a/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW-result.txt b/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW-stderr.txt
new file mode 100644
index 0000000..2241962
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at CMP0121-INSERT-Common.cmake:3 \(list\):
+  list index: junk2 is not a valid index
+Call Stack \(most recent call first\):
+  CMP0121-INSERT-NEW.cmake:2 \(include\)
+  CMakeLists.txt:3 \(include\)
+
+
+INSERT: -->a;b;c;d;e<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW.cmake b/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW.cmake
new file mode 100644
index 0000000..db627d1
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-INSERT-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 NEW)
+include(CMP0121-INSERT-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-INSERT-OLD-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-INSERT-OLD-stderr.txt
new file mode 100644
index 0000000..52f34ad
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-INSERT-OLD-stderr.txt
@@ -0,0 +1 @@
+INSERT: -->new;a;b;c;d;e<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-INSERT-OLD.cmake b/Tests/RunCMake/CMP0121/CMP0121-INSERT-OLD.cmake
new file mode 100644
index 0000000..60364d7
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-INSERT-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 OLD)
+include(CMP0121-INSERT-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-INSERT-WARN-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-INSERT-WARN-stderr.txt
new file mode 100644
index 0000000..5fa7d17
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-INSERT-WARN-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at CMP0121-INSERT-Common.cmake:3 \(list\):
+  Policy CMP0121 is not set: The list\(\) command now validates parsing of
+  index arguments.  Run "cmake --help-policy CMP0121" for policy details.
+  Use the cmake_policy command to set the policy and suppress this warning.
+  Invalid list index "junk2".
+Call Stack \(most recent call first\):
+  CMP0121-INSERT-WARN.cmake:2 \(include\)
+  CMakeLists.txt:3 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+INSERT: -->new;a;b;c;d;e<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-INSERT-WARN.cmake b/Tests/RunCMake/CMP0121/CMP0121-INSERT-WARN.cmake
new file mode 100644
index 0000000..55f13e2
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-INSERT-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0121-INSERT-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-Common.cmake b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-Common.cmake
new file mode 100644
index 0000000..ec92387
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-Common.cmake
@@ -0,0 +1,4 @@
+set(listvar a b c d e)
+
+list(REMOVE_AT listvar 0 invalid)
+message("REMOVE_AT: -->${listvar}<--")
diff --git a/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW-result.txt b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW-stderr.txt
new file mode 100644
index 0000000..f17bafd
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at CMP0121-REMOVE_AT-Common.cmake:3 \(list\):
+  list index: invalid is not a valid index
+Call Stack \(most recent call first\):
+  CMP0121-REMOVE_AT-NEW.cmake:2 \(include\)
+  CMakeLists.txt:3 \(include\)
+
+
+REMOVE_AT: -->a;b;c;d;e<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW.cmake b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW.cmake
new file mode 100644
index 0000000..d1f09e3
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 NEW)
+include(CMP0121-REMOVE_AT-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-OLD-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-OLD-stderr.txt
new file mode 100644
index 0000000..09af1ae
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-OLD-stderr.txt
@@ -0,0 +1 @@
+REMOVE_AT: -->b;c;d;e<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-OLD.cmake b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-OLD.cmake
new file mode 100644
index 0000000..ac83226
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 OLD)
+include(CMP0121-REMOVE_AT-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-WARN-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-WARN-stderr.txt
new file mode 100644
index 0000000..e2d47af
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-WARN-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at CMP0121-REMOVE_AT-Common.cmake:3 \(list\):
+  Policy CMP0121 is not set: The list\(\) command now validates parsing of
+  index arguments.  Run "cmake --help-policy CMP0121" for policy details.
+  Use the cmake_policy command to set the policy and suppress this warning.
+  Invalid list index "invalid".
+Call Stack \(most recent call first\):
+  CMP0121-REMOVE_AT-WARN.cmake:2 \(include\)
+  CMakeLists.txt:3 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+REMOVE_AT: -->b;c;d;e<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-WARN.cmake b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-WARN.cmake
new file mode 100644
index 0000000..2b4a824
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-REMOVE_AT-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0121-REMOVE_AT-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-Common.cmake b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-Common.cmake
new file mode 100644
index 0000000..93f46c5
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-Common.cmake
@@ -0,0 +1,4 @@
+set(listvar a b c d e)
+
+list(SUBLIST listvar 0 invalid out)
+message("SUBLIST-length: -->${out}<--")
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW-result.txt b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW-stderr.txt
new file mode 100644
index 0000000..28bd362
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at CMP0121-SUBLIST-length-Common.cmake:3 \(list\):
+  list index: invalid is not a valid index
+Call Stack \(most recent call first\):
+  CMP0121-SUBLIST-length-NEW.cmake:2 \(include\)
+  CMakeLists.txt:3 \(include\)
+
+
+SUBLIST-length: --><--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW.cmake b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW.cmake
new file mode 100644
index 0000000..c7875cb
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 NEW)
+include(CMP0121-SUBLIST-length-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-OLD-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-OLD-stderr.txt
new file mode 100644
index 0000000..00fcf07
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-OLD-stderr.txt
@@ -0,0 +1 @@
+SUBLIST-length: --><--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-OLD.cmake b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-OLD.cmake
new file mode 100644
index 0000000..e9b78ee
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 OLD)
+include(CMP0121-SUBLIST-length-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-WARN-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-WARN-stderr.txt
new file mode 100644
index 0000000..bd06c2f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-WARN-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at CMP0121-SUBLIST-length-Common.cmake:3 \(list\):
+  Policy CMP0121 is not set: The list\(\) command now validates parsing of
+  index arguments.  Run "cmake --help-policy CMP0121" for policy details.
+  Use the cmake_policy command to set the policy and suppress this warning.
+  Invalid list index "invalid".
+Call Stack \(most recent call first\):
+  CMP0121-SUBLIST-length-WARN.cmake:2 \(include\)
+  CMakeLists.txt:3 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+SUBLIST-length: --><--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-WARN.cmake b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-WARN.cmake
new file mode 100644
index 0000000..27318bf
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-length-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0121-SUBLIST-length-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-Common.cmake b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-Common.cmake
new file mode 100644
index 0000000..33f57a3
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-Common.cmake
@@ -0,0 +1,4 @@
+set(listvar a b c d e)
+
+list(SUBLIST listvar invalid 2 out)
+message("SUBLIST-start: -->${out}<--")
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW-result.txt b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW-stderr.txt
new file mode 100644
index 0000000..9819f95
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW-stderr.txt
@@ -0,0 +1,8 @@
+CMake Error at CMP0121-SUBLIST-start-Common.cmake:3 \(list\):
+  list index: invalid is not a valid index
+Call Stack \(most recent call first\):
+  CMP0121-SUBLIST-start-NEW.cmake:2 \(include\)
+  CMakeLists.txt:3 \(include\)
+
+
+SUBLIST-start: --><--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW.cmake b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW.cmake
new file mode 100644
index 0000000..3d676a3
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 NEW)
+include(CMP0121-SUBLIST-start-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-OLD-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-OLD-stderr.txt
new file mode 100644
index 0000000..8da2881
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-OLD-stderr.txt
@@ -0,0 +1 @@
+SUBLIST-start: -->a;b<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-OLD.cmake b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-OLD.cmake
new file mode 100644
index 0000000..268f317
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0121 OLD)
+include(CMP0121-SUBLIST-start-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-WARN-stderr.txt b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-WARN-stderr.txt
new file mode 100644
index 0000000..39d0e0e
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-WARN-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at CMP0121-SUBLIST-start-Common.cmake:3 \(list\):
+  Policy CMP0121 is not set: The list\(\) command now validates parsing of
+  index arguments.  Run "cmake --help-policy CMP0121" for policy details.
+  Use the cmake_policy command to set the policy and suppress this warning.
+  Invalid list index "invalid".
+Call Stack \(most recent call first\):
+  CMP0121-SUBLIST-start-WARN.cmake:2 \(include\)
+  CMakeLists.txt:3 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+SUBLIST-start: -->a;b<--
diff --git a/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-WARN.cmake b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-WARN.cmake
new file mode 100644
index 0000000..a407879
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMP0121-SUBLIST-start-WARN.cmake
@@ -0,0 +1,2 @@
+
+include(CMP0121-SUBLIST-start-Common.cmake)
diff --git a/Tests/RunCMake/CMP0121/CMakeLists.txt b/Tests/RunCMake/CMP0121/CMakeLists.txt
new file mode 100644
index 0000000..7cabeb6
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.20)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0121/RunCMakeTest.cmake b/Tests/RunCMake/CMP0121/RunCMakeTest.cmake
new file mode 100644
index 0000000..1ed5b1a
--- /dev/null
+++ b/Tests/RunCMake/CMP0121/RunCMakeTest.cmake
@@ -0,0 +1,7 @@
+include(RunCMake)
+
+foreach (subcommand IN ITEMS ERANGE GET INSERT REMOVE_AT SUBLIST-length SUBLIST-start)
+  run_cmake(CMP0121-${subcommand}-WARN)
+  run_cmake(CMP0121-${subcommand}-OLD)
+  run_cmake(CMP0121-${subcommand}-NEW)
+endforeach ()
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 78e0b6a..5f23c05 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -29,6 +29,10 @@
     ${TEST_ARGS}
     -P "${CMAKE_CURRENT_SOURCE_DIR}/${Test_Dir}/RunCMakeTest.cmake"
     )
+  set_tests_properties("RunCMake.${test}" PROPERTIES LABELS "CMake;run")
+  if(${test} MATCHES ^CMP)
+    set_property(TEST "RunCMake.${test}" APPEND PROPERTY LABELS "policy")
+  endif()
 endmacro()
 
 function(add_RunCMake_test_group test types)
@@ -131,6 +135,7 @@
 endif()
 add_RunCMake_test(CMP0118)
 add_RunCMake_test(CMP0119 -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
+add_RunCMake_test(CMP0121)
 
 # The test for Policy 65 requires the use of the
 # CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode
@@ -262,6 +267,7 @@
 add_RunCMake_test(GenEx-DEVICE_LINK)
 add_RunCMake_test(GenEx-TARGET_FILE -DLINKER_SUPPORTS_PDB=${LINKER_SUPPORTS_PDB})
 add_RunCMake_test(GenEx-GENEX_EVAL)
+add_RunCMake_test(GenEx-TARGET_RUNTIME_DLLS)
 add_RunCMake_test(GeneratorExpression)
 add_RunCMake_test(GeneratorInstance)
 add_RunCMake_test(GeneratorPlatform)
@@ -276,7 +282,7 @@
 add_RunCMake_test(TargetPropertyGeneratorExpressions)
 add_RunCMake_test(Languages)
 add_RunCMake_test(LinkStatic)
-if(CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang)$")
+if(CMAKE_CXX_COMPILER_ID MATCHES "^(Cray|PGI|NVHPC|XL|XLClang|Fujitsu|FujitsuClang)$")
   add_RunCMake_test(MetaCompileFeatures)
 endif()
 if(MSVC)
@@ -420,6 +426,15 @@
       set(CMAKE_C_STANDARD_DEFAULT "")
     endif()
   endif()
+  if(CMAKE_VERSION VERSION_LESS 3.20.20210225 AND "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang")
+    # Older CMake versions do not know about Clang MSVC compatibility mode
+    # standards. Approximate the logic from Clang-C.cmake.
+    if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 11.0)
+      set(CMAKE_C_STANDARD_DEFAULT 17)
+    elseif(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.5.2)
+      set(CMAKE_C_STANDARD_DEFAULT 11)
+    endif()
+  endif()
   foreach(var
       CMAKE_SYSTEM_NAME
       CMAKE_C_COMPILER_ID
diff --git a/Tests/RunCMake/CMakePresets/ConditionFuture-result.txt b/Tests/RunCMake/CMakePresets/ConditionFuture-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ConditionFuture-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/ConditionFuture-stderr.txt b/Tests/RunCMake/CMakePresets/ConditionFuture-stderr.txt
new file mode 100644
index 0000000..ea5f47f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ConditionFuture-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/ConditionFuture: File version must be 3 or higher for condition support$
diff --git a/Tests/RunCMake/CMakePresets/ConditionFuture.json.in b/Tests/RunCMake/CMakePresets/ConditionFuture.json.in
new file mode 100644
index 0000000..9d4798b
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ConditionFuture.json.in
@@ -0,0 +1,11 @@
+{
+  "version": 2,
+  "configurePresets": [
+    {
+      "name": "ConditionFuture",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build",
+      "condition": true
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/Conditions.json.in b/Tests/RunCMake/CMakePresets/Conditions.json.in
new file mode 100644
index 0000000..9c0c6bd
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/Conditions.json.in
@@ -0,0 +1,406 @@
+{
+  "version": 3,
+  "configurePresets": [
+    {
+      "name": "Base",
+      "hidden": true,
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build"
+    },
+    {
+      "name": "SimpleTrue",
+      "inherits": "Base",
+      "condition": true
+    },
+    {
+      "name": "SimpleFalse",
+      "inherits": "Base",
+      "condition": false
+    },
+    {
+      "name": "Null",
+      "inherits": "Base",
+      "condition": null
+    },
+    {
+      "name": "ConstTrue",
+      "inherits": "Base",
+      "condition": {
+        "type": "const",
+        "value": true
+      }
+    },
+    {
+      "name": "ConstFalse",
+      "inherits": "Base",
+      "condition": {
+        "type": "const",
+        "value": false
+      }
+    },
+    {
+      "name": "EqualsTrue",
+      "inherits": "Base",
+      "condition": {
+        "type": "equals",
+        "lhs": "abc",
+        "rhs": "abc"
+      }
+    },
+    {
+      "name": "EqualsFalse",
+      "inherits": "Base",
+      "condition": {
+        "type": "equals",
+        "lhs": "abc",
+        "rhs": "abcd"
+      }
+    },
+    {
+      "name": "EqualsMacroLeft",
+      "inherits": "Base",
+      "condition": {
+        "type": "equals",
+        "lhs": "${presetName}",
+        "rhs": "EqualsMacroLeft"
+      }
+    },
+    {
+      "name": "EqualsMacroRight",
+      "inherits": "Base",
+      "condition": {
+        "type": "equals",
+        "lhs": "EqualsMacroRight",
+        "rhs": "${presetName}"
+      }
+    },
+    {
+      "name": "NotEqualsTrue",
+      "inherits": "Base",
+      "condition": {
+        "type": "notEquals",
+        "lhs": "abc",
+        "rhs": "abcd"
+      }
+    },
+    {
+      "name": "NotEqualsFalse",
+      "inherits": "Base",
+      "condition": {
+        "type": "notEquals",
+        "lhs": "abc",
+        "rhs": "abc"
+      }
+    },
+    {
+      "name": "InListTrue",
+      "inherits": "Base",
+      "condition": {
+        "type": "inList",
+        "string": "b",
+        "list": [
+          "a",
+          "b",
+          "c"
+        ]
+      }
+    },
+    {
+      "name": "InListFalse",
+      "inherits": "Base",
+      "condition": {
+        "type": "inList",
+        "string": "d",
+        "list": [
+          "a",
+          "b",
+          "c"
+        ]
+      }
+    },
+    {
+      "name": "InListMacroString",
+      "inherits": "Base",
+      "condition": {
+        "type": "inList",
+        "string": "${presetName}",
+        "list": [
+          "InListMacroString",
+          "AnotherString"
+        ]
+      }
+    },
+    {
+      "name": "InListMacroList",
+      "inherits": "Base",
+      "condition": {
+        "type": "inList",
+        "string": "InListMacroList",
+        "list": [
+          "${presetName}",
+          "AnotherString"
+        ]
+      }
+    },
+    {
+      "name": "InListShortCircuit",
+      "inherits": "Base",
+      "condition": {
+        "type": "inList",
+        "string": "a",
+        "list": [
+          "a",
+          "${invalidMacro}"
+        ]
+      }
+    },
+    {
+      "name": "NotInListTrue",
+      "inherits": "Base",
+      "condition": {
+        "type": "notInList",
+        "string": "d",
+        "list": [
+          "a",
+          "b",
+          "c"
+        ]
+      }
+    },
+    {
+      "name": "NotInListFalse",
+      "inherits": "Base",
+      "condition": {
+        "type": "notInList",
+        "string": "a",
+        "list": [
+          "a",
+          "b",
+          "c"
+        ]
+      }
+    },
+    {
+      "name": "MatchesTrue",
+      "inherits": "Base",
+      "condition": {
+        "type": "matches",
+        "string": "aaa",
+        "regex": "^a*$"
+      }
+    },
+    {
+      "name": "MatchesFalse",
+      "inherits": "Base",
+      "condition": {
+        "type": "matches",
+        "string": "aab",
+        "regex": "^a*$"
+      }
+    },
+    {
+      "name": "MatchesMacroString",
+      "inherits": "Base",
+      "condition": {
+        "type": "matches",
+        "string": "${presetName}",
+        "regex": "^Matches"
+      }
+    },
+    {
+      "name": "MatchesMacroRegex",
+      "inherits": "Base",
+      "condition": {
+        "type": "matches",
+        "string": "stuff",
+        "regex": "$env{CONDITION_REGEX}"
+      },
+      "environment": {
+        "CONDITION_REGEX": "^stuf*$"
+      }
+    },
+    {
+      "name": "NotMatchesTrue",
+      "inherits": "Base",
+      "condition": {
+        "type": "notMatches",
+        "string": "aab",
+        "regex": "^a*$"
+      }
+    },
+    {
+      "name": "NotMatchesFalse",
+      "inherits": "Base",
+      "condition": {
+        "type": "notMatches",
+        "string": "aaa",
+        "regex": "^a*$"
+      }
+    },
+    {
+      "name": "AnyOfTrue1",
+      "inherits": "Base",
+      "condition": {
+        "type": "anyOf",
+        "conditions": [
+          true,
+          false
+        ]
+      }
+    },
+    {
+      "name": "AnyOfTrue2",
+      "inherits": "Base",
+      "condition": {
+        "type": "anyOf",
+        "conditions": [
+          false,
+          true
+        ]
+      }
+    },
+    {
+      "name": "AnyOfFalse",
+      "inherits": "Base",
+      "condition": {
+        "type": "anyOf",
+        "conditions": [
+          false,
+          {
+            "type": "equals",
+            "lhs": "abc",
+            "rhs": "abcd"
+          }
+        ]
+      }
+    },
+    {
+      "name": "AnyOfShortCircuit",
+      "inherits": "Base",
+      "condition": {
+        "type": "anyOf",
+        "conditions": [
+          true,
+          {
+            "type": "equals",
+            "lhs": "${invalidMacro}",
+            "rhs": ""
+          }
+        ]
+      }
+    },
+    {
+      "name": "AnyOfEmpty",
+      "inherits": "Base",
+      "condition": {
+        "type": "anyOf",
+        "conditions": []
+      }
+    },
+    {
+      "name": "AllOfTrue",
+      "inherits": "Base",
+      "condition": {
+        "type": "allOf",
+        "conditions": [
+          true,
+          {
+            "type": "equals",
+            "lhs": "abc",
+            "rhs": "abc"
+          }
+        ]
+      }
+    },
+    {
+      "name": "AllOfFalse1",
+      "inherits": "Base",
+      "condition": {
+        "type": "allOf",
+        "conditions": [
+          false,
+          true
+        ]
+      }
+    },
+    {
+      "name": "AllOfFalse2",
+      "inherits": "Base",
+      "condition": {
+        "type": "allOf",
+        "conditions": [
+          true,
+          false
+        ]
+      }
+    },
+    {
+      "name": "AllOfShortCircuit",
+      "inherits": "Base",
+      "condition": {
+        "type": "allOf",
+        "conditions": [
+          false,
+          {
+            "type": "equals",
+            "lhs": "${invalidMacro}",
+            "rhs": ""
+          }
+        ]
+      }
+    },
+    {
+      "name": "AllOfEmpty",
+      "inherits": "Base",
+      "condition": {
+        "type": "allOf",
+        "conditions": []
+      }
+    },
+    {
+      "name": "NotTrue",
+      "inherits": "Base",
+      "condition": {
+        "type": "not",
+        "condition": true
+      }
+    },
+    {
+      "name": "NotFalse",
+      "inherits": "Base",
+      "condition": {
+        "type": "not",
+        "condition": false
+      }
+    },
+    {
+      "name": "InheritanceBase",
+      "inherits": "Base",
+      "hidden": true,
+      "condition": {
+        "type": "equals",
+        "lhs": "${presetName}",
+        "rhs": "InheritanceChildTrue"
+      }
+    },
+    {
+      "name": "InheritanceChildTrue",
+      "inherits": "InheritanceBase"
+    },
+    {
+      "name": "InheritanceChildFalse",
+      "inherits": "InheritanceBase"
+    },
+    {
+      "name": "InheritanceNull",
+      "inherits": "Null"
+    },
+    {
+      "name": "InheritanceNullFalse",
+      "inherits": [
+        "Null",
+        "SimpleFalse"
+      ]
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField-result.txt b/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField-stderr.txt b/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField-stderr.txt
new file mode 100644
index 0000000..36123bd
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField: File version must be 3 or higher for installDir preset support.$
diff --git a/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField.json.in b/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField.json.in
new file mode 100644
index 0000000..2e5f7d5
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/FuturePresetInstallDirField.json.in
@@ -0,0 +1,11 @@
+{
+  "version": 1,
+  "configurePresets": [
+    {
+      "name": "FuturePresetInstallDirField",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build",
+      "installDir": "${sourceDir}/install"
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/GoodInstall.json.in b/Tests/RunCMake/CMakePresets/GoodInstall.json.in
new file mode 100644
index 0000000..6287c65
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodInstall.json.in
@@ -0,0 +1,30 @@
+{
+    "version": 3,
+    "configurePresets": [
+        {
+            "name": "GoodInstallDefault",
+            "generator": "@RunCMake_GENERATOR@",
+            "binaryDir": "${sourceDir}/build/${presetName}",
+            "installDir": "${sourceDir}/build/install_dir1"
+        },
+        {
+            "name": "GoodInstallInherit",
+            "inherits": "GoodInstallDefault",
+            "cacheVariables": {
+                "CMAKE_INSTALL_PREFIX": {
+                "type": "PATH",
+                "value": "${sourceDir}/build/bad_path"
+                }
+            }
+        },
+        {
+            "name": "GoodInstallOverride",
+            "inherits": "GoodInstallInherit",
+            "installDir": "${sourceDir}/build/install_dir2"
+        },
+        {
+            "name": "GoodInstallCommandLine",
+            "inherits": "GoodInstallOverride"
+        }
+    ]
+}
diff --git a/Tests/RunCMake/CMakePresets/GoodInstallCommandLine.cmake b/Tests/RunCMake/CMakePresets/GoodInstallCommandLine.cmake
new file mode 100644
index 0000000..a4f6178
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodInstallCommandLine.cmake
@@ -0,0 +1,3 @@
+include("${RunCMake_SOURCE_DIR}/TestVariable.cmake")
+
+test_variable("CMAKE_INSTALL_PREFIX" "PATH" "${RunCMake_SOURCE_DIR}/path/passed/on/command_line")
diff --git a/Tests/RunCMake/CMakePresets/GoodInstallDefault.cmake b/Tests/RunCMake/CMakePresets/GoodInstallDefault.cmake
new file mode 100644
index 0000000..656fda0
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodInstallDefault.cmake
@@ -0,0 +1,3 @@
+include("${RunCMake_SOURCE_DIR}/TestVariable.cmake")
+
+test_variable("CMAKE_INSTALL_PREFIX" "PATH" "${CMAKE_SOURCE_DIR}/build/install_dir1")
diff --git a/Tests/RunCMake/CMakePresets/GoodInstallInherit.cmake b/Tests/RunCMake/CMakePresets/GoodInstallInherit.cmake
new file mode 100644
index 0000000..656fda0
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodInstallInherit.cmake
@@ -0,0 +1,3 @@
+include("${RunCMake_SOURCE_DIR}/TestVariable.cmake")
+
+test_variable("CMAKE_INSTALL_PREFIX" "PATH" "${CMAKE_SOURCE_DIR}/build/install_dir1")
diff --git a/Tests/RunCMake/CMakePresets/GoodInstallOverride.cmake b/Tests/RunCMake/CMakePresets/GoodInstallOverride.cmake
new file mode 100644
index 0000000..3d12b07
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/GoodInstallOverride.cmake
@@ -0,0 +1,3 @@
+include("${RunCMake_SOURCE_DIR}/TestVariable.cmake")
+
+test_variable("CMAKE_INSTALL_PREFIX" "PATH" "${CMAKE_SOURCE_DIR}/build/install_dir2")
diff --git a/Tests/RunCMake/CMakePresets/HostSystemName.cmake b/Tests/RunCMake/CMakePresets/HostSystemName.cmake
new file mode 100644
index 0000000..dc0998a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/HostSystemName.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(TEST_HOST_SYSTEM_NAME "" "${CMAKE_HOST_SYSTEM_NAME}")
diff --git a/Tests/RunCMake/CMakePresets/HostSystemName.json.in b/Tests/RunCMake/CMakePresets/HostSystemName.json.in
new file mode 100644
index 0000000..7fcd8c8
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/HostSystemName.json.in
@@ -0,0 +1,13 @@
+{
+  "version": 3,
+  "configurePresets": [
+    {
+      "name": "HostSystemName",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build",
+      "cacheVariables": {
+        "TEST_HOST_SYSTEM_NAME": "${hostSystemName}"
+      }
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/HostSystemNameFuture-result.txt b/Tests/RunCMake/CMakePresets/HostSystemNameFuture-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/HostSystemNameFuture-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/HostSystemNameFuture-stderr.txt b/Tests/RunCMake/CMakePresets/HostSystemNameFuture-stderr.txt
new file mode 100644
index 0000000..7f4bb9a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/HostSystemNameFuture-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/HostSystemNameFuture: Invalid macro expansion$
diff --git a/Tests/RunCMake/CMakePresets/HostSystemNameFuture.json.in b/Tests/RunCMake/CMakePresets/HostSystemNameFuture.json.in
new file mode 100644
index 0000000..7a2f0aa
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/HostSystemNameFuture.json.in
@@ -0,0 +1,13 @@
+{
+  "version": 2,
+  "configurePresets": [
+    {
+      "name": "HostSystemNameFuture",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build",
+      "cacheVariables": {
+        "TEST_HOST_SYSTEM_NAME": "${hostSystemName}"
+      }
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/InvalidRegex-result.txt b/Tests/RunCMake/CMakePresets/InvalidRegex-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidRegex-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/InvalidRegex-stderr.txt b/Tests/RunCMake/CMakePresets/InvalidRegex-stderr.txt
new file mode 100644
index 0000000..5b500e4
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidRegex-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/InvalidRegex: Invalid macro expansion$
diff --git a/Tests/RunCMake/CMakePresets/InvalidRegex.json.in b/Tests/RunCMake/CMakePresets/InvalidRegex.json.in
new file mode 100644
index 0000000..69114d2
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/InvalidRegex.json.in
@@ -0,0 +1,15 @@
+{
+  "version": 3,
+  "configurePresets": [
+    {
+      "name": "InvalidRegex",
+      "binaryDir": "${sourceDir}/build",
+      "generator": "@RunCMake_GENERATOR@",
+      "condition": {
+        "type": "matches",
+        "string": "a",
+        "regex": "+"
+      }
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/ListConditions-stdout.txt b/Tests/RunCMake/CMakePresets/ListConditions-stdout.txt
new file mode 100644
index 0000000..91e0017
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/ListConditions-stdout.txt
@@ -0,0 +1,26 @@
+Available configure presets:
+
+  "SimpleTrue"
+  "Null"
+  "ConstTrue"
+  "EqualsTrue"
+  "EqualsMacroLeft"
+  "EqualsMacroRight"
+  "NotEqualsTrue"
+  "InListTrue"
+  "InListMacroString"
+  "InListMacroList"
+  "InListShortCircuit"
+  "NotInListTrue"
+  "MatchesTrue"
+  "MatchesMacroString"
+  "MatchesMacroRegex"
+  "NotMatchesTrue"
+  "AnyOfTrue1"
+  "AnyOfTrue2"
+  "AnyOfShortCircuit"
+  "AllOfTrue"
+  "AllOfEmpty"
+  "NotFalse"
+  "InheritanceChildTrue"
+  "InheritanceNull"$
diff --git a/Tests/RunCMake/CMakePresets/OptionalBinaryDirField.cmake b/Tests/RunCMake/CMakePresets/OptionalBinaryDirField.cmake
new file mode 100644
index 0000000..49e7a25
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/OptionalBinaryDirField.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_BINARY_DIR "" "${CMAKE_SOURCE_DIR}/build")
diff --git a/Tests/RunCMake/CMakePresets/OptionalBinaryDirField.json.in b/Tests/RunCMake/CMakePresets/OptionalBinaryDirField.json.in
new file mode 100644
index 0000000..ee17a22
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/OptionalBinaryDirField.json.in
@@ -0,0 +1,9 @@
+{
+  "version": 3,
+  "configurePresets": [
+    {
+      "name": "OptionalBinaryDirField",
+      "generator": "@RunCMake_GENERATOR@"
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/OptionalGeneratorField.cmake b/Tests/RunCMake/CMakePresets/OptionalGeneratorField.cmake
new file mode 100644
index 0000000..4319e72
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/OptionalGeneratorField.cmake
@@ -0,0 +1,3 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TestVariable.cmake)
+
+test_variable(CMAKE_GENERATOR "" "${RunCMake_GENERATOR}")
diff --git a/Tests/RunCMake/CMakePresets/OptionalGeneratorField.json.in b/Tests/RunCMake/CMakePresets/OptionalGeneratorField.json.in
new file mode 100644
index 0000000..920d056
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/OptionalGeneratorField.json.in
@@ -0,0 +1,9 @@
+{
+  "version": 3,
+  "configurePresets": [
+    {
+      "name": "OptionalGeneratorField",
+      "binaryDir": "${sourceDir}/build"
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
index dfc56ee..bcbd177 100644
--- a/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMakePresets/RunCMakeTest.cmake
@@ -94,6 +94,7 @@
 run_cmake_presets(ExtraRootField)
 run_cmake_presets(ExtraPresetField)
 run_cmake_presets(ExtraVariableField)
+run_cmake_presets(FuturePresetInstallDirField)
 run_cmake_presets(InvalidPresetVendor)
 set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
 run_cmake_presets(DuplicatePresets)
@@ -116,7 +117,10 @@
 run_cmake_presets(EnvCycle)
 run_cmake_presets(EmptyEnv)
 run_cmake_presets(EmptyPenv)
+run_cmake_presets(InvalidRegex)
 set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
+run_cmake_presets(ConditionFuture)
+run_cmake_presets(SubConditionNull)
 
 # Test cmakeMinimumRequired field
 run_cmake_presets(MinimumRequiredInvalid)
@@ -181,6 +185,13 @@
 run_cmake_presets(GoodInheritanceMultiSecond)
 run_cmake_presets(GoodInheritanceMacro)
 
+set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/GoodInstall.json.in")
+run_cmake_presets(GoodInstallDefault)
+run_cmake_presets(GoodInstallInherit)
+run_cmake_presets(GoodInstallOverride)
+run_cmake_presets(GoodInstallCommandLine  "--install-prefix=${RunCMake_SOURCE_DIR}/path/passed/on/command_line")
+
+set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/CMakePresets.json.in")
 # Test bad preset arguments
 run_cmake_presets(VendorMacro)
 run_cmake_presets(InvalidGenerator)
@@ -253,6 +264,23 @@
 run_cmake_presets(NoDebug)
 run_cmake_presets(Debug)
 
+# Test ${hostSystemName} macro
+set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/HostSystemName.json.in")
+run_cmake_presets(HostSystemName)
+set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/HostSystemNameFuture.json.in")
+run_cmake_presets(HostSystemNameFuture)
+
+# Test conditions
+set(CMakePresets_FILE "${RunCMake_SOURCE_DIR}/Conditions.json.in")
+run_cmake_presets(ListConditions --list-presets)
+run_cmake_presets(SimpleTrue)
+run_cmake_presets(SimpleFalse)
+unset(CMakePresets_FILE)
+
+# Test optional generator and buildDir fields
+run_cmake_presets(OptionalBinaryDirField -B "${RunCMake_BINARY_DIR}/OptionalBinaryDirField/build")
+run_cmake_presets(OptionalGeneratorField -G "${RunCMake_GENERATOR}")
+
 # Test the example from the documentation
 file(READ "${RunCMake_SOURCE_DIR}/../../../Help/manual/presets/example.json" _example)
 string(REPLACE "\"generator\": \"Ninja\"" "\"generator\": \"@RunCMake_GENERATOR@\"" _example "${_example}")
diff --git a/Tests/RunCMake/CMakePresets/SimpleFalse-result.txt b/Tests/RunCMake/CMakePresets/SimpleFalse-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/SimpleFalse-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/SimpleFalse-stderr.txt b/Tests/RunCMake/CMakePresets/SimpleFalse-stderr.txt
new file mode 100644
index 0000000..6a9a7de
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/SimpleFalse-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: Could not use disabled preset "SimpleFalse"$
diff --git a/Tests/RunCMake/CMakePresets/SimpleTrue.cmake b/Tests/RunCMake/CMakePresets/SimpleTrue.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/SimpleTrue.cmake
diff --git a/Tests/RunCMake/CMakePresets/SubConditionNull-result.txt b/Tests/RunCMake/CMakePresets/SubConditionNull-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/SubConditionNull-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresets/SubConditionNull-stderr.txt b/Tests/RunCMake/CMakePresets/SubConditionNull-stderr.txt
new file mode 100644
index 0000000..42b74d6
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/SubConditionNull-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/SubConditionNull: Invalid preset condition$
diff --git a/Tests/RunCMake/CMakePresets/SubConditionNull.json.in b/Tests/RunCMake/CMakePresets/SubConditionNull.json.in
new file mode 100644
index 0000000..eed3da6
--- /dev/null
+++ b/Tests/RunCMake/CMakePresets/SubConditionNull.json.in
@@ -0,0 +1,14 @@
+{
+  "version": 3,
+  "configurePresets": [
+    {
+      "name": "SubConditionNull",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build",
+      "condition": {
+        "type": "not",
+        "condition": null
+      }
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-result.txt b/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-stderr.txt
new file mode 100644
index 0000000..c35f5d7
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Condition-build-disabled-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Cannot use disabled build preset in [^
+]*/Tests/RunCMake/CMakePresetsBuild/Condition: "disabled"$
diff --git a/Tests/RunCMake/CMakePresetsBuild/Condition.cmake b/Tests/RunCMake/CMakePresetsBuild/Condition.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Condition.cmake
diff --git a/Tests/RunCMake/CMakePresetsBuild/Condition.json.in b/Tests/RunCMake/CMakePresetsBuild/Condition.json.in
new file mode 100644
index 0000000..aaee96a
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/Condition.json.in
@@ -0,0 +1,22 @@
+{
+  "version": 3,
+  "configurePresets": [
+    {
+      "name": "default",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build"
+    }
+  ],
+  "buildPresets": [
+    {
+      "name": "enabled",
+      "configurePreset": "default",
+      "condition": true
+    },
+    {
+      "name": "disabled",
+      "configurePreset": "default",
+      "condition": false
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-result.txt b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-stderr.txt b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-stderr.txt
new file mode 100644
index 0000000..f08f4c1
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture-build-conditionFuture-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsBuild/ConditionFuture: File version must be 3 or higher for condition support$
diff --git a/Tests/RunCMake/CMakePresetsBuild/ConditionFuture.json.in b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture.json.in
new file mode 100644
index 0000000..2f3f7d8
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsBuild/ConditionFuture.json.in
@@ -0,0 +1,17 @@
+{
+  "version": 2,
+  "configurePresets": [
+    {
+      "name": "default",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build"
+    }
+  ],
+  "buildPresets": [
+    {
+      "name": "conditionFuture",
+      "configurePreset": "default",
+      "condition": true
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresetsBuild/ListPresets-build-x-stdout.txt b/Tests/RunCMake/CMakePresetsBuild/ListPresets-build-x-stdout.txt
index 4d30707..2d362d4 100644
--- a/Tests/RunCMake/CMakePresetsBuild/ListPresets-build-x-stdout.txt
+++ b/Tests/RunCMake/CMakePresetsBuild/ListPresets-build-x-stdout.txt
@@ -1,5 +1,6 @@
-Available build presets:
+^Available build presets:
 
   "build-default" - build-default displayName
   "empty"
   "display"       - display displayName
+  "true"$
diff --git a/Tests/RunCMake/CMakePresetsBuild/ListPresets.json.in b/Tests/RunCMake/CMakePresetsBuild/ListPresets.json.in
index 3f5e02c..26504d3 100644
--- a/Tests/RunCMake/CMakePresetsBuild/ListPresets.json.in
+++ b/Tests/RunCMake/CMakePresetsBuild/ListPresets.json.in
@@ -1,5 +1,5 @@
 {
-    "version": 2,
+    "version": 3,
     "configurePresets": [
         {
             "name": "default",
@@ -26,6 +26,16 @@
         {
             "name": "hidden",
             "hidden": true
+        },
+        {
+            "name": "true",
+            "inherits": "build-default",
+            "condition": true
+        },
+        {
+            "name": "false",
+            "inherits": "build-default",
+            "condition": false
         }
     ]
 }
diff --git a/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake
index 2559b12..afa22eb 100644
--- a/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMakePresetsBuild/RunCMakeTest.cmake
@@ -64,6 +64,7 @@
 
 run_cmake_build_presets(Good "default;other" "build-other;withEnvironment;noEnvironment;macros;vendorObject")
 run_cmake_build_presets(InvalidConfigurePreset "default" "badConfigurePreset")
+run_cmake_build_presets(Condition "default" "enabled;disabled")
 
 set(CMakePresetsBuild_BUILD_ONLY 1)
 run_cmake_build_presets(ListPresets "x" "x" "--list-presets")
@@ -72,5 +73,6 @@
 
 set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
 run_cmake_build_presets(PresetsUnsupported "x" "x")
+run_cmake_build_presets(ConditionFuture "x" "conditionFuture")
 set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
 set(CMakePresetsBuild_BUILD_ONLY 0)
diff --git a/Tests/RunCMake/CMakePresetsTest/Condition.json.in b/Tests/RunCMake/CMakePresetsTest/Condition.json.in
new file mode 100644
index 0000000..0baf176
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/Condition.json.in
@@ -0,0 +1,22 @@
+{
+  "version": 3,
+  "configurePresets": [
+    {
+      "name": "default",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build"
+    }
+  ],
+  "testPresets": [
+    {
+      "name": "enabled",
+      "configurePreset": "default",
+      "condition": true
+    },
+    {
+      "name": "disabled",
+      "configurePreset": "default",
+      "condition": false
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-result.txt b/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-stderr.txt b/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-stderr.txt
new file mode 100644
index 0000000..b814bbb
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/ConditionFuture-test-x-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresetsTest/ConditionFuture: File version must be 3 or higher for condition support$
diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionFuture.json.in b/Tests/RunCMake/CMakePresetsTest/ConditionFuture.json.in
new file mode 100644
index 0000000..4b9f33f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/ConditionFuture.json.in
@@ -0,0 +1,17 @@
+{
+  "version": 2,
+  "configurePresets": [
+    {
+      "name": "default",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build"
+    }
+  ],
+  "testPresets": [
+    {
+      "name": "conditionFuture",
+      "configurePreset": "default",
+      "condition": true
+    }
+  ]
+}
diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionListPresets-test-x-stdout.txt b/Tests/RunCMake/CMakePresetsTest/ConditionListPresets-test-x-stdout.txt
new file mode 100644
index 0000000..11918e5
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/ConditionListPresets-test-x-stdout.txt
@@ -0,0 +1,3 @@
+^Available test presets:
+
+  "enabled"$
diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-result.txt b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-stderr.txt b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-stderr.txt
new file mode 100644
index 0000000..5db3b77
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests-test-disabled-stderr.txt
@@ -0,0 +1,2 @@
+^CMake Error: Cannot use disabled test preset in [^
+]*/Tests/RunCMake/CMakePresetsTest/ConditionRunTests: "disabled"$
diff --git a/Tests/RunCMake/CMakePresetsTest/ConditionRunTests.cmake b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests.cmake
new file mode 100644
index 0000000..b29161e
--- /dev/null
+++ b/Tests/RunCMake/CMakePresetsTest/ConditionRunTests.cmake
@@ -0,0 +1,2 @@
+enable_testing()
+add_test(true ${CMAKE_COMMAND} -E true)
diff --git a/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake b/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake
index c93dff3..70d25d4 100644
--- a/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMakePresetsTest/RunCMakeTest.cmake
@@ -90,6 +90,12 @@
 set(CMakePresetsTest_NO_CONFIGURE 1)
 set(CMakePresetsTest_FILE "${RunCMake_SOURCE_DIR}/Good.json.in")
 run_cmake_test_presets(ListPresets "" "" "x" "--list-presets")
+
+set(CMakePresetsTest_FILE "${RunCMake_SOURCE_DIR}/Condition.json.in")
+run_cmake_test_presets(ConditionListPresets "" "" "x" "--list-presets")
+unset(CMakePresetsTest_NO_CONFIGURE)
+run_cmake_test_presets(ConditionRunTests "default" "" "enabled;disabled")
+set(CMakePresetsTest_NO_CONFIGURE 1)
 unset(CMakePresetsTest_FILE)
 
 run_cmake_test_presets(NoConfigurePreset "" "" "noConfigurePreset")
@@ -98,6 +104,7 @@
 
 set(CMakePresets_SCHEMA_EXPECTED_RESULT 1)
 run_cmake_test_presets(PresetsUnsupported "" "" "x")
+run_cmake_test_presets(ConditionFuture "" "" "x")
 set(CMakePresets_SCHEMA_EXPECTED_RESULT 0)
 set(CMakePresetsTest_NO_CONFIGURE 0)
 
diff --git a/Tests/RunCMake/CPack/RPM/Prerequirements.cmake b/Tests/RunCMake/CPack/RPM/Prerequirements.cmake
index 3416205..e95cd15 100644
--- a/Tests/RunCMake/CPack/RPM/Prerequirements.cmake
+++ b/Tests/RunCMake/CPack/RPM/Prerequirements.cmake
@@ -13,4 +13,11 @@
         "\nset(RPMBUILD_EXECUTABLE \"${RPMBUILD_EXECUTABLE}\")")
     set(${found_var} true PARENT_SCOPE)
   endif()
+
+  # optional tool for some tests
+  find_program(OBJDUMP_EXECUTABLE objdump)
+  if(OBJDUMP_EXECUTABLE)
+    file(APPEND "${config_file}"
+      "\nset(OBJDUMP_EXECUTABLE \"${OBJDUMP_EXECUTABLE}\")")
+  endif()
 endfunction()
diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake
index 15bfb60..a3c72a1 100644
--- a/Tests/RunCMake/CPack/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake
@@ -16,7 +16,7 @@
 run_cpack_test(EXTRA "DEB.EXTRA" false "COMPONENT")
 run_cpack_test_subtests(GENERATE_SHLIBS "soversion_not_zero;soversion_zero" "DEB.GENERATE_SHLIBS" true "COMPONENT")
 run_cpack_test(GENERATE_SHLIBS_LDCONFIG "DEB.GENERATE_SHLIBS_LDCONFIG" true "COMPONENT")
-run_cpack_test(INSTALL_SCRIPTS "RPM.INSTALL_SCRIPTS" false "COMPONENT")
+run_cpack_test_subtests(INSTALL_SCRIPTS "default;single_debug_info;no_scripts;no_scripts_single_debug_info" "RPM.INSTALL_SCRIPTS" false "COMPONENT")
 run_cpack_test(LONG_FILENAMES "DEB.LONG_FILENAMES" false "MONOLITHIC")
 run_cpack_test_subtests(MAIN_COMPONENT "invalid;found" "RPM.MAIN_COMPONENT" false "COMPONENT")
 run_cpack_test(MINIMAL "RPM.MINIMAL;DEB.MINIMAL;7Z;TBZ2;TGZ;TXZ;TZ;ZIP;STGZ;External" false "MONOLITHIC;COMPONENT")
diff --git a/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/ExpectedFiles.cmake
index de38df9..5a87c44 100644
--- a/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/ExpectedFiles.cmake
+++ b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/ExpectedFiles.cmake
@@ -1,5 +1,10 @@
+if(RunCMake_SUBTEST_SUFFIX MATCHES ".*single_debug_info")
+  set(EXPECTED_FILE_1 "install_scripts-0.1.1-1.*.rpm")
+else()
+  set(EXPECTED_FILE_1_COMPONENT "foo")
+endif()
+
 set(EXPECTED_FILES_COUNT "2")
-set(EXPECTED_FILE_1_COMPONENT "foo")
 set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/CMakeLists.txt")
 set(EXPECTED_FILE_2_COMPONENT "bar")
 set(EXPECTED_FILE_CONTENT_2_LIST "/bar;/bar/CMakeLists.txt")
diff --git a/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-COMPONENT-no_scripts_single_debug_info-stderr.txt b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-COMPONENT-no_scripts_single_debug_info-stderr.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-COMPONENT-no_scripts_single_debug_info-stderr.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-COMPONENT-single_debug_info-stderr.txt b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-COMPONENT-single_debug_info-stderr.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-COMPONENT-single_debug_info-stderr.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-Prerequirements.cmake b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-Prerequirements.cmake
new file mode 100644
index 0000000..90cfe44
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/RPM-Prerequirements.cmake
@@ -0,0 +1,11 @@
+function(get_test_prerequirements found_var config_file)
+  if(SUBTEST_SUFFIX MATCHES ".*single_debug_info")
+    include(${config_file})
+
+    if(OBJDUMP_EXECUTABLE)
+      set(${found_var} true PARENT_SCOPE)
+    endif()
+  else()
+    set(${found_var} true PARENT_SCOPE)
+  endif()
+endfunction()
diff --git a/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/VerifyResult.cmake
index 1a1e983..0c42d90 100644
--- a/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/VerifyResult.cmake
+++ b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/VerifyResult.cmake
@@ -7,23 +7,34 @@
           ERROR_QUIET
           OUTPUT_STRIP_TRAILING_WHITESPACE)
 
-  string(REPLACE "\n" ";" FILE_SCRIPTS_LIST_ "${FILE_SCRIPTS_}")
+  if(COMPARE_LIST STREQUAL "")
+    if(NOT FILE_SCRIPTS_ STREQUAL "")
+      message(FATAL_ERROR "No scripts were expected in '${FILE}'; file info: '${FILE_SCRIPTS_}'")
+    endif()
+  else()
+    string(REPLACE "\n" ";" FILE_SCRIPTS_LIST_ "${FILE_SCRIPTS_}")
 
-  foreach(COMPARE_REGEX_ IN LISTS COMPARE_LIST)
-    unset(FOUND_)
+    foreach(COMPARE_REGEX_ IN LISTS COMPARE_LIST)
+      unset(FOUND_)
 
-    foreach(COMPARE_ IN LISTS FILE_SCRIPTS_LIST_)
-      if(COMPARE_ MATCHES "${COMPARE_REGEX_}")
-        set(FOUND_ true)
-        break()
+      foreach(COMPARE_ IN LISTS FILE_SCRIPTS_LIST_)
+        if(COMPARE_ MATCHES "${COMPARE_REGEX_}")
+          set(FOUND_ true)
+          break()
+        endif()
+      endforeach()
+
+      if(NOT FOUND_)
+        message(FATAL_ERROR "Missing scripts in '${FILE}'; file info: '${FILE_SCRIPTS_}'; missing: '${COMPARE_REGEX_}'")
       endif()
     endforeach()
-
-    if(NOT FOUND_)
-      message(FATAL_ERROR "Missing scripts in '${FILE}'; file info: '${FILE_SCRIPTS_}'; missing: '${COMPARE_REGEX_}'")
-    endif()
-  endforeach()
+  endif()
 endfunction()
 
-checkScripts_("${FOUND_FILE_1}" "echo \"pre install foo\";echo \"post install foo\";echo \"pre uninstall foo\";echo \"post uninstall foo\";echo \"pre trans foo\";echo \"post trans foo\"")
-checkScripts_("${FOUND_FILE_2}" "echo \"pre install\";echo \"post install\";echo \"pre uninstall\";echo \"post uninstall\";echo \"pre trans\";echo \"post trans\"")
+if(RunCMake_SUBTEST_SUFFIX MATCHES "no_scripts.*")
+  checkScripts_("${FOUND_FILE_1}" "")
+  checkScripts_("${FOUND_FILE_2}" "")
+else()
+  checkScripts_("${FOUND_FILE_1}" "echo \"pre install foo\";echo \"post install foo\";echo \"pre uninstall foo\";echo \"post uninstall foo\";echo \"pre trans foo\";echo \"post trans foo\"")
+  checkScripts_("${FOUND_FILE_2}" "echo \"pre install\";echo \"post install\";echo \"pre uninstall\";echo \"post uninstall\";echo \"pre trans\";echo \"post trans\"")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/test.cmake b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/test.cmake
index c200fa5..ce5db0c 100644
--- a/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/test.cmake
+++ b/Tests/RunCMake/CPack/tests/INSTALL_SCRIPTS/test.cmake
@@ -1,60 +1,70 @@
 if(GENERATOR_TYPE STREQUAL "RPM")
-  set(CPACK_RPM_PRE_INSTALL_SCRIPT_FILE
-    "${CMAKE_CURRENT_BINARY_DIR}/pre_install.sh")
-  set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE
-    "${CMAKE_CURRENT_BINARY_DIR}/post_install.sh")
-  set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE
-    "${CMAKE_CURRENT_BINARY_DIR}/pre_uninstall.sh")
-  set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE
-    "${CMAKE_CURRENT_BINARY_DIR}/post_uninstall.sh")
-  set(CPACK_RPM_PRE_TRANS_SCRIPT_FILE
-    "${CMAKE_CURRENT_BINARY_DIR}/pre_trans.sh")
-  set(CPACK_RPM_POST_TRANS_SCRIPT_FILE
-    "${CMAKE_CURRENT_BINARY_DIR}/post_trans.sh")
-
-  set(CPACK_RPM_foo_PRE_INSTALL_SCRIPT_FILE
-    "${CMAKE_CURRENT_BINARY_DIR}/pre_install_foo.sh")
-  set(CPACK_RPM_foo_POST_INSTALL_SCRIPT_FILE
-    "${CMAKE_CURRENT_BINARY_DIR}/post_install_foo.sh")
-  set(CPACK_RPM_foo_PRE_UNINSTALL_SCRIPT_FILE
-    "${CMAKE_CURRENT_BINARY_DIR}/pre_uninstall_foo.sh")
-  set(CPACK_RPM_foo_POST_UNINSTALL_SCRIPT_FILE
-    "${CMAKE_CURRENT_BINARY_DIR}/post_uninstall_foo.sh")
-  set(CPACK_RPM_foo_PRE_TRANS_SCRIPT_FILE
-    "${CMAKE_CURRENT_BINARY_DIR}/pre_trans_foo.sh")
-  set(CPACK_RPM_foo_POST_TRANS_SCRIPT_FILE
-    "${CMAKE_CURRENT_BINARY_DIR}/post_trans_foo.sh")
+  if(RunCMake_SUBTEST_SUFFIX MATCHES ".*single_debug_info")
+    set(CPACK_RPM_MAIN_COMPONENT "foo")
+    set(CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE ON)
+    set(CPACK_RPM_FOO_FILE_NAME "RPM-DEFAULT")
+  endif()
 endif()
 
 set(CMAKE_BUILD_WITH_INSTALL_RPATH 1)
 
-# default
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_install.sh"
-    "echo \"pre install\"\n")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_install.sh"
-    "echo \"post install\"\n")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_uninstall.sh"
-    "echo \"pre uninstall\"\n")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_uninstall.sh"
-    "echo \"post uninstall\"\n")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_trans.sh"
-    "echo \"pre trans\"\n")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_trans.sh"
-    "echo \"post trans\"\n")
+if(NOT RunCMake_SUBTEST_SUFFIX MATCHES "no_scripts.*")
+  if(GENERATOR_TYPE STREQUAL "RPM")
+    set(CPACK_RPM_PRE_INSTALL_SCRIPT_FILE
+      "${CMAKE_CURRENT_BINARY_DIR}/pre_install.sh")
+    set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE
+      "${CMAKE_CURRENT_BINARY_DIR}/post_install.sh")
+    set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE
+      "${CMAKE_CURRENT_BINARY_DIR}/pre_uninstall.sh")
+    set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE
+      "${CMAKE_CURRENT_BINARY_DIR}/post_uninstall.sh")
+    set(CPACK_RPM_PRE_TRANS_SCRIPT_FILE
+      "${CMAKE_CURRENT_BINARY_DIR}/pre_trans.sh")
+    set(CPACK_RPM_POST_TRANS_SCRIPT_FILE
+      "${CMAKE_CURRENT_BINARY_DIR}/post_trans.sh")
 
-# specific
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_install_foo.sh"
-    "echo \"pre install foo\"\n")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_install_foo.sh"
-    "echo \"post install foo\"\n")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_uninstall_foo.sh"
-    "echo \"pre uninstall foo\"\n")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_uninstall_foo.sh"
-    "echo \"post uninstall foo\"\n")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_trans_foo.sh"
-    "echo \"pre trans foo\"\n")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_trans_foo.sh"
-    "echo \"post trans foo\"\n")
+    set(CPACK_RPM_foo_PRE_INSTALL_SCRIPT_FILE
+      "${CMAKE_CURRENT_BINARY_DIR}/pre_install_foo.sh")
+    set(CPACK_RPM_foo_POST_INSTALL_SCRIPT_FILE
+      "${CMAKE_CURRENT_BINARY_DIR}/post_install_foo.sh")
+    set(CPACK_RPM_foo_PRE_UNINSTALL_SCRIPT_FILE
+      "${CMAKE_CURRENT_BINARY_DIR}/pre_uninstall_foo.sh")
+    set(CPACK_RPM_foo_POST_UNINSTALL_SCRIPT_FILE
+      "${CMAKE_CURRENT_BINARY_DIR}/post_uninstall_foo.sh")
+    set(CPACK_RPM_foo_PRE_TRANS_SCRIPT_FILE
+      "${CMAKE_CURRENT_BINARY_DIR}/pre_trans_foo.sh")
+    set(CPACK_RPM_foo_POST_TRANS_SCRIPT_FILE
+      "${CMAKE_CURRENT_BINARY_DIR}/post_trans_foo.sh")
+  endif()
+
+  # default
+  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_install.sh"
+      "echo \"pre install\"\n")
+  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_install.sh"
+      "echo \"post install\"\n")
+  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_uninstall.sh"
+      "echo \"pre uninstall\"\n")
+  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_uninstall.sh"
+      "echo \"post uninstall\"\n")
+  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_trans.sh"
+      "echo \"pre trans\"\n")
+  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_trans.sh"
+      "echo \"post trans\"\n")
+
+  # specific
+  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_install_foo.sh"
+      "echo \"pre install foo\"\n")
+  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_install_foo.sh"
+      "echo \"post install foo\"\n")
+  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_uninstall_foo.sh"
+      "echo \"pre uninstall foo\"\n")
+  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_uninstall_foo.sh"
+      "echo \"post uninstall foo\"\n")
+  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pre_trans_foo.sh"
+      "echo \"pre trans foo\"\n")
+  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post_trans_foo.sh"
+      "echo \"post trans foo\"\n")
+endif()
 
 install(FILES CMakeLists.txt DESTINATION foo COMPONENT foo)
 install(FILES CMakeLists.txt DESTINATION bar COMPONENT bar)
diff --git a/Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/ExpectedFiles.cmake
index 936e4ed..1dc7084 100644
--- a/Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/ExpectedFiles.cmake
+++ b/Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/ExpectedFiles.cmake
@@ -9,7 +9,7 @@
   set(EXPECTED_FILE_2 "single_debuginfo*-headers.rpm")
   set(EXPECTED_FILE_CONTENT_2_LIST "/bar;/bar/CMakeLists.txt")
   set(EXPECTED_FILE_3 "single_debuginfo*-libs.rpm")
-  set(EXPECTED_FILE_CONTENT_3_LIST "/bas;/bas/libtest_lib.so")
+  set(EXPECTED_FILE_CONTENT_3_LIST "/bas;/bas/libtest_lib.so;/empty_dir")
 
   set(EXPECTED_FILE_4_COMPONENT "debuginfo")
   set(EXPECTED_FILE_CONTENT_4 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/main.cpp${whitespaces_}/src/src_1/test_lib.cpp.*\.debug.*")
diff --git a/Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/test.cmake b/Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/test.cmake
index 60e9038..064539e 100644
--- a/Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/test.cmake
+++ b/Tests/RunCMake/CPack/tests/SINGLE_DEBUGINFO/test.cmake
@@ -30,6 +30,9 @@
   OR RunCMake_SUBTEST_SUFFIX STREQUAL "no_debuginfo")
   install(FILES CMakeLists.txt DESTINATION bar COMPONENT headers)
   install(TARGETS test_lib DESTINATION bas COMPONENT libs)
+
+  # test that we correctly handle empty dir in non main component
+  install(DIRECTORY DESTINATION empty_dir COMPONENT libs)
 elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "one_component"
   OR RunCMake_SUBTEST_SUFFIX STREQUAL "one_component_no_debuginfo")
   set(CPACK_COMPONENTS_ALL applications)
diff --git a/Tests/RunCMake/CPackSymlinks/RunCMakeTest.cmake b/Tests/RunCMake/CPackSymlinks/RunCMakeTest.cmake
index 439d95e..5a8b7a0 100644
--- a/Tests/RunCMake/CPackSymlinks/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CPackSymlinks/RunCMakeTest.cmake
@@ -15,6 +15,7 @@
   run_cmake_command(SrcSymlinksCPack
     ${CMAKE_CPACK_COMMAND} --config CPackSourceConfig.cmake
     )
+  run_cmake_script(SrcSymlinksCheck)
 endfunction()
 
 run_cpack_symlink_test()
diff --git a/Tests/RunCMake/CPackSymlinks/SrcSymlinksCheck.cmake b/Tests/RunCMake/CPackSymlinks/SrcSymlinksCheck.cmake
new file mode 100644
index 0000000..0041c92
--- /dev/null
+++ b/Tests/RunCMake/CPackSymlinks/SrcSymlinksCheck.cmake
@@ -0,0 +1,21 @@
+set(dir ${CMAKE_CURRENT_SOURCE_DIR})
+
+set(tarball ${dir}/SrcSymlinks-0.1-Source.tar.gz)
+set(extrdir ${dir}/SrcSymlinks-0.1-Source)
+
+message(STATUS "Extracting ${tarball} in ${dir}...")
+execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf ${tarball}
+  RESULT_VARIABLE result
+  OUTPUT_VARIABLE output
+  ERROR_VARIABLE output
+  WORKING_DIRECTORY ${dir})
+message(STATUS "result='${result}'")
+message(STATUS "output='${output}'")
+
+if(NOT ${result} EQUAL 0)
+  message(FATAL_ERROR "Cannot unpack source tarball")
+endif()
+
+if(NOT EXISTS ${extrdir}/dirlink/src.h)
+  message(FATAL_ERROR "${extrdir}/dirlink/src.h not found")
+endif()
diff --git a/Tests/RunCMake/CPackSymlinks/SrcSymlinksTar-stdout.txt b/Tests/RunCMake/CPackSymlinks/SrcSymlinksTar-stdout.txt
index 24ad124..8b1ae57 100644
--- a/Tests/RunCMake/CPackSymlinks/SrcSymlinksTar-stdout.txt
+++ b/Tests/RunCMake/CPackSymlinks/SrcSymlinksTar-stdout.txt
@@ -1,7 +1,6 @@
-^x CMakeLists.txt
-x cygwin/
-x cygwin/build.sh
-x cygwin/setup.patch
+^x build.sh
+x CMakeLists.txt
+x dirlink
 x include/
 x include/src.h
 x link.h
diff --git a/Tests/RunCMake/CPackSymlinks/testcpacksym.tar b/Tests/RunCMake/CPackSymlinks/testcpacksym.tar
index a44c656..c24af48 100644
--- a/Tests/RunCMake/CPackSymlinks/testcpacksym.tar
+++ b/Tests/RunCMake/CPackSymlinks/testcpacksym.tar
Binary files differ
diff --git a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
index 6cf1476..2f4d731 100644
--- a/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CTestCommandLine/RunCMakeTest.cmake
@@ -202,7 +202,7 @@
   add_test(TestLoad1 \"${CMAKE_COMMAND}\" -E echo \"test of --test-load\")
   add_test(TestLoad2 \"${CMAKE_COMMAND}\" -E echo \"test of --test-load\")
 ")
-  run_cmake_command(${name} ${CMAKE_CTEST_COMMAND} -j2 --test-load ${load})
+  run_cmake_command(${name} ${CMAKE_CTEST_COMMAND} -VV -j2 --test-load ${load})
 endfunction()
 
 # Tests for the --test-load feature of ctest
diff --git a/Tests/RunCMake/CTestCommandLine/test-load-invalid-stdout.txt b/Tests/RunCMake/CTestCommandLine/test-load-invalid-stdout.txt
index 7ee3dae..5101985 100644
--- a/Tests/RunCMake/CTestCommandLine/test-load-invalid-stdout.txt
+++ b/Tests/RunCMake/CTestCommandLine/test-load-invalid-stdout.txt
@@ -1,7 +1,20 @@
-^Test project .*/Tests/RunCMake/CTestCommandLine/TestLoad
+Test project [^
+]*/Tests/RunCMake/CTestCommandLine/TestLoad(
+[^*][^
+]*)*
+test 1
     Start 1: TestLoad1
++(
+[^*][^
+]*)*
+test 2
     Start 2: TestLoad2
-1/2 Test #[1-2]: TestLoad[1-2] ........................   Passed +[0-9.]+ sec
++(
+[^*][^
+]*)*
+1/2 Test #[1-2]: TestLoad[1-2] ........................   Passed +[0-9.]+ sec(
+[^*][^
+]*)*
 2/2 Test #[1-2]: TestLoad[1-2] ........................   Passed +[0-9.]+ sec
 +
 100% tests passed, 0 tests failed out of 2
diff --git a/Tests/RunCMake/CTestCommandLine/test-load-pass-stdout.txt b/Tests/RunCMake/CTestCommandLine/test-load-pass-stdout.txt
index 7ee3dae..5101985 100644
--- a/Tests/RunCMake/CTestCommandLine/test-load-pass-stdout.txt
+++ b/Tests/RunCMake/CTestCommandLine/test-load-pass-stdout.txt
@@ -1,7 +1,20 @@
-^Test project .*/Tests/RunCMake/CTestCommandLine/TestLoad
+Test project [^
+]*/Tests/RunCMake/CTestCommandLine/TestLoad(
+[^*][^
+]*)*
+test 1
     Start 1: TestLoad1
++(
+[^*][^
+]*)*
+test 2
     Start 2: TestLoad2
-1/2 Test #[1-2]: TestLoad[1-2] ........................   Passed +[0-9.]+ sec
++(
+[^*][^
+]*)*
+1/2 Test #[1-2]: TestLoad[1-2] ........................   Passed +[0-9.]+ sec(
+[^*][^
+]*)*
 2/2 Test #[1-2]: TestLoad[1-2] ........................   Passed +[0-9.]+ sec
 +
 100% tests passed, 0 tests failed out of 2
diff --git a/Tests/RunCMake/CTestCommandLine/test-load-wait-stdout.txt b/Tests/RunCMake/CTestCommandLine/test-load-wait-stdout.txt
index 11a768a..db7d7f3 100644
--- a/Tests/RunCMake/CTestCommandLine/test-load-wait-stdout.txt
+++ b/Tests/RunCMake/CTestCommandLine/test-load-wait-stdout.txt
@@ -1,8 +1,21 @@
-^Test project .*/Tests/RunCMake/CTestCommandLine/TestLoad
+Test project [^
+]*/Tests/RunCMake/CTestCommandLine/TestLoad(
+[^*][^
+]*)*
 \*\*\*\*\* WAITING, System Load: 5, Max Allowed Load: 3, Smallest test TestLoad[1-2] requires 1\*\*\*\*\*
+test 1
     Start 1: TestLoad1
++(
+[^*][^
+]*)*
+test 2
     Start 2: TestLoad2
-1/2 Test #[1-2]: TestLoad[1-2] ........................   Passed +[0-9.]+ sec
++(
+[^*][^
+]*)*
+1/2 Test #[1-2]: TestLoad[1-2] ........................   Passed +[0-9.]+ sec(
+[^*][^
+]*)*
 2/2 Test #[1-2]: TestLoad[1-2] ........................   Passed +[0-9.]+ sec
 +
 100% tests passed, 0 tests failed out of 2
diff --git a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
index c76c92d..3df3e52 100644
--- a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
+++ b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
@@ -1 +1 @@
-^{"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":2}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"version":{.*}}$
+^{"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":3}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"version":{.*}}$
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index 8072a2c..c497472 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -61,6 +61,9 @@
 run_cmake_command(build-bad-generator
   ${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR}/cache-bad-generator)
 
+
+run_cmake_command(install-prefix-no-arg ${CMAKE_COMMAND} -B DummyBuildDir --install-prefix)
+
 run_cmake_command(install-no-dir
   ${CMAKE_COMMAND} --install)
 run_cmake_command(install-bad-dir
diff --git a/Tests/RunCMake/CommandLine/install-prefix-no-arg-result.txt b/Tests/RunCMake/CommandLine/install-prefix-no-arg-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/install-prefix-no-arg-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/install-prefix-no-arg-stderr.txt b/Tests/RunCMake/CommandLine/install-prefix-no-arg-stderr.txt
new file mode 100644
index 0000000..a464c70
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/install-prefix-no-arg-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: No install directory specified for --install-prefix
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateful-check.cmake b/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateful-check.cmake
index fb78e87..91cdf7c 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateful-check.cmake
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateful-check.cmake
@@ -4,6 +4,7 @@
   query/client-foo/query.json
   reply
   reply/codemodel-v2-[0-9a-f]+\\.json
+  .*
   reply/index-[0-9.T-]+\\.json
   .*
   )
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateless-check.cmake b/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateless-check.cmake
index 7c6a35a..9aa9e4a 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateless-check.cmake
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateless-check.cmake
@@ -4,6 +4,7 @@
   query/client-foo/codemodel-v2
   reply
   reply/codemodel-v2-[0-9a-f]+\\.json
+  .*
   reply/index-[0-9.T-]+\\.json
   .*
   )
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-SharedStateless-check.cmake b/Tests/RunCMake/FileAPI/codemodel-v2-SharedStateless-check.cmake
index cc2f31b..43d1a0b 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-SharedStateless-check.cmake
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-SharedStateless-check.cmake
@@ -3,6 +3,7 @@
   query/codemodel-v2
   reply
   reply/codemodel-v2-[0-9a-f]+\\.json
+  .*
   reply/index-[0-9.T-]+\\.json
   .*
   )
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-check.py b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
index df2410a..0d718a4 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-check.py
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
@@ -12,7 +12,7 @@
 def check_objects(o, g):
     assert is_list(o)
     assert len(o) == 1
-    check_index_object(o[0], "codemodel", 2, 2, check_object_codemodel(g))
+    check_index_object(o[0], "codemodel", 2, 3, check_object_codemodel(g))
 
 def check_backtrace(t, b, backtrace):
     btg = t["backtraceGraph"]
@@ -55,7 +55,7 @@
 def check_directory(c):
     def _check(actual, expected):
         assert is_dict(actual)
-        expected_keys = ["build", "source", "projectIndex"]
+        expected_keys = ["build", "jsonFile", "source", "projectIndex"]
         assert matches(actual["build"], expected["build"])
 
         assert is_int(actual["projectIndex"])
@@ -92,10 +92,99 @@
 
         assert sorted(actual.keys()) == sorted(expected_keys)
 
+        assert is_string(actual["jsonFile"])
+        filepath = os.path.join(reply_dir, actual["jsonFile"])
+        with open(filepath) as f:
+            d = json.load(f)
+
+        assert is_dict(d)
+        assert sorted(d.keys()) == ["backtraceGraph", "installers", "paths"]
+
+        assert is_string(d["paths"]["source"], actual["source"])
+        assert is_string(d["paths"]["build"], actual["build"])
+
+        check_backtrace_graph(d["backtraceGraph"])
+
+        assert is_list(d["installers"])
+        assert len(d["installers"]) == len(expected["installers"])
+        for a, e in zip(d["installers"], expected["installers"]):
+            assert is_dict(a)
+            expected_keys = ["component", "type"]
+
+            assert is_string(a["component"], e["component"])
+            assert is_string(a["type"], e["type"])
+
+            if e["destination"] is not None:
+                expected_keys.append("destination")
+                assert is_string(a["destination"], e["destination"])
+
+            if e["paths"] is not None:
+                expected_keys.append("paths")
+                assert is_list(a["paths"])
+                assert len(a["paths"]) == len(e["paths"])
+
+                for ap, ep in zip(a["paths"], e["paths"]):
+                    if is_string(ep):
+                        assert matches(ap, ep)
+                    else:
+                        assert is_dict(ap)
+                        assert sorted(ap.keys()) == ["from", "to"]
+                        assert matches(ap["from"], ep["from"])
+                        assert matches(ap["to"], ep["to"])
+
+            if e["isExcludeFromAll"] is not None:
+                expected_keys.append("isExcludeFromAll")
+                assert is_bool(a["isExcludeFromAll"], e["isExcludeFromAll"])
+
+            if e["isOptional"] is not None:
+                expected_keys.append("isOptional")
+                assert is_bool(a["isOptional"], e["isOptional"])
+
+            if e["targetId"] is not None:
+                expected_keys.append("targetId")
+                assert matches(a["targetId"], e["targetId"])
+
+            if e["targetIndex"] is not None:
+                expected_keys.append("targetIndex")
+                assert is_int(a["targetIndex"])
+                assert c["targets"][a["targetIndex"]]["name"] == e["targetIndex"]
+
+            if e["targetIsImportLibrary"] is not None:
+                expected_keys.append("targetIsImportLibrary")
+                assert is_bool(a["targetIsImportLibrary"], e["targetIsImportLibrary"])
+
+            if e["targetInstallNamelink"] is not None:
+                expected_keys.append("targetInstallNamelink")
+                assert is_string(a["targetInstallNamelink"], e["targetInstallNamelink"])
+
+            if e["exportName"] is not None:
+                expected_keys.append("exportName")
+                assert is_string(a["exportName"], e["exportName"])
+
+            if e["exportTargets"] is not None:
+                expected_keys.append("exportTargets")
+                assert is_list(a["exportTargets"])
+                assert len(a["exportTargets"]) == len(e["exportTargets"])
+                for at, et in zip(a["exportTargets"], e["exportTargets"]):
+                    assert is_dict(at)
+                    assert sorted(at.keys()) == ["id", "index"]
+                    assert matches(at["id"], et["id"])
+                    assert is_int(at["index"])
+                    assert c["targets"][at["index"]]["name"] == et["index"]
+
+            if e["scriptFile"] is not None:
+                expected_keys.append("scriptFile")
+                assert is_string(a["scriptFile"], e["scriptFile"])
+
+            if e["backtrace"] is not None:
+                expected_keys.append("backtrace")
+                check_backtrace(d, a["backtrace"], e["backtrace"])
+
+            assert sorted(a.keys()) == sorted(expected_keys)
+
     return _check
 
-def check_target_backtrace_graph(t):
-    btg = t["backtraceGraph"]
+def check_backtrace_graph(btg):
     assert is_dict(btg)
     assert sorted(btg.keys()) == ["commands", "files", "nodes"]
     assert is_list(btg["commands"])
@@ -148,7 +237,7 @@
         assert is_string(obj["name"], expected["name"])
         assert matches(obj["id"], expected["id"])
         assert is_string(obj["type"], expected["type"])
-        check_target_backtrace_graph(obj)
+        check_backtrace_graph(obj["backtraceGraph"])
 
         assert is_dict(obj["paths"])
         assert sorted(obj["paths"].keys()) == ["build", "source"]
@@ -543,6 +632,20 @@
         for e in expected:
             e["targetIds"] = filter_list(lambda t: not matches(t, "^\\^(ALL_BUILD|ZERO_CHECK)"), e["targetIds"])
 
+    if sys.platform in ("win32", "cygwin", "msys") or "aix" in sys.platform:
+        for e in expected:
+            e["installers"] = list(filter(lambda i: i["targetInstallNamelink"] is None or i["targetInstallNamelink"] == "skip", e["installers"]))
+            for i in e["installers"]:
+                i["targetInstallNamelink"] = None
+
+    if sys.platform not in ("win32", "cygwin", "msys"):
+        for e in expected:
+            e["installers"] = list(filter(lambda i: "_dllExtra" not in i or not i["_dllExtra"], e["installers"]))
+            if "aix" not in sys.platform:
+                for i in e["installers"]:
+                    if "pathsNamelink" in i:
+                        i["paths"] = i["pathsNamelink"]
+
     return expected
 
 def check_directories(c, g):
@@ -705,6 +808,13 @@
     if sys.platform not in ("win32", "cygwin", "msys"):
         for e in expected:
             e["artifacts"] = filter_list(lambda a: not a["_dllExtra"], e["artifacts"])
+            if e["install"] is not None:
+                e["install"]["destinations"] = filter_list(lambda d: "_dllExtra" not in d or not d["_dllExtra"], e["install"]["destinations"])
+
+    else:
+        for e in expected:
+            if e["install"] is not None:
+                e["install"]["destinations"] = filter_list(lambda d: "_namelink" not in d or not d["_namelink"], e["install"]["destinations"])
 
     if "aix" not in sys.platform:
         for e in expected:
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/alias.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/alias.json
index 9f0c48a..6514910 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/alias.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/alias.json
@@ -11,5 +11,6 @@
     ],
     "projectName": "Alias",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": null
+    "hasInstallRule": null,
+    "installers": []
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/custom.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/custom.json
index afd41f3..c89e4f9 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/custom.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/custom.json
@@ -11,5 +11,6 @@
     ],
     "projectName": "Custom",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": null
+    "hasInstallRule": null,
+    "installers": []
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/cxx.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/cxx.json
index a51b6eb..7168306 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/cxx.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/cxx.json
@@ -17,5 +17,6 @@
     ],
     "projectName": "Cxx",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": null
+    "hasInstallRule": null,
+    "installers": []
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir.json
index afbd43a..8509f08 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir.json
@@ -8,5 +8,6 @@
     "targetIds": null,
     "projectName": "codemodel-v2",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": null
+    "hasInstallRule": null,
+    "installers": []
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir_dir.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir_dir.json
index 3737ad5..27184cd 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir_dir.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir_dir.json
@@ -6,5 +6,6 @@
     "targetIds": null,
     "projectName": "codemodel-v2",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": null
+    "hasInstallRule": null,
+    "installers": []
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/external.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/external.json
index 521e3c7..55dd573 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/external.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/external.json
@@ -10,5 +10,69 @@
     ],
     "projectName": "External",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": null
+    "hasInstallRule": true,
+    "installers": [
+        {
+            "component": "Unspecified",
+            "type": "directory",
+            "destination": "dir3",
+            "paths": [
+                "^.*/Tests/RunCMake/FileAPIExternalSource/\\.$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": null,
+            "targetIndex": null,
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^.*/Tests/RunCMake/FileAPIExternalSource/CMakeLists\\.txt$",
+                    "line": 15,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^.*/Tests/RunCMake/FileAPIExternalSource/CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "directory",
+            "destination": "dir4",
+            "paths": [
+                "^.*/Tests/RunCMake/FileAPIExternalSource$"
+            ],
+            "isExcludeFromAll": true,
+            "isOptional": null,
+            "targetId": null,
+            "targetIndex": null,
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^.*/Tests/RunCMake/FileAPIExternalSource/CMakeLists\\.txt$",
+                    "line": 16,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^.*/Tests/RunCMake/FileAPIExternalSource/CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        }
+    ]
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json
index a41b79b..d127274 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json
@@ -14,5 +14,6 @@
     ],
     "projectName": "Imported",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": null
+    "hasInstallRule": null,
+    "installers": []
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/interface.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/interface.json
index b10d496..90664dc 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/interface.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/interface.json
@@ -10,5 +10,6 @@
     ],
     "projectName": "Interface",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": null
+    "hasInstallRule": null,
+    "installers": []
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/object.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/object.json
index 1e647ad..ef2dd0b 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/object.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/object.json
@@ -13,5 +13,69 @@
     ],
     "projectName": "Object",
     "minimumCMakeVersion": "3.13",
-    "hasInstallRule": true
+    "hasInstallRule": true,
+    "installers": [
+        {
+            "component": "Unspecified",
+            "type": "target",
+            "destination": "bin",
+            "paths": [
+                "^object/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?c_object_exe(\\.exe)?$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": "^c_object_exe::@5ed5358f70faf8d8af7a$",
+            "targetIndex": "c_object_exe",
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^object/CMakeLists\\.txt$",
+                    "line": 13,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^object/CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "target",
+            "destination": "bin",
+            "paths": [
+                "^object/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?cxx_object_exe(\\.exe)?$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": "^cxx_object_exe::@5ed5358f70faf8d8af7a$",
+            "targetIndex": "cxx_object_exe",
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^object/CMakeLists\\.txt$",
+                    "line": 13,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^object/CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        }
+    ]
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/top.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/top.json
index 736d1f5..ce45947 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/top.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/top.json
@@ -25,5 +25,549 @@
     ],
     "projectName": "codemodel-v2",
     "minimumCMakeVersion": "3.12",
-    "hasInstallRule": true
+    "hasInstallRule": true,
+    "installers": [
+        {
+            "component": "Tools",
+            "type": "target",
+            "destination": "bin",
+            "paths": [
+                "^cxx/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?cxx_exe(\\.exe)?$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": "^cxx_exe::@a56b12a3f5c0529fb296$",
+            "targetIndex": "cxx_exe",
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 38,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "target",
+            "destination": "lib",
+            "paths": [
+                "^((Debug|Release|MinSizeRel|RelWithDebInfo)/)?(lib)?c_shared_lib\\.(lib|dll\\.a)$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": "^c_shared_lib::@6890427a1f51a3e7e1df$",
+            "targetIndex": "c_shared_lib",
+            "targetIsImportLibrary": true,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "_dllExtra": true,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 41,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "target",
+            "destination": "lib",
+            "paths": [
+                "^lib/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?(lib|cyg)?c_shared_lib(-1)?\\.(dll|so)$"
+            ],
+            "pathsNamelink": [
+                "^lib/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?(lib)?c_shared_lib\\.(so\\.1\\.2\\.3|1\\.2\\.3\\.dylib)$",
+                "^lib/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?(lib)?c_shared_lib\\.(so\\.1|1\\.dylib)$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": "^c_shared_lib::@6890427a1f51a3e7e1df$",
+            "targetIndex": "c_shared_lib",
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": "skip",
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 41,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "target",
+            "destination": "lib",
+            "paths": [
+                "^cxx/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?(lib)?cxx_shared_lib\\.(lib|dll\\.a)$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": "^cxx_shared_lib::@a56b12a3f5c0529fb296$",
+            "targetIndex": "cxx_shared_lib",
+            "targetIsImportLibrary": true,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "_dllExtra": true,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 41,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "target",
+            "destination": "lib",
+            "paths": [
+                "^cxx/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?(lib|cyg)?cxx_shared_lib\\.(dll|so|dylib)$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": "^cxx_shared_lib::@a56b12a3f5c0529fb296$",
+            "targetIndex": "cxx_shared_lib",
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 41,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "target",
+            "destination": "lib",
+            "paths": [
+                "^lib/((Debug|Release|MinSizeRel|RelWithDebInfo)/)?(lib)?c_shared_lib\\.(dll|so|dylib)$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": "^c_shared_lib::@6890427a1f51a3e7e1df$",
+            "targetIndex": "c_shared_lib",
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": "only",
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 46,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "file",
+            "destination": "include",
+            "paths": [
+                {
+                    "from": "^empty\\.h$",
+                    "to": "^empty-renamed\\.h$"
+                }
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": true,
+            "targetId": null,
+            "targetIndex": null,
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 48,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "file",
+            "destination": "include",
+            "paths": [
+                "^codemodel-v2\\.cmake$",
+                "^empty\\.h$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": null,
+            "targetIndex": null,
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 49,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "directory",
+            "destination": "dir1",
+            "paths": [
+                "^\\.$",
+                "^dir$",
+                {
+                    "from": "^cxx$",
+                    "to": "^\\.$"
+                }
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": true,
+            "targetId": null,
+            "targetIndex": null,
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 50,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "directory",
+            "destination": "dir2",
+            "paths": [
+                {
+                    "from": "^\\.$",
+                    "to": "^FileAPI$"
+                },
+                "^dir$",
+                {
+                    "from": "^cxx$",
+                    "to": "^\\.$"
+                }
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": null,
+            "targetIndex": null,
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 51,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "export",
+            "destination": "lib/cmake/foo",
+            "paths": [
+                "^CMakeFiles/Export/lib/cmake/foo/FooTargets\\.cmake$"
+            ],
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": null,
+            "targetIndex": null,
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": "FooTargets",
+            "exportTargets": [
+                {
+                    "id": "^cxx_exe::@a56b12a3f5c0529fb296$",
+                    "index": "cxx_exe"
+                }
+            ],
+            "scriptFile": null,
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 52,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        },
+        {
+            "component": "Unspecified",
+            "type": "script",
+            "destination": null,
+            "paths": null,
+            "isExcludeFromAll": null,
+            "isOptional": null,
+            "targetId": null,
+            "targetIndex": null,
+            "targetIsImportLibrary": null,
+            "targetInstallNamelink": null,
+            "exportName": null,
+            "exportTargets": null,
+            "scriptFile": "InstallScript.cmake",
+            "backtrace": [
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": 53,
+                    "command": "install",
+                    "hasParent": true
+                },
+                {
+                    "file": "^codemodel-v2\\.cmake$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": 3,
+                    "command": "include",
+                    "hasParent": true
+                },
+                {
+                    "file": "^CMakeLists\\.txt$",
+                    "line": null,
+                    "command": null,
+                    "hasParent": false
+                }
+            ]
+        }
+    ]
 }
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json
index 176a857..5588bd5 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json
@@ -90,10 +90,10 @@
         }
     ],
     "folder": null,
-    "nameOnDisk": "^(lib|cyg)?c_shared_lib\\.(so|dylib|dll)$",
+    "nameOnDisk": "^(lib|cyg)?c_shared_lib(-1)?\\.(so|dylib|dll)$",
     "artifacts": [
         {
-            "path": "^lib/((Debug|Release|RelWithDebInfo|MinSizeRel)/)?(lib|cyg)?c_shared_lib\\.(so|dylib|dll)$",
+            "path": "^lib/((Debug|Release|RelWithDebInfo|MinSizeRel)/)?(lib|cyg)?c_shared_lib(-1)?\\.(so|dylib|dll)$",
             "_dllExtra": false
         },
         {
@@ -101,13 +101,106 @@
             "_dllExtra": true
         },
         {
-            "path": "^lib/((Debug|Release|RelWithDebInfo|MinSizeRel)/)?(lib|cyg)?c_shared_lib\\.pdb$",
+            "path": "^lib/((Debug|Release|RelWithDebInfo|MinSizeRel)/)?(lib|cyg)?c_shared_lib(-1)?\\.pdb$",
             "_dllExtra": true
         }
     ],
     "build": "^\\.$",
     "source": "^\\.$",
-    "install": null,
+    "install": {
+        "prefix": "^(/usr/local|[A-Za-z]:.*/codemodel-v2)$",
+        "destinations": [
+            {
+                "path": "lib",
+                "backtrace": [
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": 41,
+                        "command": "install",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": 3,
+                        "command": "include",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": false
+                    }
+                ]
+            },
+            {
+                "path": "lib",
+                "_dllExtra": true,
+                "backtrace": [
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": 41,
+                        "command": "install",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": 3,
+                        "command": "include",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": false
+                    }
+                ]
+            },
+            {
+                "path": "lib",
+                "_namelink": true,
+                "backtrace": [
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": 46,
+                        "command": "install",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": 3,
+                        "command": "include",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": false
+                    }
+                ]
+            }
+        ]
+    },
     "link": {
         "language": "C",
         "lto": true,
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json
index 171a4f5..e5e1d0d 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json
@@ -83,7 +83,100 @@
     ],
     "build": "^cxx$",
     "source": "^cxx$",
-    "install": null,
+    "install": {
+        "prefix": "^(/usr/local|[A-Za-z]:.*/codemodel-v2)$",
+        "destinations": [
+            {
+                "path": "lib",
+                "backtrace": [
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": 41,
+                        "command": "install",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": 3,
+                        "command": "include",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": false
+                    }
+                ]
+            },
+            {
+                "path": "lib",
+                "_dllExtra": true,
+                "backtrace": [
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": 41,
+                        "command": "install",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": 3,
+                        "command": "include",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": false
+                    }
+                ]
+            },
+            {
+                "path": "lib",
+                "_namelink": true,
+                "backtrace": [
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": 46,
+                        "command": "install",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^codemodel-v2\\.cmake$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": 3,
+                        "command": "include",
+                        "hasParent": true
+                    },
+                    {
+                        "file": "^CMakeLists\\.txt$",
+                        "line": null,
+                        "command": null,
+                        "hasParent": false
+                    }
+                ]
+            }
+        ]
+    },
     "link": {
         "language": "CXX",
         "lto": null,
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2.cmake b/Tests/RunCMake/FileAPI/codemodel-v2.cmake
index 2405954..528f075 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2.cmake
+++ b/Tests/RunCMake/FileAPI/codemodel-v2.cmake
@@ -35,4 +35,19 @@
   file(WRITE "${CMAKE_BINARY_DIR}/ipo_enabled.txt" "")
 endif()
 
-install(TARGETS cxx_exe)
+install(TARGETS cxx_exe COMPONENT Tools EXPORT FooTargets)
+
+set_target_properties(c_shared_lib PROPERTIES VERSION 1.2.3 SOVERSION 1)
+install(TARGETS c_shared_lib cxx_shared_lib
+  ARCHIVE DESTINATION lib
+  RUNTIME DESTINATION lib
+  LIBRARY DESTINATION lib NAMELINK_SKIP
+  )
+install(TARGETS c_shared_lib cxx_shared_lib LIBRARY NAMELINK_ONLY)
+
+install(FILES empty.h TYPE INCLUDE RENAME empty-renamed.h OPTIONAL)
+install(FILES codemodel-v2.cmake empty.h DESTINATION include)
+install(DIRECTORY . dir cxx/ OPTIONAL DESTINATION dir1)
+install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/dir" "${CMAKE_CURRENT_SOURCE_DIR}/cxx/" DESTINATION dir2)
+install(EXPORT FooTargets DESTINATION lib/cmake/foo)
+install(SCRIPT InstallScript.cmake)
diff --git a/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt b/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt
index 76235f5..95c803f 100644
--- a/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt
+++ b/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt
@@ -16,7 +16,7 @@
 
 target_compile_options(cxx_exe PUBLIC TargetCompileOptions)
 target_link_options(cxx_exe PUBLIC TargetLinkOptions)
-target_link_directories(cxx_exe PUBLIC "${CMAKE_BINARY_DIR}/TargetLinkDir")
+target_link_directories(cxx_exe PUBLIC "$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/TargetLinkDir>")
 
 target_precompile_headers(cxx_exe PUBLIC ../empty.h)
 
diff --git a/Tests/RunCMake/FileAPIExternalSource/CMakeLists.txt b/Tests/RunCMake/FileAPIExternalSource/CMakeLists.txt
index b3ca660..2865864 100644
--- a/Tests/RunCMake/FileAPIExternalSource/CMakeLists.txt
+++ b/Tests/RunCMake/FileAPIExternalSource/CMakeLists.txt
@@ -11,3 +11,6 @@
 target_include_directories(generated_exe SYSTEM PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
 target_compile_definitions(generated_exe PRIVATE GENERATED_EXE=1 -DTGT_DUMMY)
 set_source_files_properties(empty.c PROPERTIES COMPILE_OPTIONS SRC_COMPILE_OPTIONS_DUMMY)
+
+install(DIRECTORY . DESTINATION dir3)
+install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} EXCLUDE_FROM_ALL DESTINATION dir4)
diff --git a/Tests/RunCMake/File_Generate/OutputNameMatchesObjects-stderr.txt b/Tests/RunCMake/File_Generate/OutputNameMatchesObjects-stderr.txt
index 4c2e35f..4d7370c 100644
--- a/Tests/RunCMake/File_Generate/OutputNameMatchesObjects-stderr.txt
+++ b/Tests/RunCMake/File_Generate/OutputNameMatchesObjects-stderr.txt
@@ -3,7 +3,7 @@
 
     \$<TARGET_OBJECTS:foo>
 
-  Objects of target "foo" referenced but is not an allowed library types
-  \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\).
+  Objects of target "foo" referenced but is not one of the allowed target
+  types \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\).
 Call Stack \(most recent call first\):
   CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/CMakeLists.txt b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/CMakeLists.txt
new file mode 100644
index 0000000..ab1a20c
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.19)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/RunCMakeTest.cmake
new file mode 100644
index 0000000..edc495c
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/RunCMakeTest.cmake
@@ -0,0 +1,7 @@
+include(RunCMake)
+
+run_cmake(TARGET_RUNTIME_DLLS)
+run_cmake(TARGET_RUNTIME_DLLS-static)
+run_cmake(TARGET_RUNTIME_DLLS-target_link_libraries)
+run_cmake(TARGET_RUNTIME_DLLS-target_link_libraries-cycle1)
+run_cmake(TARGET_RUNTIME_DLLS-target_link_libraries-cycle2)
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-check.cmake b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-check.cmake
new file mode 100644
index 0000000..e19598e
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-check.cmake
@@ -0,0 +1,15 @@
+function(check_genex expected actual)
+  if(NOT expected STREQUAL actual)
+    string(APPEND RunCMake_TEST_FAILED "Expected DLLs:\n")
+    foreach(dll IN LISTS expected)
+      string(APPEND RunCMake_TEST_FAILED "  ${dll}\n")
+    endforeach()
+    string(APPEND RunCMake_TEST_FAILED "Actual DLLs:\n")
+    foreach(dll IN LISTS actual)
+      string(APPEND RunCMake_TEST_FAILED "  ${dll}\n")
+    endforeach()
+  endif()
+  set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE)
+endfunction()
+
+include("${RunCMake_TEST_BINARY_DIR}/dlls.cmake")
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static-result.txt b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static-stderr.txt b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static-stderr.txt
new file mode 100644
index 0000000..7ce588a
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at TARGET_RUNTIME_DLLS-static\.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_RUNTIME_DLLS:static>
+
+  Objects of target "static" referenced but is not one of the allowed target
+  types \(EXECUTABLE, SHARED, MODULE\)\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static.cmake b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static.cmake
new file mode 100644
index 0000000..dc900dd
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-static.cmake
@@ -0,0 +1,9 @@
+enable_language(C)
+
+add_library(static STATIC static.c)
+set(condition)
+get_property(multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(multi_config)
+  set(condition CONDITION "$<CONFIG:Debug>")
+endif()
+file(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/dlls.txt" CONTENT "$<TARGET_RUNTIME_DLLS:static>" ${condition})
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1-result.txt b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1-stderr.txt b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1-stderr.txt
new file mode 100644
index 0000000..8cfcf7e
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1-stderr.txt
@@ -0,0 +1,5 @@
+CMake Error at TARGET_RUNTIME_DLLS-target_link_libraries-cycle1\.cmake:[0-9]+ \(add_library\):
+  The SOURCES of "lib1" use a generator expression that depends on the
+  SOURCES themselves\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1.cmake b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1.cmake
new file mode 100644
index 0000000..f19e9e6
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle1.cmake
@@ -0,0 +1,4 @@
+enable_language(C)
+
+add_library(lib1 SHARED lib1.c)
+target_link_libraries(lib1 PRIVATE $<TARGET_RUNTIME_DLLS:lib1>)
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2-result.txt b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2-stderr.txt b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2-stderr.txt
new file mode 100644
index 0000000..bacbf63
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2-stderr.txt
@@ -0,0 +1,5 @@
+CMake Error at TARGET_RUNTIME_DLLS-target_link_libraries-cycle2\.cmake:[0-9]+ \(add_library\):
+  The SOURCES of "(lib1|lib2)" use a generator expression that depends on the
+  SOURCES themselves\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2.cmake b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2.cmake
new file mode 100644
index 0000000..7d035bd
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries-cycle2.cmake
@@ -0,0 +1,6 @@
+enable_language(C)
+
+add_library(lib1 SHARED lib1.c)
+add_library(lib2 SHARED lib2.c)
+target_link_libraries(lib1 PRIVATE $<TARGET_RUNTIME_DLLS:lib2>)
+target_link_libraries(lib2 PRIVATE $<TARGET_RUNTIME_DLLS:lib1>)
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries.cmake b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries.cmake
new file mode 100644
index 0000000..f44dbf4
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS-target_link_libraries.cmake
@@ -0,0 +1,5 @@
+enable_language(C)
+
+add_library(lib1 SHARED lib1.c)
+add_library(lib2 SHARED lib2.c)
+target_link_libraries(lib1 PRIVATE $<TARGET_RUNTIME_DLLS:lib2>)
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS.cmake b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS.cmake
new file mode 100644
index 0000000..806f0b6
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/TARGET_RUNTIME_DLLS.cmake
@@ -0,0 +1,37 @@
+enable_language(C)
+
+add_executable(exe main.c)
+add_library(lib1 SHARED lib1.c)
+add_library(lib2 SHARED lib2.c)
+add_library(lib3 SHARED lib3.c)
+add_library(static STATIC static.c)
+add_library(imported SHARED IMPORTED)
+set_property(TARGET imported PROPERTY IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/imported.dll")
+set_property(TARGET imported PROPERTY IMPORTED_IMPLIB "${CMAKE_SOURCE_DIR}/imported.lib")
+add_library(imported2 SHARED IMPORTED)
+if(NOT WIN32 AND NOT CYGWIN)
+  set_property(TARGET imported2 PROPERTY IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/imported2.dll")
+endif()
+set_property(TARGET imported2 PROPERTY IMPORTED_IMPLIB "${CMAKE_SOURCE_DIR}/imported2.lib")
+
+target_link_libraries(exe PRIVATE lib1 static imported imported2)
+target_link_libraries(lib1 PRIVATE lib2)
+target_link_libraries(lib1 INTERFACE lib3)
+
+set(expected_dlls "")
+if(WIN32 OR CYGWIN)
+  set(expected_dlls
+    "$<TARGET_FILE:lib1>"
+    "$<TARGET_FILE:imported>"
+    "$<TARGET_FILE:lib3>"
+    "$<TARGET_FILE:lib2>"
+    )
+endif()
+
+set(content "check_genex(\"${expected_dlls}\" \"$<TARGET_RUNTIME_DLLS:exe>\")\n")
+set(condition)
+get_property(multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(multi_config)
+  set(condition CONDITION "$<CONFIG:Debug>")
+endif()
+file(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/dlls.cmake" CONTENT "${content}" ${condition})
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib1.c b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib1.c
new file mode 100644
index 0000000..524b5b2
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib1.c
@@ -0,0 +1,12 @@
+#ifdef _WIN32
+__declspec(dllimport)
+#endif
+  extern void lib2(void);
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+  void lib1(void)
+{
+  lib2();
+}
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib2.c b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib2.c
new file mode 100644
index 0000000..e145117
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib2.c
@@ -0,0 +1,6 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+  void lib2(void)
+{
+}
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib3.c b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib3.c
new file mode 100644
index 0000000..5392f7a
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/lib3.c
@@ -0,0 +1,6 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+  void lib3(void)
+{
+}
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/main.c b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/static.c b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/static.c
new file mode 100644
index 0000000..7f5dab5
--- /dev/null
+++ b/Tests/RunCMake/GenEx-TARGET_RUNTIME_DLLS/static.c
@@ -0,0 +1,3 @@
+void static_func(void)
+{
+}
diff --git a/Tests/RunCMake/GeneratorPlatform/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorPlatform/RunCMakeTest.cmake
index 27ede06..83e63f9 100644
--- a/Tests/RunCMake/GeneratorPlatform/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GeneratorPlatform/RunCMakeTest.cmake
@@ -11,9 +11,9 @@
   run_cmake(BadPlatform)
 endif()
 
-set(RunCMake_GENERATOR_TOOLSET "")
+set(RunCMake_GENERATOR_PLATFORM "")
 
-set(RunCMake_TEST_OPTIONS -A "Extra Platform")
+set(RunCMake_TEST_OPTIONS -A "Test Platform" -A "Extra Platform")
 run_cmake(TwoPlatforms)
 unset(RunCMake_TEST_OPTIONS)
 
diff --git a/Tests/RunCMake/GeneratorToolset/BadToolsetCustomFlagTableDir-result.txt b/Tests/RunCMake/GeneratorToolset/BadToolsetCustomFlagTableDir-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/BadToolsetCustomFlagTableDir-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorToolset/BadToolsetCustomFlagTableDir-stderr.txt b/Tests/RunCMake/GeneratorToolset/BadToolsetCustomFlagTableDir-stderr.txt
new file mode 100644
index 0000000..d8b6c5e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/BadToolsetCustomFlagTableDir-stderr.txt
@@ -0,0 +1,11 @@
+CMake Error at CMakeLists.txt:[0-9]+ \(project\):
+  Generator
+
+    Visual Studio [^
+]*
+
+  given toolset
+
+    customFlagTableDir=does_not_exist
+
+  that is not an absolute path to an existing directory.$
diff --git a/Tests/RunCMake/GeneratorToolset/BadToolsetCustomFlagTableDir.cmake b/Tests/RunCMake/GeneratorToolset/BadToolsetCustomFlagTableDir.cmake
new file mode 100644
index 0000000..2fc38e5
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/BadToolsetCustomFlagTableDir.cmake
@@ -0,0 +1 @@
+message(FATAL_ERROR "This should not be reached!")
diff --git a/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake
index 5f12d79..faed8f7 100644
--- a/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake
@@ -1,5 +1,11 @@
 include(RunCMake)
 
+if("${RunCMake_GENERATOR}" MATCHES "Visual Studio 1[012456]")
+  run_cmake(VsNormal)
+  include("${RunCMake_BINARY_DIR}/VsNormal-build/defaults.cmake" OPTIONAL)
+  message(STATUS "VsNormal: platform='${VsNormal_Platform}' toolset='${VsNormal_Toolset}'")
+endif()
+
 set(RunCMake_GENERATOR_TOOLSET "")
 run_cmake(NoToolset)
 
@@ -12,8 +18,31 @@
   run_cmake(TestToolsetCudaVersionOnly)
   set(RunCMake_GENERATOR_TOOLSET "cuda=0.0")
   run_cmake(TestToolsetCudaVersionOnly)
-  set(RunCMake_GENERATOR_TOOLSET "cuda=C:\\dummy\\cuda")
+  set(RunCMake_GENERATOR_TOOLSET "cuda=${CMAKE_CURRENT_BINARY_DIR}/CudaStandaloneToolset")
   run_cmake(TestToolsetCudaPathOnly)
+  set(RunCMake_GENERATOR_TOOLSET "cuda=${CMAKE_CURRENT_BINARY_DIR}/CudaStandaloneToolset")
+  file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/CudaStandaloneToolset/CUDAVisualStudioIntegration")
+  run_cmake(TestToolsetCudaPathOnlyOldLayout)
+  file(REMOVE_RECURSE "${CMAKE_CURRENT_BINARY_DIR}/CudaStandaloneToolset")
+  if (VsNormal_Platform MATCHES "^(x64|Win32)$" AND
+      EXISTS "${CMAKE_ROOT}/Templates/MSBuild/FlagTables/${VsNormal_Toolset}_CL.json")
+    set(flagTableDir "${RunCMake_BINARY_DIR}/FlagTables")
+    file(READ "${CMAKE_ROOT}/Templates/MSBuild/FlagTables/${VsNormal_Toolset}_CL.json" flagTableContent)
+    string(REPLACE [["WX-"]] [["TESTWX-"]] flagTableContent "${flagTableContent}")
+    file(REMOVE_RECURSE "${flagTableDir}")
+    file(WRITE "${flagTableDir}/${VsNormal_Platform}_${VsNormal_Toolset}_CL.json" "${flagTableContent}")
+    set(RunCMake_GENERATOR_TOOLSET "${VsNormal_Toolset},customFlagTableDir=${flagTableDir}")
+    set(RunCMake_TEST_VARIANT_DESCRIPTION ":${VsNormal_Platform}_${VsNormal_Toolset}_CL.json")
+    run_cmake(TestToolsetCustomFlagTableDir)
+    file(REMOVE_RECURSE "${flagTableDir}")
+    file(WRITE "${flagTableDir}/${VsNormal_Platform}_CL.json" "${flagTableContent}")
+    set(RunCMake_GENERATOR_TOOLSET "${VsNormal_Toolset},customFlagTableDir=${flagTableDir}")
+    set(RunCMake_TEST_VARIANT_DESCRIPTION ":${VsNormal_Platform}_CL.json")
+    run_cmake(TestToolsetCustomFlagTableDir)
+    unset(RunCMake_TEST_VARIANT_DESCRIPTION)
+    set(RunCMake_GENERATOR_TOOLSET "${VsNormal_Toolset},customFlagTableDir=does_not_exist")
+    run_cmake(BadToolsetCustomFlagTableDir)
+  endif()
   if("${RunCMake_GENERATOR}" MATCHES "Visual Studio 1[2456]")
     set(RunCMake_GENERATOR_TOOLSET "Test Toolset,host=x64")
     run_cmake(TestToolsetHostArchBoth)
@@ -76,7 +105,7 @@
 
 set(RunCMake_GENERATOR_TOOLSET "")
 
-set(RunCMake_TEST_OPTIONS -T "Extra Toolset")
+set(RunCMake_TEST_OPTIONS -T "Test Toolset" -T "Extra Toolset")
 run_cmake(TwoToolsets)
 unset(RunCMake_TEST_OPTIONS)
 
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnly-stderr.txt b/Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnly-stderr.txt
index b17745f..5236787 100644
--- a/Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnly-stderr.txt
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnly-stderr.txt
@@ -5,8 +5,8 @@
 
   given toolset
 
-    cuda=C:\\dummy\\cuda\\
+    cuda=.*/Tests/RunCMake/CudaStandaloneToolset\\
 
   cannot detect Visual Studio integration files in path
 
-    C:/dummy/cuda/CUDAVisualStudioIntegration/extras/visual_studio_integration/MSBuildExtensions
+    .*/Tests/RunCMake/CudaStandaloneToolset/extras/visual_studio_integration/MSBuildExtensions
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnlyOldLayout-result.txt b/Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnlyOldLayout-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnlyOldLayout-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnlyOldLayout-stderr.txt b/Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnlyOldLayout-stderr.txt
new file mode 100644
index 0000000..3ce79f8
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnlyOldLayout-stderr.txt
@@ -0,0 +1,12 @@
+CMake Error at CMakeLists.txt:[0-9]+ \(project\):
+  Generator
+
+    Visual Studio .*
+
+  given toolset
+
+    cuda=.*/Tests/RunCMake/CudaStandaloneToolset\\
+
+  cannot detect Visual Studio integration files in path
+
+    .*/Tests/RunCMake/CudaStandaloneToolset/CUDAVisualStudioIntegration/extras/visual_studio_integration/MSBuildExtensions
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnlyOldLayout.cmake b/Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnlyOldLayout.cmake
new file mode 100644
index 0000000..2fc38e5
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetCudaPathOnlyOldLayout.cmake
@@ -0,0 +1 @@
+message(FATAL_ERROR "This should not be reached!")
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetCustomFlagTableDir-check.cmake b/Tests/RunCMake/GeneratorToolset/TestToolsetCustomFlagTableDir-check.cmake
new file mode 100644
index 0000000..79752b1
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetCustomFlagTableDir-check.cmake
@@ -0,0 +1,24 @@
+set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/main.vcxproj")
+if(NOT EXISTS "${vcProjectFile}")
+  set(RunCMake_TEST_FAILED "Project file\n  ${vcProjectFile}\ndoes not exist.")
+  return()
+endif()
+
+set(TreatWarningAsError_FOUND FALSE)
+file(STRINGS "${vcProjectFile}" lines)
+foreach(line IN LISTS lines)
+  if(line MATCHES "^ *<TreatWarningAsError>([^<>]*)</TreatWarningAsError>$")
+    set(TreatWarningAsError_FOUND TRUE)
+    set(expectedValue "false")
+    set(actualValue "${CMAKE_MATCH_1}")
+    if(NOT (${actualValue} STREQUAL ${expectedValue}))
+      set(RunCMake_TEST_FAILED "TreatWarningAsError \"${actualValue}\" differs from expected value \"${expectedValue}\".")
+      return()
+    endif()
+  endif()
+endforeach()
+
+if(NOT TreatWarningAsError_FOUND)
+  set(RunCMake_TEST_FAILED "Property TreatWarningAsError not found in project file:\n ${vcProjectFile}.")
+  return()
+endif()
diff --git a/Tests/RunCMake/GeneratorToolset/TestToolsetCustomFlagTableDir.cmake b/Tests/RunCMake/GeneratorToolset/TestToolsetCustomFlagTableDir.cmake
new file mode 100644
index 0000000..91c6b44
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/TestToolsetCustomFlagTableDir.cmake
@@ -0,0 +1,3 @@
+enable_language(C)
+string(APPEND CMAKE_C_FLAGS " -TESTWX-")
+add_executable(main main.c)
diff --git a/Tests/RunCMake/GeneratorToolset/VsNormal-stdout.txt b/Tests/RunCMake/GeneratorToolset/VsNormal-stdout.txt
new file mode 100644
index 0000000..25fa3bf
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/VsNormal-stdout.txt
@@ -0,0 +1,2 @@
+-- CMAKE_VS_PLATFORM_NAME='[^']+'
+-- CMAKE_VS_PLATFORM_TOOLSET='v[0-9]+'
diff --git a/Tests/RunCMake/GeneratorToolset/VsNormal.cmake b/Tests/RunCMake/GeneratorToolset/VsNormal.cmake
new file mode 100644
index 0000000..e891708
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/VsNormal.cmake
@@ -0,0 +1,6 @@
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/defaults.cmake" "# VS Defaults
+set(VsNormal_Platform [[${CMAKE_VS_PLATFORM_NAME}]])
+set(VsNormal_Toolset [[${CMAKE_VS_PLATFORM_TOOLSET}]])
+")
+message(STATUS "CMAKE_VS_PLATFORM_NAME='${CMAKE_VS_PLATFORM_NAME}'")
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET='${CMAKE_VS_PLATFORM_TOOLSET}'")
diff --git a/Tests/RunCMake/GeneratorToolset/main.c b/Tests/RunCMake/GeneratorToolset/main.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorToolset/main.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/IfacePaths/RunCMakeTest.cmake b/Tests/RunCMake/IfacePaths/RunCMakeTest.cmake
index 066c83e..c84e95e 100644
--- a/Tests/RunCMake/IfacePaths/RunCMakeTest.cmake
+++ b/Tests/RunCMake/IfacePaths/RunCMakeTest.cmake
@@ -18,6 +18,9 @@
 set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/DirInInstallPrefix/prefix")
 run_cmake(DirInInstallPrefix)
 
+set(RunCMake_TEST_OPTIONS "--install-prefix=${RunCMake_BINARY_DIR}/DirInInstallPrefix/prefix")
+run_cmake(DirInInstallPrefix)
+
 configure_file(
   "${RunCMake_SOURCE_DIR}/CMakeLists.txt"
   "${RunCMake_BINARY_DIR}/copy/CMakeLists.txt"
@@ -34,14 +37,13 @@
   COPYONLY
 )
 set(RunCMake_TEST_OPTIONS
-  "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/copy/SourceDirectoryInInterface/prefix"
+  "--install-prefix=${RunCMake_BINARY_DIR}/copy/SourceDirectoryInInterface/prefix"
   "-DTEST_FILE=${RunCMake_BINARY_DIR}/copy/SourceDirectoryInInterface.cmake"
   )
 set(RunCMake_TEST_SOURCE_DIR "${RunCMake_BINARY_DIR}/copy")
 run_cmake(InstallInSrcDir)
 unset(RunCMake_TEST_SOURCE_DIR)
 
-set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/InstallInBinDir-build/prefix")
 set(RunCMake_TEST_OPTIONS
   "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/InstallInBinDir-build/prefix"
   "-DTEST_FILE=${RunCMake_SOURCE_DIR}/BinaryDirectoryInInterface.cmake"
@@ -77,7 +79,7 @@
     set(policySuffix -CMP0052-${policyStatus})
   endif()
   set(RunCMake_TEST_OPTIONS
-    "-DCMAKE_INSTALL_PREFIX=${RunCMake_BINARY_DIR}/prefix" ${policyOption}
+    "--install-prefix ${RunCMake_BINARY_DIR}/prefix" ${policyOption}
     "-DTEST_FILE=${RunCMake_SOURCE_DIR}/BinaryDirectoryInInterface.cmake"
     )
   # Set the RunCMake_TEST_SOURCE_DIR here to the copy too. This is needed to run
diff --git a/Tests/RunCMake/Ninja/CustomCommandDepfile-check.cmake b/Tests/RunCMake/Ninja/CustomCommandDepfile-check.cmake
index 189de64..51f4f52 100644
--- a/Tests/RunCMake/Ninja/CustomCommandDepfile-check.cmake
+++ b/Tests/RunCMake/Ninja/CustomCommandDepfile-check.cmake
@@ -1,5 +1,10 @@
 set(log "${RunCMake_BINARY_DIR}/CustomCommandDepfile-build/build.ninja")
 file(READ "${log}" build_file)
+
+set(RunCMake_TEST_FAILED)
 if(NOT "${build_file}" MATCHES "depfile = test\\.d")
-  set(RunCMake_TEST_FAILED "Log file:\n ${log}\ndoes not have expected line: depfile = test.d")
+  list(APPEND RunCMake_TEST_FAILED "Log file:\n ${log}\ndoes not have expected line: depfile = test.d")
+endif()
+if(NOT "${build_file}" MATCHES "depfile = test_Debug\\.d")
+  list(APPEND RunCMake_TEST_FAILED "\nLog file:\n ${log}\ndoes not have expected line: depfile = test_Debug.d")
 endif()
diff --git a/Tests/RunCMake/Ninja/CustomCommandDepfile.cmake b/Tests/RunCMake/Ninja/CustomCommandDepfile.cmake
index dbef2a5..0838d14 100644
--- a/Tests/RunCMake/Ninja/CustomCommandDepfile.cmake
+++ b/Tests/RunCMake/Ninja/CustomCommandDepfile.cmake
@@ -6,6 +6,17 @@
   WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
   DEPFILE "test.d"
   )
-add_custom_target(copy ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/hello.copy.c")
+
+add_custom_command(
+  OUTPUT hello.copy2.c
+  COMMAND "${CMAKE_COMMAND}" -E copy
+          "${CMAKE_CURRENT_SOURCE_DIR}/hello.c"
+          hello.copy2.c
+  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+  DEPFILE "test_$<CONFIG>.d"
+  )
+
+add_custom_target(copy ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/hello.copy.c"
+  "${CMAKE_CURRENT_BINARY_DIR}/hello.copy2.c")
 
 include(CheckNoPrefixSubDir.cmake)
diff --git a/Tests/RunCMake/Ninja/RunCMakeTest.cmake b/Tests/RunCMake/Ninja/RunCMakeTest.cmake
index 0c0619d..1350326 100644
--- a/Tests/RunCMake/Ninja/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Ninja/RunCMakeTest.cmake
@@ -67,7 +67,7 @@
 run_CMP0058(NEW-no)
 run_CMP0058(NEW-by)
 
-run_cmake(CustomCommandDepfile)
+run_cmake_with_options(CustomCommandDepfile -DCMAKE_BUILD_TYPE=Debug)
 run_cmake(CustomCommandJobPool)
 run_cmake(JobPoolUsesTerminal)
 
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandDepfile-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandDepfile-check.cmake
index c595b10..a7837ca 100644
--- a/Tests/RunCMake/NinjaMultiConfig/CustomCommandDepfile-check.cmake
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandDepfile-check.cmake
@@ -1,5 +1,10 @@
 set(log "${RunCMake_BINARY_DIR}/CustomCommandDepfile-build/CMakeFiles/impl-Debug.ninja")
 file(READ "${log}" build_file)
+
+set(RunCMake_TEST_FAILED)
 if(NOT "${build_file}" MATCHES "depfile = test\\.d")
-  set(RunCMake_TEST_FAILED "Log file:\n ${log}\ndoes not have expected line: depfile = test.d")
+  list(APPEND RunCMake_TEST_FAILED "Log file:\n ${log}\ndoes not have expected line: depfile = test.d")
+endif()
+if(NOT "${build_file}" MATCHES "depfile = test_Debug\\.d")
+  list(APPEND RunCMake_TEST_FAILED "\nLog file:\n ${log}\ndoes not have expected line: depfile = test_Debug.d")
 endif()
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandDepfile.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandDepfile.cmake
index 1a42670..4f8c114 100644
--- a/Tests/RunCMake/NinjaMultiConfig/CustomCommandDepfile.cmake
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandDepfile.cmake
@@ -6,4 +6,15 @@
   WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
   DEPFILE "test.d"
   )
-add_custom_target(copy ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/main.copy.c")
+
+add_custom_command(
+  OUTPUT main.copy2.c
+  COMMAND "${CMAKE_COMMAND}" -E copy
+          "${CMAKE_CURRENT_SOURCE_DIR}/main.c"
+          main.copy2.c
+  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+  DEPFILE "test_$<CONFIG>.d"
+  )
+
+add_custom_target(copy ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/main.copy.c"
+                                   "${CMAKE_CURRENT_BINARY_DIR}/main.copy2.c")
diff --git a/Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt b/Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt
index 4dbd861..6a7c171 100644
--- a/Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt
+++ b/Tests/RunCMake/ObjectLibrary/BadSourceExpression3-stderr.txt
@@ -3,7 +3,7 @@
 
     \$<TARGET_OBJECTS:NotObjLib>
 
-  Objects of target "NotObjLib" referenced but is not an allowed library
-  types \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\).
+  Objects of target "NotObjLib" referenced but is not one of the allowed
+  target types \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\).
 Call Stack \(most recent call first\):
   CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/RunCMake.cmake b/Tests/RunCMake/RunCMake.cmake
index ea94a5b..7994fc2 100644
--- a/Tests/RunCMake/RunCMake.cmake
+++ b/Tests/RunCMake/RunCMake.cmake
@@ -64,15 +64,6 @@
   else()
     include(${top_src}/${test}-prep.cmake OPTIONAL)
   endif()
-  if(NOT DEFINED RunCMake_TEST_OPTIONS)
-    set(RunCMake_TEST_OPTIONS "")
-  endif()
-  if(APPLE)
-    list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0025=NEW)
-  endif()
-  if(RunCMake_MAKE_PROGRAM)
-    list(APPEND RunCMake_TEST_OPTIONS "-DCMAKE_MAKE_PROGRAM=${RunCMake_MAKE_PROGRAM}")
-  endif()
   if(RunCMake_TEST_OUTPUT_MERGE)
     set(actual_stderr_var actual_stdout)
     set(actual_stderr "")
@@ -91,50 +82,51 @@
   else()
     set(maybe_input_file "")
   endif()
-  if(RunCMake_TEST_COMMAND)
-    if(NOT RunCMake_TEST_COMMAND_WORKING_DIRECTORY)
-      set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+  if(NOT RunCMake_TEST_COMMAND)
+    if(NOT DEFINED RunCMake_TEST_OPTIONS)
+      set(RunCMake_TEST_OPTIONS "")
     endif()
-    execute_process(
-      COMMAND ${RunCMake_TEST_COMMAND}
-      WORKING_DIRECTORY "${RunCMake_TEST_COMMAND_WORKING_DIRECTORY}"
-      OUTPUT_VARIABLE actual_stdout
-      ERROR_VARIABLE ${actual_stderr_var}
-      RESULT_VARIABLE actual_result
-      ENCODING UTF8
-      ${maybe_timeout}
-      ${maybe_input_file}
+    if(APPLE)
+      list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0025=NEW)
+    endif()
+    if(RunCMake_MAKE_PROGRAM)
+      list(APPEND RunCMake_TEST_OPTIONS "-DCMAKE_MAKE_PROGRAM=${RunCMake_MAKE_PROGRAM}")
+    endif()
+    set(RunCMake_TEST_COMMAND ${CMAKE_COMMAND})
+    if(NOT RunCMake_TEST_NO_SOURCE_DIR)
+      list(APPEND RunCMake_TEST_COMMAND "${RunCMake_TEST_SOURCE_DIR}")
+    endif()
+    list(APPEND RunCMake_TEST_COMMAND -G "${RunCMake_GENERATOR}")
+    if(RunCMake_GENERATOR_PLATFORM)
+      list(APPEND RunCMake_TEST_COMMAND -A "${RunCMake_GENERATOR_PLATFORM}")
+    endif()
+    if(RunCMake_GENERATOR_TOOLSET)
+      list(APPEND RunCMake_TEST_COMMAND -T "${RunCMake_GENERATOR_TOOLSET}")
+    endif()
+    if(RunCMake_GENERATOR_INSTANCE)
+      list(APPEND RunCMake_TEST_COMMAND "-DCMAKE_GENERATOR_INSTANCE=${RunCMake_GENERATOR_INSTANCE}")
+    endif()
+    list(APPEND RunCMake_TEST_COMMAND
+      -DRunCMake_TEST=${test}
+      --no-warn-unused-cli
       )
   else()
-    if(RunCMake_GENERATOR_INSTANCE)
-      set(_D_CMAKE_GENERATOR_INSTANCE "-DCMAKE_GENERATOR_INSTANCE=${RunCMake_GENERATOR_INSTANCE}")
-    else()
-      set(_D_CMAKE_GENERATOR_INSTANCE "")
-    endif()
-    if(NOT RunCMake_TEST_NO_SOURCE_DIR)
-      set(maybe_source_dir "${RunCMake_TEST_SOURCE_DIR}")
-    else()
-      set(maybe_source_dir "")
-    endif()
-    execute_process(
-      COMMAND ${CMAKE_COMMAND}
-                ${maybe_source_dir}
-                -G "${RunCMake_GENERATOR}"
-                -A "${RunCMake_GENERATOR_PLATFORM}"
-                -T "${RunCMake_GENERATOR_TOOLSET}"
-                ${_D_CMAKE_GENERATOR_INSTANCE}
-                -DRunCMake_TEST=${test}
-                --no-warn-unused-cli
-                ${RunCMake_TEST_OPTIONS}
-      WORKING_DIRECTORY "${RunCMake_TEST_BINARY_DIR}"
-      OUTPUT_VARIABLE actual_stdout
-      ERROR_VARIABLE ${actual_stderr_var}
-      RESULT_VARIABLE actual_result
-      ENCODING UTF8
-      ${maybe_timeout}
-      ${maybe_input_file}
-      )
+    set(RunCMake_TEST_OPTIONS "")
   endif()
+  if(NOT RunCMake_TEST_COMMAND_WORKING_DIRECTORY)
+    set(RunCMake_TEST_COMMAND_WORKING_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+  endif()
+  execute_process(
+    COMMAND ${RunCMake_TEST_COMMAND}
+            ${RunCMake_TEST_OPTIONS}
+    WORKING_DIRECTORY "${RunCMake_TEST_COMMAND_WORKING_DIRECTORY}"
+    OUTPUT_VARIABLE actual_stdout
+    ERROR_VARIABLE ${actual_stderr_var}
+    RESULT_VARIABLE actual_result
+    ENCODING UTF8
+    ${maybe_timeout}
+    ${maybe_input_file}
+    )
   set(msg "")
   if(NOT "${actual_result}" MATCHES "${expect_result}")
     string(APPEND msg "Result is [${actual_result}], not [${expect_result}].\n")
@@ -191,14 +183,18 @@
   if(RunCMake_TEST_FAILED)
     set(msg "${RunCMake_TEST_FAILED}\n${msg}")
   endif()
-  if(msg AND RunCMake_TEST_COMMAND)
+  if(msg)
     string(REPLACE ";" "\" \"" command "\"${RunCMake_TEST_COMMAND}\"")
+    if(RunCMake_TEST_OPTIONS)
+      string(REPLACE ";" "\" \"" options "\"${RunCMake_TEST_OPTIONS}\"")
+      string(APPEND command " ${options}")
+    endif()
     string(APPEND msg "Command was:\n command> ${command}\n")
   endif()
   if(msg)
     string(REGEX REPLACE "\n" "\n actual-out> " actual_out " actual-out> ${actual_stdout}")
     string(REGEX REPLACE "\n" "\n actual-err> " actual_err " actual-err> ${actual_stderr}")
-    message(SEND_ERROR "${test} - FAILED:\n"
+    message(SEND_ERROR "${test}${RunCMake_TEST_VARIANT_DESCRIPTION} - FAILED:\n"
       "${msg}"
       "${expect_out}"
       "Actual stdout:\n${actual_out}\n"
@@ -206,7 +202,7 @@
       "Actual stderr:\n${actual_err}\n"
       )
   else()
-    message(STATUS "${test} - PASSED")
+    message(STATUS "${test}${RunCMake_TEST_VARIANT_DESCRIPTION} - PASSED")
   endif()
 endfunction()
 
diff --git a/Tests/RunCMake/RunCTest.cmake b/Tests/RunCMake/RunCTest.cmake
index 98fdf20..59db395 100644
--- a/Tests/RunCMake/RunCTest.cmake
+++ b/Tests/RunCMake/RunCTest.cmake
@@ -11,10 +11,13 @@
   endif()
   configure_file(${RunCMake_SOURCE_DIR}/CMakeLists.txt.in
                  ${RunCMake_BINARY_DIR}/${CASE_NAME}/CMakeLists.txt @ONLY)
+  if(NOT DEFINED RunCTest_VERBOSE_FLAG)
+    set(RunCTest_VERBOSE_FLAG "-V")
+  endif()
   run_cmake_command(${CASE_NAME} ${CMAKE_CTEST_COMMAND}
     -C Debug
     -S ${RunCMake_BINARY_DIR}/${CASE_NAME}/test.cmake
-    -V
+    ${RunCTest_VERBOSE_FLAG}
     --output-log ${RunCMake_BINARY_DIR}/${CASE_NAME}-build/testOutput.log
     --no-compress-output
     ${ARGN}
diff --git a/Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt b/Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt
index 77c4afd..9145a56 100644
--- a/Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt
+++ b/Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt
@@ -3,7 +3,7 @@
 
     \$<TARGET_OBJECTS:IFaceLib>
 
-  Objects of target "IFaceLib" referenced but is not an allowed library types
-  \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\).
+  Objects of target "IFaceLib" referenced but is not one of the allowed
+  target types \(EXECUTABLE, STATIC, SHARED, MODULE, OBJECT\).
 Call Stack \(most recent call first\):
   CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/UseSWIG/CMP0078-OLD-stderr.txt b/Tests/RunCMake/UseSWIG/CMP0078-OLD-stderr.txt
new file mode 100644
index 0000000..2afdc4f
--- /dev/null
+++ b/Tests/RunCMake/UseSWIG/CMP0078-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0078-OLD.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0078 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/UseSWIG/CMP0122-NEW-check.cmake b/Tests/RunCMake/UseSWIG/CMP0122-NEW-check.cmake
new file mode 100644
index 0000000..a26c278
--- /dev/null
+++ b/Tests/RunCMake/UseSWIG/CMP0122-NEW-check.cmake
@@ -0,0 +1,10 @@
+
+cmake_policy(VERSION 3.1)
+
+file(STRINGS "${RunCMake_TEST_BINARY_DIR}/CMP0122-library-name.txt" prefixes)
+
+list(GET prefixes 0 std_prefix)
+list(GET prefixes 1 lib_prefix)
+if (NOT std_prefix STREQUAL lib_prefix)
+  string (APPEND RunCMake_TEST_FAILED "\nFound prefix: '${lib_prefix}', expected: '${std_prefix}'.")
+endif()
diff --git a/Tests/RunCMake/UseSWIG/CMP0122-NEW.cmake b/Tests/RunCMake/UseSWIG/CMP0122-NEW.cmake
new file mode 100644
index 0000000..fecb7db
--- /dev/null
+++ b/Tests/RunCMake/UseSWIG/CMP0122-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0122 NEW)
+include(CMP0122-common.cmake)
diff --git a/Tests/RunCMake/UseSWIG/CMP0122-OLD-check.cmake b/Tests/RunCMake/UseSWIG/CMP0122-OLD-check.cmake
new file mode 100644
index 0000000..01657d0
--- /dev/null
+++ b/Tests/RunCMake/UseSWIG/CMP0122-OLD-check.cmake
@@ -0,0 +1,10 @@
+
+cmake_policy(VERSION 3.1)
+
+file(STRINGS "${RunCMake_TEST_BINARY_DIR}/CMP0122-library-name.txt" prefixes)
+
+list(GET prefixes 1 lib_prefix)
+if (lib_prefix)
+  # prefix must be empty
+  string (APPEND RunCMake_TEST_FAILED "\nFound unexpected prefix: '${lib_prefix}'.")
+endif()
diff --git a/Tests/RunCMake/UseSWIG/CMP0122-OLD.cmake b/Tests/RunCMake/UseSWIG/CMP0122-OLD.cmake
new file mode 100644
index 0000000..a787b68
--- /dev/null
+++ b/Tests/RunCMake/UseSWIG/CMP0122-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0122 OLD)
+include(CMP0122-common.cmake)
diff --git a/Tests/RunCMake/UseSWIG/CMP0122-WARN-stderr.txt b/Tests/RunCMake/UseSWIG/CMP0122-WARN-stderr.txt
new file mode 100644
index 0000000..37c4fbd
--- /dev/null
+++ b/Tests/RunCMake/UseSWIG/CMP0122-WARN-stderr.txt
@@ -0,0 +1,10 @@
+CMake Warning \(dev\) at .*/Modules/UseSWIG.cmake:[0-9]+ \(message\):
+  Policy CMP0122 is not set: UseSWIG use standard library name conventions
+  for csharp language\.  Run "cmake --help-policy CMP0122" for policy details\.
+  Use the cmake_policy command to set the policy and suppress this warning\.
+
+Call Stack \(most recent call first\):
+  CMP0122-common.cmake:9 \(swig_add_library\)
+  CMP0122-WARN.cmake:1 \(include\)
+  CMakeLists.txt:3 \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.$
diff --git a/Tests/RunCMake/UseSWIG/CMP0122-WARN.cmake b/Tests/RunCMake/UseSWIG/CMP0122-WARN.cmake
new file mode 100644
index 0000000..5d571aa
--- /dev/null
+++ b/Tests/RunCMake/UseSWIG/CMP0122-WARN.cmake
@@ -0,0 +1 @@
+include(CMP0122-common.cmake)
diff --git a/Tests/RunCMake/UseSWIG/CMP0122-common.cmake b/Tests/RunCMake/UseSWIG/CMP0122-common.cmake
new file mode 100644
index 0000000..be880ec
--- /dev/null
+++ b/Tests/RunCMake/UseSWIG/CMP0122-common.cmake
@@ -0,0 +1,12 @@
+
+cmake_policy(SET CMP0078 NEW)
+cmake_policy(SET CMP0086 NEW)
+
+set(SWIG_EXECUTABLE "swig")
+set(SWIG_DIR "/swig")
+include(UseSWIG)
+
+swig_add_library(example LANGUAGE csharp TYPE SHARED SOURCES example.i)
+
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/CMP0122-library-name.txt"
+     CONTENT "${CMAKE_SHARED_LIBRARY_PREFIX}\n$<TARGET_FILE_PREFIX:example>\n")
diff --git a/Tests/RunCMake/UseSWIG/RunCMakeTest.cmake b/Tests/RunCMake/UseSWIG/RunCMakeTest.cmake
index 6acf719..c7a118f 100644
--- a/Tests/RunCMake/UseSWIG/RunCMakeTest.cmake
+++ b/Tests/RunCMake/UseSWIG/RunCMakeTest.cmake
@@ -23,3 +23,7 @@
   run_cmake_target(CMP0086-NEW build example)
 
 endif()
+
+run_cmake(CMP0122-WARN)
+run_cmake(CMP0122-OLD)
+run_cmake(CMP0122-NEW)
diff --git a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
index 8b03216..c8b75eb 100644
--- a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
+++ b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
@@ -387,4 +387,30 @@
   XcodeRemoveExcessiveISystemSDK(iphoneos)
   XcodeRemoveExcessiveISystemSDK(iphonesimulator)
 endif()
+
+if (XCODE_VERSION VERSION_GREATER_EQUAL 7.3)
+  function(xctest_add_bundle_test SystemName SDK BuildSystemVersion ExpectedOutputDir)
+    set(RunCMake_TEST_BINARY_DIR
+      ${RunCMake_BINARY_DIR}/DeploymentTarget-${SystemName}-${SDK}-${BuildSystemVersion}-build)
+    set(RunCMake_TEST_OPTIONS
+      "-DCMAKE_SYSTEM_NAME=${SystemName}"
+      "-DCMAKE_OSX_SYSROOT=${SDK}"
+      "-DTEST_EXPECTED_OUTPUT_DIR=${ExpectedOutputDir}")
+    unset(RunCMake_GENERATOR_TOOLSET)
+    if(BuildSystemVersion)
+      set(RunCMake_GENERATOR_TOOLSET "buildsystem=${BuildSystemVersion}")
+    endif()
+    run_cmake(XCTestAddBundle)
+  endfunction()
+
+  if(XCODE_VERSION VERSION_GREATER_EQUAL 12)
+    xctest_add_bundle_test(Darwin macosx "1" "$<TARGET_BUNDLE_CONTENT_DIR:TestedApp>/PlugIns")
+    xctest_add_bundle_test(Darwin macosx "12" "$<TARGET_BUNDLE_CONTENT_DIR:TestedApp>/PlugIns")
+    xctest_add_bundle_test(iOS iphoneos "1" "$<TARGET_BUNDLE_CONTENT_DIR:TestedApp>/PlugIns")
+    xctest_add_bundle_test(iOS iphoneos "12" "$<TARGET_BUNDLE_CONTENT_DIR:TestedApp>")
+  else()
+    xctest_add_bundle_test(Darwin macosx "" "$<TARGET_BUNDLE_CONTENT_DIR:TestedApp>/PlugIns")
+    xctest_add_bundle_test(iOS iphoneos "" "$<TARGET_BUNDLE_CONTENT_DIR:TestedApp>/PlugIns")
+  endif()
+endif()
 # Please add macOS-only tests above before the device-specific tests.
diff --git a/Tests/RunCMake/XcodeProject/XCTestAddBundle.cmake b/Tests/RunCMake/XcodeProject/XCTestAddBundle.cmake
new file mode 100644
index 0000000..444c730
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/XCTestAddBundle.cmake
@@ -0,0 +1,17 @@
+enable_language(Swift)
+find_package(XCTest REQUIRED)
+
+add_executable(TestedApp MACOSX_BUNDLE EXCLUDE_FROM_ALL foo.swift)
+
+xctest_add_bundle(TestingAppBundle TestedApp foo.swift)
+
+get_target_property(_lib_output_dir TestingAppBundle LIBRARY_OUTPUT_DIRECTORY)
+
+if (NOT DEFINED TEST_EXPECTED_OUTPUT_DIR)
+    message(FATAL_ERROR "Testing variable TEST_EXPECTED_OUTPUT_DIR is not set")
+endif()
+
+if (NOT _lib_output_dir STREQUAL TEST_EXPECTED_OUTPUT_DIR)
+    message(SEND_ERROR "Property LIBRARY_OUTPUT_DIRECTORY is expected to be ${TEST_EXPECTED_OUTPUT_DIR} "
+        "but was ${_lib_output_dir}")
+endif()
diff --git a/Tests/RunCMake/ctest_test/CTestTestLoadInvalid-stdout.txt b/Tests/RunCMake/ctest_test/CTestTestLoadInvalid-stdout.txt
index b54220c..acda9e2 100644
--- a/Tests/RunCMake/ctest_test/CTestTestLoadInvalid-stdout.txt
+++ b/Tests/RunCMake/ctest_test/CTestTestLoadInvalid-stdout.txt
@@ -1,5 +1,12 @@
-Test project .*/Tests/RunCMake/ctest_test/CTestTestLoadInvalid-build
+Test project [^
+]*/Tests/RunCMake/ctest_test/CTestTestLoadInvalid-build(
+[^*][^
+]*)*
+test 1
     Start 1: RunCMakeVersion
++(
+[^*][^
+]*)*
 1/1 Test #1: RunCMakeVersion ..................   Passed +[0-9.]+ sec
 +
 100% tests passed, 0 tests failed out of 1
diff --git a/Tests/RunCMake/ctest_test/CTestTestLoadPass-stdout.txt b/Tests/RunCMake/ctest_test/CTestTestLoadPass-stdout.txt
index c221eed..4081f98 100644
--- a/Tests/RunCMake/ctest_test/CTestTestLoadPass-stdout.txt
+++ b/Tests/RunCMake/ctest_test/CTestTestLoadPass-stdout.txt
@@ -1,5 +1,12 @@
-Test project .*/Tests/RunCMake/ctest_test/CTestTestLoadPass-build
+Test project [^
+]*/Tests/RunCMake/ctest_test/CTestTestLoadPass-build(
+[^*][^
+]*)*
+test 1
     Start 1: RunCMakeVersion
++(
+[^*][^
+]*)*
 1/1 Test #1: RunCMakeVersion ..................   Passed +[0-9.]+ sec
 +
 100% tests passed, 0 tests failed out of 1
diff --git a/Tests/RunCMake/ctest_test/CTestTestLoadWait-stdout.txt b/Tests/RunCMake/ctest_test/CTestTestLoadWait-stdout.txt
index 2af3838..2f4468f 100644
--- a/Tests/RunCMake/ctest_test/CTestTestLoadWait-stdout.txt
+++ b/Tests/RunCMake/ctest_test/CTestTestLoadWait-stdout.txt
@@ -1,6 +1,13 @@
-Test project .*/Tests/RunCMake/ctest_test/CTestTestLoadWait-build
+Test project [^
+]*/Tests/RunCMake/ctest_test/CTestTestLoadWait-build(
+[^*][^
+]*)*
 \*\*\*\*\* WAITING, System Load: 5, Max Allowed Load: 4, Smallest test RunCMakeVersion requires 1\*\*\*\*\*
+test 1
     Start 1: RunCMakeVersion
++(
+[^*][^
+]*)*
 1/1 Test #1: RunCMakeVersion ..................   Passed +[0-9.]+ sec
 +
 100% tests passed, 0 tests failed out of 1
diff --git a/Tests/RunCMake/ctest_test/RunCMakeTest.cmake b/Tests/RunCMake/ctest_test/RunCMakeTest.cmake
index b82335f..8cf6a61 100644
--- a/Tests/RunCMake/ctest_test/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ctest_test/RunCMakeTest.cmake
@@ -18,6 +18,7 @@
 #
 # Spoof a load average value to make these tests more reliable.
 set(ENV{__CTEST_FAKE_LOAD_AVERAGE_FOR_TESTING} 5)
+set(RunCTest_VERBOSE_FLAG -VV)
 
 # Verify that new tests are started when the load average falls below
 # our threshold.
@@ -53,6 +54,7 @@
 
 unset(ENV{__CTEST_FAKE_LOAD_AVERAGE_FOR_TESTING})
 unset(CASE_CTEST_TEST_LOAD)
+unset(RunCTest_VERBOSE_FLAG)
 
 function(run_TestChangeId)
   set(CASE_TEST_PREFIX_CODE [[
diff --git a/Tests/RunCMake/ctest_test/TestLoadInvalid-stdout.txt b/Tests/RunCMake/ctest_test/TestLoadInvalid-stdout.txt
index c4fd35b..8d21f91 100644
--- a/Tests/RunCMake/ctest_test/TestLoadInvalid-stdout.txt
+++ b/Tests/RunCMake/ctest_test/TestLoadInvalid-stdout.txt
@@ -1,5 +1,12 @@
-Test project .*/Tests/RunCMake/ctest_test/TestLoadInvalid-build
+Test project [^
+]*/Tests/RunCMake/ctest_test/TestLoadInvalid-build(
+[^*][^
+]*)*
+test 1
     Start 1: RunCMakeVersion
++(
+[^*][^
+]*)*
 1/1 Test #1: RunCMakeVersion ..................   Passed +[0-9.]+ sec
 +
 100% tests passed, 0 tests failed out of 1
diff --git a/Tests/RunCMake/ctest_test/TestLoadOrder-stdout.txt b/Tests/RunCMake/ctest_test/TestLoadOrder-stdout.txt
index 22da092..1ef5f5a 100644
--- a/Tests/RunCMake/ctest_test/TestLoadOrder-stdout.txt
+++ b/Tests/RunCMake/ctest_test/TestLoadOrder-stdout.txt
@@ -1,5 +1,12 @@
-Test project .*/Tests/RunCMake/ctest_test/TestLoadOrder-build
+Test project [^
+]*/Tests/RunCMake/ctest_test/TestLoadOrder-build(
+[^*][^
+]*)*
+test 1
     Start 1: RunCMakeVersion
++(
+[^*][^
+]*)*
 1/1 Test #1: RunCMakeVersion ..................   Passed +[0-9.]+ sec
 +
 100% tests passed, 0 tests failed out of 1
diff --git a/Tests/RunCMake/ctest_test/TestLoadPass-stdout.txt b/Tests/RunCMake/ctest_test/TestLoadPass-stdout.txt
index e5048f4..f3e7cd1 100644
--- a/Tests/RunCMake/ctest_test/TestLoadPass-stdout.txt
+++ b/Tests/RunCMake/ctest_test/TestLoadPass-stdout.txt
@@ -1,5 +1,12 @@
-Test project .*/Tests/RunCMake/ctest_test/TestLoadPass-build
+Test project [^
+]*/Tests/RunCMake/ctest_test/TestLoadPass-build(
+[^*][^
+]*)*
+test 1
     Start 1: RunCMakeVersion
++(
+[^*][^
+]*)*
 1/1 Test #1: RunCMakeVersion ..................   Passed +[0-9.]+ sec
 +
 100% tests passed, 0 tests failed out of 1
diff --git a/Tests/RunCMake/ctest_test/TestLoadWait-stdout.txt b/Tests/RunCMake/ctest_test/TestLoadWait-stdout.txt
index 07f4ed3..fc32958 100644
--- a/Tests/RunCMake/ctest_test/TestLoadWait-stdout.txt
+++ b/Tests/RunCMake/ctest_test/TestLoadWait-stdout.txt
@@ -1,6 +1,13 @@
-Test project .*/Tests/RunCMake/ctest_test/TestLoadWait-build
+Test project [^
+]*/Tests/RunCMake/ctest_test/TestLoadWait-build(
+[^*][^
+]*)*
 \*\*\*\*\* WAITING, System Load: 5, Max Allowed Load: 2, Smallest test RunCMakeVersion requires 1\*\*\*\*\*
+test 1
     Start 1: RunCMakeVersion
++(
+[^*][^
+]*)*
 1/1 Test #1: RunCMakeVersion ..................   Passed +[0-9.]+ sec
 +
 100% tests passed, 0 tests failed out of 1
diff --git a/Tests/RunCMake/file/COPY_FILE-arg-missing-result.txt b/Tests/RunCMake/file/COPY_FILE-arg-missing-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-arg-missing-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/COPY_FILE-arg-missing-stderr.txt b/Tests/RunCMake/file/COPY_FILE-arg-missing-stderr.txt
new file mode 100644
index 0000000..2ba38b6
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-arg-missing-stderr.txt
@@ -0,0 +1,3 @@
+^CMake Error at [^
+]*/Tests/RunCMake/file/COPY_FILE-arg-missing.cmake:1 \(file\):
+  file COPY_FILE must be called with at least two additional arguments
diff --git a/Tests/RunCMake/file/COPY_FILE-arg-missing.cmake b/Tests/RunCMake/file/COPY_FILE-arg-missing.cmake
new file mode 100644
index 0000000..0e56c38
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-arg-missing.cmake
@@ -0,0 +1 @@
+file(COPY_FILE "old")
diff --git a/Tests/RunCMake/file/COPY_FILE-arg-unknown-result.txt b/Tests/RunCMake/file/COPY_FILE-arg-unknown-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-arg-unknown-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/COPY_FILE-arg-unknown-stderr.txt b/Tests/RunCMake/file/COPY_FILE-arg-unknown-stderr.txt
new file mode 100644
index 0000000..e5ccd33
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-arg-unknown-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at [^
+]*/Tests/RunCMake/file/COPY_FILE-arg-unknown.cmake:1 \(file\):
+  file COPY_FILE unknown argument:
+
+    unknown$
diff --git a/Tests/RunCMake/file/COPY_FILE-arg-unknown.cmake b/Tests/RunCMake/file/COPY_FILE-arg-unknown.cmake
new file mode 100644
index 0000000..835f39e
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-arg-unknown.cmake
@@ -0,0 +1 @@
+file(COPY_FILE "old" "new" unknown)
diff --git a/Tests/RunCMake/file/COPY_FILE-dir-to-file-capture-stdout.txt b/Tests/RunCMake/file/COPY_FILE-dir-to-file-capture-stdout.txt
new file mode 100644
index 0000000..45b3d27
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-dir-to-file-capture-stdout.txt
@@ -0,0 +1 @@
+^-- file\(COPY_FILE\) failed with result: cannot copy a directory
diff --git a/Tests/RunCMake/file/COPY_FILE-dir-to-file-capture.cmake b/Tests/RunCMake/file/COPY_FILE-dir-to-file-capture.cmake
new file mode 100644
index 0000000..acec05a
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-dir-to-file-capture.cmake
@@ -0,0 +1,8 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(MAKE_DIRECTORY "${oldname}")
+file(COPY_FILE "${oldname}" "${newname}" RESULT result)
+message(STATUS "file(COPY_FILE) failed with result: ${result}")
+if(EXISTS "${newname}")
+  message(FATAL_ERROR "The new name exists:\n ${newname}")
+endif()
diff --git a/Tests/RunCMake/file/COPY_FILE-dir-to-file-fail-result.txt b/Tests/RunCMake/file/COPY_FILE-dir-to-file-fail-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-dir-to-file-fail-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/COPY_FILE-dir-to-file-fail-stderr.txt b/Tests/RunCMake/file/COPY_FILE-dir-to-file-fail-stderr.txt
new file mode 100644
index 0000000..2fe8bec
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-dir-to-file-fail-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Error at [^
+]*/Tests/RunCMake/file/COPY_FILE-dir-to-file-fail.cmake:[0-9] \(file\):
+  file COPY_FILE cannot copy a directory
+
+    [^
+]*/Tests/RunCMake/file/COPY_FILE-dir-to-file-fail-build/input
diff --git a/Tests/RunCMake/file/COPY_FILE-dir-to-file-fail.cmake b/Tests/RunCMake/file/COPY_FILE-dir-to-file-fail.cmake
new file mode 100644
index 0000000..a86ba8d
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-dir-to-file-fail.cmake
@@ -0,0 +1,4 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(MAKE_DIRECTORY "${oldname}")
+file(COPY_FILE "${oldname}" "${newname}")
diff --git a/Tests/RunCMake/file/COPY_FILE-dirlink-to-file-capture-stdout.txt b/Tests/RunCMake/file/COPY_FILE-dirlink-to-file-capture-stdout.txt
new file mode 100644
index 0000000..45b3d27
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-dirlink-to-file-capture-stdout.txt
@@ -0,0 +1 @@
+^-- file\(COPY_FILE\) failed with result: cannot copy a directory
diff --git a/Tests/RunCMake/file/COPY_FILE-dirlink-to-file-capture.cmake b/Tests/RunCMake/file/COPY_FILE-dirlink-to-file-capture.cmake
new file mode 100644
index 0000000..acec05a
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-dirlink-to-file-capture.cmake
@@ -0,0 +1,8 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(MAKE_DIRECTORY "${oldname}")
+file(COPY_FILE "${oldname}" "${newname}" RESULT result)
+message(STATUS "file(COPY_FILE) failed with result: ${result}")
+if(EXISTS "${newname}")
+  message(FATAL_ERROR "The new name exists:\n ${newname}")
+endif()
diff --git a/Tests/RunCMake/file/COPY_FILE-dirlink-to-file-fail-result.txt b/Tests/RunCMake/file/COPY_FILE-dirlink-to-file-fail-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-dirlink-to-file-fail-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/COPY_FILE-dirlink-to-file-fail-stderr.txt b/Tests/RunCMake/file/COPY_FILE-dirlink-to-file-fail-stderr.txt
new file mode 100644
index 0000000..c58dc2c
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-dirlink-to-file-fail-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Error at [^
+]*/Tests/RunCMake/file/COPY_FILE-dirlink-to-file-fail.cmake:[0-9] \(file\):
+  file COPY_FILE cannot copy a directory
+
+    [^
+]*/Tests/RunCMake/file/COPY_FILE-dirlink-to-file-fail-build/input
diff --git a/Tests/RunCMake/file/COPY_FILE-dirlink-to-file-fail.cmake b/Tests/RunCMake/file/COPY_FILE-dirlink-to-file-fail.cmake
new file mode 100644
index 0000000..a86ba8d
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-dirlink-to-file-fail.cmake
@@ -0,0 +1,4 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(MAKE_DIRECTORY "${oldname}")
+file(COPY_FILE "${oldname}" "${newname}")
diff --git a/Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-capture.cmake b/Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-capture.cmake
new file mode 100644
index 0000000..028220e
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-capture.cmake
@@ -0,0 +1,9 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(WRITE "${oldname}" "")
+file(MAKE_DIRECTORY "${newname}")
+file(COPY_FILE "${oldname}" "${newname}" RESULT result ONLY_IF_DIFFERENT)
+message(STATUS "file(COPY_FILE) failed with result: ${result}")
+if(NOT EXISTS "${oldname}")
+  message(FATAL_ERROR "The old name still does not exist:\n ${oldname}")
+endif()
diff --git a/Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-fail-result.txt b/Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-fail-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-fail-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-fail-stderr.txt b/Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-fail-stderr.txt
new file mode 100644
index 0000000..fd5ceee
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-fail-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Error at [^
+]*/Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-fail.cmake:[0-9] \(file\):
+  file COPY_FILE cannot copy to a directory
+
+    [^
+]*/Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-fail-build/output
diff --git a/Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-fail.cmake b/Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-fail.cmake
new file mode 100644
index 0000000..a56b4e7
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-fail.cmake
@@ -0,0 +1,5 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(WRITE "${oldname}" "")
+file(MAKE_DIRECTORY "${newname}")
+file(COPY_FILE "${oldname}" "${newname}" ONLY_IF_DIFFERENT)
diff --git a/Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-no-overwrite.cmake b/Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-no-overwrite.cmake
new file mode 100644
index 0000000..059a308
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-file-ONLY_IF_DIFFERENT-no-overwrite.cmake
@@ -0,0 +1,12 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(WRITE "${oldname}" "")
+execute_process(COMMAND "${CMAKE_COMMAND} -E sleep 1")
+file(WRITE "${newname}" "")
+file(TIMESTAMP "${newname}" before_copy UTC)
+file(COPY_FILE "${oldname}" "${newname}" RESULT result ONLY_IF_DIFFERENT)
+file(TIMESTAMP "${newname}" after_copy UTC)
+if (NOT before_copy STREQUAL after_copy)
+  message(FATAL_ERROR
+    "${newname} was modified even though ONLY_IF_DIFFERENT was specified")
+endif ()
diff --git a/Tests/RunCMake/file/COPY_FILE-file-replace.cmake b/Tests/RunCMake/file/COPY_FILE-file-replace.cmake
new file mode 100644
index 0000000..40e4290
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-file-replace.cmake
@@ -0,0 +1,9 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(WRITE "${oldname}" "a")
+file(WRITE "${newname}" "b")
+file(COPY_FILE "${oldname}" "${newname}")
+file(READ "${newname}" new)
+if(NOT "${new}" STREQUAL "a")
+  message(FATAL_ERROR "New name:\n  ${newname}\ndoes not contain expected content 'a'.")
+endif()
diff --git a/Tests/RunCMake/file/COPY_FILE-file-to-dir-capture-stdout.txt b/Tests/RunCMake/file/COPY_FILE-file-to-dir-capture-stdout.txt
new file mode 100644
index 0000000..24f969f
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-file-to-dir-capture-stdout.txt
@@ -0,0 +1 @@
+^-- file\(COPY_FILE\) failed with result: cannot copy to a directory
diff --git a/Tests/RunCMake/file/COPY_FILE-file-to-dir-capture.cmake b/Tests/RunCMake/file/COPY_FILE-file-to-dir-capture.cmake
new file mode 100644
index 0000000..98621c6
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-file-to-dir-capture.cmake
@@ -0,0 +1,9 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(WRITE "${oldname}" "")
+file(MAKE_DIRECTORY "${newname}")
+file(COPY_FILE "${oldname}" "${newname}" RESULT result)
+message(STATUS "file(COPY_FILE) failed with result: ${result}")
+if(NOT EXISTS "${oldname}")
+  message(FATAL_ERROR "The old name does not exist:\n ${oldname}")
+endif()
diff --git a/Tests/RunCMake/file/COPY_FILE-file-to-dir-fail-result.txt b/Tests/RunCMake/file/COPY_FILE-file-to-dir-fail-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-file-to-dir-fail-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/COPY_FILE-file-to-dir-fail-stderr.txt b/Tests/RunCMake/file/COPY_FILE-file-to-dir-fail-stderr.txt
new file mode 100644
index 0000000..ba2a027
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-file-to-dir-fail-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Error at [^
+]*/Tests/RunCMake/file/COPY_FILE-file-to-dir-fail.cmake:[0-9] \(file\):
+  file COPY_FILE cannot copy to a directory
+
+    [^
+]*/Tests/RunCMake/file/COPY_FILE-file-to-dir-fail-build/output
diff --git a/Tests/RunCMake/file/COPY_FILE-file-to-dir-fail.cmake b/Tests/RunCMake/file/COPY_FILE-file-to-dir-fail.cmake
new file mode 100644
index 0000000..c2628dd
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-file-to-dir-fail.cmake
@@ -0,0 +1,5 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(WRITE "${oldname}" "")
+file(MAKE_DIRECTORY "${newname}")
+file(COPY_FILE "${oldname}" "${newname}")
diff --git a/Tests/RunCMake/file/COPY_FILE-file-to-file.cmake b/Tests/RunCMake/file/COPY_FILE-file-to-file.cmake
new file mode 100644
index 0000000..26b702a
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-file-to-file.cmake
@@ -0,0 +1,10 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(WRITE "${oldname}" "")
+file(COPY_FILE "${oldname}" "${newname}")
+if(NOT EXISTS "${oldname}")
+  message(FATAL_ERROR "The old name does not exist:\n ${oldname}")
+endif()
+if(NOT EXISTS "${newname}")
+  message(FATAL_ERROR "The new name does not exist:\n ${newname}")
+endif()
diff --git a/Tests/RunCMake/file/COPY_FILE-link-to-file.cmake b/Tests/RunCMake/file/COPY_FILE-link-to-file.cmake
new file mode 100644
index 0000000..93a0204
--- /dev/null
+++ b/Tests/RunCMake/file/COPY_FILE-link-to-file.cmake
@@ -0,0 +1,10 @@
+set(lnkname "${CMAKE_CURRENT_BINARY_DIR}/link")
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(WRITE "${lnkname}" "a")
+file(CREATE_LINK "${lnkname}" "${oldname}")
+file(COPY_FILE "${oldname}" "${newname}")
+file(READ "${newname}" new)
+if(NOT "${new}" STREQUAL "a")
+  message(FATAL_ERROR "New name:\n  ${newname}\ndoes not contain expected content 'a'.")
+endif()
diff --git a/Tests/RunCMake/file/RENAME-arg-missing-result.txt b/Tests/RunCMake/file/RENAME-arg-missing-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-arg-missing-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/RENAME-arg-missing-stderr.txt b/Tests/RunCMake/file/RENAME-arg-missing-stderr.txt
new file mode 100644
index 0000000..98d2961
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-arg-missing-stderr.txt
@@ -0,0 +1,3 @@
+^CMake Error at [^
+]*/Tests/RunCMake/file/RENAME-arg-missing.cmake:1 \(file\):
+  file RENAME must be called with at least two additional arguments$
diff --git a/Tests/RunCMake/file/RENAME-arg-missing.cmake b/Tests/RunCMake/file/RENAME-arg-missing.cmake
new file mode 100644
index 0000000..2358ce9
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-arg-missing.cmake
@@ -0,0 +1 @@
+file(RENAME "old")
diff --git a/Tests/RunCMake/file/RENAME-arg-unknown-result.txt b/Tests/RunCMake/file/RENAME-arg-unknown-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-arg-unknown-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/RENAME-arg-unknown-stderr.txt b/Tests/RunCMake/file/RENAME-arg-unknown-stderr.txt
new file mode 100644
index 0000000..16edb25
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-arg-unknown-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at [^
+]*/Tests/RunCMake/file/RENAME-arg-unknown.cmake:1 \(file\):
+  file RENAME unknown argument:
+
+    unknown$
diff --git a/Tests/RunCMake/file/RENAME-arg-unknown.cmake b/Tests/RunCMake/file/RENAME-arg-unknown.cmake
new file mode 100644
index 0000000..3110f70
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-arg-unknown.cmake
@@ -0,0 +1 @@
+file(RENAME "old" "new" unknown)
diff --git a/Tests/RunCMake/file/RENAME-file-NO_REPLACE-capture-stdout.txt b/Tests/RunCMake/file/RENAME-file-NO_REPLACE-capture-stdout.txt
new file mode 100644
index 0000000..a116330
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-file-NO_REPLACE-capture-stdout.txt
@@ -0,0 +1 @@
+^-- file\(RENAME\) failed with result: NO_REPLACE$
diff --git a/Tests/RunCMake/file/RENAME-file-NO_REPLACE-capture.cmake b/Tests/RunCMake/file/RENAME-file-NO_REPLACE-capture.cmake
new file mode 100644
index 0000000..1ff4178
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-file-NO_REPLACE-capture.cmake
@@ -0,0 +1,9 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(WRITE "${oldname}" "a")
+file(WRITE "${newname}" "b")
+file(RENAME "${oldname}" "${newname}" NO_REPLACE RESULT result)
+message(STATUS "file(RENAME) failed with result: ${result}")
+if(NOT EXISTS "${oldname}")
+  message(FATAL_ERROR "The old name does not still exist:\n ${oldname}")
+endif()
diff --git a/Tests/RunCMake/file/RENAME-file-NO_REPLACE-fail-result.txt b/Tests/RunCMake/file/RENAME-file-NO_REPLACE-fail-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-file-NO_REPLACE-fail-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/RENAME-file-NO_REPLACE-fail-stderr.txt b/Tests/RunCMake/file/RENAME-file-NO_REPLACE-fail-stderr.txt
new file mode 100644
index 0000000..dd7294c
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-file-NO_REPLACE-fail-stderr.txt
@@ -0,0 +1,13 @@
+^CMake Error at [^
+]*/Tests/RunCMake/file/RENAME-file-NO_REPLACE-fail.cmake:[0-9] \(file\):
+  file RENAME failed to rename
+
+    [^
+]*/Tests/RunCMake/file/RENAME-file-NO_REPLACE-fail-build/input
+
+  to
+
+    [^
+]*/Tests/RunCMake/file/RENAME-file-NO_REPLACE-fail-build/output
+
+  because: path not replaced$
diff --git a/Tests/RunCMake/file/RENAME-file-NO_REPLACE-fail.cmake b/Tests/RunCMake/file/RENAME-file-NO_REPLACE-fail.cmake
new file mode 100644
index 0000000..c05dd63
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-file-NO_REPLACE-fail.cmake
@@ -0,0 +1,5 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(WRITE "${oldname}" "a")
+file(WRITE "${newname}" "b")
+file(RENAME "${oldname}" "${newname}" NO_REPLACE)
diff --git a/Tests/RunCMake/file/RENAME-file-replace.cmake b/Tests/RunCMake/file/RENAME-file-replace.cmake
new file mode 100644
index 0000000..efbfaed
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-file-replace.cmake
@@ -0,0 +1,9 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(WRITE "${oldname}" "a")
+file(WRITE "${newname}" "b")
+file(RENAME "${oldname}" "${newname}")
+file(READ "${newname}" new)
+if(NOT "${new}" STREQUAL "a")
+  message(FATAL_ERROR "New name:\n  ${newname}\ndoes not contain expected content 'a'.")
+endif()
diff --git a/Tests/RunCMake/file/RENAME-file-to-dir-capture-stdout.txt b/Tests/RunCMake/file/RENAME-file-to-dir-capture-stdout.txt
new file mode 100644
index 0000000..0276a5f
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-file-to-dir-capture-stdout.txt
@@ -0,0 +1 @@
+^-- file\(RENAME\) failed with result: [A-Za-z]
diff --git a/Tests/RunCMake/file/RENAME-file-to-dir-capture.cmake b/Tests/RunCMake/file/RENAME-file-to-dir-capture.cmake
new file mode 100644
index 0000000..4f817e8
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-file-to-dir-capture.cmake
@@ -0,0 +1,9 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(WRITE "${oldname}" "")
+file(MAKE_DIRECTORY "${newname}")
+file(RENAME "${oldname}" "${newname}" RESULT result)
+message(STATUS "file(RENAME) failed with result: ${result}")
+if(NOT EXISTS "${oldname}")
+  message(FATAL_ERROR "The old name does not still exist:\n ${oldname}")
+endif()
diff --git a/Tests/RunCMake/file/RENAME-file-to-dir-fail-result.txt b/Tests/RunCMake/file/RENAME-file-to-dir-fail-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-file-to-dir-fail-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/RENAME-file-to-dir-fail-stderr.txt b/Tests/RunCMake/file/RENAME-file-to-dir-fail-stderr.txt
new file mode 100644
index 0000000..e4dbc38
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-file-to-dir-fail-stderr.txt
@@ -0,0 +1,13 @@
+^CMake Error at [^
+]*/Tests/RunCMake/file/RENAME-file-to-dir-fail.cmake:[0-9] \(file\):
+  file RENAME failed to rename
+
+    [^
+]*/Tests/RunCMake/file/RENAME-file-to-dir-fail-build/input
+
+  to
+
+    [^
+]*/Tests/RunCMake/file/RENAME-file-to-dir-fail-build/output
+
+  because: [A-Za-z]
diff --git a/Tests/RunCMake/file/RENAME-file-to-dir-fail.cmake b/Tests/RunCMake/file/RENAME-file-to-dir-fail.cmake
new file mode 100644
index 0000000..61fa644
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-file-to-dir-fail.cmake
@@ -0,0 +1,5 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(WRITE "${oldname}" "")
+file(MAKE_DIRECTORY "${newname}")
+file(RENAME "${oldname}" "${newname}")
diff --git a/Tests/RunCMake/file/RENAME-file-to-file.cmake b/Tests/RunCMake/file/RENAME-file-to-file.cmake
new file mode 100644
index 0000000..dbc411be
--- /dev/null
+++ b/Tests/RunCMake/file/RENAME-file-to-file.cmake
@@ -0,0 +1,10 @@
+set(oldname "${CMAKE_CURRENT_BINARY_DIR}/input")
+set(newname "${CMAKE_CURRENT_BINARY_DIR}/output")
+file(WRITE "${oldname}" "")
+file(RENAME "${oldname}" "${newname}")
+if(EXISTS "${oldname}")
+  message(FATAL_ERROR "The old name still exists:\n ${oldname}")
+endif()
+if(NOT EXISTS "${newname}")
+  message(FATAL_ERROR "The new name does not exist:\n ${newname}")
+endif()
diff --git a/Tests/RunCMake/file/RunCMakeTest.cmake b/Tests/RunCMake/file/RunCMakeTest.cmake
index 22813eb..b4ea9ba 100644
--- a/Tests/RunCMake/file/RunCMakeTest.cmake
+++ b/Tests/RunCMake/file/RunCMakeTest.cmake
@@ -50,6 +50,30 @@
 
 run_cmake(REMOVE-empty)
 
+run_cmake_script(COPY_FILE-file-replace)
+run_cmake_script(COPY_FILE-dir-to-file-capture)
+run_cmake_script(COPY_FILE-dir-to-file-fail)
+run_cmake_script(COPY_FILE-dirlink-to-file-capture)
+run_cmake_script(COPY_FILE-dirlink-to-file-fail)
+run_cmake_script(COPY_FILE-file-to-file)
+run_cmake_script(COPY_FILE-file-to-dir-capture)
+run_cmake_script(COPY_FILE-file-to-dir-fail)
+run_cmake_script(COPY_FILE-file-ONLY_IF_DIFFERENT-capture)
+run_cmake_script(COPY_FILE-file-ONLY_IF_DIFFERENT-fail)
+run_cmake_script(COPY_FILE-file-ONLY_IF_DIFFERENT-no-overwrite)
+run_cmake_script(COPY_FILE-link-to-file)
+run_cmake_script(COPY_FILE-arg-missing)
+run_cmake_script(COPY_FILE-arg-unknown)
+
+run_cmake_script(RENAME-file-replace)
+run_cmake_script(RENAME-file-to-file)
+run_cmake_script(RENAME-file-to-dir-capture)
+run_cmake_script(RENAME-file-to-dir-fail)
+run_cmake_script(RENAME-file-NO_REPLACE-capture)
+run_cmake_script(RENAME-file-NO_REPLACE-fail)
+run_cmake_script(RENAME-arg-missing)
+run_cmake_script(RENAME-arg-unknown)
+
 # tests are valid both for GLOB and GLOB_RECURSE
 run_cmake(GLOB-sort-dedup)
 run_cmake(GLOB-error-LIST_DIRECTORIES-not-boolean)
diff --git a/Tests/RunCMake/option/CMP0077-OLD-stderr.txt b/Tests/RunCMake/option/CMP0077-OLD-stderr.txt
new file mode 100644
index 0000000..9d963cb
--- /dev/null
+++ b/Tests/RunCMake/option/CMP0077-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0077-OLD.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0077 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/project/ProjectIsTopLevel-stdout.txt b/Tests/RunCMake/project/ProjectIsTopLevel-stdout.txt
new file mode 100644
index 0000000..af8abfd
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectIsTopLevel-stdout.txt
@@ -0,0 +1,2 @@
+-- PROJECT_IS_TOP_LEVEL=ON
+-- ProjectIsTopLevel_IS_TOP_LEVEL=ON
diff --git a/Tests/RunCMake/project/ProjectIsTopLevel.cmake b/Tests/RunCMake/project/ProjectIsTopLevel.cmake
new file mode 100644
index 0000000..5a0af0a
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectIsTopLevel.cmake
@@ -0,0 +1,9 @@
+# no project() call, includer already calls project(${RunCMake_TEST} NONE)
+if(NOT DEFINED PROJECT_IS_TOP_LEVEL)
+  message(FATAL_ERROR "PROJECT_IS_TOP_LEVEL is not defined")
+endif()
+if(NOT DEFINED "CACHE{${RunCMake_TEST}_IS_TOP_LEVEL}")
+  message(FATAL_ERROR "IsTopLevel_IS_TOP_LEVEL is not defined")
+endif()
+message(STATUS "PROJECT_IS_TOP_LEVEL=${PROJECT_IS_TOP_LEVEL}")
+message(STATUS "${RunCMake_TEST}_IS_TOP_LEVEL=${${RunCMake_TEST}_IS_TOP_LEVEL}")
diff --git a/Tests/RunCMake/project/ProjectIsTopLevelMultiple-stdout.txt b/Tests/RunCMake/project/ProjectIsTopLevelMultiple-stdout.txt
new file mode 100644
index 0000000..75d787f
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectIsTopLevelMultiple-stdout.txt
@@ -0,0 +1,3 @@
+-- PROJECT_IS_TOP_LEVEL=ON
+-- ProjectIsTopLevelMultiple_IS_TOP_LEVEL=ON
+-- IsTopLevel_IS_TOP_LEVEL=ON
diff --git a/Tests/RunCMake/project/ProjectIsTopLevelMultiple.cmake b/Tests/RunCMake/project/ProjectIsTopLevelMultiple.cmake
new file mode 100644
index 0000000..98ba55b
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectIsTopLevelMultiple.cmake
@@ -0,0 +1,14 @@
+# only one project() call, includer already calls project(${RunCMake_TEST} NONE)
+project(IsTopLevel NONE)
+if(NOT DEFINED PROJECT_IS_TOP_LEVEL)
+  message(FATAL_ERROR "PROJECT_IS_TOP_LEVEL is not defined")
+endif()
+if(NOT DEFINED "CACHE{${RunCMake_TEST}_IS_TOP_LEVEL}")
+  message(FATAL_ERROR "${RunCMake_TEST}_IS_TOP_LEVEL is not defined")
+endif()
+if(NOT DEFINED CACHE{IsTopLevel_IS_TOP_LEVEL})
+  message(FATAL_ERROR "IsTopLevel_IS_TOP_LEVEL is not defined")
+endif()
+message(STATUS "PROJECT_IS_TOP_LEVEL=${PROJECT_IS_TOP_LEVEL}")
+message(STATUS "${RunCMake_TEST}_IS_TOP_LEVEL=${${RunCMake_TEST}_IS_TOP_LEVEL}")
+message(STATUS "IsTopLevel_IS_TOP_LEVEL=${IsTopLevel_IS_TOP_LEVEL}")
diff --git a/Tests/RunCMake/project/ProjectIsTopLevelSubdirectory-stdout.txt b/Tests/RunCMake/project/ProjectIsTopLevelSubdirectory-stdout.txt
new file mode 100644
index 0000000..d9e15ff
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectIsTopLevelSubdirectory-stdout.txt
@@ -0,0 +1,6 @@
+-- PROJECT_IS_TOP_LEVEL=ON
+-- PROJECT_IS_TOP_LEVEL=ON
+-- PROJECT_IS_TOP_LEVEL=OFF
+-- PROJECT_IS_TOP_LEVEL=ON
+-- ProjectIsTopLevelSubdirectory_IS_TOP_LEVEL=ON
+-- NotTopLevel_IS_TOP_LEVEL=OFF
diff --git a/Tests/RunCMake/project/ProjectIsTopLevelSubdirectory.cmake b/Tests/RunCMake/project/ProjectIsTopLevelSubdirectory.cmake
new file mode 100644
index 0000000..b5df84b
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectIsTopLevelSubdirectory.cmake
@@ -0,0 +1,8 @@
+# no project() call, includer already calls project(${RunCMake_TEST} NONE)
+message(STATUS "PROJECT_IS_TOP_LEVEL=${PROJECT_IS_TOP_LEVEL}")
+
+add_subdirectory(ProjectIsTopLevelSubdirectory)
+
+message(STATUS "PROJECT_IS_TOP_LEVEL=${PROJECT_IS_TOP_LEVEL}")
+message(STATUS "${RunCMake_TEST}_IS_TOP_LEVEL=${${RunCMake_TEST}_IS_TOP_LEVEL}")
+message(STATUS "NotTopLevel_IS_TOP_LEVEL=${NotTopLevel_IS_TOP_LEVEL}")
diff --git a/Tests/RunCMake/project/ProjectIsTopLevelSubdirectory/CMakeLists.txt b/Tests/RunCMake/project/ProjectIsTopLevelSubdirectory/CMakeLists.txt
new file mode 100644
index 0000000..d2f16ea
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectIsTopLevelSubdirectory/CMakeLists.txt
@@ -0,0 +1,5 @@
+message(STATUS "PROJECT_IS_TOP_LEVEL=${PROJECT_IS_TOP_LEVEL}")
+
+project(NotTopLevel NONE)
+
+message(STATUS "PROJECT_IS_TOP_LEVEL=${PROJECT_IS_TOP_LEVEL}")
diff --git a/Tests/RunCMake/project/RunCMakeTest.cmake b/Tests/RunCMake/project/RunCMakeTest.cmake
index 6914699..349e8ac 100644
--- a/Tests/RunCMake/project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/project/RunCMakeTest.cmake
@@ -15,6 +15,9 @@
 run_cmake(ProjectHomepage)
 run_cmake(ProjectHomepage2)
 run_cmake(ProjectHomepageNoArg)
+run_cmake(ProjectIsTopLevel)
+run_cmake(ProjectIsTopLevelMultiple)
+run_cmake(ProjectIsTopLevelSubdirectory)
 run_cmake(ProjectTwice)
 run_cmake(VersionAndLanguagesEmpty)
 run_cmake(VersionEmpty)
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD-stderr.txt b/Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD-stderr.txt
new file mode 100644
index 0000000..c664505
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0079-iface-OLD.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0079 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_link_libraries/CMP0079-link-OLD-stderr.txt b/Tests/RunCMake/target_link_libraries/CMP0079-link-OLD-stderr.txt
index 0b4c4c6..14f4789 100644
--- a/Tests/RunCMake/target_link_libraries/CMP0079-link-OLD-stderr.txt
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-OLD-stderr.txt
@@ -1,4 +1,15 @@
-^CMake Error at CMP0079-link/CMakeLists.txt:[0-9]+ \(target_link_libraries\):
+^CMake Deprecation Warning at CMP0079-link-OLD.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0079 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\)
++
+CMake Error at CMP0079-link/CMakeLists.txt:[0-9]+ \(target_link_libraries\):
   Attempt to add link library "foo" to target "top" which is not built in
   this directory.
 
diff --git a/Tests/StringFileTest/CMakeLists.txt b/Tests/StringFileTest/CMakeLists.txt
index faf3bc9..068fae9 100644
--- a/Tests/StringFileTest/CMakeLists.txt
+++ b/Tests/StringFileTest/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(StringFileTest)
 include_directories(${StringFileTest_BINARY_DIR})
 
diff --git a/Tests/SubDirSpaces/CMakeLists.txt b/Tests/SubDirSpaces/CMakeLists.txt
index 0d45db8..ecd4353 100644
--- a/Tests/SubDirSpaces/CMakeLists.txt
+++ b/Tests/SubDirSpaces/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(SUBDIR)
 
 # Some systems do not seem to support rpath with spaces.
diff --git a/Tests/TargetName/CMakeLists.txt b/Tests/TargetName/CMakeLists.txt
index 9729d21..21752b7 100644
--- a/Tests/TargetName/CMakeLists.txt
+++ b/Tests/TargetName/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(TargetName)
 
 add_subdirectory(executables)
diff --git a/Tests/TestDriver/CMakeLists.txt b/Tests/TestDriver/CMakeLists.txt
index 663ecab..3cc69c0 100644
--- a/Tests/TestDriver/CMakeLists.txt
+++ b/Tests/TestDriver/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(TestDriverTest)
 
 set(Extra_SRCS testExtraStuff.cxx testExtraStuff2.cxx )
diff --git a/Tests/TestsWorkingDirectory/CMakeLists.txt b/Tests/TestsWorkingDirectory/CMakeLists.txt
index 6a6e9b6..2a0b015 100644
--- a/Tests/TestsWorkingDirectory/CMakeLists.txt
+++ b/Tests/TestsWorkingDirectory/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.6)
+cmake_minimum_required(VERSION 2.8.12)
 project(TestsWorkingDirectoryProj)
 
 add_executable(WorkingDirectory main.c)
diff --git a/Tests/TryCompile/CMakeLists.txt b/Tests/TryCompile/CMakeLists.txt
index 0c6b938..fa0549f 100644
--- a/Tests/TryCompile/CMakeLists.txt
+++ b/Tests/TryCompile/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(TryCompile)
 
 macro(TEST_ASSERT value msg)
diff --git a/Tests/TryCompile/Inner/CMakeLists.txt b/Tests/TryCompile/Inner/CMakeLists.txt
index d62bcc4..d8c22d0 100644
--- a/Tests/TryCompile/Inner/CMakeLists.txt
+++ b/Tests/TryCompile/Inner/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.6)
+cmake_minimum_required(VERSION 2.8.12)
 project(TryCompileInner C)
 
 try_compile(SHOULD_PASS
diff --git a/Tests/VSExternalInclude/CMakeLists.txt b/Tests/VSExternalInclude/CMakeLists.txt
index 8ca7252..e38df8e 100644
--- a/Tests/VSExternalInclude/CMakeLists.txt
+++ b/Tests/VSExternalInclude/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.12)
 project(VSExternalInclude)
 
 if(${CMAKE_GENERATOR} MATCHES "Visual Studio 1[012456]")
diff --git a/Tests/VSGNUFortran/subdir/fortran/CMakeLists.txt b/Tests/VSGNUFortran/subdir/fortran/CMakeLists.txt
index abd0628..950ec25 100644
--- a/Tests/VSGNUFortran/subdir/fortran/CMakeLists.txt
+++ b/Tests/VSGNUFortran/subdir/fortran/CMakeLists.txt
@@ -43,4 +43,9 @@
       target_link_libraries(hello PRIVATE sunquad)
     endif()
   endif()
+elseif(CMAKE_Fortran_COMPILER_ID MATCHES Fujitsu)
+  # Fujitsu Fortran doesn't automatically link its runtime libraries into
+  # SOs
+  target_link_libraries(world PRIVATE fj90i fj90f fjsrcinfo)
+  target_link_libraries(hello PRIVATE fj90i fj90f fjsrcinfo)
 endif()
diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt
index a880f7a..0ccb721 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.1...3.18 FATAL_ERROR)
+  cmake_minimum_required(VERSION 3.1...3.19 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/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp
index c2aced5..f2aef3e 100644
--- a/Utilities/IWYU/mapping.imp
+++ b/Utilities/IWYU/mapping.imp
@@ -96,6 +96,7 @@
   { symbol: [ "std::enable_if<true, std::chrono::duration<long, std::ratio<1, 1> > >::type", private, "\"cmConfigure.h\"", public ] },
   { symbol: [ "std::enable_if<true, std::chrono::duration<long, std::ratio<60, 1> > >::type", private, "\"cmConfigure.h\"", public ] },
   { symbol: [ "std::enable_if<true, std::chrono::duration<long, std::ratio<1, 1000> > >::type", private, "\"cmConfigure.h\"", public ] },
+  { symbol: [ "__gnu_cxx::__enable_if<true, bool>::__type", private, "\"cmConfigure.h\"", public ] },
 
   # Wrappers for 3rd-party libraries
   { include: [ "@<.*curl/curlver.h>", private, "<cm3p/curl/curl.h>", public ] },
diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt
index f989907..32efd48 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.1...3.18 FATAL_ERROR)
+  cmake_minimum_required(VERSION 3.1...3.19 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)
@@ -22,6 +22,7 @@
 option(SPHINX_HTML "Build html help with Sphinx" OFF)
 option(SPHINX_SINGLEHTML "Build html single page help with Sphinx" OFF)
 option(SPHINX_QTHELP "Build Qt help with Sphinx" OFF)
+option(SPHINX_LATEXPDF "Build PDF help with Sphinx using LaTeX" OFF)
 option(SPHINX_TEXT "Build text help with Sphinx (not installed)" OFF)
 find_program(SPHINX_EXECUTABLE
   NAMES sphinx-build
@@ -33,7 +34,7 @@
 mark_as_advanced(SPHINX_TEXT)
 mark_as_advanced(SPHINX_FLAGS)
 
-if(NOT SPHINX_INFO AND NOT SPHINX_MAN AND NOT SPHINX_HTML AND NOT SPHINX_SINGLEHTML AND NOT SPHINX_QTHELP AND NOT SPHINX_TEXT)
+if(NOT SPHINX_INFO AND NOT SPHINX_MAN AND NOT SPHINX_HTML AND NOT SPHINX_SINGLEHTML AND NOT SPHINX_QTHELP AND NOT SPHINX_TEXT AND NOT SPHINX_LATEXPDF)
   return()
 elseif(NOT SPHINX_EXECUTABLE)
   message(FATAL_ERROR "SPHINX_EXECUTABLE (sphinx-build) is not found!")
@@ -117,28 +118,51 @@
       ${CMAKE_CURRENT_BINARY_DIR}/qthelp/CMake.qhcp
   )
 endif()
-
+if(SPHINX_LATEXPDF)
+  list(APPEND doc_formats latexpdf)
+endif()
 
 set(doc_format_outputs "")
 set(doc_format_last "")
 foreach(format ${doc_formats})
   set(doc_format_output "doc_format_${format}")
   set(doc_format_log "build-${format}.log")
-  add_custom_command(
-    OUTPUT ${doc_format_output}
-    COMMAND ${SPHINX_EXECUTABLE}
-            -c ${CMAKE_CURRENT_BINARY_DIR}
-            -d ${CMAKE_CURRENT_BINARY_DIR}/doctrees
-            -b ${format}
-            ${sphinx_flags}
-            ${CMake_SOURCE_DIR}/Help
-            ${CMAKE_CURRENT_BINARY_DIR}/${format}
-            > ${doc_format_log} # log stdout, pass stderr
-    ${${format}_extra_commands}
-    DEPENDS ${doc_format_last}
-    COMMENT "sphinx-build ${format}: see Utilities/Sphinx/${doc_format_log}"
-    VERBATIM
-    )
+  if(format STREQUAL "latexpdf")
+    # This format does not use builder (-b) but make_mode (-M) which expects
+    # arguments in peculiar order
+    add_custom_command(
+      OUTPUT ${doc_format_output}
+      COMMAND ${SPHINX_EXECUTABLE}
+              -M ${format}
+              ${CMake_SOURCE_DIR}/Help
+              ${CMAKE_CURRENT_BINARY_DIR}/${format}
+              -c ${CMAKE_CURRENT_BINARY_DIR}
+              -d ${CMAKE_CURRENT_BINARY_DIR}/doctrees
+              ${sphinx_flags}
+              > ${doc_format_log} # log stdout, pass stderr
+      ${${format}_extra_commands}
+      DEPENDS ${doc_format_last}
+      COMMENT "sphinx-build ${format}: see Utilities/Sphinx/${doc_format_log}"
+      VERBATIM
+      )
+  else()
+    # other formats use standard builder (-b) mode
+    add_custom_command(
+      OUTPUT ${doc_format_output}
+      COMMAND ${SPHINX_EXECUTABLE}
+              -c ${CMAKE_CURRENT_BINARY_DIR}
+              -d ${CMAKE_CURRENT_BINARY_DIR}/doctrees
+              -b ${format}
+              ${sphinx_flags}
+              ${CMake_SOURCE_DIR}/Help
+              ${CMAKE_CURRENT_BINARY_DIR}/${format}
+              > ${doc_format_log} # log stdout, pass stderr
+      ${${format}_extra_commands}
+      DEPENDS ${doc_format_last}
+      COMMENT "sphinx-build ${format}: see Utilities/Sphinx/${doc_format_log}"
+      VERBATIM
+      )
+  endif()
   set_property(SOURCE ${doc_format_output} PROPERTY SYMBOLIC 1)
   list(APPEND doc_format_outputs ${doc_format_output})
   set(doc_format_last ${doc_format_output})
@@ -219,3 +243,10 @@
           DESTINATION ${CMAKE_DOC_DIR} ${COMPONENT}
           )
 endif()
+
+if(SPHINX_LATEXPDF)
+  CMake_OPTIONAL_COMPONENT(sphinx-latexpdf)
+  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/latexpdf/latex/CMake.pdf
+          DESTINATION ${CMAKE_DOC_DIR} ${COMPONENT}
+          )
+endif()
diff --git a/bootstrap b/bootstrap
index f85d57e..2a81ef2 100755
--- a/bootstrap
+++ b/bootstrap
@@ -84,6 +84,7 @@
 cmake_sphinx_man=""
 cmake_sphinx_html=""
 cmake_sphinx_qthelp=""
+cmake_sphinx_latexpdf=""
 cmake_sphinx_build=""
 cmake_sphinx_flags=""
 
@@ -524,6 +525,7 @@
   FStream \
   Glob \
   RegularExpression \
+  Status \
   SystemTools"
 
 KWSYS_FILES="\
@@ -534,6 +536,7 @@
   Glob.hxx \
   Process.h \
   RegularExpression.hxx \
+  Status.hxx \
   String.h \
   String.hxx \
   System.h \
@@ -662,6 +665,7 @@
   --sphinx-man            build man pages with Sphinx
   --sphinx-html           build html help with Sphinx
   --sphinx-qthelp         build qch help with Sphinx
+  --sphinx-latexpdf       build PDF with Sphinx using LaTeX
   --sphinx-build=<sb>     use <sb> as the sphinx-build executable
   --sphinx-flags=<flags>  pass <flags> to sphinx-build executable
 
@@ -926,6 +930,7 @@
   --sphinx-man) cmake_sphinx_man="1" ;;
   --sphinx-html) cmake_sphinx_html="1" ;;
   --sphinx-qthelp) cmake_sphinx_qthelp="1" ;;
+  --sphinx-latexpdf) cmake_sphinx_latexpdf="1" ;;
   --sphinx-build=*) cmake_sphinx_build=`cmake_arg "$1"` ;;
   --sphinx-flags=*) cmake_sphinx_flags=`cmake_arg "$1"` ;;
   --help) cmake_usage ;;
@@ -1917,6 +1922,11 @@
 set (SPHINX_QTHELP "'"${cmake_sphinx_qthelp}"'" CACHE BOOL "Build qch help with Sphinx" FORCE)
 ' >> "${cmake_bootstrap_dir}/InitialCacheFlags.cmake"
 fi
+if test "x${cmake_sphinx_latexpdf}" != "x"; then
+  echo '
+set (SPHINX_LATEXPDF "'"${cmake_sphinx_latexpdf}"'" CACHE BOOL "Build PDF help with Sphinx using LaTeX" FORCE)
+' >> "${cmake_bootstrap_dir}/InitialCacheFlags.cmake"
+fi
 if test "x${cmake_sphinx_build}" != "x"; then
   echo '
 set (SPHINX_EXECUTABLE "'"${cmake_sphinx_build}"'" CACHE FILEPATH "Location of Qt sphinx-build" FORCE)