Merge topic 'FindCxxTest-doc'

676d1da38b FindCxxTest: Modernize documentation formatting
dfe0f58962 FindCxxTest: Update link to cxxtest project page

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !8589
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 297afda..d8806c3 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -826,6 +826,15 @@
     variables:
         CMAKE_CI_JOB_CONTINUOUS: "true"
 
+b:macos-arm64-pch:
+    extends:
+        - .macos_arm64_pch
+        - .cmake_build_macos
+        - .macos_arm64_tags
+        - .run_manually
+    variables:
+        CMAKE_CI_JOB_NIGHTLY: "true"
+
 t:macos-x86_64-ninja:
     extends:
         - .macos_x86_64_ninja
@@ -998,6 +1007,15 @@
         - .windows_x86_64_tags_nonconcurrent_vs2022
         - .run_manually
 
+b:windows-vs2022-x64-pch:
+    extends:
+        - .windows_vs2022_x64_pch
+        - .cmake_build_windows
+        - .windows_x86_64_tags_nonconcurrent_vs2022
+        - .run_manually
+    variables:
+        CMAKE_CI_JOB_NIGHTLY: "true"
+
 t:windows-vs2022-x64-ninja:
     extends:
         - .windows_vs2022_x64_ninja
diff --git a/.gitlab/ci/configure_debian10_aarch64_ninja.cmake b/.gitlab/ci/configure_debian10_aarch64_ninja.cmake
index dff0db1..91d4632 100644
--- a/.gitlab/ci/configure_debian10_aarch64_ninja.cmake
+++ b/.gitlab/ci/configure_debian10_aarch64_ninja.cmake
@@ -74,9 +74,12 @@
 set(CMake_TEST_FindPostgreSQL "ON" CACHE BOOL "")
 set(CMake_TEST_FindProtobuf "ON" CACHE BOOL "")
 set(CMake_TEST_FindProtobuf_gRPC "ON" CACHE BOOL "")
-set(CMake_TEST_FindPython "ON" CACHE BOOL "")
-set(CMake_TEST_FindPython_NumPy "ON" CACHE BOOL "")
-set(CMake_TEST_FindPython_PyPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython2 "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython3 "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython2_NumPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython3_NumPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython2_PyPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython3_PyPy "ON" CACHE BOOL "")
 set(CMake_TEST_FindRuby "ON" CACHE BOOL "")
 set(CMake_TEST_FindSDL "ON" CACHE BOOL "")
 set(CMake_TEST_FindSQLite3 "ON" CACHE BOOL "")
diff --git a/.gitlab/ci/configure_debian10_ninja.cmake b/.gitlab/ci/configure_debian10_ninja.cmake
index 211a2a7..eca92bc 100644
--- a/.gitlab/ci/configure_debian10_ninja.cmake
+++ b/.gitlab/ci/configure_debian10_ninja.cmake
@@ -78,10 +78,13 @@
 set(CMake_TEST_FindPostgreSQL "ON" CACHE BOOL "")
 set(CMake_TEST_FindProtobuf "ON" CACHE BOOL "")
 set(CMake_TEST_FindProtobuf_gRPC "ON" CACHE BOOL "")
-set(CMake_TEST_FindPython "ON" CACHE BOOL "")
-set(CMake_TEST_FindPython_IronPython "ON" CACHE BOOL "")
-set(CMake_TEST_FindPython_NumPy "ON" CACHE BOOL "")
-set(CMake_TEST_FindPython_PyPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython2 "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython3 "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython2_IronPython "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython2_NumPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython2_NumPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython2_PyPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython3_PyPy "ON" CACHE BOOL "")
 set(CMake_TEST_FindRuby "ON" CACHE BOOL "")
 set(CMake_TEST_FindRuby_RVM "ON" CACHE BOOL "")
 set(CMake_TEST_FindSDL "ON" CACHE BOOL "")
diff --git a/.gitlab/ci/configure_fedora38_makefiles.cmake b/.gitlab/ci/configure_fedora38_makefiles.cmake
index c2f9982..a3881cf 100644
--- a/.gitlab/ci/configure_fedora38_makefiles.cmake
+++ b/.gitlab/ci/configure_fedora38_makefiles.cmake
@@ -74,9 +74,12 @@
 set(CMake_TEST_FindPostgreSQL "ON" CACHE BOOL "")
 set(CMake_TEST_FindProtobuf "ON" CACHE BOOL "")
 set(CMake_TEST_FindProtobuf_gRPC "ON" CACHE BOOL "")
-set(CMake_TEST_FindPython "ON" CACHE BOOL "")
-set(CMake_TEST_FindPython_NumPy "ON" CACHE BOOL "")
-set(CMake_TEST_FindPython_PyPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython2 "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython3 "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython2_NumPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython3_NumPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython2_PyPy "ON" CACHE BOOL "")
+set(CMake_TEST_FindPython3_PyPy "ON" CACHE BOOL "")
 set(CMake_TEST_FindRuby "ON" CACHE BOOL "")
 set(CMake_TEST_FindRuby_RVM "ON" CACHE BOOL "")
 set(CMake_TEST_FindSDL "ON" CACHE BOOL "")
diff --git a/.gitlab/ci/configure_macos_arm64_ninja_multi.cmake b/.gitlab/ci/configure_macos_arm64_ninja_multi.cmake
index b22285c..d81bd30 100644
--- a/.gitlab/ci/configure_macos_arm64_ninja_multi.cmake
+++ b/.gitlab/ci/configure_macos_arm64_ninja_multi.cmake
@@ -2,5 +2,9 @@
   set(CMake_TEST_ISPC "ON" CACHE STRING "")
 endif()
 
+# FIXME: sccache sometimes fails with "Compiler killed by signal 9".
+# This job does not compile much anyway, so suppress it for now.
+set(configure_no_sccache 1)
+
 include("${CMAKE_CURRENT_LIST_DIR}/configure_macos_common.cmake")
 include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_macos_arm64_pch.cmake b/.gitlab/ci/configure_macos_arm64_pch.cmake
new file mode 100644
index 0000000..e2676ba
--- /dev/null
+++ b/.gitlab/ci/configure_macos_arm64_pch.cmake
@@ -0,0 +1,7 @@
+set(CMake_BUILD_PCH "ON" CACHE BOOL "")
+
+# sccache does not forward the PCH '-Xarch_arm64 "-include/..."' flag correctly.
+set(configure_no_sccache 1)
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_macos_common.cmake")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")
diff --git a/.gitlab/ci/configure_windows_vs2022_x64_pch.cmake b/.gitlab/ci/configure_windows_vs2022_x64_pch.cmake
new file mode 100644
index 0000000..2a2eed7
--- /dev/null
+++ b/.gitlab/ci/configure_windows_vs2022_x64_pch.cmake
@@ -0,0 +1,2 @@
+set(CMake_BUILD_PCH "ON" CACHE BOOL "")
+include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_common.cmake")
diff --git a/.gitlab/ci/docker/debian10/deps_packages.lst b/.gitlab/ci/docker/debian10/deps_packages.lst
index 0b79675..fc5c174 100644
--- a/.gitlab/ci/docker/debian10/deps_packages.lst
+++ b/.gitlab/ci/docker/debian10/deps_packages.lst
@@ -96,5 +96,5 @@
 swig
 unixodbc-dev
 
-# CMake_TEST_FindPython_IronPython
+# CMake_TEST_FindPython2_IronPython
 libmono-system-windows-forms4.0-cil
diff --git a/.gitlab/ci/ispc.sh b/.gitlab/ci/ispc.sh
index 59ee200..c1e3793 100755
--- a/.gitlab/ci/ispc.sh
+++ b/.gitlab/ci/ispc.sh
@@ -12,12 +12,12 @@
         ;;
     Darwin-arm64)
         shatool="shasum -a 256"
-        sha256sum="62cee043a3a4dbff8c2f6d3885a7e573901bbc1325dd93d50f92904b7ea67fec"
+        sha256sum="c423a5a88d7a9a6ed667e41d025801c123fa0c5fd384d4ea138fa1fcf2bc24c9"
         platform="macOS.arm64"
         ;;
     Darwin-x86_64)
         shatool="shasum -a 256"
-        sha256sum="da0f11a048a316081a8ad8170d48b170b2ed7efc3b140fc88b8611238809c8e4"
+        sha256sum="e25222d2d6f4f8e3561556ac73f88721ceb5486439d6c2a566d37407ad9a5907"
         platform="macOS.x86_64"
         ;;
     *)
diff --git a/.gitlab/os-macos.yml b/.gitlab/os-macos.yml
index 09d7598..fbba288 100644
--- a/.gitlab/os-macos.yml
+++ b/.gitlab/os-macos.yml
@@ -38,6 +38,12 @@
         CMAKE_CONFIGURATION: macos_arm64_ninja
         CTEST_NO_WARNINGS_ALLOWED: 1
 
+.macos_arm64_pch:
+    extends: .macos_arm64_ninja
+
+    variables:
+        CMAKE_CONFIGURATION: macos_arm64_pch
+
 .macos_x86_64_makefiles:
     extends: .macos_build
 
diff --git a/.gitlab/os-windows.yml b/.gitlab/os-windows.yml
index 026f2f4..422e147 100644
--- a/.gitlab/os-windows.yml
+++ b/.gitlab/os-windows.yml
@@ -55,6 +55,13 @@
         VCVARSPLATFORM: "arm64"
         VCVARSVERSION: "14.36.32532"
 
+.windows_vs2022_x64_pch:
+    extends:
+        - .windows_vs2022_x64_ninja
+
+    variables:
+        CMAKE_CONFIGURATION: windows_vs2022_x64_pch
+
 .windows_vs2022_x64_ninja:
     extends:
         - .windows_build_ninja
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d559c08..2823ca4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,7 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-cmake_minimum_required(VERSION 3.13...3.25 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.13...3.26 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)
 
@@ -131,6 +131,8 @@
   endif()
 endif()
 
+option(CMake_BUILD_PCH "Compile CMake with precompiled headers" OFF)
+
 # Check whether to build support for the debugger mode.
 if(NOT CMake_TEST_EXTERNAL_CMAKE)
   if(NOT DEFINED CMake_ENABLE_DEBUGGER)
@@ -153,7 +155,6 @@
 # simply to improve readability of the main script
 #-----------------------------------------------------------------------
 macro(CMAKE_HANDLE_SYSTEM_LIBRARIES)
-  # Options have dependencies.
   include(CMakeDependentOption)
 
   # Allow the user to enable/disable all system utility library options by
@@ -324,6 +325,9 @@
 
 option(CMake_RUN_IWYU "Run include-what-you-use with the compiler." OFF)
 if(CMake_RUN_IWYU)
+  if(CMake_BUILD_PCH)
+    message(FATAL_ERROR "CMake_RUN_IWYU and CMake_BUILD_PCH are ON, but they are incompatible!")
+  endif()
   find_program(IWYU_COMMAND NAMES include-what-you-use iwyu)
   if(NOT IWYU_COMMAND)
     message(FATAL_ERROR "CMake_RUN_IWYU is ON but include-what-you-use is not found!")
diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst
index 7b3aa1a..6dc6832 100644
--- a/Help/command/add_custom_command.rst
+++ b/Help/command/add_custom_command.rst
@@ -512,7 +512,7 @@
   Because generator expressions can be used in custom commands,
   it is possible to define ``COMMAND`` lines or whole custom commands
   which evaluate to empty strings for certain configurations.
-  For **Visual Studio 11 2012 (and newer)** generators these command
+  For **Visual Studio 12 2013 (and newer)** generators these command
   lines or custom commands will be omitted for the specific
   configuration and no "empty-string-command" will be added.
 
diff --git a/Help/envvar/CMAKE_CROSSCOMPILING_EMULATOR.rst b/Help/envvar/CMAKE_CROSSCOMPILING_EMULATOR.rst
new file mode 100644
index 0000000..3e397d8
--- /dev/null
+++ b/Help/envvar/CMAKE_CROSSCOMPILING_EMULATOR.rst
@@ -0,0 +1,11 @@
+CMAKE_CROSSCOMPILING_EMULATOR
+-----------------------------
+
+.. versionadded:: 3.28
+
+.. include:: ENV_VAR.txt
+
+The default value for :variable:`CMAKE_CROSSCOMPILING_EMULATOR` when there
+is no explicit configuration given on the first run while creating a new
+build tree.  On later runs in an existing build tree the value persists in
+the cache as :variable:`CMAKE_CROSSCOMPILING_EMULATOR`.
diff --git a/Help/generator/Visual Studio 11 2012.rst b/Help/generator/Visual Studio 11 2012.rst
index 4e7195c..fd8c314 100644
--- a/Help/generator/Visual Studio 11 2012.rst
+++ b/Help/generator/Visual Studio 11 2012.rst
@@ -1,57 +1,8 @@
 Visual Studio 11 2012
 ---------------------
 
-Deprecated.  Generates Visual Studio 11 (VS 2012) project files.
-
-.. note::
-  This generator is deprecated and will be removed in a future version
-  of CMake.  It will still be possible to build with VS 11 2012 tools
-  using the :generator:`Visual Studio 12 2013` (or above) generator
-  with :variable:`CMAKE_GENERATOR_TOOLSET` set to ``v110``, or by
-  using the :generator:`NMake Makefiles` generator.
-
-For compatibility with CMake versions prior to 3.0, one may specify this
-generator using the name "Visual Studio 11" without the year component.
-
-Project Types
-^^^^^^^^^^^^^
-
-Only Visual C++ and C# projects may be generated (and Fortran with
-Intel compiler integration).  Other types of projects (JavaScript,
-Database, Website, etc.) are not supported.
-
-Platform Selection
-^^^^^^^^^^^^^^^^^^
-
-The default target platform name (architecture) is ``Win32``.
-
-.. versionadded:: 3.1
-  The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
-  via the :option:`cmake -A` option, to specify a target platform
-  name (architecture).  For example:
-
-  * ``cmake -G "Visual Studio 11 2012" -A Win32``
-  * ``cmake -G "Visual Studio 11 2012" -A x64``
-  * ``cmake -G "Visual Studio 11 2012" -A ARM``
-  * ``cmake -G "Visual Studio 11 2012" -A <WinCE-SDK>``
-    (Specify a target platform matching a Windows CE SDK name.)
-
-For compatibility with CMake versions prior to 3.1, one may specify
-a target platform name optionally at the end of the generator name.
-This is supported only for:
-
-``Visual Studio 11 2012 Win64``
-  Specify target platform ``x64``.
-
-``Visual Studio 11 2012 ARM``
-  Specify target platform ``ARM``.
-
-``Visual Studio 11 2012 <WinCE-SDK>``
-  Specify target platform matching a Windows CE SDK name.
-
-Toolset Selection
-^^^^^^^^^^^^^^^^^
-
-The ``v110`` toolset that comes with Visual Studio 11 2012 is selected by
-default.  The :variable:`CMAKE_GENERATOR_TOOLSET` option may be set, perhaps
-via the :option:`cmake -T` option, to specify another toolset.
+Removed.  This once generated Visual Studio 11 2012 project files, but
+the generator has been removed since CMake 3.28.  It is still possible
+to build with VS 11 2012 tools using the :generator:`Visual Studio 12 2013`
+(or above) generator with :variable:`CMAKE_GENERATOR_TOOLSET` set to ``v110``,
+or by using the :generator:`NMake Makefiles` generator.
diff --git a/Help/manual/cmake-env-variables.7.rst b/Help/manual/cmake-env-variables.7.rst
index 197e56e..356e73d 100644
--- a/Help/manual/cmake-env-variables.7.rst
+++ b/Help/manual/cmake-env-variables.7.rst
@@ -43,6 +43,7 @@
    /envvar/CMAKE_COLOR_DIAGNOSTICS
    /envvar/CMAKE_CONFIGURATION_TYPES
    /envvar/CMAKE_CONFIG_TYPE
+   /envvar/CMAKE_CROSSCOMPILING_EMULATOR
    /envvar/CMAKE_EXPORT_COMPILE_COMMANDS
    /envvar/CMAKE_GENERATOR
    /envvar/CMAKE_GENERATOR_INSTANCE
diff --git a/Help/prop_tgt/VS_DEBUGGER_COMMAND.rst b/Help/prop_tgt/VS_DEBUGGER_COMMAND.rst
index 5bf47a3..8c136f2 100644
--- a/Help/prop_tgt/VS_DEBUGGER_COMMAND.rst
+++ b/Help/prop_tgt/VS_DEBUGGER_COMMAND.rst
@@ -11,5 +11,5 @@
 :variable:`CMAKE_VS_DEBUGGER_COMMAND` if it is set when a target is
 created.
 
-This property only works for Visual Studio 11 2012 and above;
+This property only works for Visual Studio 12 2013 and above;
 it is ignored on other generators.
diff --git a/Help/prop_tgt/VS_DEBUGGER_COMMAND_ARGUMENTS.rst b/Help/prop_tgt/VS_DEBUGGER_COMMAND_ARGUMENTS.rst
index 4b9dff7..2656826 100644
--- a/Help/prop_tgt/VS_DEBUGGER_COMMAND_ARGUMENTS.rst
+++ b/Help/prop_tgt/VS_DEBUGGER_COMMAND_ARGUMENTS.rst
@@ -11,5 +11,5 @@
 :variable:`CMAKE_VS_DEBUGGER_COMMAND_ARGUMENTS` if it is set when a target is
 created.
 
-This property only works for Visual Studio 11 2012 and above;
+This property only works for Visual Studio 12 2013 and above;
 it is ignored on other generators.
diff --git a/Help/prop_tgt/VS_DEBUGGER_ENVIRONMENT.rst b/Help/prop_tgt/VS_DEBUGGER_ENVIRONMENT.rst
index 8373dbb..d78d594 100644
--- a/Help/prop_tgt/VS_DEBUGGER_ENVIRONMENT.rst
+++ b/Help/prop_tgt/VS_DEBUGGER_ENVIRONMENT.rst
@@ -11,5 +11,5 @@
 :variable:`CMAKE_VS_DEBUGGER_ENVIRONMENT` if it is set when a target is
 created.
 
-This property only works for Visual Studio 11 2012 and above;
+This property only works for Visual Studio 12 2013 and above;
 it is ignored on other generators.
diff --git a/Help/prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY.rst b/Help/prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY.rst
index 3942047..1026dfa 100644
--- a/Help/prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY.rst
+++ b/Help/prop_tgt/VS_DEBUGGER_WORKING_DIRECTORY.rst
@@ -11,5 +11,5 @@
 :variable:`CMAKE_VS_DEBUGGER_WORKING_DIRECTORY` if it is set when a target is
 created.
 
-This property only works for Visual Studio 11 2012 and above;
+This property only works for Visual Studio 12 2013 and above;
 it is ignored on other generators.
diff --git a/Help/prop_tgt/VS_DOTNET_STARTUP_OBJECT.rst b/Help/prop_tgt/VS_DOTNET_STARTUP_OBJECT.rst
index 8a85ba4..eeb7dda 100644
--- a/Help/prop_tgt/VS_DOTNET_STARTUP_OBJECT.rst
+++ b/Help/prop_tgt/VS_DOTNET_STARTUP_OBJECT.rst
@@ -12,7 +12,7 @@
 than one ``Main()`` method is available in the current project, the property
 becomes mandatory for building the project.
 
-This property only works for Visual Studio 11 2012 and above;
+This property only works for Visual Studio 12 2013 and above;
 it is ignored on other generators.
 
 .. code-block:: cmake
diff --git a/Help/prop_tgt/VS_KEYWORD.rst b/Help/prop_tgt/VS_KEYWORD.rst
index 221b986..f04d109 100644
--- a/Help/prop_tgt/VS_KEYWORD.rst
+++ b/Help/prop_tgt/VS_KEYWORD.rst
@@ -7,4 +7,4 @@
 integration works better if this is set to Qt4VSv1.0.
 
 Use the :prop_tgt:`VS_GLOBAL_KEYWORD` target property to set the
-keyword for Visual Studio 11 (2012) and newer.
+keyword for Visual Studio 12 (2013) and newer.
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/CMAKE_CROSSCOMPILING_EMULATOR-env-variable.rst b/Help/release/dev/CMAKE_CROSSCOMPILING_EMULATOR-env-variable.rst
new file mode 100644
index 0000000..269e739
--- /dev/null
+++ b/Help/release/dev/CMAKE_CROSSCOMPILING_EMULATOR-env-variable.rst
@@ -0,0 +1,6 @@
+CMAKE_CROSSCOMPILING_EMULATOR-env-variable
+------------------------------------------
+
+* The :envvar:`CMAKE_CROSSCOMPILING_EMULATOR` environment variable
+  was added to initialize the :variable:`CMAKE_CROSSCOMPILING_EMULATOR`
+  cache variable.
diff --git a/Help/release/dev/FindCURL-static.rst b/Help/release/dev/FindCURL-static.rst
new file mode 100644
index 0000000..3c369d2
--- /dev/null
+++ b/Help/release/dev/FindCURL-static.rst
@@ -0,0 +1,5 @@
+FindCURL-static
+---------------
+
+* The :module:`FindCURL` module gained a ``CURL_USE_STATIC_LIBS`` hint
+  to select static libraries.
diff --git a/Help/release/dev/FindEXPAT-static.rst b/Help/release/dev/FindEXPAT-static.rst
new file mode 100644
index 0000000..8808ebd
--- /dev/null
+++ b/Help/release/dev/FindEXPAT-static.rst
@@ -0,0 +1,5 @@
+FindEXPAT-static
+----------------
+
+* The :module:`FindEXPAT` module gained a ``EXPAT_USE_STATIC_LIBS`` hint
+  to select static libraries.
diff --git a/Help/release/dev/remove-vs11-generator.rst b/Help/release/dev/remove-vs11-generator.rst
new file mode 100644
index 0000000..971d679
--- /dev/null
+++ b/Help/release/dev/remove-vs11-generator.rst
@@ -0,0 +1,4 @@
+remove-vs11-generator
+---------------------
+
+* The :generator:`Visual Studio 11 2012` generator has been removed.
diff --git a/Help/release/index.rst b/Help/release/index.rst
index fc1f744..3851b7e 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_CFG_INTDIR.rst b/Help/variable/CMAKE_CFG_INTDIR.rst
index 3a57659..3045d91 100644
--- a/Help/variable/CMAKE_CFG_INTDIR.rst
+++ b/Help/variable/CMAKE_CFG_INTDIR.rst
@@ -19,7 +19,7 @@
 ::
 
   $(ConfigurationName) = Visual Studio 9
-  $(Configuration)     = Visual Studio 11 and above
+  $(Configuration)     = Visual Studio 12 and above
   $(CONFIGURATION)     = Xcode
   .                    = Make-based tools
   .                    = Ninja
diff --git a/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst b/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst
index e21b35d..1c3a26c 100644
--- a/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst
+++ b/Help/variable/CMAKE_CROSSCOMPILING_EMULATOR.rst
@@ -12,6 +12,10 @@
   Lists>`, then the first value is the command and remaining values are its
   arguments.
 
+.. versionadded:: 3.28
+  This variable can be initialized via an
+  :envvar:`CMAKE_CROSSCOMPILING_EMULATOR` environment variable.
+
 The command will be used to run :command:`try_run` generated executables,
 which avoids manual population of the ``TryRunResults.cmake`` file.
 
diff --git a/Help/variable/CMAKE_LINK_DEPENDS_USE_LINKER.rst b/Help/variable/CMAKE_LINK_DEPENDS_USE_LINKER.rst
index e1b37a5..1867ad8 100644
--- a/Help/variable/CMAKE_LINK_DEPENDS_USE_LINKER.rst
+++ b/Help/variable/CMAKE_LINK_DEPENDS_USE_LINKER.rst
@@ -10,3 +10,11 @@
 
 This feature is also deactivated if the :prop_tgt:`LINK_DEPENDS_NO_SHARED`
 target property is true.
+
+.. note::
+
+  CMake version |release| defaults this variable to ``FALSE`` because
+  GNU binutils linkers (``ld``, ``ld.bfd``, ``ld.gold``) generate spurious
+  dependencies on temporary files when LTO is enabled.  See `GNU bug 30568`_.
+
+.. _`GNU bug 30568`: https://sourceware.org/bugzilla/show_bug.cgi?id=30568
diff --git a/Help/variable/CMAKE_VS_DEVENV_COMMAND.rst b/Help/variable/CMAKE_VS_DEVENV_COMMAND.rst
index 2bb97c4..155931f 100644
--- a/Help/variable/CMAKE_VS_DEVENV_COMMAND.rst
+++ b/Help/variable/CMAKE_VS_DEVENV_COMMAND.rst
@@ -10,5 +10,5 @@
 is installed on the computer.
 
 The :variable:`CMAKE_VS_MSBUILD_COMMAND` is also provided for
-:generator:`Visual Studio 11 2012` and above.
+:generator:`Visual Studio 12 2013` and above.
 See also the :variable:`CMAKE_MAKE_PROGRAM` variable.
diff --git a/Help/variable/CMAKE_VS_MSBUILD_COMMAND.rst b/Help/variable/CMAKE_VS_MSBUILD_COMMAND.rst
index 8a521a3..96924d5 100644
--- a/Help/variable/CMAKE_VS_MSBUILD_COMMAND.rst
+++ b/Help/variable/CMAKE_VS_MSBUILD_COMMAND.rst
@@ -1,7 +1,7 @@
 CMAKE_VS_MSBUILD_COMMAND
 ------------------------
 
-The generators for :generator:`Visual Studio 11 2012` and above set this
+The generators for :generator:`Visual Studio 12 2013` and above set this
 variable to the ``MSBuild.exe`` command installed with the corresponding
 Visual Studio version.
 
diff --git a/Modules/CMakeDetermineCSharpCompiler.cmake b/Modules/CMakeDetermineCSharpCompiler.cmake
index fe98469..652eb63 100644
--- a/Modules/CMakeDetermineCSharpCompiler.cmake
+++ b/Modules/CMakeDetermineCSharpCompiler.cmake
@@ -3,7 +3,7 @@
 
 if(NOT ${CMAKE_GENERATOR} MATCHES "Visual Studio ([^9]|[9][0-9])")
   message(FATAL_ERROR
-    "C# is currently only supported for Microsoft Visual Studio 11 2012 and later.")
+    "C# is currently only supported for Microsoft Visual Studio 12 2013 and later.")
 endif()
 
 include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
diff --git a/Modules/Compiler/GNU.cmake b/Modules/Compiler/GNU.cmake
index 251e05a..d01054b 100644
--- a/Modules/Compiler/GNU.cmake
+++ b/Modules/Compiler/GNU.cmake
@@ -53,6 +53,9 @@
   endif()
 
   # define flags for linker depfile generation
+  set(CMAKE_${lang}_LINKER_DEPFILE_FLAGS "LINKER:--dependency-file,<DEP_FILE>")
+  set(CMAKE_${lang}_LINKER_DEPFILE_FORMAT gcc)
+
   if(NOT DEFINED CMAKE_${lang}_LINKER_DEPFILE_SUPPORTED)
     ## Ensure ninja tool is recent enough...
     if(CMAKE_GENERATOR MATCHES "^Ninja")
@@ -82,15 +85,19 @@
       unset(_linker_capabilities)
     endif()
   endif()
-
   if (CMAKE_${lang}_LINKER_DEPFILE_SUPPORTED)
-    set(CMAKE_${lang}_LINKER_DEPFILE_FLAGS "LINKER:--dependency-file,<DEP_FILE>")
-    set(CMAKE_${lang}_LINKER_DEPFILE_FORMAT gcc)
     set(CMAKE_${lang}_LINK_DEPENDS_USE_LINKER TRUE)
   else()
     unset(CMAKE_${lang}_LINK_DEPENDS_USE_LINKER)
   endif()
 
+  # For now, due to GNU binutils ld bug when LTO is enabled (see GNU bug
+    # `30568 <https://sourceware.org/bugzilla/show_bug.cgi?id=30568>`_),
+  # deactivate this feature.
+  if (NOT DEFINED CMAKE_LINK_DEPENDS_USE_LINKER)
+    set(CMAKE_LINK_DEPENDS_USE_LINKER FALSE)
+  endif()
+
   # Initial configuration flags.
   string(APPEND CMAKE_${lang}_FLAGS_INIT " ")
   string(APPEND CMAKE_${lang}_FLAGS_DEBUG_INIT " -g")
diff --git a/Modules/Compiler/NVHPC-Fortran.cmake b/Modules/Compiler/NVHPC-Fortran.cmake
index 59755b3..ca5f1b2 100644
--- a/Modules/Compiler/NVHPC-Fortran.cmake
+++ b/Modules/Compiler/NVHPC-Fortran.cmake
@@ -1,3 +1,7 @@
 include(Compiler/PGI-Fortran)
 include(Compiler/NVHPC)
 __compiler_nvhpc(Fortran)
+if(CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 21.7)
+  # Before NVHPC 21.7 nvfortran didn't support isystem
+  unset(CMAKE_INCLUDE_SYSTEM_FLAG_Fortran)
+endif()
diff --git a/Modules/FindCURL.cmake b/Modules/FindCURL.cmake
index acb87dc..2f33dac 100644
--- a/Modules/FindCURL.cmake
+++ b/Modules/FindCURL.cmake
@@ -58,6 +58,18 @@
 
 Set ``CURL_NO_CURL_CMAKE`` to ``ON`` to disable this search.
 
+Hints
+^^^^^
+
+``CURL_USE_STATIC_LIBS``
+
+  .. versionadded:: 3.28
+
+  Set to ``TRUE`` to use static libraries.
+
+  This is meaningful only when CURL is not found via its
+  CMake Package Configuration file.
+
 #]=======================================================================]
 
 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
@@ -193,6 +205,11 @@
     set_target_properties(CURL::libcurl PROPERTIES
       INTERFACE_INCLUDE_DIRECTORIES "${CURL_INCLUDE_DIRS}")
 
+    if(CURL_USE_STATIC_LIBS)
+      set_property(TARGET CURL::libcurl APPEND PROPERTY
+                   INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB")
+    endif()
+
     if(EXISTS "${CURL_LIBRARY}")
       set_target_properties(CURL::libcurl PROPERTIES
         IMPORTED_LINK_INTERFACE_LANGUAGES "C"
@@ -212,5 +229,11 @@
         IMPORTED_LINK_INTERFACE_LANGUAGES "C"
         IMPORTED_LOCATION_DEBUG "${CURL_LIBRARY_DEBUG}")
     endif()
+
+    if(CURL_USE_STATIC_LIBS AND MSVC)
+       set_target_properties(CURL::libcurl PROPERTIES
+           INTERFACE_LINK_LIBRARIES "normaliz.lib;ws2_32.lib;wldap32.lib")
+    endif()
+
   endif()
 endif()
diff --git a/Modules/FindEXPAT.cmake b/Modules/FindEXPAT.cmake
index 3bedc73..762931e 100644
--- a/Modules/FindEXPAT.cmake
+++ b/Modules/FindEXPAT.cmake
@@ -30,6 +30,15 @@
 ``EXPAT_FOUND``
   true if the Expat headers and libraries were found.
 
+Hints
+^^^^^
+
+``EXPAT_USE_STATIC_LIBS``
+
+  .. versionadded:: 3.28
+
+  Set to ``TRUE`` to use static libraries.
+
 #]=======================================================================]
 
 find_package(PkgConfig QUIET)
@@ -43,8 +52,13 @@
 set(EXPAT_NAMES_DEBUG expatd expatwd)
 
 if(WIN32)
-  list(APPEND EXPAT_NAMES expatMT expatMD expatwMT expatwMD)
-  list(APPEND EXPAT_NAMES_DEBUG expatdMT expatdMD expatwdMT expatwdMD)
+  if(EXPAT_USE_STATIC_LIBS)
+    list(APPEND EXPAT_NAMES expatMT expatwMT)
+    list(APPEND EXPAT_NAMES_DEBUG expatdMT expatwdMT)
+  else()
+    list(APPEND EXPAT_NAMES expatMT expatMD expatwMT expatwMD)
+    list(APPEND EXPAT_NAMES_DEBUG expatdMT expatdMD expatwdMT expatwdMD)
+  endif()
 endif()
 
 # Allow EXPAT_LIBRARY to be set manually, as the location of the expat library
@@ -115,6 +129,11 @@
       IMPORTED_LINK_INTERFACE_LANGUAGES "C"
       INTERFACE_INCLUDE_DIRECTORIES "${EXPAT_INCLUDE_DIRS}")
 
+    if(EXPAT_USE_STATIC_LIBS)
+      set_property(TARGET EXPAT::EXPAT APPEND PROPERTY
+                   INTERFACE_COMPILE_DEFINITIONS "XML_STATIC")
+    endif()
+
     if(EXPAT_LIBRARY_RELEASE)
       set_property(TARGET EXPAT::EXPAT APPEND PROPERTY
         IMPORTED_CONFIGURATIONS RELEASE)
diff --git a/Modules/UseSWIG.cmake b/Modules/UseSWIG.cmake
index ca16bc2..cece973 100644
--- a/Modules/UseSWIG.cmake
+++ b/Modules/UseSWIG.cmake
@@ -189,7 +189,7 @@
   :ref:`Makefile <Makefile Generators>`,
   :ref:`Ninja <Ninja Generators>`, :generator:`Xcode`, and
   :ref:`Visual Studio <Visual Studio Generators>`
-  (:generator:`Visual Studio 11 2012` and above) generators. Default value is
+  (:generator:`Visual Studio 12 2013` and above) generators. Default value is
   ``FALSE``.
 
   .. versionadded:: 3.21
@@ -353,7 +353,7 @@
   :ref:`Makefile <Makefile Generators>`,
   :ref:`Ninja <Ninja Generators>`, :generator:`Xcode`, and
   :ref:`Visual Studio <Visual Studio Generators>`
-  (:generator:`Visual Studio 11 2012` and above) generators. Default value is
+  (:generator:`Visual Studio 12 2013` and above) generators. Default value is
   ``FALSE``.
 
   Source file property ``USE_SWIG_DEPENDENCIES``, if not defined, will be
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index b01e1e7..708aec7 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -438,6 +438,7 @@
   cmUVHandlePtr.h
   cmUVProcessChain.cxx
   cmUVProcessChain.h
+  cmUVStream.h
   cmUVStreambuf.h
   cmUVSignalHackRAII.h
   cmVariableWatch.cxx
@@ -928,6 +929,44 @@
     )
 endif()
 
+if(CMake_BUILD_PCH)
+  target_precompile_headers(CMakeLib PRIVATE
+    "$<$<COMPILE_LANGUAGE:CXX>:<string$<ANGLE-R>>"
+    "$<$<COMPILE_LANGUAGE:CXX>:<iostream$<ANGLE-R>>"
+    "$<$<COMPILE_LANGUAGE:CXX>:<sstream$<ANGLE-R>>"
+    "$<$<COMPILE_LANGUAGE:CXX>:<iomanip$<ANGLE-R>>"
+    "$<$<COMPILE_LANGUAGE:CXX>:<cm/memory$<ANGLE-R>>"
+    "$<$<COMPILE_LANGUAGE:CXX>:<cm3p/cppdap/protocol.h$<ANGLE-R>>"
+    "$<$<COMPILE_LANGUAGE:CXX>:cmMakefile.h>"
+    "$<$<COMPILE_LANGUAGE:CXX>:cmGlobalGenerator.h>"
+    "$<$<COMPILE_LANGUAGE:CXX>:cmLocalGenerator.h>"
+    "$<$<COMPILE_LANGUAGE:CXX>:cmGeneratorTarget.h>"
+    "$<$<COMPILE_LANGUAGE:CXX>:cmGeneratorExpression.h>"
+    "$<$<COMPILE_LANGUAGE:CXX>:cmArgumentParser.h>"
+    "$<$<COMPILE_LANGUAGE:CXX>:cmake.h>"
+    "$<$<COMPILE_LANGUAGE:CXX>:cmCMakePath.h>"
+    "$<$<COMPILE_LANGUAGE:CXX>:cmDebuggerPipeConnection.h>"
+    "$<$<COMPILE_LANGUAGE:CXX>:cmCurl.h>")
+
+    set_source_files_properties(
+      "LexerParser/cmFortranLexer.cxx"
+      PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
+
+  if(WIN32)
+    target_precompile_headers(CMakeLib PRIVATE
+      "$<$<COMPILE_LANGUAGE:CXX>:<cm3p/uv.h$<ANGLE-R>>"
+      "$<$<COMPILE_LANGUAGE:CXX>:cmVSSetupHelper.h>")
+    set_source_files_properties("LexerParser/cmFortranParser.cxx" PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
+  else()
+    set_source_files_properties(
+      "LexerParser/cmCommandArgumentLexer.cxx"
+      "LexerParser/cmGccDepfileLexer.cxx"
+      "LexerParser/cmExprLexer.cxx"
+      "LexerParser/cmDependsJavaLexer.cxx"
+      PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
+  endif()
+endif()
+
 # Temporary variable for tools targets
 set(_tools)
 
@@ -1040,6 +1079,24 @@
   )
 target_link_libraries(CTestLib PUBLIC CMakeLib)
 
+if(CMake_BUILD_PCH)
+  target_precompile_headers(CTestLib PRIVATE
+    "cmDuration.h"
+    "cmMakefile.h"
+    "cmSystemTools.h"
+    "cmGlobalGenerator.h"
+    "cmake.h"
+    "CTest/cmCTestGenericHandler.h"
+    "<sstream>"
+    "<cm3p/uv.h>")
+
+  if(WIN32)
+    target_precompile_headers(CTestLib PRIVATE "cmCurl.h" "CTest/cmCTestMultiProcessHandler.h")
+  else()
+    set_source_files_properties("LexerParser/cmCTestResourceGroupsLexer.cxx" PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
+  endif()
+endif()
+
 #
 # Build CPackLib
 #
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index add9fd1..183dfea 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,8 +1,8 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 27)
-set(CMake_VERSION_PATCH 0)
-set(CMake_VERSION_RC 3)
+set(CMake_VERSION_PATCH 20230626)
+#set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
 # Start with the full version number used in tags.  It has no dev info.
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
index afd85cd..11d90c0 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -1119,8 +1119,8 @@
   // Run post-build actions
   cmValue postBuildScripts = this->GetOption("CPACK_POST_BUILD_SCRIPTS");
   if (postBuildScripts) {
-    this->MakefileMap->AddDefinition("CPACK_PACKAGE_FILES",
-                                     cmJoin(this->packageFileNames, ";"));
+    this->MakefileMap->AddDefinition(
+      "CPACK_PACKAGE_FILES", cmList::to_string(this->packageFileNames));
 
     const cmList scripts{ postBuildScripts };
     for (const auto& script : scripts) {
diff --git a/Source/CPack/cmCPackNuGetGenerator.cxx b/Source/CPack/cmCPackNuGetGenerator.cxx
index 5de8179..aa99fb6 100644
--- a/Source/CPack/cmCPackNuGetGenerator.cxx
+++ b/Source/CPack/cmCPackNuGetGenerator.cxx
@@ -12,7 +12,7 @@
 
 #include "cmCPackComponentGroup.h"
 #include "cmCPackLog.h"
-#include "cmStringAlgorithms.h"
+#include "cmList.h"
 #include "cmSystemTools.h"
 #include "cmValue.h"
 
@@ -82,10 +82,10 @@
                      std::back_inserter(components),
                      [](cmCPackComponent const* comp) { return comp->Name; });
       this->SetOption("CPACK_NUGET_" + compGUp + "_GROUP_COMPONENTS",
-                      cmJoin(components, ";"));
+                      cmList::to_string(components));
     }
     if (!groups.empty()) {
-      this->SetOption("CPACK_NUGET_GROUPS", cmJoin(groups, ";"));
+      this->SetOption("CPACK_NUGET_GROUPS", cmList::to_string(groups));
     }
 
     // Handle Orphan components (components not belonging to any groups)
@@ -103,7 +103,7 @@
       }
     }
     if (!components.empty()) {
-      this->SetOption("CPACK_NUGET_COMPONENTS", cmJoin(components, ";"));
+      this->SetOption("CPACK_NUGET_COMPONENTS", cmList::to_string(components));
     }
 
   } else {
@@ -114,7 +114,7 @@
                    [](std::pair<std::string, cmCPackComponent> const& comp) {
                      return comp.first;
                    });
-    this->SetOption("CPACK_NUGET_COMPONENTS", cmJoin(components, ";"));
+    this->SetOption("CPACK_NUGET_COMPONENTS", cmList::to_string(components));
   }
 }
 
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
index 90716e6..00c8fa2 100644
--- a/Source/CPack/cpack.cxx
+++ b/Source/CPack/cpack.cxx
@@ -363,11 +363,11 @@
     }
 
     if (!expandedPreset->Generators.empty() && generator.empty()) {
-      generator = cmJoin(expandedPreset->Generators, ";");
+      generator = cmList::to_string(expandedPreset->Generators);
     }
 
     if (!expandedPreset->Configurations.empty() && cpackBuildConfig.empty()) {
-      cpackBuildConfig = cmJoin(expandedPreset->Configurations, ";");
+      cpackBuildConfig = cmList::to_string(expandedPreset->Configurations);
     }
 
     definitions.insert(expandedPreset->Variables.begin(),
diff --git a/Source/Checks/Curses/CMakeLists.txt b/Source/Checks/Curses/CMakeLists.txt
index 0fee7ac..bc6b906 100644
--- a/Source/Checks/Curses/CMakeLists.txt
+++ b/Source/Checks/Curses/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.13...3.24 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.13...3.26 FATAL_ERROR)
 project(CheckCurses C)
 
 set(CURSES_NEED_NCURSES TRUE)
diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx
index a1b2149..77a0048 100644
--- a/Source/CursesDialog/cmCursesMainForm.cxx
+++ b/Source/CursesDialog/cmCursesMainForm.cxx
@@ -458,6 +458,14 @@
   }
 }
 
+void cmCursesMainForm::Write()
+{
+  this->FillCacheManagerFromUI();
+  this->CMakeInstance->SaveCache(
+    this->CMakeInstance->GetHomeOutputDirectory());
+  this->LoadCache(nullptr);
+}
+
 int cmCursesMainForm::Configure(int noconfigure)
 {
   this->ResetOutputs();
@@ -471,10 +479,7 @@
   }
 
   // always save the current gui values to disk
-  this->FillCacheManagerFromUI();
-  this->CMakeInstance->SaveCache(
-    this->CMakeInstance->GetHomeOutputDirectory());
-  this->LoadCache(nullptr);
+  this->Write();
 
   // run the generate process
   this->OkToGenerate = true;
@@ -794,6 +799,21 @@
       else if (key == KEY_PPAGE || key == ctrl('u')) {
         form_driver(this->Form, REQ_PREV_PAGE);
       }
+      // first entry
+      else if (key == KEY_HOME) {
+        form_driver(this->Form, REQ_FIRST_PAGE);
+        form_driver(this->Form, REQ_FIRST_FIELD);
+      }
+      // last entry
+      else if (key == KEY_END) {
+        form_driver(this->Form, REQ_LAST_PAGE);
+        form_driver(this->Form, REQ_LAST_FIELD);
+      }
+      // write and quit
+      else if (key == 'w') {
+        this->Write();
+        break;
+      }
       // configure
       else if (key == 'c') {
         this->Configure();
@@ -854,6 +874,10 @@
         if (!this->OldSearchString.empty()) {
           this->JumpToCacheEntry(this->OldSearchString.c_str());
         }
+      } else if (key == 'N') {
+        if (!this->OldSearchString.empty()) {
+          this->JumpToCacheEntry(this->OldSearchString.c_str(), true);
+        }
       }
       // switch advanced on/off
       else if (key == 't') {
@@ -945,6 +969,11 @@
 
 void cmCursesMainForm::JumpToCacheEntry(const char* astr)
 {
+  this->JumpToCacheEntry(astr, false);
+}
+
+void cmCursesMainForm::JumpToCacheEntry(const char* astr, bool reverse)
+{
   std::string str;
   if (astr) {
     str = cmSystemTools::LowerCase(astr);
@@ -973,12 +1002,21 @@
         }
       }
     }
-    if (static_cast<size_t>(findex) >= 3 * this->NumberOfVisibleEntries - 1) {
-      set_current_field(this->Form, this->Fields[2]);
-    } else if (new_page(this->Fields[findex + 1])) {
-      form_driver(this->Form, REQ_NEXT_PAGE);
+    if (!reverse &&
+        static_cast<size_t>(findex) >= 3 * this->NumberOfVisibleEntries - 1) {
+      form_driver(this->Form, REQ_FIRST_PAGE);
+      form_driver(this->Form, REQ_FIRST_FIELD);
+    } else if (reverse && static_cast<size_t>(findex) < 3) {
+      form_driver(this->Form, REQ_LAST_PAGE);
+      form_driver(this->Form, REQ_LAST_FIELD);
+    } else if (this->Fields[findex + (reverse ? -3 : 1)]->page !=
+               this->Fields[findex]->page) {
+      form_driver(this->Form, reverse ? REQ_PREV_PAGE : REQ_NEXT_PAGE);
+      if (reverse) {
+        form_driver(this->Form, REQ_LAST_FIELD);
+      }
     } else {
-      form_driver(this->Form, REQ_NEXT_FIELD);
+      form_driver(this->Form, reverse ? REQ_PREV_FIELD : REQ_NEXT_FIELD);
     }
     cur = current_field(this->Form);
     findex = field_index(cur);
@@ -1040,15 +1078,21 @@
   "hit 'g' to have CMake generate all the build files (i.e. makefiles or "
   "project files) and exit. "
   "At any point during the process, you can exit ccmake with 'q'. However, "
-  "this will not generate/change any build files.\n\n"
+  "this will not generate/change any build files. Additionally, you can exit "
+  "ccmake with 'w' to write changes to the cache file without generating or "
+  "changing the build files.\n\n"
   "ccmake KEYS:\n\n"
   "Navigation: "
   "You can use the arrow keys and page up, down to navigate the options. "
-  "Alternatively, you can use the following keys: \n"
+  "Additionally, you can use the following keys: \n"
   " C-n or j : next option\n"
   " C-p or k : previous options\n"
   " C-d : down one page\n"
-  " C-u : up one page\n\n"
+  " C-u : up one page\n"
+  " Home : jump to first option\n"
+  " End : jump to last option\n"
+  " n : next search result\n"
+  " N : previous search result\n\n"
   "Editing options: "
   "To change an option  press enter or return. If the current options is a "
   "boolean, this will toggle its value. "
diff --git a/Source/CursesDialog/cmCursesMainForm.h b/Source/CursesDialog/cmCursesMainForm.h
index 112b7e8..1ce75e7 100644
--- a/Source/CursesDialog/cmCursesMainForm.h
+++ b/Source/CursesDialog/cmCursesMainForm.h
@@ -87,6 +87,11 @@
   void AddError(const std::string& message, const char* title) override;
 
   /**
+   * Write files to cache file without reconfiguring.
+   */
+  void Write();
+
+  /**
    * Used to do a configure. If argument is specified, it does only the check
    * and not configure.
    */
@@ -123,6 +128,7 @@
 
   // Jump to the cache entry whose name matches the string.
   void JumpToCacheEntry(const char* str);
+  void JumpToCacheEntry(const char* str, bool reverse);
 
   // Clear and reset the output log and state
   void ResetOutputs();
diff --git a/Source/cmAuxSourceDirectoryCommand.cxx b/Source/cmAuxSourceDirectoryCommand.cxx
index 35f4c88..b2e3cad 100644
--- a/Source/cmAuxSourceDirectoryCommand.cxx
+++ b/Source/cmAuxSourceDirectoryCommand.cxx
@@ -11,6 +11,7 @@
 #include "cmsys/Directory.hxx"
 
 #include "cmExecutionStatus.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmSourceFile.h"
 #include "cmStringAlgorithms.h"
@@ -67,7 +68,7 @@
   if (!sourceListValue.empty()) {
     sourceListValue += ";";
   }
-  sourceListValue += cmJoin(files, ";");
+  sourceListValue += cmList::to_string(files);
   mf.AddDefinition(args[1], sourceListValue);
   return true;
 }
diff --git a/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx
index 566e4a4..8043f82 100644
--- a/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx
+++ b/Source/cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.cxx
@@ -10,6 +10,7 @@
 #include "cmRuntimeDependencyArchive.h"
 #include "cmSystemTools.h"
 #include "cmUVProcessChain.h"
+#include "cmUVStream.h"
 
 cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool::
   cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool(
@@ -35,7 +36,7 @@
   builder.AddCommand(command);
 
   auto process = builder.Start();
-  if (!process.Valid()) {
+  if (!process.Valid() || process.GetStatus(0).SpawnResult != 0) {
     std::ostringstream e;
     e << "Failed to start objdump process for:\n  " << file;
     this->SetError(e.str());
@@ -46,7 +47,8 @@
   static const cmsys::RegularExpression neededRegex("^ *NEEDED *([^\n]*)$");
   static const cmsys::RegularExpression rpathRegex("^ *RPATH *([^\n]*)$");
   static const cmsys::RegularExpression runpathRegex("^ *RUNPATH *([^\n]*)$");
-  while (std::getline(*process.OutputStream(), line)) {
+  cmUVPipeIStream output(process.GetLoop(), process.OutputStream());
+  while (std::getline(output, line)) {
     cmsys::RegularExpressionMatch match;
     if (neededRegex.find(line.c_str(), match)) {
       needed.push_back(match.match(1));
@@ -73,8 +75,7 @@
     this->SetError(e.str());
     return false;
   }
-  auto status = process.GetStatus();
-  if (!status[0] || status[0]->ExitStatus != 0) {
+  if (process.GetStatus(0).ExitStatus != 0) {
     std::ostringstream e;
     e << "Failed to run objdump on:\n  " << file;
     this->SetError(e.str());
diff --git a/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx
index 6d97720..4c35841 100644
--- a/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx
+++ b/Source/cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool.cxx
@@ -9,6 +9,7 @@
 
 #include "cmRuntimeDependencyArchive.h"
 #include "cmUVProcessChain.h"
+#include "cmUVStream.h"
 
 cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool::
   cmBinUtilsMacOSMachOOToolGetRuntimeDependenciesTool(
@@ -34,7 +35,7 @@
     .AddCommand(command);
 
   auto process = builder.Start();
-  if (!process.Valid()) {
+  if (!process.Valid() || process.GetStatus(0).SpawnResult != 0) {
     std::ostringstream e;
     e << "Failed to start otool process for:\n  " << file;
     this->SetError(e.str());
@@ -49,11 +50,12 @@
     "^ *path (.*) \\(offset [0-9]+\\)$");
   static const cmsys::RegularExpression nameRegex(
     "^ *name (.*) \\(offset [0-9]+\\)$");
-  while (std::getline(*process.OutputStream(), line)) {
+  cmUVPipeIStream output(process.GetLoop(), process.OutputStream());
+  while (std::getline(output, line)) {
     cmsys::RegularExpressionMatch cmdMatch;
     if (rpathRegex.find(line.c_str(), cmdMatch)) {
-      if (!std::getline(*process.OutputStream(), line) ||
-          !std::getline(*process.OutputStream(), line)) {
+      // NOLINTNEXTLINE(misc-redundant-expression)
+      if (!std::getline(output, line) || !std::getline(output, line)) {
         this->SetError("Invalid output from otool");
         return false;
       }
@@ -66,8 +68,8 @@
         return false;
       }
     } else if (loadDylibRegex.find(line.c_str(), cmdMatch)) {
-      if (!std::getline(*process.OutputStream(), line) ||
-          !std::getline(*process.OutputStream(), line)) {
+      // NOLINTNEXTLINE(misc-redundant-expression)
+      if (!std::getline(output, line) || !std::getline(output, line)) {
         this->SetError("Invalid output from otool");
         return false;
       }
@@ -88,8 +90,7 @@
     this->SetError(e.str());
     return false;
   }
-  auto status = process.GetStatus();
-  if (!status[0] || status[0]->ExitStatus != 0) {
+  if (process.GetStatus(0).ExitStatus != 0) {
     std::ostringstream e;
     e << "Failed to run otool on:\n  " << file;
     this->SetError(e.str());
diff --git a/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx
index f342884..cd21140 100644
--- a/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx
+++ b/Source/cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool.cxx
@@ -9,6 +9,7 @@
 
 #include "cmRuntimeDependencyArchive.h"
 #include "cmUVProcessChain.h"
+#include "cmUVStream.h"
 
 cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool::
   cmBinUtilsWindowsPEDumpbinGetRuntimeDependenciesTool(
@@ -33,7 +34,7 @@
   builder.AddCommand(command);
 
   auto process = builder.Start();
-  if (!process.Valid()) {
+  if (!process.Valid() || process.GetStatus(0).SpawnResult != 0) {
     std::ostringstream e;
     e << "Failed to start dumpbin process for:\n  " << file;
     this->SetError(e.str());
@@ -43,7 +44,8 @@
   std::string line;
   static const cmsys::RegularExpression regex(
     "^    ([^\n]*\\.[Dd][Ll][Ll])\r$");
-  while (std::getline(*process.OutputStream(), line)) {
+  cmUVPipeIStream output(process.GetLoop(), process.OutputStream());
+  while (std::getline(output, line)) {
     cmsys::RegularExpressionMatch match;
     if (regex.find(line.c_str(), match)) {
       needed.push_back(match.match(1));
@@ -56,8 +58,7 @@
     this->SetError(e.str());
     return false;
   }
-  auto status = process.GetStatus();
-  if (!status[0] || status[0]->ExitStatus != 0) {
+  if (process.GetStatus(0).ExitStatus != 0) {
     std::ostringstream e;
     e << "Failed to run dumpbin on:\n  " << file;
     this->SetError(e.str());
diff --git a/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx b/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
index f14de55..d95da95 100644
--- a/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
+++ b/Source/cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx
@@ -10,6 +10,7 @@
 #include "cmRuntimeDependencyArchive.h"
 #include "cmSystemTools.h"
 #include "cmUVProcessChain.h"
+#include "cmUVStream.h"
 
 cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool::
   cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool(
@@ -34,7 +35,7 @@
   builder.AddCommand(command);
 
   auto process = builder.Start();
-  if (!process.Valid()) {
+  if (!process.Valid() || process.GetStatus(0).SpawnResult != 0) {
     std::ostringstream e;
     e << "Failed to start objdump process for:\n  " << file;
     this->SetError(e.str());
@@ -44,7 +45,8 @@
   std::string line;
   static const cmsys::RegularExpression regex(
     "^\t*DLL Name: ([^\n]*\\.[Dd][Ll][Ll])$");
-  while (cmSystemTools::GetLineFromStream(*process.OutputStream(), line)) {
+  cmUVPipeIStream output(process.GetLoop(), process.OutputStream());
+  while (cmSystemTools::GetLineFromStream(output, line)) {
     cmsys::RegularExpressionMatch match;
     if (regex.find(line.c_str(), match)) {
       needed.push_back(match.match(1));
@@ -57,8 +59,7 @@
     this->SetError(e.str());
     return false;
   }
-  auto status = process.GetStatus();
-  if (!status[0] || status[0]->ExitStatus != 0) {
+  if (process.GetStatus(0).ExitStatus != 0) {
     std::ostringstream e;
     e << "Failed to run objdump on:\n  " << file;
     this->SetError(e.str());
diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx
index 1c00f15..81ed41f 100644
--- a/Source/cmCMakeHostSystemInformationCommand.cxx
+++ b/Source/cmCMakeHostSystemInformationCommand.cxx
@@ -529,12 +529,12 @@
   if (arguments.ValueNames) {
     auto result = registry.GetValueNames(key, view);
     if (result) {
-      makefile.AddDefinition(variable, cmJoin(*result, ";"_s));
+      makefile.AddDefinition(variable, cmList::to_string(*result));
     }
   } else if (arguments.SubKeys) {
     auto result = registry.GetSubKeys(key, view);
     if (result) {
-      makefile.AddDefinition(variable, cmJoin(*result, ";"_s));
+      makefile.AddDefinition(variable, cmList::to_string(*result));
     }
   } else {
     auto result =
diff --git a/Source/cmDebuggerVariablesHelper.cxx b/Source/cmDebuggerVariablesHelper.cxx
index 1322b20..b2e85f2 100644
--- a/Source/cmDebuggerVariablesHelper.cxx
+++ b/Source/cmDebuggerVariablesHelper.cxx
@@ -10,7 +10,7 @@
 #include <map>
 #include <sstream>
 
-#include "cm_codecvt.hxx"
+#include "cm_codecvt_Encoding.hxx"
 
 #include "cmDebuggerStackFrame.h"
 #include "cmDebuggerVariables.h"
@@ -578,17 +578,17 @@
     return {};
   }
 
-  auto makeFileEncodingString = [](codecvt::Encoding encoding) {
+  auto makeFileEncodingString = [](codecvt_Encoding encoding) {
     switch (encoding) {
-      case codecvt::Encoding::None:
+      case codecvt_Encoding::None:
         return "None";
-      case codecvt::Encoding::UTF8:
+      case codecvt_Encoding::UTF8:
         return "UTF8";
-      case codecvt::Encoding::UTF8_WITH_BOM:
+      case codecvt_Encoding::UTF8_WITH_BOM:
         return "UTF8_WITH_BOM";
-      case codecvt::Encoding::ANSI:
+      case codecvt_Encoding::ANSI:
         return "ANSI";
-      case codecvt::Encoding::ConsoleOutput:
+      case codecvt_Encoding::ConsoleOutput:
         return "ConsoleOutput";
       default:
         return "Unknown";
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
index 7fbd826..3b98219 100644
--- a/Source/cmExecuteProcessCommand.cxx
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -20,6 +20,7 @@
 
 #include "cmArgumentParser.h"
 #include "cmExecutionStatus.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmProcessOutput.h"
@@ -356,7 +357,7 @@
           }
         }
         status.GetMakefile().AddDefinition(arguments.ResultsVariable,
-                                           cmJoin(res, ";"));
+                                           cmList::to_string(res));
       } break;
       case cmsysProcess_State_Exception:
         status.GetMakefile().AddDefinition(
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index df26bad..8d3960c 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -19,6 +19,7 @@
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -237,7 +238,7 @@
     }
 
     // Store the property.
-    properties[prop] = cmJoin(objects, ";");
+    properties[prop] = cmList::to_string(objects);
   } else {
     // Add the main target file.
     {
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 22276ae..481c98f 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -383,7 +383,7 @@
   cmGeneratorExpression ge(*target->Makefile->GetCMakeInstance());
 
   std::string dirs = cmGeneratorExpression::Preprocess(
-    cmJoin(target->Target->GetInstallIncludeDirectoriesEntries(te), ";"),
+    cmList::to_string(target->Target->GetInstallIncludeDirectoriesEntries(te)),
     preprocessRule, true);
   this->ReplaceInstallPrefix(dirs);
   std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(dirs);
@@ -955,13 +955,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.25 (this upper limit may be reviewed
+  // policy settings for up to CMake 3.26 (this upper limit may be reviewed
   // and increased from time to time). This reduces the opportunity for CMake
   // warnings when an older export file is later used with newer CMake
   // versions.
   /* clang-format off */
   os << "cmake_policy(PUSH)\n"
-     << "cmake_policy(VERSION 2.8.3...3.25)\n";
+     << "cmake_policy(VERSION 2.8.3...3.26)\n";
   /* clang-format on */
 }
 
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index 538c883..264c947 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -19,6 +19,7 @@
 #include "cmInstallExportGenerator.h"
 #include "cmInstallFileSetGenerator.h"
 #include "cmInstallTargetGenerator.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -430,7 +431,7 @@
     }
 
     // Store the property.
-    properties[prop] = cmJoin(objects, ";");
+    properties[prop] = cmList::to_string(objects);
     importedLocations.insert(prop);
   } else {
     if (target->IsFrameworkOnApple() && target->HasImportLibrary(config)) {
@@ -590,10 +591,12 @@
   auto cge = ge.Parse(te->FileSetGenerators.at(fileSet)->GetDestination());
 
   for (auto const& config : configs) {
-    auto dest = cmStrCat("${_IMPORT_PREFIX}/",
-                         cmOutputConverter::EscapeForCMake(
-                           cge->Evaluate(gte->LocalGenerator, config, gte),
-                           cmOutputConverter::WrapQuotes::NoWrap));
+    auto unescapedDest = cge->Evaluate(gte->LocalGenerator, config, gte);
+    auto dest = cmOutputConverter::EscapeForCMake(
+      unescapedDest, cmOutputConverter::WrapQuotes::NoWrap);
+    if (!cmSystemTools::FileIsFullPath(unescapedDest)) {
+      dest = cmStrCat("${_IMPORT_PREFIX}/", dest);
+    }
 
     auto const& type = fileSet->GetType();
     // C++ modules do not support interface file sets which are dependent upon
@@ -645,11 +648,14 @@
       fileSet->EvaluateFileEntry(directories, files, entry,
                                  gte->LocalGenerator, config, gte);
     }
-    auto dest = cmStrCat("${_IMPORT_PREFIX}/",
-                         cmOutputConverter::EscapeForCMake(
-                           destCge->Evaluate(gte->LocalGenerator, config, gte),
-                           cmOutputConverter::WrapQuotes::NoWrap),
-                         '/');
+    auto unescapedDest = destCge->Evaluate(gte->LocalGenerator, config, gte);
+    auto dest =
+      cmStrCat(cmOutputConverter::EscapeForCMake(
+                 unescapedDest, cmOutputConverter::WrapQuotes::NoWrap),
+               '/');
+    if (!cmSystemTools::FileIsFullPath(unescapedDest)) {
+      dest = cmStrCat("${_IMPORT_PREFIX}/", dest);
+    }
 
     bool const contextSensitive = destCge->GetHadContextSensitiveCondition() ||
       std::any_of(directoryEntries.begin(), directoryEntries.end(),
diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx
index f30c3c3..7e525d5 100644
--- a/Source/cmExportTryCompileFileGenerator.cxx
+++ b/Source/cmExportTryCompileFileGenerator.cxx
@@ -156,12 +156,12 @@
   cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/)
 {
   return cmOutputConverter::EscapeForCMake(
-    cmJoin(fileSet->GetDirectoryEntries(), ";"));
+    cmList::to_string(fileSet->GetDirectoryEntries()));
 }
 
 std::string cmExportTryCompileFileGenerator::GetFileSetFiles(
   cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/)
 {
   return cmOutputConverter::EscapeForCMake(
-    cmJoin(fileSet->GetFileEntries(), ";"));
+    cmList::to_string(fileSet->GetFileEntries()));
 }
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 45fba8b..def09fe 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -42,6 +42,7 @@
 #include "cmGeneratorExpression.h"
 #include "cmGlobalGenerator.h"
 #include "cmHexFileConverter.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -805,7 +806,7 @@
 
   std::sort(files.begin(), files.end());
   files.erase(std::unique(files.begin(), files.end()), files.end());
-  status.GetMakefile().AddDefinition(variable, cmJoin(files, ";"));
+  status.GetMakefile().AddDefinition(variable, cmList::to_string(files));
   return true;
 }
 
@@ -1556,7 +1557,7 @@
 #endif
   std::vector<std::string> path = cmSystemTools::SplitString(args[1], pathSep);
 
-  std::string value = cmJoin(cmMakeRange(path).transform(convert), ";");
+  std::string value = cmList::to_string(cmMakeRange(path).transform(convert));
   status.GetMakefile().AddDefinition(args[2], value);
   return true;
 }
@@ -3157,7 +3158,7 @@
       if (!parsedArgs.RPathPrefix.empty()) {
         status.GetMakefile().AddDefinition(
           parsedArgs.RPathPrefix + "_" + firstPath,
-          cmJoin(archive.GetRPaths().at(firstPath), ";"));
+          cmList::to_string(archive.GetRPaths().at(firstPath)));
       }
     } else if (!parsedArgs.ConflictingDependenciesPrefix.empty()) {
       conflictingDeps.push_back(val.first);
@@ -3165,7 +3166,7 @@
       paths.insert(paths.begin(), val.second.begin(), val.second.end());
       std::string varName =
         parsedArgs.ConflictingDependenciesPrefix + "_" + val.first;
-      std::string pathsStr = cmJoin(paths, ";");
+      std::string pathsStr = cmList::to_string(paths);
       status.GetMakefile().AddDefinition(varName, pathsStr);
     } else {
       std::ostringstream e;
@@ -3196,17 +3197,17 @@
   }
 
   if (!parsedArgs.ResolvedDependenciesVar.empty()) {
-    std::string val = cmJoin(deps, ";");
+    std::string val = cmList::to_string(deps);
     status.GetMakefile().AddDefinition(parsedArgs.ResolvedDependenciesVar,
                                        val);
   }
   if (!parsedArgs.UnresolvedDependenciesVar.empty()) {
-    std::string val = cmJoin(unresolvedDeps, ";");
+    std::string val = cmList::to_string(unresolvedDeps);
     status.GetMakefile().AddDefinition(parsedArgs.UnresolvedDependenciesVar,
                                        val);
   }
   if (!parsedArgs.ConflictingDependenciesPrefix.empty()) {
-    std::string val = cmJoin(conflictingDeps, ";");
+    std::string val = cmList::to_string(conflictingDeps);
     status.GetMakefile().AddDefinition(
       parsedArgs.ConflictingDependenciesPrefix + "_FILENAMES", val);
   }
diff --git a/Source/cmFileLock.cxx b/Source/cmFileLock.cxx
index 5d197d2..548e327 100644
--- a/Source/cmFileLock.cxx
+++ b/Source/cmFileLock.cxx
@@ -12,11 +12,7 @@
 cmFileLock::cmFileLock(cmFileLock&& other) noexcept
 {
   this->File = other.File;
-#if defined(_WIN32)
-  other.File = INVALID_HANDLE_VALUE;
-#else
-  other.File = -1;
-#endif
+  other.File = (decltype(other.File))-1;
   this->Filename = std::move(other.Filename);
 }
 
@@ -32,11 +28,7 @@
 cmFileLock& cmFileLock::operator=(cmFileLock&& other) noexcept
 {
   this->File = other.File;
-#if defined(_WIN32)
-  other.File = INVALID_HANDLE_VALUE;
-#else
-  other.File = -1;
-#endif
+  other.File = (decltype(other.File))-1;
   this->Filename = std::move(other.Filename);
 
   return *this;
diff --git a/Source/cmFileLock.h b/Source/cmFileLock.h
index 94baea1..0f2e7d9 100644
--- a/Source/cmFileLock.h
+++ b/Source/cmFileLock.h
@@ -7,7 +7,7 @@
 #include <string>
 
 #if defined(_WIN32)
-#  include <windows.h> // HANDLE
+using HANDLE = void*;
 #endif
 
 class cmFileLockResult;
@@ -53,8 +53,8 @@
   cmFileLockResult LockWithTimeout(unsigned long timeoutSec);
 
 #if defined(_WIN32)
-  HANDLE File = INVALID_HANDLE_VALUE;
-  BOOL LockFile(DWORD flags);
+  HANDLE File = (HANDLE)-1;
+  int LockFile(int flags);
 #else
   int File = -1;
   int LockFile(int cmd, int type) const;
diff --git a/Source/cmFileLockResult.cxx b/Source/cmFileLockResult.cxx
index b7f7f38..632c0e9 100644
--- a/Source/cmFileLockResult.cxx
+++ b/Source/cmFileLockResult.cxx
@@ -5,6 +5,10 @@
 #include <cerrno>
 #include <cstring>
 
+#ifdef _WIN32
+#  include <Windows.h>
+#endif
+
 cmFileLockResult cmFileLockResult::MakeOk()
 {
   return { OK, 0 };
diff --git a/Source/cmFileLockResult.h b/Source/cmFileLockResult.h
index 8a58d1f..e252de7 100644
--- a/Source/cmFileLockResult.h
+++ b/Source/cmFileLockResult.h
@@ -6,10 +6,6 @@
 
 #include <string>
 
-#if defined(_WIN32)
-#  include <windows.h> // DWORD
-#endif
-
 /**
  * @brief Result of the locking/unlocking file.
  * @note See @c cmFileLock
@@ -17,11 +13,7 @@
 class cmFileLockResult
 {
 public:
-#if defined(_WIN32)
-  using Error = DWORD;
-#else
   using Error = int;
-#endif
 
   /**
    * @brief Successful lock/unlock.
diff --git a/Source/cmFileLockWin32.cxx b/Source/cmFileLockWin32.cxx
index 7bee5f2..244ade2 100644
--- a/Source/cmFileLockWin32.cxx
+++ b/Source/cmFileLockWin32.cxx
@@ -78,7 +78,7 @@
   }
 }
 
-BOOL cmFileLock::LockFile(DWORD flags)
+int cmFileLock::LockFile(int flags)
 {
   const DWORD reserved = 0;
   const unsigned long len = static_cast<unsigned long>(-1);
diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx
index f4768b6..8d2d972 100644
--- a/Source/cmFunctionCommand.cxx
+++ b/Source/cmFunctionCommand.cxx
@@ -11,6 +11,7 @@
 
 #include "cmExecutionStatus.h"
 #include "cmFunctionBlocker.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmPolicies.h"
@@ -89,9 +90,9 @@
   }
 
   // define ARGV and ARGN
-  auto const argvDef = cmJoin(expandedArgs, ";");
+  auto const argvDef = cmList::to_string(expandedArgs);
   auto const eit = expandedArgs.begin() + (this->Args.size() - 1);
-  auto const argnDef = cmJoin(cmMakeRange(eit, expandedArgs.end()), ";");
+  auto const argnDef = cmList::to_string(cmMakeRange(eit, expandedArgs.end()));
   makefile.AddDefinition(ARGV, argvDef);
   makefile.MarkVariableAsUsed(ARGV);
   makefile.AddDefinition(ARGN, argnDef);
diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx
index 133bf5f..e669f68 100644
--- a/Source/cmGeneratedFileStream.cxx
+++ b/Source/cmGeneratedFileStream.cxx
@@ -16,7 +16,7 @@
 cmGeneratedFileStream::cmGeneratedFileStream(Encoding encoding)
 {
 #ifndef CMAKE_BOOTSTRAP
-  if (encoding != codecvt::None) {
+  if (encoding != codecvt_Encoding::None) {
     this->imbue(std::locale(this->getloc(), new codecvt(encoding)));
   }
 #else
@@ -35,13 +35,13 @@
     cmSystemTools::ReportLastSystemError("");
   }
 #ifndef CMAKE_BOOTSTRAP
-  if (encoding != codecvt::None) {
+  if (encoding != codecvt_Encoding::None) {
     this->imbue(std::locale(this->getloc(), new codecvt(encoding)));
   }
 #else
   static_cast<void>(encoding);
 #endif
-  if (encoding == codecvt::UTF8_WITH_BOM) {
+  if (encoding == codecvt_Encoding::UTF8_WITH_BOM) {
     // Write the BOM encoding header into the file
     char magic[] = { static_cast<char>(0xEF), static_cast<char>(0xBB),
                      static_cast<char>(0xBF) };
diff --git a/Source/cmGeneratedFileStream.h b/Source/cmGeneratedFileStream.h
index bfc121f..a26616d 100644
--- a/Source/cmGeneratedFileStream.h
+++ b/Source/cmGeneratedFileStream.h
@@ -8,7 +8,7 @@
 
 #include "cmsys/FStream.hxx"
 
-#include "cm_codecvt.hxx"
+#include "cm_codecvt_Encoding.hxx"
 
 // This is the first base class of cmGeneratedFileStream.  It will be
 // created before and destroyed after the ofstream portion and can
@@ -77,13 +77,13 @@
 {
 public:
   using Stream = cmsys::ofstream;
-  using Encoding = codecvt::Encoding;
+  using Encoding = codecvt_Encoding;
 
   /**
    * This constructor prepares a default stream.  The open method must
    * be used before writing to the stream.
    */
-  cmGeneratedFileStream(Encoding encoding = codecvt::None);
+  cmGeneratedFileStream(codecvt_Encoding encoding = codecvt_Encoding::None);
 
   /**
    * This constructor takes the name of the file to be generated.  It
@@ -92,7 +92,7 @@
    * second argument is set to true.
    */
   cmGeneratedFileStream(std::string const& name, bool quiet = false,
-                        Encoding encoding = codecvt::None);
+                        codecvt_Encoding encoding = codecvt_Encoding::None);
 
   /**
    * The destructor checks the stream status to be sure the temporary
@@ -151,5 +151,5 @@
    * Write a specific string using an alternate encoding.
    * Afterward, the original encoding is restored.
    */
-  void WriteAltEncoding(std::string const& data, Encoding encoding);
+  void WriteAltEncoding(std::string const& data, codecvt_Encoding encoding);
 };
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index bb4fc7e..647c62d 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -2538,7 +2538,7 @@
     list.front() = LL_BEGIN;
     list.push_back(LL_END);
 
-    return cmJoin(list, ";"_s);
+    return list.to_string();
   }
 } linkLibraryNode;
 
@@ -2607,7 +2607,7 @@
     list.front() = LG_BEGIN;
     list.push_back(LG_END);
 
-    return cmJoin(list, ";"_s);
+    return list.to_string();
   }
 } linkGroupNode;
 
@@ -2632,7 +2632,7 @@
     }
 
     return context->HeadTarget->IsDeviceLink() ? std::string()
-                                               : cmJoin(parameters, ";");
+                                               : cmList::to_string(parameters);
   }
 } hostLinkNode;
 
@@ -2667,7 +2667,7 @@
       list.insert(list.begin(), static_cast<std::string>(DL_BEGIN));
       list.push_back(static_cast<std::string>(DL_END));
 
-      return cmJoin(list, ";");
+      return list.to_string();
     }
 
     return std::string();
@@ -3104,7 +3104,7 @@
       mf->AddTargetObject(tgtName, o);
     }
 
-    return cmJoin(objects, ";");
+    return objects.to_string();
   }
 } targetObjectsNode;
 
@@ -3164,7 +3164,7 @@
     cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
   {
     std::vector<std::string> dlls = CollectDlls(parameters, context, content);
-    return cmJoin(dlls, ";");
+    return cmList::to_string(dlls);
   }
 } targetRuntimeDllsNode;
 
@@ -3187,7 +3187,7 @@
         dllDirs.push_back(directory);
       }
     }
-    return cmJoin(dllDirs, ";");
+    return cmList::to_string(dllDirs);
   }
 } targetRuntimeDllDirsNode;
 
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 357d0a6..50bbfb1 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -190,7 +190,7 @@
     }
 
     static std::string filesStr;
-    filesStr = cmJoin(files, ";");
+    filesStr = cmList::to_string(files);
     return filesStr;
   }
 
@@ -322,8 +322,7 @@
     values.push_back(se->GetInput());
   }
   static std::string value;
-  value.clear();
-  value = cmJoin(values, ";");
+  value = cmList::to_string(values);
   return cmValue(value);
 }
 
@@ -1493,9 +1492,9 @@
   }
 
   std::string directories;
-  if (const auto* interface = target->GetLinkInterfaceLibraries(
+  if (const auto* link_interface = target->GetLinkInterfaceLibraries(
         config, root, LinkInterfaceFor::Usage)) {
-    for (const cmLinkItem& library : interface->Libraries) {
+    for (const cmLinkItem& library : link_interface->Libraries) {
       if (const cmGeneratorTarget* dependency = library.Target) {
         if (cm::contains(dependency->GetAllConfigCompileLanguages(), lang)) {
           auto* lg = dependency->GetLocalGenerator();
diff --git a/Source/cmGetCMakePropertyCommand.cxx b/Source/cmGetCMakePropertyCommand.cxx
index 42bd206..d2c4fd6 100644
--- a/Source/cmGetCMakePropertyCommand.cxx
+++ b/Source/cmGetCMakePropertyCommand.cxx
@@ -6,9 +6,9 @@
 
 #include "cmExecutionStatus.h"
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmState.h"
-#include "cmStringAlgorithms.h"
 #include "cmValue.h"
 
 // cmGetCMakePropertyCommand
@@ -35,7 +35,7 @@
   } else if (args[1] == "COMPONENTS") {
     const std::set<std::string>* components =
       status.GetMakefile().GetGlobalGenerator()->GetInstallComponents();
-    output = cmJoin(*components, ";");
+    output = cmList::to_string(*components);
   } else {
     cmValue prop = nullptr;
     if (!args[1].empty()) {
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 5175aae..3d7d5a7 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -24,10 +24,6 @@
 #include "cmsys/FStream.hxx"
 #include "cmsys/RegularExpression.hxx"
 
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#  include <windows.h>
-#endif
-
 #include "cmAlgorithms.h"
 #include "cmCPackPropertiesGenerator.h"
 #include "cmComputeTargetDepends.h"
@@ -142,6 +138,10 @@
 {
   this->ClearGeneratorMembers();
 }
+codecvt_Encoding cmGlobalGenerator::GetMakefileEncoding() const
+{
+  return codecvt_Encoding::None;
+}
 
 #if !defined(CMAKE_BOOTSTRAP)
 Json::Value cmGlobalGenerator::GetJson() const
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 9aefaff..bc59514 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -19,7 +19,7 @@
 #include <cmext/algorithm>
 #include <cmext/string_view>
 
-#include "cm_codecvt.hxx"
+#include "cm_codecvt_Encoding.hxx"
 
 #include "cmBuildOptions.h"
 #include "cmCustomCommandLines.h"
@@ -120,10 +120,7 @@
   }
 
   /** Get encoding used by generator for makefile files */
-  virtual codecvt::Encoding GetMakefileEncoding() const
-  {
-    return codecvt::None;
-  }
+  virtual codecvt_Encoding GetMakefileEncoding() const;
 
 #if !defined(CMAKE_BOOTSTRAP)
   /** Get a JSON object describing the generator.  */
diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h
index 436ebca..bc8fc34 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.h
+++ b/Source/cmGlobalNMakeMakefileGenerator.h
@@ -7,7 +7,7 @@
 #include <string>
 #include <vector>
 
-#include "cm_codecvt.hxx"
+#include "cm_codecvt_Encoding.hxx"
 
 #include "cmGlobalGeneratorFactory.h"
 #include "cmGlobalUnixMakefileGenerator3.h"
@@ -38,9 +38,10 @@
   static std::string GetActualName() { return "NMake Makefiles"; }
 
   /** Get encoding used by generator for makefile files */
-  codecvt::Encoding GetMakefileEncoding() const override
+  codecvt_Encoding GetMakefileEncoding() const override
   {
-    return this->NMakeSupportsUTF8 ? codecvt::UTF8_WITH_BOM : codecvt::ANSI;
+    return this->NMakeSupportsUTF8 ? codecvt_Encoding::UTF8_WITH_BOM
+                                   : codecvt_Encoding::ANSI;
   }
 
   /** Get the documentation entry for this generator.  */
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index e20f157..65851f3 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -566,7 +566,7 @@
     cm::make_unique<cmLocalNinjaGenerator>(this, mf));
 }
 
-codecvt::Encoding cmGlobalNinjaGenerator::GetMakefileEncoding() const
+codecvt_Encoding cmGlobalNinjaGenerator::GetMakefileEncoding() const
 {
   return this->NinjaExpectedEncoding;
 }
@@ -799,7 +799,7 @@
   if (this->NinjaSupportsCodePage) {
     this->CheckNinjaCodePage();
   } else {
-    this->NinjaExpectedEncoding = codecvt::ANSI;
+    this->NinjaExpectedEncoding = codecvt_Encoding::ANSI;
   }
 #endif
 }
@@ -830,9 +830,9 @@
           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;
+          this->NinjaExpectedEncoding = codecvt_Encoding::None;
         } else {
-          this->NinjaExpectedEncoding = codecvt::ANSI;
+          this->NinjaExpectedEncoding = codecvt_Encoding::ANSI;
         }
         found = true;
         break;
@@ -842,10 +842,10 @@
       this->GetCMakeInstance()->IssueMessage(
         MessageType::WARNING,
         "Could not determine Ninja's code page, defaulting to UTF-8");
-      this->NinjaExpectedEncoding = codecvt::None;
+      this->NinjaExpectedEncoding = codecvt_Encoding::None;
     }
   } else {
-    this->NinjaExpectedEncoding = codecvt::ANSI;
+    this->NinjaExpectedEncoding = codecvt_Encoding::ANSI;
   }
 }
 
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index bfbe57f..95d64e3 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -16,7 +16,7 @@
 
 #include <cm/optional>
 
-#include "cm_codecvt.hxx"
+#include "cm_codecvt_Encoding.hxx"
 
 #include "cmBuildOptions.h"
 #include "cmGeneratedFileStream.h"
@@ -192,7 +192,7 @@
   bool IsNinja() const override { return true; }
 
   /** Get encoding used by generator for ninja files */
-  codecvt::Encoding GetMakefileEncoding() const override;
+  codecvt_Encoding GetMakefileEncoding() const override;
 
   static cmDocumentationEntry GetDocumentation();
 
@@ -590,7 +590,7 @@
   bool NinjaSupportsMetadataOnRegeneration = false;
   bool NinjaSupportsCodePage = false;
 
-  codecvt::Encoding NinjaExpectedEncoding = codecvt::None;
+  codecvt_Encoding NinjaExpectedEncoding = codecvt_Encoding::None;
 
   bool DiagnosedCxxModuleNinjaSupport = false;
 
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index 321f377..f1d04e5 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -1230,7 +1230,6 @@
 {
   switch (this->Version) {
     case cmGlobalVisualStudioGenerator::VSVersion::VS9:
-    case cmGlobalVisualStudioGenerator::VSVersion::VS11:
       return "4.0";
 
       // in Visual Studio 2013 they detached the MSBuild tools version
diff --git a/Source/cmGlobalVisualStudio11Generator.cxx b/Source/cmGlobalVisualStudio11Generator.cxx
index 3ad10eb..c4e1e11 100644
--- a/Source/cmGlobalVisualStudio11Generator.cxx
+++ b/Source/cmGlobalVisualStudio11Generator.cxx
@@ -8,156 +8,17 @@
 #include <vector>
 
 #include "cmGlobalGenerator.h"
-#include "cmGlobalGeneratorFactory.h"
 #include "cmGlobalVisualStudioGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
-static const char vs11generatorName[] = "Visual Studio 11 2012";
-
-// Map generator name without year to name with year.
-static const char* cmVS11GenName(const std::string& name, std::string& genName)
-{
-  if (strncmp(name.c_str(), vs11generatorName,
-              sizeof(vs11generatorName) - 6) != 0) {
-    return nullptr;
-  }
-  const char* p = name.c_str() + sizeof(vs11generatorName) - 6;
-  if (cmHasLiteralPrefix(p, " 2012")) {
-    p += 5;
-  }
-  genName = std::string(vs11generatorName) + p;
-  return p;
-}
-
-class cmGlobalVisualStudio11Generator::Factory
-  : public cmGlobalGeneratorFactory
-{
-public:
-  std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator(
-    const std::string& name, bool allowArch, cmake* cm) const override
-  {
-    std::string genName;
-    const char* p = cmVS11GenName(name, genName);
-    if (!p) {
-      return std::unique_ptr<cmGlobalGenerator>();
-    }
-    if (!*p) {
-      return std::unique_ptr<cmGlobalGenerator>(
-        new cmGlobalVisualStudio11Generator(cm, genName, ""));
-    }
-    if (!allowArch || *p++ != ' ') {
-      return std::unique_ptr<cmGlobalGenerator>();
-    }
-    if (strcmp(p, "Win64") == 0) {
-      return std::unique_ptr<cmGlobalGenerator>(
-        new cmGlobalVisualStudio11Generator(cm, genName, "x64"));
-    }
-    if (strcmp(p, "ARM") == 0) {
-      return std::unique_ptr<cmGlobalGenerator>(
-        new cmGlobalVisualStudio11Generator(cm, genName, "ARM"));
-    }
-
-    std::set<std::string> installedSDKs =
-      cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs();
-
-    if (installedSDKs.find(p) == installedSDKs.end()) {
-      return std::unique_ptr<cmGlobalGenerator>();
-    }
-
-    auto ret = std::unique_ptr<cmGlobalVisualStudio11Generator>(
-      new cmGlobalVisualStudio11Generator(cm, name, p));
-    ret->WindowsCEVersion = "8.00";
-    return std::unique_ptr<cmGlobalGenerator>(std::move(ret));
-  }
-
-  cmDocumentationEntry GetDocumentation() const override
-  {
-    return { std::string(vs11generatorName) + " [arch]",
-             "Deprecated.  Generates Visual Studio 2012 project files.  "
-             "Optional [arch] can be \"Win64\" or \"ARM\"." };
-  }
-
-  std::vector<std::string> GetGeneratorNames() const override
-  {
-    std::vector<std::string> names;
-    names.push_back(vs11generatorName);
-    return names;
-  }
-
-  std::vector<std::string> GetGeneratorNamesWithPlatform() const override
-  {
-    std::vector<std::string> names;
-    names.push_back(vs11generatorName + std::string(" ARM"));
-    names.push_back(vs11generatorName + std::string(" Win64"));
-
-    std::set<std::string> installedSDKs =
-      cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs();
-    for (std::string const& i : installedSDKs) {
-      names.push_back(std::string(vs11generatorName) + " " + i);
-    }
-
-    return names;
-  }
-
-  bool SupportsToolset() const override { return true; }
-  bool SupportsPlatform() const override { return true; }
-
-  std::vector<std::string> GetKnownPlatforms() const override
-  {
-    std::vector<std::string> platforms;
-    platforms.emplace_back("x64");
-    platforms.emplace_back("Win32");
-    platforms.emplace_back("ARM");
-
-    std::set<std::string> installedSDKs =
-      cmGlobalVisualStudio11Generator::GetInstalledWindowsCESDKs();
-    for (std::string const& i : installedSDKs) {
-      platforms.emplace_back(i);
-    }
-
-    return platforms;
-  }
-
-  std::string GetDefaultPlatformName() const override { return "Win32"; }
-};
-
-std::unique_ptr<cmGlobalGeneratorFactory>
-cmGlobalVisualStudio11Generator::NewFactory()
-{
-  return std::unique_ptr<cmGlobalGeneratorFactory>(new Factory);
-}
-
 cmGlobalVisualStudio11Generator::cmGlobalVisualStudio11Generator(
   cmake* cm, const std::string& name,
   std::string const& platformInGeneratorName)
   : cmGlobalVisualStudio10Generator(cm, name, platformInGeneratorName)
 {
-  std::string vc11Express;
-  this->ExpressEdition = cmSystemTools::ReadRegistryValue(
-    "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\11.0\\Setup\\VC;"
-    "ProductDir",
-    vc11Express, cmSystemTools::KeyWOW64_32);
-  this->DefaultPlatformToolset = "v110";
-  this->DefaultCLFlagTableName = "v11";
-  this->DefaultCSharpFlagTableName = "v11";
-  this->DefaultLibFlagTableName = "v11";
-  this->DefaultLinkFlagTableName = "v11";
-  this->DefaultMasmFlagTableName = "v11";
-  this->DefaultRCFlagTableName = "v11";
-  this->Version = VSVersion::VS11;
-}
-
-bool cmGlobalVisualStudio11Generator::MatchesGeneratorName(
-  const std::string& name) const
-{
-  std::string genName;
-  if (cmVS11GenName(name, genName)) {
-    return genName == this->GetName();
-  }
-  return false;
 }
 
 void cmGlobalVisualStudio11Generator::EnableLanguage(
diff --git a/Source/cmGlobalVisualStudio11Generator.h b/Source/cmGlobalVisualStudio11Generator.h
index fd25984..ad12c1f 100644
--- a/Source/cmGlobalVisualStudio11Generator.h
+++ b/Source/cmGlobalVisualStudio11Generator.h
@@ -13,7 +13,6 @@
 #include "cmGlobalVisualStudio10Generator.h"
 #include "cmTransformDepfile.h"
 
-class cmGlobalGeneratorFactory;
 class cmMakefile;
 class cmake;
 
@@ -21,10 +20,6 @@
 class cmGlobalVisualStudio11Generator : public cmGlobalVisualStudio10Generator
 {
 public:
-  static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory();
-
-  bool MatchesGeneratorName(const std::string& name) const override;
-
   void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
                       bool optional) override;
 
@@ -58,8 +53,4 @@
 
   /** Return true if target system supports debugging deployment. */
   bool TargetSystemSupportsDeployment() const override;
-
-private:
-  class Factory;
-  friend class Factory;
 };
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index b254777..62c0b5b 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -329,26 +329,6 @@
         "Add CMAKE_WARN_VS9=OFF to the cache to disable this warning.");
     }
   }
-
-  if (this->Version == VSVersion::VS11 &&
-      !this->CMakeInstance->GetIsInTryCompile()) {
-    std::string cmakeWarnVS11;
-    if (cmValue cached = this->CMakeInstance->GetState()->GetCacheEntryValue(
-          "CMAKE_WARN_VS11")) {
-      this->CMakeInstance->MarkCliAsUsed("CMAKE_WARN_VS11");
-      cmakeWarnVS11 = *cached;
-    } else {
-      cmSystemTools::GetEnv("CMAKE_WARN_VS11", cmakeWarnVS11);
-    }
-    if (cmakeWarnVS11.empty() || !cmIsOff(cmakeWarnVS11)) {
-      this->CMakeInstance->IssueMessage(
-        MessageType::WARNING,
-        "The \"Visual Studio 11 2012\" generator is deprecated "
-        "and will be removed in a future version of CMake."
-        "\n"
-        "Add CMAKE_WARN_VS11=OFF to the cache to disable this warning.");
-    }
-  }
 }
 
 void cmGlobalVisualStudio7Generator::OutputSLNFile(
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index 6b024db..4d7571a 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -105,8 +105,6 @@
   switch (this->Version) {
     case cmGlobalVisualStudioGenerator::VSVersion::VS9:
       return "9.0";
-    case cmGlobalVisualStudioGenerator::VSVersion::VS11:
-      return "11.0";
     case cmGlobalVisualStudioGenerator::VSVersion::VS12:
       return "12.0";
     case cmGlobalVisualStudioGenerator::VSVersion::VS14:
@@ -132,14 +130,6 @@
       fout << "Microsoft Visual Studio Solution File, Format Version 10.00\n";
       fout << "# Visual Studio 2008\n";
       break;
-    case cmGlobalVisualStudioGenerator::VSVersion::VS11:
-      fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
-      if (this->ExpressEdition) {
-        fout << "# Visual Studio Express 2012 for Windows Desktop\n";
-      } else {
-        fout << "# Visual Studio 2012\n";
-      }
-      break;
     case cmGlobalVisualStudioGenerator::VSVersion::VS12:
       fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n";
       if (this->ExpressEdition) {
diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h
index 52db98d..76713fa 100644
--- a/Source/cmGlobalVisualStudioGenerator.h
+++ b/Source/cmGlobalVisualStudioGenerator.h
@@ -10,7 +10,7 @@
 #include <string>
 #include <vector>
 
-#include "cm_codecvt.hxx"
+#include "cm_codecvt_Encoding.hxx"
 
 #include "cmGlobalGenerator.h"
 #include "cmTargetDepend.h"
@@ -35,7 +35,6 @@
   enum class VSVersion : uint16_t
   {
     VS9 = 90,
-    VS11 = 110,
     VS12 = 120,
     /* VS13 = 130 was skipped */
     VS14 = 140,
@@ -120,9 +119,9 @@
 
   /** Get encoding used by generator for generated source files
    */
-  codecvt::Encoding GetMakefileEncoding() const override
+  codecvt_Encoding GetMakefileEncoding() const override
   {
-    return codecvt::ANSI;
+    return codecvt_Encoding::ANSI;
   }
 
   class TargetSet : public std::set<cmGeneratorTarget const*>
diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
index 602b42f..9fe66d3 100644
--- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx
+++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx
@@ -127,8 +127,6 @@
   switch (v) {
     case cmGlobalVisualStudioGenerator::VSVersion::VS9:
       return 9;
-    case cmGlobalVisualStudioGenerator::VSVersion::VS11:
-      return 11;
     case cmGlobalVisualStudioGenerator::VSVersion::VS12:
       return 12;
     case cmGlobalVisualStudioGenerator::VSVersion::VS14:
@@ -149,8 +147,6 @@
   switch (v) {
     case cmGlobalVisualStudioGenerator::VSVersion::VS9:
       return "v90";
-    case cmGlobalVisualStudioGenerator::VSVersion::VS11:
-      return "v110";
     case cmGlobalVisualStudioGenerator::VSVersion::VS12:
       return "v120";
     case cmGlobalVisualStudioGenerator::VSVersion::VS14:
@@ -171,8 +167,6 @@
   switch (v) {
     case cmGlobalVisualStudioGenerator::VSVersion::VS9:
       return "9";
-    case cmGlobalVisualStudioGenerator::VSVersion::VS11:
-      return "11";
     case cmGlobalVisualStudioGenerator::VSVersion::VS12:
       return "12";
     case cmGlobalVisualStudioGenerator::VSVersion::VS14:
@@ -192,7 +186,6 @@
 {
   switch (v) {
     case cmGlobalVisualStudioGenerator::VSVersion::VS9:
-    case cmGlobalVisualStudioGenerator::VSVersion::VS11:
     case cmGlobalVisualStudioGenerator::VSVersion::VS12:
       return "";
     case cmGlobalVisualStudioGenerator::VSVersion::VS14:
@@ -493,7 +486,6 @@
   std::string genName;
   switch (this->Version) {
     case cmGlobalVisualStudioGenerator::VSVersion::VS9:
-    case cmGlobalVisualStudioGenerator::VSVersion::VS11:
     case cmGlobalVisualStudioGenerator::VSVersion::VS12:
     case cmGlobalVisualStudioGenerator::VSVersion::VS14:
       break;
@@ -761,7 +753,6 @@
 {
   switch (this->Version) {
     case cmGlobalVisualStudioGenerator::VSVersion::VS9:
-    case cmGlobalVisualStudioGenerator::VSVersion::VS11:
     case cmGlobalVisualStudioGenerator::VSVersion::VS12:
       return "";
     case cmGlobalVisualStudioGenerator::VSVersion::VS14:
diff --git a/Source/cmLDConfigLDConfigTool.cxx b/Source/cmLDConfigLDConfigTool.cxx
index 0752b33..154aa27 100644
--- a/Source/cmLDConfigLDConfigTool.cxx
+++ b/Source/cmLDConfigLDConfigTool.cxx
@@ -14,6 +14,7 @@
 #include "cmRuntimeDependencyArchive.h"
 #include "cmSystemTools.h"
 #include "cmUVProcessChain.h"
+#include "cmUVStream.h"
 
 cmLDConfigLDConfigTool::cmLDConfigLDConfigTool(
   cmRuntimeDependencyArchive* archive)
@@ -43,14 +44,15 @@
   builder.SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
     .AddCommand(ldConfigCommand);
   auto process = builder.Start();
-  if (!process.Valid()) {
+  if (!process.Valid() || process.GetStatus(0).SpawnResult != 0) {
     this->Archive->SetError("Failed to start ldconfig process");
     return false;
   }
 
   std::string line;
   static const cmsys::RegularExpression regex("^([^\t:]*):");
-  while (std::getline(*process.OutputStream(), line)) {
+  cmUVPipeIStream output(process.GetLoop(), process.OutputStream());
+  while (std::getline(output, line)) {
     cmsys::RegularExpressionMatch match;
     if (regex.find(line.c_str(), match)) {
       paths.push_back(match.match(1));
@@ -61,8 +63,7 @@
     this->Archive->SetError("Failed to wait on ldconfig process");
     return false;
   }
-  auto status = process.GetStatus();
-  if (!status[0] || status[0]->ExitStatus != 0) {
+  if (process.GetStatus(0).ExitStatus != 0) {
     this->Archive->SetError("Failed to run ldconfig");
     return false;
   }
diff --git a/Source/cmLinkDirectoriesCommand.cxx b/Source/cmLinkDirectoriesCommand.cxx
index 1ec071b..6775a60 100644
--- a/Source/cmLinkDirectoriesCommand.cxx
+++ b/Source/cmLinkDirectoriesCommand.cxx
@@ -6,6 +6,7 @@
 
 #include "cmExecutionStatus.h"
 #include "cmGeneratorExpression.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
@@ -39,7 +40,7 @@
     AddLinkDir(mf, *i, directories);
   }
 
-  mf.AddLinkDirectory(cmJoin(directories, ";"), before);
+  mf.AddLinkDirectory(cmList::to_string(directories), before);
 
   return true;
 }
diff --git a/Source/cmList.cxx b/Source/cmList.cxx
index 022fcd2..3835e59 100644
--- a/Source/cmList.cxx
+++ b/Source/cmList.cxx
@@ -19,6 +19,7 @@
 
 #include "cmAlgorithms.h"
 #include "cmGeneratorExpression.h"
+#include "cmListFileCache.h"
 #include "cmRange.h"
 #include "cmStringAlgorithms.h"
 #include "cmStringReplaceHelper.h"
@@ -802,11 +803,6 @@
   return *this;
 }
 
-std::string cmList::join(cm::string_view glue) const
-{
-  return cmJoin(this->Values, glue);
-}
-
 std::string& cmList::append(std::string& list, cm::string_view value)
 {
   if (list.empty()) {
@@ -1001,3 +997,8 @@
   }
   return container.begin() + delta;
 }
+
+std::string const& cmList::ToString(BT<std::string> const& s)
+{
+  return s.Value;
+}
diff --git a/Source/cmList.h b/Source/cmList.h
index eba0400..9ee4a46 100644
--- a/Source/cmList.h
+++ b/Source/cmList.h
@@ -22,6 +22,9 @@
 
 #include "cmValue.h"
 
+template <typename T>
+class BT;
+
 /**
  * CMake lists management
  * A CMake list is a string where list elements are separated by the ';'
@@ -936,7 +939,10 @@
                     std::vector<std::string> const& args,
                     std::unique_ptr<TransformSelector> = {});
 
-  std::string join(cm::string_view glue) const;
+  std::string join(cm::string_view glue) const
+  {
+    return cmList::Join(this->Values, glue);
+  }
 
   void swap(cmList& other) noexcept { this->Values.swap(other.Values); }
 
@@ -1092,8 +1098,8 @@
     return cmList::append(list,
                           cm::string_view{ std::accumulate(
                             std::next(first), last, *first,
-                            [](std::string a, const std::string& b) {
-                              return std::move(a) +
+                            [](const std::string& a, const std::string& b) {
+                              return a +
                                 std::string(cmList::element_separator) + b;
                             }) });
   }
@@ -1116,6 +1122,13 @@
                              }) });
   }
 
+  template <typename Range,
+            cm::enable_if_t<cm::is_range<Range>::value, int> = 0>
+  static std::string to_string(Range const& r)
+  {
+    return cmList::Join(r, cmList::element_separator);
+  }
+
   // Non-members
   // ===========
   friend inline bool operator==(const cmList& lhs, const cmList& rhs) noexcept
@@ -1185,6 +1198,28 @@
     return container.begin() + delta;
   }
 
+  static std::string const& ToString(std::string const& s) { return s; }
+  static std::string ToString(cm::string_view s) { return std::string{ s }; }
+  static std::string const& ToString(BT<std::string> const&);
+
+  template <typename Range>
+  static std::string Join(Range const& r, cm::string_view glue)
+  {
+    if (cm::size(r) == 0) {
+      return std::string{};
+    }
+
+    const auto sep = std::string{ glue };
+
+    return std::accumulate(
+      std::next(std::begin(r)), std::end(r), cmList::ToString(*std::begin(r)),
+      [&sep](std::string const& a,
+             typename std::iterator_traits<decltype(std::begin(
+               r))>::value_type const& b) -> std::string {
+        return a + sep + cmList::ToString(b);
+      });
+  }
+
   container_type Values;
 };
 
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index af0e118..24ef5c2 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -198,7 +198,7 @@
   // Intel Fortran always uses VS9 format ".vfproj" files.
   cmGlobalVisualStudioGenerator::VSVersion realVersion = gg->GetVersion();
   if (this->FortranProject &&
-      gg->GetVersion() >= cmGlobalVisualStudioGenerator::VSVersion::VS11) {
+      gg->GetVersion() >= cmGlobalVisualStudioGenerator::VSVersion::VS12) {
     gg->SetVersion(cmGlobalVisualStudioGenerator::VSVersion::VS9);
   }
 
diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx
index 47ad749..3d7cd8b 100644
--- a/Source/cmMacroCommand.cxx
+++ b/Source/cmMacroCommand.cxx
@@ -12,6 +12,7 @@
 
 #include "cmExecutionStatus.h"
 #include "cmFunctionBlocker.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmPolicies.h"
@@ -66,8 +67,9 @@
   std::string argcDef = std::to_string(expandedArgs.size());
 
   auto eit = expandedArgs.begin() + (this->Args.size() - 1);
-  std::string expandedArgn = cmJoin(cmMakeRange(eit, expandedArgs.end()), ";");
-  std::string expandedArgv = cmJoin(expandedArgs, ";");
+  std::string expandedArgn =
+    cmList::to_string(cmMakeRange(eit, expandedArgs.end()));
+  std::string expandedArgv = cmList::to_string(expandedArgs);
   std::vector<std::string> variables;
   variables.reserve(this->Args.size() - 1);
   for (unsigned int j = 1; j < this->Args.size(); ++j) {
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 0af0ed0..5890819 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -1980,7 +1980,7 @@
     return;
   }
 
-  std::string entryString = cmJoin(incs, ";");
+  std::string entryString = cmList::to_string(incs);
   if (before) {
     this->StateSnapshot.GetDirectory().PrependIncludeDirectoriesEntry(
       BT<std::string>(entryString, this->Backtrace));
@@ -3004,12 +3004,11 @@
 {
   cm::optional<std::string> ids;
   if (this->Defer) {
-    ids = cmJoin(
+    ids = cmList::to_string(
       cmMakeRange(this->Defer->Commands)
         .filter([](DeferCommand const& dc) -> bool { return !dc.Id.empty(); })
         .transform(
-          [](DeferCommand const& dc) -> std::string const& { return dc.Id; }),
-      ";");
+          [](DeferCommand const& dc) -> std::string const& { return dc.Id; }));
   }
   return ids;
 }
@@ -4160,7 +4159,7 @@
     std::transform(
       t->Tests.begin(), t->Tests.end(), std::back_inserter(keys),
       [](decltype(t->Tests)::value_type const& pair) { return pair.first; });
-    output = cmJoin(keys, ";");
+    output = cmList::to_string(keys);
     return cmValue(output);
   }
 
@@ -4613,7 +4612,7 @@
   }
 
   // Deprecate old policies.
-  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0114 &&
+  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0120 &&
       !(this->GetCMakeInstance()->GetIsInTryCompile() &&
         (
           // Policies set by cmCoreTryCompile::TryCompileCode.
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 5f27856..1dd48b3 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -17,7 +17,7 @@
 #include <cmext/algorithm>
 #include <cmext/string_view>
 
-#include "cm_codecvt.hxx"
+#include "cm_codecvt_Encoding.hxx"
 
 #include "cmComputeLinkInformation.h"
 #include "cmCustomCommand.h"
@@ -2129,12 +2129,12 @@
   // FIXME: Find a better way to determine the response file encoding,
   // perhaps using tool-specific platform information variables.
   // For now, use the makefile encoding as a heuristic.
-  codecvt::Encoding responseEncoding =
+  codecvt_Encoding responseEncoding =
     this->GlobalGenerator->GetMakefileEncoding();
   // Non-MSVC tooling doesn't understand BOM encoded files.
-  if (responseEncoding == codecvt::UTF8_WITH_BOM &&
+  if (responseEncoding == codecvt_Encoding::UTF8_WITH_BOM &&
       (language == "CUDA" || !this->Makefile->IsOn("MSVC"))) {
-    responseEncoding = codecvt::UTF8;
+    responseEncoding = codecvt_Encoding::UTF8;
   }
 
   // Create the response file.
diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx
index b0462f0..f193ed9 100644
--- a/Source/cmParseArgumentsCommand.cxx
+++ b/Source/cmParseArgumentsCommand.cxx
@@ -20,7 +20,9 @@
 #include "cmSystemTools.h"
 #include "cmValue.h"
 
-static std::string EscapeArg(const std::string& arg)
+namespace {
+
+std::string EscapeArg(const std::string& arg)
 {
   // replace ";" with "\;" so output argument lists will split correctly
   std::string escapedArg;
@@ -33,14 +35,12 @@
   return escapedArg;
 }
 
-static std::string JoinList(std::vector<std::string> const& arg, bool escape)
+std::string JoinList(std::vector<std::string> const& arg, bool escape)
 {
-  return escape ? cmJoin(cmMakeRange(arg).transform(EscapeArg), ";")
-                : cmJoin(cmMakeRange(arg), ";");
+  return escape ? cmList::to_string(cmMakeRange(arg).transform(EscapeArg))
+                : cmList::to_string(cmMakeRange(arg));
 }
 
-namespace {
-
 using options_map = std::map<std::string, bool>;
 using single_map = std::map<std::string, std::string>;
 using multi_map =
@@ -108,8 +108,9 @@
   }
 
   if (!keywordsMissingValues.empty()) {
-    makefile.AddDefinition(prefix + "KEYWORDS_MISSING_VALUES",
-                           cmJoin(cmMakeRange(keywordsMissingValues), ";"));
+    makefile.AddDefinition(
+      prefix + "KEYWORDS_MISSING_VALUES",
+      cmList::to_string(cmMakeRange(keywordsMissingValues)));
   } else {
     makefile.RemoveDefinition(prefix + "KEYWORDS_MISSING_VALUES");
   }
diff --git a/Source/cmSeparateArgumentsCommand.cxx b/Source/cmSeparateArgumentsCommand.cxx
index 17285e7..3576e4f 100644
--- a/Source/cmSeparateArgumentsCommand.cxx
+++ b/Source/cmSeparateArgumentsCommand.cxx
@@ -9,6 +9,7 @@
 
 #include "cmArgumentParser.h"
 #include "cmExecutionStatus.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmRange.h"
 #include "cmStringAlgorithms.h"
@@ -159,7 +160,7 @@
       pos += 2;
     }
   });
-  auto value = cmJoin(values, ";");
+  auto value = cmList::to_string(values);
   status.GetMakefile().AddDefinition(var, value);
 
   return true;
diff --git a/Source/cmSetCommand.cxx b/Source/cmSetCommand.cxx
index 040eb08..c4bb949 100644
--- a/Source/cmSetCommand.cxx
+++ b/Source/cmSetCommand.cxx
@@ -3,6 +3,7 @@
 #include "cmSetCommand.h"
 
 #include "cmExecutionStatus.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmRange.h"
@@ -103,7 +104,8 @@
   }
 
   // collect any values into a single semi-colon separated value list
-  value = cmJoin(cmMakeRange(args).advance(1).retreat(ignoreLastArgs), ";");
+  value =
+    cmList::to_string(cmMakeRange(args).advance(1).retreat(ignoreLastArgs));
 
   if (parentScope) {
     status.GetMakefile().RaiseScope(variable, value.c_str());
diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx
index 3403745..1be680a 100644
--- a/Source/cmSourceFile.cxx
+++ b/Source/cmSourceFile.cxx
@@ -8,6 +8,7 @@
 #include <cmext/string_view>
 
 #include "cmGlobalGenerator.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -390,7 +391,7 @@
     }
 
     static std::string output;
-    output = cmJoin(this->IncludeDirectories, ";");
+    output = cmList::to_string(this->IncludeDirectories);
     return cmValue(output);
   }
 
@@ -400,7 +401,7 @@
     }
 
     static std::string output;
-    output = cmJoin(this->CompileOptions, ";");
+    output = cmList::to_string(this->CompileOptions);
     return cmValue(output);
   }
 
@@ -410,7 +411,7 @@
     }
 
     static std::string output;
-    output = cmJoin(this->CompileDefinitions, ";");
+    output = cmList::to_string(this->CompileDefinitions);
     return cmValue(output);
   }
 
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index 2596d8c..d41e8e5 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -17,6 +17,7 @@
 #include "cmDefinitions.h"
 #include "cmExecutionStatus.h"
 #include "cmGlobVerificationManager.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -584,10 +585,10 @@
 {
   if (prop == "CACHE_VARIABLES") {
     std::vector<std::string> cacheKeys = this->GetCacheEntryKeys();
-    this->SetGlobalProperty("CACHE_VARIABLES", cmJoin(cacheKeys, ";"));
+    this->SetGlobalProperty("CACHE_VARIABLES", cmList::to_string(cacheKeys));
   } else if (prop == "COMMANDS") {
     std::vector<std::string> commands = this->GetCommandNames();
-    this->SetGlobalProperty("COMMANDS", cmJoin(commands, ";"));
+    this->SetGlobalProperty("COMMANDS", cmList::to_string(commands));
   } else if (prop == "IN_TRY_COMPILE") {
     this->SetGlobalProperty(
       "IN_TRY_COMPILE",
@@ -596,8 +597,7 @@
     this->SetGlobalProperty("GENERATOR_IS_MULTI_CONFIG",
                             this->IsGeneratorMultiConfig ? "1" : "0");
   } else if (prop == "ENABLED_LANGUAGES") {
-    std::string langs;
-    langs = cmJoin(this->EnabledLanguages, ";");
+    auto langs = cmList::to_string(this->EnabledLanguages);
     this->SetGlobalProperty("ENABLED_LANGUAGES", langs);
   } else if (prop == "CMAKE_ROLE") {
     std::string mode = this->GetModeString();
diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx
index 6e6fcbd..39353f3 100644
--- a/Source/cmStateDirectory.cxx
+++ b/Source/cmStateDirectory.cxx
@@ -13,6 +13,7 @@
 #include <cmext/string_view>
 
 #include "cmAlgorithms.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmProperty.h"
 #include "cmPropertyMap.h"
@@ -20,7 +21,6 @@
 #include "cmState.h"
 #include "cmStatePrivate.h"
 #include "cmStateTypes.h"
-#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmValue.h"
 
@@ -381,15 +381,15 @@
     for (cmStateSnapshot const& ci : children) {
       child_dirs.push_back(ci.GetDirectory().GetCurrentSource());
     }
-    output = cmJoin(child_dirs, ";");
+    output = cmList::to_string(child_dirs);
     return cmValue(output);
   }
   if (prop == kBUILDSYSTEM_TARGETS) {
-    output = cmJoin(this->DirectoryState->NormalTargetNames, ";");
+    output = cmList::to_string(this->DirectoryState->NormalTargetNames);
     return cmValue(output);
   }
   if (prop == "IMPORTED_TARGETS"_s) {
-    output = cmJoin(this->DirectoryState->ImportedTargetNames, ";");
+    output = cmList::to_string(this->DirectoryState->ImportedTargetNames);
     return cmValue(output);
   }
 
@@ -401,38 +401,38 @@
       snp = snp.GetCallStackParent();
     }
     std::reverse(listFiles.begin(), listFiles.end());
-    output = cmJoin(listFiles, ";");
+    output = cmList::to_string(listFiles);
     return cmValue(output);
   }
   if (prop == "CACHE_VARIABLES") {
-    output = cmJoin(this->Snapshot_.State->GetCacheEntryKeys(), ";");
+    output = cmList::to_string(this->Snapshot_.State->GetCacheEntryKeys());
     return cmValue(output);
   }
   if (prop == "VARIABLES") {
     std::vector<std::string> res = this->Snapshot_.ClosureKeys();
     cm::append(res, this->Snapshot_.State->GetCacheEntryKeys());
     std::sort(res.begin(), res.end());
-    output = cmJoin(res, ";");
+    output = cmList::to_string(res);
     return cmValue(output);
   }
   if (prop == "INCLUDE_DIRECTORIES") {
-    output = cmJoin(this->GetIncludeDirectoriesEntries(), ";");
+    output = cmList::to_string(this->GetIncludeDirectoriesEntries());
     return cmValue(output);
   }
   if (prop == "COMPILE_OPTIONS") {
-    output = cmJoin(this->GetCompileOptionsEntries(), ";");
+    output = cmList::to_string(this->GetCompileOptionsEntries());
     return cmValue(output);
   }
   if (prop == "COMPILE_DEFINITIONS") {
-    output = cmJoin(this->GetCompileDefinitionsEntries(), ";");
+    output = cmList::to_string(this->GetCompileDefinitionsEntries());
     return cmValue(output);
   }
   if (prop == "LINK_OPTIONS") {
-    output = cmJoin(this->GetLinkOptionsEntries(), ";");
+    output = cmList::to_string(this->GetLinkOptionsEntries());
     return cmValue(output);
   }
   if (prop == "LINK_DIRECTORIES") {
-    output = cmJoin(this->GetLinkDirectoriesEntries(), ";");
+    output = cmList::to_string(this->GetLinkDirectoriesEntries());
     return cmValue(output);
   }
 
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 81497f5..15f45f5 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -811,12 +811,12 @@
     did_read = true;
   } else if (prop == this->SelfEntries.PropertyName) {
     static std::string output;
-    output = cmJoin(this->SelfEntries.Entries, ";"_s);
+    output = cmList::to_string(this->SelfEntries.Entries);
     value = cmValue(output);
     did_read = true;
   } else if (prop == this->InterfaceEntries.PropertyName) {
     static std::string output;
-    output = cmJoin(this->InterfaceEntries.Entries, ";"_s);
+    output = cmList::to_string(this->InterfaceEntries.Entries);
     value = cmValue(output);
     did_read = true;
   } else if (cmHasPrefix(prop, this->DirectoryPrefix)) {
@@ -899,7 +899,7 @@
     if (!this->Entries.empty()) {
       // Storage to back the returned `cmValue`.
       static std::string output;
-      output = cmJoin(this->Entries, ";");
+      output = cmList::to_string(this->Entries);
       value = cmValue(output);
     }
     did_read = true;
@@ -2130,7 +2130,7 @@
     return nullptr;
   }
   static std::string output;
-  output = cmJoin(fileSet->GetDirectoryEntries(), ";"_s);
+  output = cmList::to_string(fileSet->GetDirectoryEntries());
   return cmValue(output);
 }
 
@@ -2150,7 +2150,7 @@
     return nullptr;
   }
   static std::string output;
-  output = cmJoin(fileSet->GetFileEntries(), ";"_s);
+  output = cmList::to_string(fileSet->GetFileEntries());
   return cmValue(output);
 }
 
@@ -2495,7 +2495,7 @@
         [](const BT<std::pair<std::string, bool>>& item) -> std::string {
           return item.Value.first;
         });
-      output = cmJoin(utilities, ";");
+      output = cmList::to_string(utilities);
       return cmValue(output);
     }
     if (prop == propIMPORTED) {
diff --git a/Source/cmTargetCompileFeaturesCommand.cxx b/Source/cmTargetCompileFeaturesCommand.cxx
index aa1abdd..37c125b 100644
--- a/Source/cmTargetCompileFeaturesCommand.cxx
+++ b/Source/cmTargetCompileFeaturesCommand.cxx
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmTargetCompileFeaturesCommand.h"
 
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmStandardLevelResolver.h"
@@ -43,7 +44,7 @@
 
   std::string Join(const std::vector<std::string>& content) override
   {
-    return cmJoin(content, ";");
+    return cmList::to_string(content);
   }
 };
 
diff --git a/Source/cmTargetCompileOptionsCommand.cxx b/Source/cmTargetCompileOptionsCommand.cxx
index 8ca3842..e73a75f 100644
--- a/Source/cmTargetCompileOptionsCommand.cxx
+++ b/Source/cmTargetCompileOptionsCommand.cxx
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmTargetCompileOptionsCommand.h"
 
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -44,7 +45,7 @@
 
   std::string Join(const std::vector<std::string>& content) override
   {
-    return cmJoin(content, ";");
+    return cmList::to_string(content);
   }
 };
 
diff --git a/Source/cmTargetLinkDirectoriesCommand.cxx b/Source/cmTargetLinkDirectoriesCommand.cxx
index 3ba27a8..dddb348 100644
--- a/Source/cmTargetLinkDirectoriesCommand.cxx
+++ b/Source/cmTargetLinkDirectoriesCommand.cxx
@@ -3,6 +3,7 @@
 #include "cmTargetLinkDirectoriesCommand.h"
 
 #include "cmGeneratorExpression.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -58,7 +59,7 @@
     directories.push_back(unixPath);
   }
 
-  return cmJoin(directories, ";");
+  return cmList::to_string(directories);
 }
 
 } // namespace
diff --git a/Source/cmTargetLinkOptionsCommand.cxx b/Source/cmTargetLinkOptionsCommand.cxx
index 3ea2d71..cd93835 100644
--- a/Source/cmTargetLinkOptionsCommand.cxx
+++ b/Source/cmTargetLinkOptionsCommand.cxx
@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmTargetLinkOptionsCommand.h"
 
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -36,7 +37,7 @@
 
   std::string Join(const std::vector<std::string>& content) override
   {
-    return cmJoin(content, ";");
+    return cmList::to_string(content);
   }
 };
 
diff --git a/Source/cmTargetPrecompileHeadersCommand.cxx b/Source/cmTargetPrecompileHeadersCommand.cxx
index 4dd158d..0173a92 100644
--- a/Source/cmTargetPrecompileHeadersCommand.cxx
+++ b/Source/cmTargetPrecompileHeadersCommand.cxx
@@ -5,6 +5,7 @@
 #include <utility>
 
 #include "cmGeneratorExpression.h"
+#include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -73,7 +74,7 @@
 
   std::string Join(const std::vector<std::string>& content) override
   {
-    return cmJoin(content, ";");
+    return cmList::to_string(content);
   }
 };
 
diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx
index 12328b1..3d484f5 100644
--- a/Source/cmTargetSourcesCommand.cxx
+++ b/Source/cmTargetSourcesCommand.cxx
@@ -98,7 +98,7 @@
 
   std::string Join(const std::vector<std::string>& content) override
   {
-    return cmJoin(content, ";");
+    return cmList::to_string(content);
   }
 
   enum class IsInterface
diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx
index ed5f38b..3de7ae5 100644
--- a/Source/cmUVProcessChain.cxx
+++ b/Source/cmUVProcessChain.cxx
@@ -5,11 +5,9 @@
 #include "cmUVProcessChain.h"
 
 #include <array>
-#include <cassert>
 #include <csignal>
 #include <cstdio>
 #include <istream> // IWYU pragma: keep
-#include <iterator>
 #include <type_traits>
 #include <utility>
 
@@ -19,43 +17,24 @@
 
 #include "cmGetPipes.h"
 #include "cmUVHandlePtr.h"
-#include "cmUVStreambuf.h"
 
 struct cmUVProcessChain::InternalData
 {
-  struct BasicStreamData
+  struct StreamData
   {
-    cmUVStreambuf Streambuf;
-    cm::uv_pipe_ptr BuiltinStream;
+    int BuiltinStream = -1;
     uv_stdio_container_t Stdio;
   };
 
-  template <typename IOStream>
-  struct StreamData : public BasicStreamData
-  {
-    StreamData()
-      : BuiltinIOStream(&this->Streambuf)
-    {
-    }
-
-    IOStream BuiltinIOStream;
-
-    IOStream* GetBuiltinStream()
-    {
-      if (this->BuiltinStream.get()) {
-        return &this->BuiltinIOStream;
-      }
-      return nullptr;
-    }
-  };
-
   struct ProcessData
   {
     cmUVProcessChain::InternalData* Data;
     cm::uv_process_ptr Process;
+    cm::uv_pipe_ptr InputPipe;
     cm::uv_pipe_ptr OutputPipe;
-    bool Finished = false;
     Status ProcessStatus;
+
+    void Finish();
   };
 
   const cmUVProcessChainBuilder* Builder = nullptr;
@@ -64,18 +43,21 @@
 
   cm::uv_loop_ptr Loop;
 
-  StreamData<std::istream> OutputStreamData;
-  StreamData<std::istream> ErrorStreamData;
+  StreamData InputStreamData;
+  StreamData OutputStreamData;
+  StreamData ErrorStreamData;
+  cm::uv_pipe_ptr TempOutputPipe;
+  cm::uv_pipe_ptr TempErrorPipe;
 
   unsigned int ProcessesCompleted = 0;
   std::vector<std::unique_ptr<ProcessData>> Processes;
 
   bool Prepare(const cmUVProcessChainBuilder* builder);
-  bool AddCommand(const cmUVProcessChainBuilder::ProcessConfiguration& config,
-                  bool first, bool last);
-  bool Finish();
-
-  static const Status* GetStatus(const ProcessData& data);
+  void SpawnProcess(
+    std::size_t index,
+    const cmUVProcessChainBuilder::ProcessConfiguration& config, bool first,
+    bool last);
+  void Finish();
 };
 
 cmUVProcessChainBuilder::cmUVProcessChainBuilder()
@@ -132,9 +114,6 @@
 {
   switch (stdio) {
     case Stream_INPUT:
-      // FIXME
-      break;
-
     case Stream_OUTPUT:
     case Stream_ERROR: {
       auto& streamData = this->Stdio[stdio];
@@ -167,11 +146,9 @@
     return chain;
   }
 
-  for (auto it = this->Processes.begin(); it != this->Processes.end(); ++it) {
-    if (!chain.Data->AddCommand(*it, it == this->Processes.begin(),
-                                it == std::prev(this->Processes.end()))) {
-      return chain;
-    }
+  for (std::size_t i = 0; i < this->Processes.size(); i++) {
+    chain.Data->SpawnProcess(i, this->Processes[i], i == 0,
+                             i == this->Processes.size() - 1);
   }
 
   chain.Data->Finish();
@@ -179,20 +156,30 @@
   return chain;
 }
 
-const cmUVProcessChain::Status* cmUVProcessChain::InternalData::GetStatus(
-  const cmUVProcessChain::InternalData::ProcessData& data)
-{
-  if (data.Finished) {
-    return &data.ProcessStatus;
-  }
-  return nullptr;
-}
-
 bool cmUVProcessChain::InternalData::Prepare(
   const cmUVProcessChainBuilder* builder)
 {
   this->Builder = builder;
 
+  auto const& input =
+    this->Builder->Stdio[cmUVProcessChainBuilder::Stream_INPUT];
+  auto& inputData = this->InputStreamData;
+  switch (input.Type) {
+    case cmUVProcessChainBuilder::None:
+      inputData.Stdio.flags = UV_IGNORE;
+      break;
+
+    case cmUVProcessChainBuilder::Builtin: {
+      // FIXME
+      break;
+    }
+
+    case cmUVProcessChainBuilder::External:
+      inputData.Stdio.flags = UV_INHERIT_FD;
+      inputData.Stdio.data.fd = input.FileDescriptor;
+      break;
+  }
+
   auto const& error =
     this->Builder->Stdio[cmUVProcessChainBuilder::Stream_ERROR];
   auto& errorData = this->ErrorStreamData;
@@ -207,12 +194,17 @@
         return false;
       }
 
-      errorData.BuiltinStream.init(*this->Loop, 0);
-      if (uv_pipe_open(errorData.BuiltinStream, pipeFd[0]) < 0) {
-        return false;
-      }
+      errorData.BuiltinStream = pipeFd[0];
       errorData.Stdio.flags = UV_INHERIT_FD;
       errorData.Stdio.data.fd = pipeFd[1];
+
+      if (this->TempErrorPipe.init(*this->Loop, 0) < 0) {
+        return false;
+      }
+      if (uv_pipe_open(this->TempErrorPipe, errorData.Stdio.data.fd) < 0) {
+        return false;
+      }
+
       break;
     }
 
@@ -232,13 +224,25 @@
 
     case cmUVProcessChainBuilder::Builtin:
       if (this->Builder->MergedBuiltinStreams) {
+        outputData.BuiltinStream = errorData.BuiltinStream;
         outputData.Stdio.flags = UV_INHERIT_FD;
         outputData.Stdio.data.fd = errorData.Stdio.data.fd;
       } else {
-        outputData.BuiltinStream.init(*this->Loop, 0);
-        outputData.Stdio.flags =
-          static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
-        outputData.Stdio.data.stream = outputData.BuiltinStream;
+        int pipeFd[2];
+        if (cmGetPipes(pipeFd) < 0) {
+          return false;
+        }
+
+        outputData.BuiltinStream = pipeFd[0];
+        outputData.Stdio.flags = UV_INHERIT_FD;
+        outputData.Stdio.data.fd = pipeFd[1];
+
+        if (this->TempOutputPipe.init(*this->Loop, 0) < 0) {
+          return false;
+        }
+        if (uv_pipe_open(this->TempOutputPipe, outputData.Stdio.data.fd) < 0) {
+          return false;
+        }
       }
       break;
 
@@ -248,16 +252,47 @@
       break;
   }
 
+  bool first = true;
+  for (std::size_t i = 0; i < this->Builder->Processes.size(); i++) {
+    this->Processes.emplace_back(cm::make_unique<ProcessData>());
+    auto& process = *this->Processes.back();
+    process.Data = this;
+    process.ProcessStatus.Finished = false;
+
+    if (!first) {
+      auto& prevProcess = *this->Processes[i - 1];
+
+      int pipeFd[2];
+      if (cmGetPipes(pipeFd) < 0) {
+        return false;
+      }
+
+      if (prevProcess.OutputPipe.init(*this->Loop, 0) < 0) {
+        return false;
+      }
+      if (uv_pipe_open(prevProcess.OutputPipe, pipeFd[1]) < 0) {
+        return false;
+      }
+      if (process.InputPipe.init(*this->Loop, 0) < 0) {
+        return false;
+      }
+      if (uv_pipe_open(process.InputPipe, pipeFd[0]) < 0) {
+        return false;
+      }
+    }
+
+    first = false;
+  }
+
   return true;
 }
 
-bool cmUVProcessChain::InternalData::AddCommand(
+void cmUVProcessChain::InternalData::SpawnProcess(
+  std::size_t index,
   const cmUVProcessChainBuilder::ProcessConfiguration& config, bool first,
   bool last)
 {
-  this->Processes.emplace_back(cm::make_unique<ProcessData>());
-  auto& process = *this->Processes.back();
-  process.Data = this;
+  auto& process = *this->Processes[index];
 
   auto options = uv_process_options_t();
 
@@ -277,24 +312,18 @@
   }
 
   std::array<uv_stdio_container_t, 3> stdio;
-  stdio[0] = uv_stdio_container_t();
   if (first) {
-    stdio[0].flags = UV_IGNORE;
+    stdio[0] = this->InputStreamData.Stdio;
   } else {
-    assert(this->Processes.size() >= 2);
-    auto& prev = *this->Processes[this->Processes.size() - 2];
+    stdio[0] = uv_stdio_container_t();
     stdio[0].flags = UV_INHERIT_STREAM;
-    stdio[0].data.stream = prev.OutputPipe;
+    stdio[0].data.stream = process.InputPipe;
   }
   if (last) {
     stdio[1] = this->OutputStreamData.Stdio;
   } else {
-    if (process.OutputPipe.init(*this->Loop, 0) < 0) {
-      return false;
-    }
     stdio[1] = uv_stdio_container_t();
-    stdio[1].flags =
-      static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
+    stdio[1].flags = UV_INHERIT_STREAM;
     stdio[1].data.stream = process.OutputPipe;
   }
   stdio[2] = this->ErrorStreamData.Stdio;
@@ -304,40 +333,24 @@
   options.exit_cb = [](uv_process_t* handle, int64_t exitStatus,
                        int termSignal) {
     auto* processData = static_cast<ProcessData*>(handle->data);
-    processData->Finished = true;
     processData->ProcessStatus.ExitStatus = exitStatus;
     processData->ProcessStatus.TermSignal = termSignal;
-    processData->Data->ProcessesCompleted++;
+    processData->Finish();
   };
 
-  return process.Process.spawn(*this->Loop, options, &process) >= 0;
+  if ((process.ProcessStatus.SpawnResult =
+         process.Process.spawn(*this->Loop, options, &process)) < 0) {
+    process.Finish();
+  }
+  process.InputPipe.reset();
+  process.OutputPipe.reset();
 }
 
-bool cmUVProcessChain::InternalData::Finish()
+void cmUVProcessChain::InternalData::Finish()
 {
-  if (this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT].Type ==
-        cmUVProcessChainBuilder::Builtin &&
-      !this->Builder->MergedBuiltinStreams) {
-    this->OutputStreamData.Streambuf.open(
-      this->OutputStreamData.BuiltinStream);
-  }
-
-  if (this->Builder->Stdio[cmUVProcessChainBuilder::Stream_ERROR].Type ==
-      cmUVProcessChainBuilder::Builtin) {
-    cm::uv_pipe_ptr tmpPipe;
-    if (tmpPipe.init(*this->Loop, 0) < 0) {
-      return false;
-    }
-    if (uv_pipe_open(tmpPipe, this->ErrorStreamData.Stdio.data.fd) < 0) {
-      return false;
-    }
-    tmpPipe.reset();
-
-    this->ErrorStreamData.Streambuf.open(this->ErrorStreamData.BuiltinStream);
-  }
-
+  this->TempOutputPipe.reset();
+  this->TempErrorPipe.reset();
   this->Valid = true;
-  return true;
 }
 
 cmUVProcessChain::cmUVProcessChain()
@@ -365,17 +378,14 @@
   return *this->Data->Loop;
 }
 
-std::istream* cmUVProcessChain::OutputStream()
+int cmUVProcessChain::OutputStream()
 {
-  if (this->Data->Builder->MergedBuiltinStreams) {
-    return this->Data->ErrorStreamData.GetBuiltinStream();
-  }
-  return this->Data->OutputStreamData.GetBuiltinStream();
+  return this->Data->OutputStreamData.BuiltinStream;
 }
 
-std::istream* cmUVProcessChain::ErrorStream()
+int cmUVProcessChain::ErrorStream()
 {
-  return this->Data->ErrorStreamData.GetBuiltinStream();
+  return this->Data->ErrorStreamData.BuiltinStream;
 }
 
 bool cmUVProcessChain::Valid() const
@@ -412,19 +422,15 @@
   std::vector<const cmUVProcessChain::Status*> statuses(
     this->Data->Processes.size(), nullptr);
   for (std::size_t i = 0; i < statuses.size(); i++) {
-    statuses[i] = this->GetStatus(i);
+    statuses[i] = &this->GetStatus(i);
   }
   return statuses;
 }
 
-const cmUVProcessChain::Status* cmUVProcessChain::GetStatus(
+const cmUVProcessChain::Status& cmUVProcessChain::GetStatus(
   std::size_t index) const
 {
-  auto const& process = *this->Data->Processes[index];
-  if (process.Finished) {
-    return &process.ProcessStatus;
-  }
-  return nullptr;
+  return this->Data->Processes[index]->ProcessStatus;
 }
 
 bool cmUVProcessChain::Finished() const
@@ -435,8 +441,12 @@
 std::pair<cmUVProcessChain::ExceptionCode, std::string>
 cmUVProcessChain::Status::GetException() const
 {
+  if (this->SpawnResult) {
+    return std::make_pair(ExceptionCode::Spawn,
+                          uv_strerror(this->SpawnResult));
+  }
 #ifdef _WIN32
-  if ((this->ExitStatus & 0xF0000000) == 0xC0000000) {
+  if (this->Finished && (this->ExitStatus & 0xF0000000) == 0xC0000000) {
     // Child terminated due to exceptional behavior.
     switch (this->ExitStatus) {
       case STATUS_CONTROL_C_EXIT:
@@ -511,9 +521,8 @@
       }
     }
   }
-  return std::make_pair(ExceptionCode::None, "");
 #else
-  if (this->TermSignal) {
+  if (this->Finished && this->TermSignal) {
     switch (this->TermSignal) {
 #  ifdef SIGSEGV
       case SIGSEGV:
@@ -670,6 +679,12 @@
       }
     }
   }
-  return std::make_pair(ExceptionCode::None, "");
 #endif
+  return std::make_pair(ExceptionCode::None, "");
+}
+
+void cmUVProcessChain::InternalData::ProcessData::Finish()
+{
+  this->ProcessStatus.Finished = true;
+  this->Data->ProcessesCompleted++;
 }
diff --git a/Source/cmUVProcessChain.h b/Source/cmUVProcessChain.h
index f92742f..d7a4a0e 100644
--- a/Source/cmUVProcessChain.h
+++ b/Source/cmUVProcessChain.h
@@ -5,7 +5,6 @@
 #include <array>
 #include <cstddef> // IWYU pragma: keep
 #include <cstdint>
-#include <iosfwd>
 #include <memory>
 #include <string>
 #include <utility>
@@ -74,11 +73,14 @@
     Illegal,
     Interrupt,
     Numerical,
+    Spawn,
     Other,
   };
 
   struct Status
   {
+    int SpawnResult;
+    bool Finished;
     int64_t ExitStatus;
     int TermSignal;
 
@@ -96,13 +98,13 @@
   uv_loop_t& GetLoop();
 
   // FIXME: Add stdin support
-  std::istream* OutputStream();
-  std::istream* ErrorStream();
+  int OutputStream();
+  int ErrorStream();
 
   bool Valid() const;
   bool Wait(int64_t milliseconds = -1);
   std::vector<const Status*> GetStatus() const;
-  const Status* GetStatus(std::size_t index) const;
+  const Status& GetStatus(std::size_t index) const;
   bool Finished() const;
 
 private:
diff --git a/Source/cmUVStream.h b/Source/cmUVStream.h
new file mode 100644
index 0000000..5998256
--- /dev/null
+++ b/Source/cmUVStream.h
@@ -0,0 +1,140 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include <cassert>
+#include <istream>
+
+#include <cm3p/uv.h>
+
+#include "cmUVHandlePtr.h"
+#include "cmUVStreambuf.h"
+
+template <typename CharT, typename Traits = std::char_traits<CharT>>
+class cmBasicUVIStream : public std::basic_istream<CharT>
+{
+public:
+  cmBasicUVIStream();
+  cmBasicUVIStream(uv_stream_t* stream);
+
+  bool is_open() const;
+
+  void open(uv_stream_t* stream);
+
+  void close();
+
+private:
+  cmBasicUVStreambuf<CharT, Traits> Buffer;
+};
+
+template <typename CharT, typename Traits>
+cmBasicUVIStream<CharT, Traits>::cmBasicUVIStream()
+  : std::basic_istream<CharT, Traits>(&this->Buffer)
+{
+}
+
+template <typename CharT, typename Traits>
+cmBasicUVIStream<CharT, Traits>::cmBasicUVIStream(uv_stream_t* stream)
+  : cmBasicUVIStream()
+{
+  this->open(stream);
+}
+
+template <typename CharT, typename Traits>
+bool cmBasicUVIStream<CharT, Traits>::is_open() const
+{
+  return this->Buffer.is_open();
+}
+
+template <typename CharT, typename Traits>
+void cmBasicUVIStream<CharT, Traits>::open(uv_stream_t* stream)
+{
+  this->Buffer.open(stream);
+}
+
+template <typename CharT, typename Traits>
+void cmBasicUVIStream<CharT, Traits>::close()
+{
+  this->Buffer.close();
+}
+
+using cmUVIStream = cmBasicUVIStream<char>;
+
+template <typename CharT, typename Traits = std::char_traits<CharT>>
+class cmBasicUVPipeIStream : public cmBasicUVIStream<CharT, Traits>
+{
+public:
+  cmBasicUVPipeIStream();
+  cmBasicUVPipeIStream(uv_loop_t& loop, int fd);
+
+  using cmBasicUVIStream<CharT, Traits>::is_open;
+
+  void open(uv_loop_t& loop, int fd);
+
+  void close();
+
+private:
+  cm::uv_pipe_ptr Pipe;
+};
+
+template <typename CharT, typename Traits>
+cmBasicUVPipeIStream<CharT, Traits>::cmBasicUVPipeIStream() = default;
+
+template <typename CharT, typename Traits>
+cmBasicUVPipeIStream<CharT, Traits>::cmBasicUVPipeIStream(uv_loop_t& loop,
+                                                          int fd)
+{
+  this->open(loop, fd);
+}
+
+template <typename CharT, typename Traits>
+void cmBasicUVPipeIStream<CharT, Traits>::open(uv_loop_t& loop, int fd)
+{
+  this->Pipe.init(loop, 0);
+  uv_pipe_open(this->Pipe, fd);
+  this->cmBasicUVIStream<CharT, Traits>::open(this->Pipe);
+}
+
+template <typename CharT, typename Traits>
+void cmBasicUVPipeIStream<CharT, Traits>::close()
+{
+  this->cmBasicUVIStream<CharT, Traits>::close();
+  this->Pipe.reset();
+}
+
+using cmUVPipeIStream = cmBasicUVPipeIStream<char>;
+
+template <typename ReadCallback, typename FinishCallback>
+void cmUVStreamRead(uv_stream_t* stream, ReadCallback onRead,
+                    FinishCallback onFinish)
+{
+  struct ReadData
+  {
+    std::vector<char> Buffer;
+    ReadCallback OnRead;
+    FinishCallback OnFinish;
+  };
+
+  stream->data = new ReadData{ {}, std::move(onRead), std::move(onFinish) };
+  uv_read_start(
+    stream,
+    [](uv_handle_t* s, std::size_t suggestedSize, uv_buf_t* buffer) {
+      auto* data = static_cast<ReadData*>(s->data);
+      data->Buffer.resize(suggestedSize);
+      buffer->base = data->Buffer.data();
+      buffer->len = suggestedSize;
+    },
+    [](uv_stream_t* s, ssize_t nread, const uv_buf_t* buffer) {
+      auto* data = static_cast<ReadData*>(s->data);
+      if (nread > 0) {
+        (void)buffer;
+        assert(buffer->base == data->Buffer.data());
+        data->Buffer.resize(nread);
+        data->OnRead(std::move(data->Buffer));
+      } else if (nread < 0 /*|| nread == UV_EOF*/) {
+        data->OnFinish();
+        uv_read_stop(s);
+        delete data;
+      }
+    });
+}
diff --git a/Source/cmUVStreambuf.h b/Source/cmUVStreambuf.h
index efe45de..4f7b209 100644
--- a/Source/cmUVStreambuf.h
+++ b/Source/cmUVStreambuf.h
@@ -14,7 +14,8 @@
 /*
  * This file is based on example code from:
  *
- * http://www.voidcn.com/article/p-vjnlygmc-gy.html
+ * https://web.archive.org/web/20170515211805/
+ *     http://www.mr-edd.co.uk/blog/beginners_guide_streambuf
  *
  * The example code was distributed under the following license:
  *
diff --git a/Source/cmUuid.cxx b/Source/cmUuid.cxx
index 6688668..5f5d3e4 100644
--- a/Source/cmUuid.cxx
+++ b/Source/cmUuid.cxx
@@ -104,20 +104,20 @@
 
     size_t bytes = kUuidGroups[i];
     for (size_t j = 0; j < bytes; ++j) {
-      unsigned char byte = input[inputIndex++];
-      output += this->ByteToHex(byte);
+      unsigned char inputByte = input[inputIndex++];
+      output += this->ByteToHex(inputByte);
     }
   }
 
   return output;
 }
 
-std::string cmUuid::ByteToHex(unsigned char byte) const
+std::string cmUuid::ByteToHex(unsigned char inputByte) const
 {
   std::string result("  ");
   for (int i = 0; i < 2; ++i) {
-    unsigned char rest = byte % 16;
-    byte /= 16;
+    unsigned char rest = inputByte % 16;
+    inputByte /= 16;
     char c = (rest < 0xA) ? static_cast<char>('0' + rest)
                           : static_cast<char>('a' + (rest - 0xA));
     result.at(1 - i) = c;
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 33152f2..dd6c4b8 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -2534,18 +2534,6 @@
         break;
       case cmGeneratorTarget::SourceKindExternalObject:
         tool = "Object";
-        if (this->LocalGenerator->GetVersion() <
-            cmGlobalVisualStudioGenerator::VSVersion::VS11) {
-          // For VS == 10 we cannot use LinkObjects to avoid linking custom
-          // command outputs.  If an object file is generated in this target,
-          // then vs10 will use it in the build, and we have to list it as
-          // None instead of Object.
-          std::vector<cmSourceFile*> const* d =
-            this->GeneratorTarget->GetSourceDepends(si.Source);
-          if (d && !d->empty()) {
-            tool = "None";
-          }
-        }
         break;
       case cmGeneratorTarget::SourceKindExtra:
         this->WriteExtraSource(e1, si.Source, toolSettings);
diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx
index 6e98874..7e4503b 100644
--- a/Source/cmVisualStudioGeneratorOptions.cxx
+++ b/Source/cmVisualStudioGeneratorOptions.cxx
@@ -75,7 +75,6 @@
   // the flag to disable exception handling.  When the user does
   // remove the flag we need to override the IDE default of on.
   switch (this->Version) {
-    case cmGlobalVisualStudioGenerator::VSVersion::VS11:
     case cmGlobalVisualStudioGenerator::VSVersion::VS12:
     case cmGlobalVisualStudioGenerator::VSVersion::VS14:
     case cmGlobalVisualStudioGenerator::VSVersion::VS15:
diff --git a/Source/cm_codecvt.cxx b/Source/cm_codecvt.cxx
index 12877b8..7b3349b 100644
--- a/Source/cm_codecvt.cxx
+++ b/Source/cm_codecvt.cxx
@@ -13,19 +13,19 @@
 #  include "cm_utf8.h"
 #endif
 
-codecvt::codecvt(Encoding e)
+codecvt::codecvt(codecvt_Encoding e)
 #if defined(_WIN32)
   : m_codepage(0)
 #endif
 {
   switch (e) {
-    case codecvt::ConsoleOutput:
+    case codecvt_Encoding::ConsoleOutput:
 #if defined(_WIN32)
       m_noconv = false;
       m_codepage = GetConsoleOutputCP();
       break;
 #endif
-    case codecvt::ANSI:
+    case codecvt_Encoding::ANSI:
 #if defined(_WIN32)
       m_noconv = false;
       m_codepage = CP_ACP;
@@ -33,10 +33,10 @@
 #endif
     // We don't know which ANSI encoding to use for other platforms than
     // Windows so we don't do any conversion there
-    case codecvt::UTF8:
-    case codecvt::UTF8_WITH_BOM:
+    case codecvt_Encoding::UTF8:
+    case codecvt_Encoding::UTF8_WITH_BOM:
     // Assume internal encoding is UTF-8
-    case codecvt::None:
+    case codecvt_Encoding::None:
     // No encoding
     default:
       this->m_noconv = true;
diff --git a/Source/cm_codecvt.hxx b/Source/cm_codecvt.hxx
index f628de7..eb98e98 100644
--- a/Source/cm_codecvt.hxx
+++ b/Source/cm_codecvt.hxx
@@ -7,21 +7,14 @@
 #include <cwchar>
 #include <locale>
 
+#include "cm_codecvt_Encoding.hxx"
+
 class codecvt : public std::codecvt<char, char, mbstate_t>
 {
 public:
-  enum Encoding
-  {
-    None,
-    UTF8,
-    UTF8_WITH_BOM,
-    ANSI,
-    ConsoleOutput,
-  };
-
 #ifndef CMAKE_BOOTSTRAP
 
-  codecvt(Encoding e);
+  codecvt(codecvt_Encoding e);
 
 protected:
   ~codecvt() override;
diff --git a/Source/cm_codecvt_Encoding.hxx b/Source/cm_codecvt_Encoding.hxx
new file mode 100644
index 0000000..b91ad8f
--- /dev/null
+++ b/Source/cm_codecvt_Encoding.hxx
@@ -0,0 +1,12 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#pragma once
+
+enum class codecvt_Encoding
+{
+  None,
+  UTF8,
+  UTF8_WITH_BOM,
+  ANSI,
+  ConsoleOutput,
+};
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index f30d4d3..b8ebca5 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -94,7 +94,6 @@
 #    include "cmGlobalBorlandMakefileGenerator.h"
 #    include "cmGlobalJOMMakefileGenerator.h"
 #    include "cmGlobalNMakeMakefileGenerator.h"
-#    include "cmGlobalVisualStudio11Generator.h"
 #    include "cmGlobalVisualStudio12Generator.h"
 #    include "cmGlobalVisualStudio14Generator.h"
 #    include "cmGlobalVisualStudio9Generator.h"
@@ -2507,6 +2506,18 @@
                         "Name of generator toolset.", cmStateEnums::INTERNAL);
   }
 
+  if (!this->State->GetInitializedCacheValue(
+        "CMAKE_CROSSCOMPILING_EMULATOR")) {
+    cm::optional<std::string> emulator =
+      cmSystemTools::GetEnvVar("CMAKE_CROSSCOMPILING_EMULATOR");
+    if (emulator && !emulator->empty()) {
+      std::string message =
+        "Emulator to run executables and tests when cross compiling.";
+      this->AddCacheEntry("CMAKE_CROSSCOMPILING_EMULATOR", *emulator, message,
+                          cmStateEnums::STRING);
+    }
+  }
+
   // reset any system configuration information, except for when we are
   // InTryCompile. With TryCompile the system info is taken from the parent's
   // info to save time
@@ -2605,7 +2616,6 @@
   static VSVersionedGenerator const vsGenerators[] = {
     { "14.0", "Visual Studio 14 2015" }, //
     { "12.0", "Visual Studio 12 2013" }, //
-    { "11.0", "Visual Studio 11 2012" }, //
     { "9.0", "Visual Studio 9 2008" }
   };
   static const char* const vsEntries[] = {
@@ -2990,7 +3000,6 @@
     cmGlobalVisualStudioVersionedGenerator::NewFactory15());
   this->Generators.push_back(cmGlobalVisualStudio14Generator::NewFactory());
   this->Generators.push_back(cmGlobalVisualStudio12Generator::NewFactory());
-  this->Generators.push_back(cmGlobalVisualStudio11Generator::NewFactory());
   this->Generators.push_back(cmGlobalVisualStudio9Generator::NewFactory());
   this->Generators.push_back(cmGlobalBorlandMakefileGenerator::NewFactory());
   this->Generators.push_back(cmGlobalNMakeMakefileGenerator::NewFactory());
@@ -3916,7 +3925,7 @@
   return [builder]() -> int {
     auto chain = builder.Start();
     chain.Wait();
-    return static_cast<int>(chain.GetStatus().front()->ExitStatus);
+    return static_cast<int>(chain.GetStatus(0).ExitStatus);
   };
 }
 #endif
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 9929e85..eb1f93d 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -28,6 +28,7 @@
 #include "cmSystemTools.h"
 #include "cmTransformDepfile.h"
 #include "cmUVProcessChain.h"
+#include "cmUVStream.h"
 #include "cmUtils.hxx"
 #include "cmValue.h"
 #include "cmVersion.h"
@@ -2008,7 +2009,7 @@
     .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR)
     .AddCommand(command);
   auto process = builder.Start();
-  if (!process.Valid()) {
+  if (!process.Valid() || process.GetStatus(0).SpawnResult != 0) {
     std::cerr << "Failed to start preprocessor.";
     return 1;
   }
@@ -2016,12 +2017,9 @@
     std::cerr << "Failed to wait for preprocessor";
     return 1;
   }
-  auto status = process.GetStatus();
-  if (!status[0] || status[0]->ExitStatus != 0) {
-    auto* errorStream = process.ErrorStream();
-    if (errorStream) {
-      std::cerr << errorStream->rdbuf();
-    }
+  if (process.GetStatus(0).ExitStatus != 0) {
+    cmUVPipeIStream errorStream(process.GetLoop(), process.ErrorStream());
+    std::cerr << errorStream.rdbuf();
 
     return 1;
   }
@@ -2130,7 +2128,7 @@
     .AddCommand(resource_compile);
   auto process = builder.Start();
   result = 0;
-  if (!process.Valid()) {
+  if (!process.Valid() || process.GetStatus(0).SpawnResult != 0) {
     std::cerr << "Failed to start resource compiler.";
     result = 1;
   } else {
@@ -2144,12 +2142,9 @@
   if (result != 0) {
     return result;
   }
-  auto status = process.GetStatus();
-  if (!status[0] || status[0]->ExitStatus != 0) {
-    auto* errorStream = process.ErrorStream();
-    if (errorStream) {
-      std::cerr << errorStream->rdbuf();
-    }
+  if (process.GetStatus(0).ExitStatus != 0) {
+    cmUVPipeIStream errorStream(process.GetLoop(), process.ErrorStream());
+    std::cerr << errorStream.rdbuf();
     return 1;
   }
 
diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt
index 5c14de2..fc3c23b 100644
--- a/Tests/CMakeLib/CMakeLists.txt
+++ b/Tests/CMakeLib/CMakeLists.txt
@@ -63,10 +63,15 @@
 endif()
 
 configure_file(testXMLParser.h.in testXMLParser.h @ONLY)
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/testUVProcessChainInput.txt" "HELLO WORLD!")
 
 create_test_sourcelist(CMakeLib_TEST_SRCS CMakeLibTests.cxx ${CMakeLib_TESTS})
 add_executable(CMakeLibTests ${CMakeLib_TEST_SRCS})
 target_link_libraries(CMakeLibTests CMakeLib CTestLib)
+if(CMake_BUILD_PCH)
+  target_precompile_headers(CMakeLibTests PRIVATE "<iostream>" "<cm3p/uv.h>")
+  target_compile_definitions(CMakeLibTests PRIVATE "NOMINMAX")
+endif()
 
 set_property(TARGET CMakeLibTests PROPERTY C_CLANG_TIDY "")
 set_property(TARGET CMakeLibTests PROPERTY CXX_CLANG_TIDY "")
diff --git a/Tests/CMakeLib/testUVProcessChain.cxx b/Tests/CMakeLib/testUVProcessChain.cxx
index 7027689..7630aa0 100644
--- a/Tests/CMakeLib/testUVProcessChain.cxx
+++ b/Tests/CMakeLib/testUVProcessChain.cxx
@@ -1,5 +1,6 @@
 #include <algorithm>
 #include <csignal>
+#include <cstdio>
 #include <functional>
 #include <iostream>
 #include <sstream>
@@ -16,11 +17,11 @@
 #include "cmStringAlgorithms.h"
 #include "cmUVHandlePtr.h"
 #include "cmUVProcessChain.h"
+#include "cmUVStream.h"
 #include "cmUVStreambuf.h"
 
 struct ExpectedStatus
 {
-  bool Finished;
   bool MatchExitStatus;
   bool MatchTermSignal;
   cmUVProcessChain::Status Status;
@@ -28,38 +29,6 @@
   std::string ExceptionString;
 };
 
-static const std::vector<ExpectedStatus> status1 = {
-  { false, false, false, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
-  { false, false, false, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
-  { false, false, false, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
-};
-
-static const std::vector<ExpectedStatus> status2 = {
-  { true, true, true, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
-  { false, false, false, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
-  { false, false, false, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
-};
-
-static const std::vector<ExpectedStatus> status3 = {
-  { true, true, true, { 0, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
-  { true, true, true, { 1, 0 }, cmUVProcessChain::ExceptionCode::None, "" },
-#ifdef _WIN32
-  { true,
-    true,
-    true,
-    { STATUS_ACCESS_VIOLATION, 0 },
-    cmUVProcessChain::ExceptionCode::Fault,
-    "Access violation" },
-#else
-  { true,
-    false,
-    true,
-    { 0, SIGABRT },
-    cmUVProcessChain::ExceptionCode::Other,
-    "Subprocess aborted" },
-#endif
-};
-
 static const char* ExceptionCodeToString(cmUVProcessChain::ExceptionCode code)
 {
   switch (code) {
@@ -73,6 +42,8 @@
       return "Interrupt";
     case cmUVProcessChain::ExceptionCode::Numerical:
       return "Numerical";
+    case cmUVProcessChain::ExceptionCode::Spawn:
+      return "Spawn";
     case cmUVProcessChain::ExceptionCode::Other:
       return "Other";
     default:
@@ -83,9 +54,10 @@
 bool operator==(const cmUVProcessChain::Status* actual,
                 const ExpectedStatus& expected)
 {
-  if (!expected.Finished) {
-    return !actual;
-  } else if (!actual) {
+  if (expected.Status.SpawnResult != actual->SpawnResult) {
+    return false;
+  }
+  if (expected.Status.Finished != actual->Finished) {
     return false;
   }
   if (expected.MatchExitStatus &&
@@ -96,7 +68,7 @@
       expected.Status.TermSignal != actual->TermSignal) {
     return false;
   }
-  if (expected.Finished &&
+  if (expected.Status.Finished &&
       std::make_pair(expected.ExceptionCode, expected.ExceptionString) !=
         actual->GetException()) {
     return false;
@@ -150,39 +122,96 @@
 {
   std::cout << "Expected: " << std::endl;
   for (auto const& e : expected) {
-    if (e.Finished) {
-      std::cout << "  ExitStatus: "
-                << printExpected(e.MatchExitStatus, e.Status.ExitStatus)
-                << ", TermSignal: "
-                << printExpected(e.MatchTermSignal, e.Status.TermSignal)
-                << ", ExceptionCode: "
-                << printExpected(e.Finished,
-                                 ExceptionCodeToString(e.ExceptionCode))
-                << ", ExceptionString: \""
-                << printExpected(e.Finished, e.ExceptionString) << '"'
-                << std::endl;
-    } else {
-      std::cout << "  null" << std::endl;
-    }
+    std::cout << "  SpawnResult: " << e.Status.SpawnResult
+              << ", Finished: " << e.Status.Finished << ", ExitStatus: "
+              << printExpected(e.MatchExitStatus, e.Status.ExitStatus)
+              << ", TermSignal: "
+              << printExpected(e.MatchTermSignal, e.Status.TermSignal)
+              << ", ExceptionCode: "
+              << printExpected(e.Status.Finished,
+                               ExceptionCodeToString(e.ExceptionCode))
+              << ", ExceptionString: \""
+              << printExpected(e.Status.Finished, e.ExceptionString) << '"'
+              << std::endl;
   }
   std::cout << "Actual:" << std::endl;
   for (auto const& a : actual) {
-    if (a) {
-      auto exception = a->GetException();
-      std::cout << "  ExitStatus: " << a->ExitStatus
-                << ", TermSignal: " << a->TermSignal << ", ExceptionCode: "
-                << ExceptionCodeToString(exception.first)
-                << ", ExceptionString: \"" << exception.second << '"'
-                << std::endl;
-    } else {
-      std::cout << "  null" << std::endl;
-    }
+    auto exception = a->GetException();
+    std::cout << "  SpawnResult: " << a->SpawnResult
+              << ", Finished: " << a->Finished
+              << ", ExitStatus: " << a->ExitStatus
+              << ", TermSignal: " << a->TermSignal
+              << ", ExceptionCode: " << ExceptionCodeToString(exception.first)
+              << ", ExceptionString: \"" << exception.second << '"'
+              << std::endl;
   }
 }
 
 static bool checkExecution(cmUVProcessChainBuilder& builder,
                            std::unique_ptr<cmUVProcessChain>& chain)
 {
+  static const std::vector<ExpectedStatus> status1 = {
+    { false,
+      false,
+      { 0, false, 0, 0 },
+      cmUVProcessChain::ExceptionCode::None,
+      "" },
+    { false,
+      false,
+      { 0, false, 0, 0 },
+      cmUVProcessChain::ExceptionCode::None,
+      "" },
+    { false,
+      false,
+      { 0, false, 0, 0 },
+      cmUVProcessChain::ExceptionCode::None,
+      "" },
+  };
+
+  static const std::vector<ExpectedStatus> status2 = {
+    { true,
+      true,
+      { 0, true, 0, 0 },
+      cmUVProcessChain::ExceptionCode::None,
+      "" },
+    { false,
+      false,
+      { 0, false, 0, 0 },
+      cmUVProcessChain::ExceptionCode::None,
+      "" },
+    { false,
+      false,
+      { 0, false, 0, 0 },
+      cmUVProcessChain::ExceptionCode::None,
+      "" },
+  };
+
+  static const std::vector<ExpectedStatus> status3 = {
+    { true,
+      true,
+      { 0, true, 0, 0 },
+      cmUVProcessChain::ExceptionCode::None,
+      "" },
+    { true,
+      true,
+      { 0, true, 1, 0 },
+      cmUVProcessChain::ExceptionCode::None,
+      "" },
+#ifdef _WIN32
+    { true,
+      true,
+      { 0, true, STATUS_ACCESS_VIOLATION, 0 },
+      cmUVProcessChain::ExceptionCode::Fault,
+      "Access violation" },
+#else
+    { false,
+      true,
+      { 0, true, 0, SIGABRT },
+      cmUVProcessChain::ExceptionCode::Other,
+      "Subprocess aborted" },
+#endif
+  };
+
   std::vector<const cmUVProcessChain::Status*> status;
 
   chain = cm::make_unique<cmUVProcessChain>(builder.Start());
@@ -201,7 +230,7 @@
     return false;
   }
 
-  if (chain->Wait(6000)) {
+  if (chain->Wait(9000)) {
     std::cout << "Wait() returned true, should be false" << std::endl;
     return false;
   }
@@ -273,16 +302,19 @@
     return false;
   }
 
-  if (!chain->OutputStream()) {
-    std::cout << "OutputStream() was null, expecting not null" << std::endl;
+  if (chain->OutputStream() < 0) {
+    std::cout << "OutputStream() was invalid, expecting valid" << std::endl;
     return false;
   }
-  if (!chain->ErrorStream()) {
-    std::cout << "ErrorStream() was null, expecting not null" << std::endl;
+  if (chain->ErrorStream() < 0) {
+    std::cout << "ErrorStream() was invalid, expecting valid" << std::endl;
     return false;
   }
 
-  if (!checkOutput(*chain->OutputStream(), *chain->ErrorStream())) {
+  cmUVPipeIStream output(chain->GetLoop(), chain->OutputStream());
+  cmUVPipeIStream error(chain->GetLoop(), chain->ErrorStream());
+
+  if (!checkOutput(output, error)) {
     return false;
   }
 
@@ -302,12 +334,12 @@
     return false;
   }
 
-  if (!chain->OutputStream()) {
-    std::cout << "OutputStream() was null, expecting not null" << std::endl;
+  if (chain->OutputStream() < 0) {
+    std::cout << "OutputStream() was invalid, expecting valid" << std::endl;
     return false;
   }
-  if (!chain->ErrorStream()) {
-    std::cout << "ErrorStream() was null, expecting not null" << std::endl;
+  if (chain->ErrorStream() < 0) {
+    std::cout << "ErrorStream() was invalid, expecting valid" << std::endl;
     return false;
   }
   if (chain->OutputStream() != chain->ErrorStream()) {
@@ -316,7 +348,9 @@
     return false;
   }
 
-  std::string merged = getInput(*chain->OutputStream());
+  cmUVPipeIStream mergedStream(chain->GetLoop(), chain->OutputStream());
+
+  std::string merged = getInput(mergedStream);
   auto qemuErrorPos = merged.find("qemu:");
   if (qemuErrorPos != std::string::npos) {
     merged.resize(qemuErrorPos);
@@ -370,12 +404,12 @@
     return false;
   }
 
-  if (chain->OutputStream()) {
-    std::cout << "OutputStream() was not null, expecting null" << std::endl;
+  if (chain->OutputStream() >= 0) {
+    std::cout << "OutputStream() was valid, expecting invalid" << std::endl;
     return false;
   }
-  if (chain->ErrorStream()) {
-    std::cout << "ErrorStream() was not null, expecting null" << std::endl;
+  if (chain->ErrorStream() >= 0) {
+    std::cout << "ErrorStream() was valid, expecting invalid" << std::endl;
     return false;
   }
 
@@ -418,12 +452,12 @@
     return false;
   }
 
-  if (chain->OutputStream()) {
-    std::cout << "OutputStream() was not null, expecting null" << std::endl;
+  if (chain->OutputStream() >= 0) {
+    std::cout << "OutputStream() was valid, expecting invalid" << std::endl;
     return false;
   }
-  if (chain->ErrorStream()) {
-    std::cout << "ErrorStream() was not null, expecting null" << std::endl;
+  if (chain->ErrorStream() >= 0) {
+    std::cout << "ErrorStream() was valid, expecting invalid" << std::endl;
     return false;
   }
 
@@ -445,7 +479,8 @@
     return false;
   }
 
-  auto cwd = getInput(*chain.OutputStream());
+  cmUVPipeIStream output(chain.GetLoop(), chain.OutputStream());
+  auto cwd = getInput(output);
   if (!cmHasLiteralSuffix(cwd, "/Tests/CMakeLib")) {
     std::cout << "Working directory was \"" << cwd
               << "\", expected to end in \"/Tests/CMakeLib\"" << std::endl;
@@ -471,7 +506,8 @@
     return false;
   }
 
-  auto cwd = getInput(*chain.OutputStream());
+  cmUVPipeIStream output(chain.GetLoop(), chain.OutputStream());
+  auto cwd = getInput(output);
   if (!cmHasLiteralSuffix(cwd, "/Tests")) {
     std::cout << "Working directory was \"" << cwd
               << "\", expected to end in \"/Tests\"" << std::endl;
@@ -481,6 +517,141 @@
   return true;
 }
 
+bool testUVProcessChainSpawnFail(const char* helperCommand)
+{
+  static const std::vector<ExpectedStatus> status1 = {
+    { false,
+      false,
+      { 0, false, 0, 0 },
+      cmUVProcessChain::ExceptionCode::None,
+      "" },
+    { false,
+      false,
+      { UV_ENOENT, true, 0, 0 },
+      cmUVProcessChain::ExceptionCode::Spawn,
+      uv_strerror(UV_ENOENT) },
+#ifdef _WIN32
+    { true,
+      true,
+      { 0, true, STATUS_ACCESS_VIOLATION, 0 },
+      cmUVProcessChain::ExceptionCode::Fault,
+      "Access violation" },
+#else
+    { false,
+      true,
+      { 0, true, 0, SIGABRT },
+      cmUVProcessChain::ExceptionCode::Other,
+      "Subprocess aborted" },
+#endif
+  };
+
+  static const std::vector<ExpectedStatus> status2 = {
+#ifdef _WIN32
+    { true,
+      true,
+      { 0, true, 0, 0 },
+      cmUVProcessChain::ExceptionCode::None,
+      "" },
+#else
+    { false,
+      true,
+      { 0, true, 0, SIGPIPE },
+      cmUVProcessChain::ExceptionCode::Other,
+      "SIGPIPE" },
+#endif
+    { false,
+      false,
+      { UV_ENOENT, true, 0, 0 },
+      cmUVProcessChain::ExceptionCode::Spawn,
+      uv_strerror(UV_ENOENT) },
+#ifdef _WIN32
+    { true,
+      true,
+      { 0, true, STATUS_ACCESS_VIOLATION, 0 },
+      cmUVProcessChain::ExceptionCode::Fault,
+      "Access violation" },
+#else
+    { false,
+      true,
+      { 0, true, 0, SIGABRT },
+      cmUVProcessChain::ExceptionCode::Other,
+      "Subprocess aborted" },
+#endif
+  };
+
+  std::vector<const cmUVProcessChain::Status*> status;
+
+  cmUVProcessChainBuilder builder;
+  builder.AddCommand({ helperCommand, "echo" })
+    .AddCommand({ "this_command_is_for_cmake_and_should_never_exist" })
+    .AddCommand({ helperCommand, "dedup" })
+    .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT)
+    .SetBuiltinStream(cmUVProcessChainBuilder::Stream_ERROR);
+
+  auto chain = builder.Start();
+  if (!chain.Valid()) {
+    std::cout << "Valid() returned false, should be true" << std::endl;
+    return false;
+  }
+
+  // Some platforms, like Solaris 10, take a long time to report a trapped
+  // subprocess to the parent process (about 1.7 seconds in the case of
+  // Solaris 10.) Wait 3 seconds to give it enough time.
+  if (chain.Wait(3000)) {
+    std::cout << "Wait() did not time out" << std::endl;
+    return false;
+  }
+
+  status = chain.GetStatus();
+  if (!resultsMatch(status, status1)) {
+    std::cout << "GetStatus() did not produce expected output" << std::endl;
+    printResults(status, status1);
+    return false;
+  }
+
+  if (!chain.Wait()) {
+    std::cout << "Wait() timed out" << std::endl;
+    return false;
+  }
+
+  status = chain.GetStatus();
+  if (!resultsMatch(status, status2)) {
+    std::cout << "GetStatus() did not produce expected output" << std::endl;
+    printResults(status, status2);
+    return false;
+  }
+
+  return true;
+}
+
+bool testUVProcessChainInputFile(const char* helperCommand)
+{
+  std::unique_ptr<FILE, int (*)(FILE*)> f(
+    fopen("testUVProcessChainInput.txt", "rb"), fclose);
+
+  cmUVProcessChainBuilder builder;
+  builder.AddCommand({ helperCommand, "dedup" })
+    .SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT, fileno(f.get()))
+    .SetBuiltinStream(cmUVProcessChainBuilder::Stream_OUTPUT);
+
+  auto chain = builder.Start();
+
+  if (!chain.Wait()) {
+    std::cout << "Wait() timed out" << std::endl;
+    return false;
+  }
+
+  cmUVPipeIStream stream(chain.GetLoop(), chain.OutputStream());
+  std::string output = getInput(stream);
+  if (output != "HELO WRD!") {
+    std::cout << "Output was \"" << output << "\", expected \"HELO WRD!\""
+              << std::endl;
+    return false;
+  }
+
+  return true;
+}
+
 int testUVProcessChain(int argc, char** const argv)
 {
   if (argc < 2) {
@@ -518,5 +689,15 @@
     return -1;
   }
 
+  if (!testUVProcessChainSpawnFail(argv[1])) {
+    std::cout << "While executing testUVProcessChainSpawnFail().\n";
+    return -1;
+  }
+
+  if (!testUVProcessChainInputFile(argv[1])) {
+    std::cout << "While executing testUVProcessChainInputFile().\n";
+    return -1;
+  }
+
   return 0;
 }
diff --git a/Tests/CMakeLib/testUVProcessChainHelper.cxx b/Tests/CMakeLib/testUVProcessChainHelper.cxx
index 99743e7..fcc45b0 100644
--- a/Tests/CMakeLib/testUVProcessChainHelper.cxx
+++ b/Tests/CMakeLib/testUVProcessChainHelper.cxx
@@ -32,13 +32,13 @@
 
   std::string command = argv[1];
   if (command == "echo") {
-    std::this_thread::sleep_for(std::chrono::milliseconds(3000));
+    std::this_thread::sleep_for(std::chrono::milliseconds(6000));
     std::cout << "HELLO world!" << std::flush;
     std::cerr << "1" << std::flush;
     return 0;
   }
   if (command == "capitalize") {
-    std::this_thread::sleep_for(std::chrono::milliseconds(9000));
+    std::this_thread::sleep_for(std::chrono::milliseconds(12000));
     std::string input = getStdin();
     for (auto& c : input) {
       c = static_cast<char>(std::toupper(c));
diff --git a/Tests/CMakeLib/testUVStreambuf.cxx b/Tests/CMakeLib/testUVStreambuf.cxx
index f9ed6af..f3977d4 100644
--- a/Tests/CMakeLib/testUVStreambuf.cxx
+++ b/Tests/CMakeLib/testUVStreambuf.cxx
@@ -3,11 +3,14 @@
 #include <string>
 #include <vector>
 
+#include <cmext/algorithm>
+
 #include <cm3p/uv.h>
 #include <stdint.h>
 
 #include "cmGetPipes.h"
 #include "cmUVHandlePtr.h"
+#include "cmUVStream.h"
 #include "cmUVStreambuf.h"
 
 #define TEST_STR_LINE_1 "This string must be exactly 128 characters long so"
@@ -437,6 +440,90 @@
   return success;
 }
 
+bool testUVPipeIStream()
+{
+  int pipe[] = { -1, -1 };
+  if (cmGetPipes(pipe) < 0) {
+    std::cout << "cmGetPipes() returned an error" << std::endl;
+    return false;
+  }
+
+  cm::uv_loop_ptr loop;
+  loop.init();
+  cm::uv_pipe_ptr pipeSink;
+  pipeSink.init(*loop, 0);
+  uv_pipe_open(pipeSink, pipe[1]);
+
+  std::string str = "Hello world!\n";
+  uv_write_t writeReq;
+  uv_buf_t buf;
+  buf.base = &str.front();
+  buf.len = str.length();
+  uv_write(&writeReq, pipeSink, &buf, 1, nullptr);
+  uv_run(loop, UV_RUN_DEFAULT);
+
+  cmUVPipeIStream pin(*loop, pipe[0]);
+  std::string line;
+  std::getline(pin, line);
+  if (line != "Hello world!") {
+    std::cout << "Line was \"" << line << "\", should be \"Hello world!\""
+              << std::endl;
+    return false;
+  }
+
+  return true;
+}
+
+bool testUVStreamRead()
+{
+  int pipe[] = { -1, -1 };
+  if (cmGetPipes(pipe) < 0) {
+    std::cout << "cmGetPipes() returned an error" << std::endl;
+    return false;
+  }
+
+  cm::uv_loop_ptr loop;
+  loop.init();
+  cm::uv_pipe_ptr pipeSink;
+  pipeSink.init(*loop, 0);
+  uv_pipe_open(pipeSink, pipe[1]);
+
+  std::string str = "Hello world!";
+  uv_write_t writeReq;
+  uv_buf_t buf;
+  buf.base = &str.front();
+  buf.len = str.length();
+  uv_write(&writeReq, pipeSink, &buf, 1, nullptr);
+  uv_run(loop, UV_RUN_DEFAULT);
+  pipeSink.reset();
+
+  cm::uv_pipe_ptr pipeSource;
+  pipeSource.init(*loop, 0);
+  uv_pipe_open(pipeSource, pipe[0]);
+
+  std::string output;
+  bool finished = false;
+  cmUVStreamRead(
+    pipeSource,
+    [&output](std::vector<char> data) { cm::append(output, data); },
+    [&output, &finished]() {
+      if (output != "Hello world!") {
+        std::cout << "Output was \"" << output
+                  << "\", should be \"Hello world!\"" << std::endl;
+        return;
+      }
+      finished = true;
+    });
+  uv_run(loop, UV_RUN_DEFAULT);
+
+  if (!finished) {
+    std::cout << "finished was not set" << std::endl;
+    return false;
+  }
+
+  return true;
+}
+
 int testUVStreambuf(int argc, char** const argv)
 {
   if (argc < 2) {
@@ -454,5 +541,15 @@
     return -1;
   }
 
+  if (!testUVPipeIStream()) {
+    std::cout << "While executing testUVPipeIStream().\n";
+    return -1;
+  }
+
+  if (!testUVStreamRead()) {
+    std::cout << "While executing testUVPipeIStream().\n";
+    return -1;
+  }
+
   return 0;
 }
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 53bb1e6..8e6017e 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -42,8 +42,6 @@
 # Suppress generator deprecation warnings in test suite.
 if(CMAKE_GENERATOR MATCHES "^Visual Studio 9 2008")
   set(TEST_WARN_VS_CODE "set(ENV{CMAKE_WARN_VS9} OFF)")
-elseif(CMAKE_GENERATOR MATCHES "^Visual Studio 11 2012")
-  set(TEST_WARN_VS_CODE "set(ENV{CMAKE_WARN_VS11} OFF)")
 else()
   set(TEST_WARN_VS_CODE "")
 endif()
@@ -1540,10 +1538,38 @@
     add_subdirectory(GoogleTest)
   endif()
 
-  if(CMake_TEST_FindPython OR CMake_TEST_FindPython_SABIModule OR CMake_TEST_FindPython_NumPy
-      OR CMake_TEST_FindPython_Conda OR CMake_TEST_FindPython_IronPython OR CMake_TEST_FindPython_PyPy)
-    if (CMake_TEST_FindPython AND CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin")
-      set(CMake_TEST_FindPython_SABIModule TRUE)
+  if(CMake_TEST_FindPython)
+    set(CMake_TEST_FindPython2 TRUE)
+    set(CMake_TEST_FindPython3 TRUE)
+  endif()
+  if(CMake_TEST_FindPython_SABIMOdule)
+    set(CMake_TEST_FindPython2_SABIModule TRUE)
+    set(CMake_TEST_FindPython3_SABIModule TRUE)
+  endif()
+  if(CMake_TEST_FindPython_NumPy)
+    set(CMake_TEST_FindPython2_NumPyy TRUE)
+    set(CMake_TEST_FindPython3_NumPy TRUE)
+  endif()
+  if(CMake_TEST_FindPython_Conda)
+    set(CMake_TEST_FindPython3_Conda TRUE)
+  endif()
+  if(CMake_TEST_FindPython_IronPython)
+    set(CMake_TEST_FindPython2_IronPython TRUE)
+  endif()
+  if(CMake_TEST_FindPython_PyPy)
+    set(CMake_TEST_FindPython2_PyPy TRUE)
+    set(CMake_TEST_FindPython3_PyPy TRUE)
+  endif()
+  if(CMake_TEST_FindPython2 OR CMake_TEST_FindPython2
+      OR CMake_TEST_FindPython2_SABIModule OR CMake_TEST_FindPython3_SABIModule
+      OR CMake_TEST_FindPython2_NumPy OR CMake_TEST_FindPython3_NumPy
+      OR CMake_TEST_FindPython3_Conda OR CMake_TEST_FindPython2_IronPython
+      OR CMake_TEST_FindPython2_PyPy OR CMake_TEST_FindPython3_PyPy)
+    if (CMake_TEST_FindPython2 AND CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin")
+      set(CMake_TEST_FindPython2_SABIModule TRUE)
+    endif()
+    if (CMake_TEST_FindPython3 AND CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin")
+      set(CMake_TEST_FindPython3_SABIModule TRUE)
     endif()
     add_subdirectory(FindPython)
   endif()
@@ -2279,11 +2305,6 @@
       list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/VSWinStorePhone/${name}")
     endmacro()
 
-    if(vs11 AND ws80)
-      add_test_VSWinStorePhone(vs11-store80-X86 "Visual Studio 11 2012" WindowsStore 8.0 Win32)
-      add_test_VSWinStorePhone(vs11-store80-ARM "Visual Studio 11 2012" WindowsStore 8.0 ARM)
-      add_test_VSWinStorePhone(vs11-store80-X64 "Visual Studio 11 2012" WindowsStore 8.0 x64)
-    endif()
     if(vs12 AND ws81)
       add_test_VSWinStorePhone(vs12-store81-X86 "Visual Studio 12 2013" WindowsStore 8.1 Win32)
       add_test_VSWinStorePhone(vs12-store81-ARM "Visual Studio 12 2013" WindowsStore 8.1 ARM)
@@ -2311,10 +2332,6 @@
       add_test_VSWinStorePhone(vs14-store10_0-ARM "Visual Studio 14 2015" WindowsStore 10.0 ARM)
       add_test_VSWinStorePhone(vs14-store10_0-X64 "Visual Studio 14 2015" WindowsStore 10.0 x64)
     endif()
-    if(vs11 AND wp80)
-      add_test_VSWinStorePhone(vs11-phone80-X86 "Visual Studio 11 2012" WindowsPhone 8.0 Win32)
-      add_test_VSWinStorePhone(vs11-phone80-ARM "Visual Studio 11 2012" WindowsPhone 8.0 ARM)
-    endif()
     if(vs12 AND wp81)
       add_test_VSWinStorePhone(vs12-phone81-X86 "Visual Studio 12 2013" WindowsPhone 8.1 Win32)
       add_test_VSWinStorePhone(vs12-phone81-ARM "Visual Studio 12 2013" WindowsPhone 8.1 ARM)
@@ -2341,10 +2358,6 @@
       endforeach()
     endmacro()
 
-    if(vs11)
-      add_test_VSWinCE(vs11-ce80-ARM "Visual Studio 11 2012" WindowsCE 8.0 ${wince_sdk})
-    endif()
-
     if(vs12)
       add_test_VSWinCE(vs12-ce80-ARM "Visual Studio 12 2013" WindowsCE 8.0 ${wince_sdk})
     endif()
@@ -2471,9 +2484,6 @@
     list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/VSAndroid/${name}")
   endmacro()
   if(tegra AND NOT "${CMake_SOURCE_DIR};${CMake_BINARY_DIR}" MATCHES " ")
-    if(vs11)
-      add_test_VSAndroid(vs11 "Visual Studio 11 2012" "Tegra-Android")
-    endif()
     if(vs12)
       add_test_VSAndroid(vs12 "Visual Studio 12 2013" "Tegra-Android")
     endif()
diff --git a/Tests/FindPython/ArtifactsInteractive/CMakeLists.txt b/Tests/FindPython/ArtifactsInteractive/CMakeLists.txt
index 99823a6..18f8fda 100644
--- a/Tests/FindPython/ArtifactsInteractive/CMakeLists.txt
+++ b/Tests/FindPython/ArtifactsInteractive/CMakeLists.txt
@@ -3,7 +3,7 @@
 project(TestArtifactsInteractive LANGUAGES C)
 
 set (components Interpreter Development)
-if (CMake_TEST_FindPython_NumPy)
+if (CMake_TEST_FindPython3_NumPy)
   list (APPEND components NumPy)
 endif()
 
@@ -12,13 +12,13 @@
 if (Python3_ARTIFACTS_INTERACTIVE)
   if (NOT DEFINED CACHE{Python3_EXECUTABLE}
       OR NOT DEFINED CACHE{Python3_LIBRARY} OR NOT DEFINED CACHE{Python3_INCLUDE_DIR}
-      OR (CMake_TEST_FindPython_NumPy AND NOT DEFINED CACHE{Python3_NumPy_INCLUDE_DIR}))
+      OR (CMake_TEST_FindPython3_NumPy AND NOT DEFINED CACHE{Python3_NumPy_INCLUDE_DIR}))
     message (FATAL_ERROR "Python3_ARTIFACTS_INTERACTIVE=ON Failed.")
   endif()
 else()
   if (DEFINED CACHE{Python3_EXECUTABLE}
       OR DEFINED CACHE{Python3_LIBRARY} OR DEFINED CACHE{Python3_INCLUDE_DIR}
-      OR (CMake_TEST_FindPython_NumPy AND DEFINED CACHE{Python3_NumPy_INCLUDE_DIR}))
+      OR (CMake_TEST_FindPython3_NumPy AND DEFINED CACHE{Python3_NumPy_INCLUDE_DIR}))
     message (FATAL_ERROR "Python3_ARTIFACTS_INTERACTIVE=OFF Failed.")
   endif()
 endif()
diff --git a/Tests/FindPython/CMakeLists.txt b/Tests/FindPython/CMakeLists.txt
index b6942c9..3e1993e 100644
--- a/Tests/FindPython/CMakeLists.txt
+++ b/Tests/FindPython/CMakeLists.txt
@@ -1,4 +1,4 @@
-if(CMake_TEST_FindPython)
+if(CMake_TEST_FindPython2)
   add_test(NAME FindPython.Python2.LOCATION COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -44,6 +44,129 @@
   set_tests_properties(FindPython.Python2Fail PROPERTIES
     PASS_REGULAR_EXPRESSION "Could NOT find Python2 \\(missing: foobar\\)")
 
+  add_test(NAME FindPython.Python.V2.LOCATION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.LOCATION"
+    ${build_generator_args}
+    --build-project TestPython
+    --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_FIND_STRATEGY=LOCATION
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+  add_test(NAME FindPython.Python.V2.VERSION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.VERSION"
+    ${build_generator_args}
+    --build-project TestPython
+    --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_FIND_STRATEGY=VERSION
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+
+  add_test(NAME FindPython.Python2.ExactVersion.LOCATION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/ExactVersion"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python2.ExactVersion.LOCATION"
+    ${build_generator_args}
+    --build-project TestExactVersion
+    --build-options ${build_options} -DPython_MAJOR_VERSION=2
+                                     -DPython_REQUESTED_VERSION=2.1.2
+                                     -DPython2_FIND_STRATEGY=LOCATION
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+  add_test(NAME FindPython.Python2.ExactVersion.VERSION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/ExactVersion"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python2.ExactVersion.VERSION"
+    ${build_generator_args}
+    --build-project TestExactVersion
+    --build-options ${build_options} -DPython_MAJOR_VERSION=2
+                                     -DPython_REQUESTED_VERSION=2.1.2
+                                     -DPython2_FIND_STRATEGY=VERSION
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+
+  add_test(NAME FindPython.Python.V2.ExactVersion.LOCATION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/ExactVersion"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.ExactVersion.LOCATION"
+    ${build_generator_args}
+    --build-project TestExactVersion
+    --build-options ${build_options} -DPython_REQUESTED_VERSION=2.1.2
+                                     -DPython_FIND_STRATEGY=LOCATION
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+  add_test(NAME FindPython.Python.V2.ExactVersion.VERSION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/ExactVersion"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.ExactVersion.VERSION"
+    ${build_generator_args}
+    --build-project TestExactVersion
+    --build-options ${build_options} -DPython_REQUESTED_VERSION=2.1.2
+                                     -DPython_FIND_STRATEGY=VERSION
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+
+  add_test(NAME FindPython.Python2.VersionRange.LOCATION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python2.VersionRange.LOCATION"
+    ${build_generator_args}
+    --build-project TestVersionRange
+    --build-options ${build_options} -DPython=Python2 -DPython_REQUESTED_VERSION=2
+                                     -DPython2_FIND_STRATEGY=LOCATION
+    )
+  add_test(NAME FindPython.Python2.VersionRange.VERSION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python2.VersionRange.VERSION"
+    ${build_generator_args}
+    --build-project TestVersionRange
+    --build-options ${build_options} -DPython=Python2 -DPython_REQUESTED_VERSION=2
+                                     -DPython2_FIND_STRATEGY=VERSION
+    )
+  add_test(NAME FindPython.Python.V2.VersionRange.LOCATION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.VersionRange.LOCATION"
+    ${build_generator_args}
+    --build-project TestVersionRange
+    --build-options ${build_options} -DPython=Python -DPython_REQUESTED_VERSION=2
+                                     -DPython_FIND_STRATEGY=LOCATION
+    )
+  add_test(NAME FindPython.Python.V2.VersionRange.VERSION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.VersionRange.VERSION"
+    ${build_generator_args}
+    --build-project TestVersionRange
+    --build-options ${build_options} -DPython=Python -DPython_REQUESTED_VERSION=2
+                                     -DPython_FIND_STRATEGY=VERSION
+    )
+
+  add_test(NAME FindPython.Python2Embedded COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/Python2Embedded"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python2Embedded"
+    ${build_generator_args}
+    --build-project TestPython2Embedded
+    --build-options ${build_options}
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+endif()
+
+if(CMake_TEST_FindPython3)
   add_test(NAME FindPython.Python3.LOCATION COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -89,46 +212,6 @@
   set_tests_properties(FindPython.Python3Fail PROPERTIES
     PASS_REGULAR_EXPRESSION "Could NOT find Python3 \\(missing: foobar\\)")
 
-  add_test(NAME FindPython.Python.LOCATION COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
-    "${CMake_BINARY_DIR}/Tests/FindPython/Python.LOCATION"
-    ${build_generator_args}
-    --build-project TestPython
-    --build-options ${build_options} -DPython_FIND_STRATEGY=LOCATION
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
-  add_test(NAME FindPython.Python.VERSION COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
-    "${CMake_BINARY_DIR}/Tests/FindPython/Python.VERSION"
-    ${build_generator_args}
-    --build-project TestPython
-    --build-options ${build_options} -DPython_FIND_STRATEGY=VERSION
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
-  add_test(NAME FindPython.Python.V2.LOCATION COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
-    "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.LOCATION"
-    ${build_generator_args}
-    --build-project TestPython
-    --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_FIND_STRATEGY=LOCATION
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
-  add_test(NAME FindPython.Python.V2.VERSION COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
-    "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.VERSION"
-    ${build_generator_args}
-    --build-project TestPython
-    --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_FIND_STRATEGY=VERSION
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
   add_test(NAME FindPython.Python.V3.LOCATION COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -150,30 +233,6 @@
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
 
-  add_test(NAME FindPython.Python2.ExactVersion.LOCATION COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/ExactVersion"
-    "${CMake_BINARY_DIR}/Tests/FindPython/Python2.ExactVersion.LOCATION"
-    ${build_generator_args}
-    --build-project TestExactVersion
-    --build-options ${build_options} -DPython_MAJOR_VERSION=2
-                                     -DPython_REQUESTED_VERSION=2.1.2
-                                     -DPython2_FIND_STRATEGY=LOCATION
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
-  add_test(NAME FindPython.Python2.ExactVersion.VERSION COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/ExactVersion"
-    "${CMake_BINARY_DIR}/Tests/FindPython/Python2.ExactVersion.VERSION"
-    ${build_generator_args}
-    --build-project TestExactVersion
-    --build-options ${build_options} -DPython_MAJOR_VERSION=2
-                                     -DPython_REQUESTED_VERSION=2.1.2
-                                     -DPython2_FIND_STRATEGY=VERSION
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
   add_test(NAME FindPython.Python3.ExactVersion.LOCATION COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -198,28 +257,6 @@
                                      -DPython3_FIND_STRATEGY=VERSION
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
-  add_test(NAME FindPython.Python.V2.ExactVersion.LOCATION COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/ExactVersion"
-    "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.ExactVersion.LOCATION"
-    ${build_generator_args}
-    --build-project TestExactVersion
-    --build-options ${build_options} -DPython_REQUESTED_VERSION=2.1.2
-                                     -DPython_FIND_STRATEGY=LOCATION
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
-  add_test(NAME FindPython.Python.V2.ExactVersion.VERSION COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/ExactVersion"
-    "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.ExactVersion.VERSION"
-    ${build_generator_args}
-    --build-project TestExactVersion
-    --build-options ${build_options} -DPython_REQUESTED_VERSION=2.1.2
-                                     -DPython_FIND_STRATEGY=VERSION
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
   add_test(NAME FindPython.Python.V3.ExactVersion.LOCATION COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -263,46 +300,6 @@
     --build-options ${build_options} -DPython=Python3 -DPython_REQUESTED_VERSION=3
                                      -DPython3_FIND_STRATEGY=VERSION
     )
-  add_test(NAME FindPython.Python2.VersionRange.LOCATION COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
-    "${CMake_BINARY_DIR}/Tests/FindPython/Python2.VersionRange.LOCATION"
-    ${build_generator_args}
-    --build-project TestVersionRange
-    --build-options ${build_options} -DPython=Python2 -DPython_REQUESTED_VERSION=2
-                                     -DPython2_FIND_STRATEGY=LOCATION
-    )
-  add_test(NAME FindPython.Python2.VersionRange.VERSION COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
-    "${CMake_BINARY_DIR}/Tests/FindPython/Python2.VersionRange.VERSION"
-    ${build_generator_args}
-    --build-project TestVersionRange
-    --build-options ${build_options} -DPython=Python2 -DPython_REQUESTED_VERSION=2
-                                     -DPython2_FIND_STRATEGY=VERSION
-    )
-  add_test(NAME FindPython.Python.V2.VersionRange.LOCATION COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
-    "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.VersionRange.LOCATION"
-    ${build_generator_args}
-    --build-project TestVersionRange
-    --build-options ${build_options} -DPython=Python -DPython_REQUESTED_VERSION=2
-                                     -DPython_FIND_STRATEGY=LOCATION
-    )
-  add_test(NAME FindPython.Python.V2.VersionRange.VERSION COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/VersionRange"
-    "${CMake_BINARY_DIR}/Tests/FindPython/Python.V2.VersionRange.VERSION"
-    ${build_generator_args}
-    --build-project TestVersionRange
-    --build-options ${build_options} -DPython=Python -DPython_REQUESTED_VERSION=2
-                                     -DPython_FIND_STRATEGY=VERSION
-    )
   add_test(NAME FindPython.Python.V3.VersionRange.LOCATION COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -324,17 +321,6 @@
                                      -DPython_FIND_STRATEGY=VERSION
     )
 
-  add_test(NAME FindPython.MultiplePackages COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/MultiplePackages"
-    "${CMake_BINARY_DIR}/Tests/FindPython/MultiplePackages"
-    ${build_generator_args}
-    --build-project TestMultiplePackages
-    --build-options ${build_options}
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
-
   add_test(NAME FindPython.VirtualEnv COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -346,16 +332,6 @@
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
 
-  add_test(NAME FindPython.Python2Embedded COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/Python2Embedded"
-    "${CMake_BINARY_DIR}/Tests/FindPython/Python2Embedded"
-    ${build_generator_args}
-    --build-project TestPython2Embedded
-    --build-options ${build_options}
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
   add_test(NAME FindPython.Python3Embedded COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -377,7 +353,7 @@
     --build-options ${build_options} "-Dbuild_generator_args=${build_generator_args}"
     "-DCMake_SOURCE_DIR=${CMake_SOURCE_DIR}"
     "-DCMake_BINARY_DIR=${CMake_BINARY_DIR}"
-    "-DCMake_TEST_FindPython_SABIModule=${CMake_TEST_FindPython_SABIModule}"
+    "-DCMake_TEST_FindPython3_SABIModule=${CMake_TEST_FindPython3_SABIModule}"
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
 
@@ -391,7 +367,7 @@
     --build-options ${build_options} "-Dbuild_generator_args=${build_generator_args}"
     "-DCMake_SOURCE_DIR=${CMake_SOURCE_DIR}"
     "-DCMake_BINARY_DIR=${CMake_BINARY_DIR}"
-    "-DCMake_TEST_FindPython_NumPy=${CMake_TEST_FindPython_NumPy}"
+    "-DCMake_TEST_FindPython3_NumPy=${CMake_TEST_FindPython3_NumPy}"
     "-DPython3_ARTIFACTS_INTERACTIVE=ON"
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
@@ -405,7 +381,7 @@
     --build-options ${build_options} "-Dbuild_generator_args=${build_generator_args}"
     "-DCMake_SOURCE_DIR=${CMake_SOURCE_DIR}"
     "-DCMake_BINARY_DIR=${CMake_BINARY_DIR}"
-    "-DCMake_TEST_FindPython_NumPy=${CMake_TEST_FindPython_NumPy}"
+    "-DCMake_TEST_FindPython3_NumPy=${CMake_TEST_FindPython3_NumPy}"
     "-DPython3_ARTIFACTS_INTERACTIVE=OFF"
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
@@ -420,7 +396,7 @@
     --build-options ${build_options} "-Dbuild_generator_args=${build_generator_args}"
     "-DCMake_SOURCE_DIR=${CMake_SOURCE_DIR}"
     "-DCMake_BINARY_DIR=${CMake_BINARY_DIR}"
-    "-DCMake_TEST_FindPython_NumPy=${CMake_TEST_FindPython_NumPy}"
+    "-DCMake_TEST_FindPython3_NumPy=${CMake_TEST_FindPython3_NumPy}"
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
 
@@ -437,6 +413,41 @@
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
 
+  if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
+    add_test(NAME FindPython.UnversionedNames COMMAND
+      ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+      --build-and-test
+      "${CMake_SOURCE_DIR}/Tests/FindPython/UnversionedNames"
+      "${CMake_BINARY_DIR}/Tests/FindPython/UnversionedNames"
+      ${build_generator_args}
+      --build-project UnversionedNames
+      --build-options ${build_options}
+    )
+  endif()
+endif()
+
+if(CMake_TEST_FindPython2 OR CMake_TEST_FindPython3)
+  add_test(NAME FindPython.Python.LOCATION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python.LOCATION"
+    ${build_generator_args}
+    --build-project TestPython
+    --build-options ${build_options} -DPython_FIND_STRATEGY=LOCATION
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+  add_test(NAME FindPython.Python.VERSION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/Python"
+    "${CMake_BINARY_DIR}/Tests/FindPython/Python.VERSION"
+    ${build_generator_args}
+    --build-project TestPython
+    --build-options ${build_options} -DPython_FIND_STRATEGY=VERSION
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+
   if (CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin")
     add_test(NAME FindPython.Interpreter.SOABI COMMAND
       ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
@@ -466,20 +477,20 @@
       )
   endif()
 
-  if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
-    add_test(NAME FindPython.UnversionedNames COMMAND
-      ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-      --build-and-test
-      "${CMake_SOURCE_DIR}/Tests/FindPython/UnversionedNames"
-      "${CMake_BINARY_DIR}/Tests/FindPython/UnversionedNames"
-      ${build_generator_args}
-      --build-project UnversionedNames
-      --build-options ${build_options}
+  add_test(NAME FindPython.MultiplePackages COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/MultiplePackages"
+    "${CMake_BINARY_DIR}/Tests/FindPython/MultiplePackages"
+    ${build_generator_args}
+    --build-project TestMultiplePackages
+    --build-options ${build_options}
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
-  endif()
 endif()
 
-if(CMake_TEST_FindPython_SABIModule)
+
+if(CMake_TEST_FindPython2_SABIModule)
   add_test(NAME FindPython.Python2.Development.SABIModule COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -492,7 +503,9 @@
     )
     set_tests_properties(FindPython.Python2.Development.SABIModule PROPERTIES
       PASS_REGULAR_EXPRESSION "Could NOT find Python2 \\(missing: .*Development\\.SABIModule")
+endif()
 
+if(CMake_TEST_FindPython3_SABIModule)
   # Use exclusively Release configuration because Debug is, on Windows with MSVC,
   # unusable with SABI: Python force link with debug version of full versioned library rather than
   # the stable ABI one.
@@ -508,7 +521,7 @@
     )
 endif()
 
-if(CMake_TEST_FindPython_NumPy)
+if(CMake_TEST_FindPython2_NumPy OR CMake_TEST_FindPython3_NumPy)
   add_test(NAME FindPython.NumPy COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -530,7 +543,7 @@
   )
 endif()
 
-if(CMake_TEST_FindPython_Conda)
+if(CMake_TEST_FindPython3_Conda)
   add_test(NAME FindPython.VirtualEnvConda COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -543,7 +556,7 @@
     )
 endif()
 
-if (CMake_TEST_FindPython AND CMake_TEST_FindPython_IronPython)
+if (CMake_TEST_FindPython2 AND CMake_TEST_FindPython2_IronPython)
   add_test(NAME FindPython.Implementation.CPython COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -566,7 +579,7 @@
     )
 endif()
 
-if(CMake_TEST_FindPython_IronPython)
+if(CMake_TEST_FindPython2_IronPython)
   add_test(NAME FindPython.IronPython2.LOCATION COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -653,7 +666,7 @@
     )
 endif()
 
-if(CMake_TEST_FindPython_PyPy)
+if(CMake_TEST_FindPython2_PyPy)
   add_test(NAME FindPython.PyPy2.LOCATION COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -675,6 +688,29 @@
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
 
+  add_test(NAME FindPython.PyPy.V2.LOCATION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy"
+    "${CMake_BINARY_DIR}/Tests/FindPython/PyPy.V2.LOCATION"
+    ${build_generator_args}
+    --build-project TestPyPy
+    --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_FIND_STRATEGY=LOCATION
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+  add_test(NAME FindPython.PyPy.V2.VERSION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy"
+    "${CMake_BINARY_DIR}/Tests/FindPython/PyPy.V2.VERSION"
+    ${build_generator_args}
+    --build-project TestPyPy
+    --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_FIND_STRATEGY=VERSION
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+endif()
+
+if(CMake_TEST_FindPython3_PyPy)
   add_test(NAME FindPython.PyPy3.LOCATION COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -696,46 +732,6 @@
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
 
-  add_test(NAME FindPython.PyPy.LOCATION COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy"
-    "${CMake_BINARY_DIR}/Tests/FindPython/PyPy.LOCATION"
-    ${build_generator_args}
-    --build-project TestPyPy
-    --build-options ${build_options} -DPython_FIND_STRATEGY=LOCATION
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
-  add_test(NAME FindPython.PyPy.VERSION COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy"
-    "${CMake_BINARY_DIR}/Tests/FindPython/PyPy.VERSION"
-    ${build_generator_args}
-    --build-project TestPyPy
-    --build-options ${build_options} -DPython_FIND_STRATEGY=VERSION
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
-  add_test(NAME FindPython.PyPy.V2.LOCATION COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy"
-    "${CMake_BINARY_DIR}/Tests/FindPython/PyPy.V2.LOCATION"
-    ${build_generator_args}
-    --build-project TestPyPy
-    --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_FIND_STRATEGY=LOCATION
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
-  add_test(NAME FindPython.PyPy.V2.VERSION COMMAND
-    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-    --build-and-test
-    "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy"
-    "${CMake_BINARY_DIR}/Tests/FindPython/PyPy.V2.VERSION"
-    ${build_generator_args}
-    --build-project TestPyPy
-    --build-options ${build_options} -DPython_REQUESTED_VERSION=2 -DPython_FIND_STRATEGY=VERSION
-    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-    )
   add_test(NAME FindPython.PyPy.V3.LOCATION COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -757,3 +753,26 @@
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
 endif()
+
+if(CMake_TEST_FindPython2_PyPy OR CMake_TEST_FindPython3_PyPy)
+  add_test(NAME FindPython.PyPy.LOCATION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy"
+    "${CMake_BINARY_DIR}/Tests/FindPython/PyPy.LOCATION"
+    ${build_generator_args}
+    --build-project TestPyPy
+    --build-options ${build_options} -DPython_FIND_STRATEGY=LOCATION
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+  add_test(NAME FindPython.PyPy.VERSION COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/PyPy"
+    "${CMake_BINARY_DIR}/Tests/FindPython/PyPy.VERSION"
+    ${build_generator_args}
+    --build-project TestPyPy
+    --build-options ${build_options} -DPython_FIND_STRATEGY=VERSION
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+endif()
diff --git a/Tests/FindPython/CustomFailureMessage/CMakeLists.txt b/Tests/FindPython/CustomFailureMessage/CMakeLists.txt
index 283aeec..e0148f3 100644
--- a/Tests/FindPython/CustomFailureMessage/CMakeLists.txt
+++ b/Tests/FindPython/CustomFailureMessage/CMakeLists.txt
@@ -62,7 +62,7 @@
   PASS_REGULAR_EXPRESSION "Reason given by package:.+Interpreter: Cannot run the interpreter.+Development: Cannot find the library")
 
 
-if (CMake_TEST_FindPython_NumPy)
+if (CMake_TEST_FindPython3_NumPy)
   add_test(NAME FindPython.CustomFailureMessage.NumPy COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
diff --git a/Tests/FindPython/MultiplePackages/CMakeLists.txt b/Tests/FindPython/MultiplePackages/CMakeLists.txt
index 4845035..352a2f6f 100644
--- a/Tests/FindPython/MultiplePackages/CMakeLists.txt
+++ b/Tests/FindPython/MultiplePackages/CMakeLists.txt
@@ -2,32 +2,44 @@
 
 project(TestMultiplePackages C)
 
-find_package (Python2 REQUIRED COMPONENTS Interpreter Development)
-find_package (Python3 REQUIRED COMPONENTS Interpreter Development)
-
-# Must find Python 3
 find_package (Python REQUIRED)
 
-if (NOT Python3_EXECUTABLE STREQUAL Python_EXECUTABLE)
-  message (FATAL_ERROR
-    "Python interpreters do not match:\n"
-    "  Python_EXECUTABLE='${Python_EXECUTABLE}'\n"
-    "  Python3_EXECUTABLE='${Python3_EXECUTABLE}'\n"
+if (CMake_TEST_FindPython2)
+  find_package (Python2 REQUIRED COMPONENTS Interpreter Development)
+
+  if (NOT CMake_TEST_FindPython3 AND NOT Python2_EXECUTABLE STREQUAL Python_EXECUTABLE)
+    message (FATAL_ERROR
+      "Python interpreters do not match:\n"
+      "  Python_EXECUTABLE='${Python_EXECUTABLE}'\n"
+      "  Python2_EXECUTABLE='${Python3_EXECUTABLE}'\n"
     )
+  endif()
+
+  Python2_add_library (spam2 MODULE ../spam.c)
+  target_compile_definitions (spam2 PRIVATE PYTHON2)
+
+  add_test (NAME python2_spam2
+            COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:spam3>"
+            "${Python2_EXECUTABLE}" -c "import spam2; spam2.system(\"cd\")")
+
 endif()
 
+if (CMake_TEST_FindPython3)
+  find_package (Python3 REQUIRED COMPONENTS Interpreter Development)
 
-Python2_add_library (spam2 MODULE ../spam.c)
-target_compile_definitions (spam2 PRIVATE PYTHON2)
+  if (NOT Python3_EXECUTABLE STREQUAL Python_EXECUTABLE)
+    message (FATAL_ERROR
+      "Python interpreters do not match:\n"
+      "  Python_EXECUTABLE='${Python_EXECUTABLE}'\n"
+      "  Python3_EXECUTABLE='${Python3_EXECUTABLE}'\n"
+    )
+  endif()
 
-Python3_add_library (spam3 MODULE ../spam.c)
-target_compile_definitions (spam3 PRIVATE PYTHON3)
+  Python3_add_library (spam3 MODULE ../spam.c)
+  target_compile_definitions (spam3 PRIVATE PYTHON3)
 
+  add_test (NAME python3_spam3
+            COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:spam3>"
+            "${Python3_EXECUTABLE}" -c "import spam3; spam3.system(\"cd\")")
 
-add_test (NAME python2_spam2
-          COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:spam3>"
-          "${Python2_EXECUTABLE}" -c "import spam2; spam2.system(\"cd\")")
-
-add_test (NAME python3_spam3
-          COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:spam3>"
-          "${Python3_EXECUTABLE}" -c "import spam3; spam3.system(\"cd\")")
+endif()
diff --git a/Tests/FindPython/NumPy/CMakeLists.txt b/Tests/FindPython/NumPy/CMakeLists.txt
index 9920336..336bb83 100644
--- a/Tests/FindPython/NumPy/CMakeLists.txt
+++ b/Tests/FindPython/NumPy/CMakeLists.txt
@@ -2,21 +2,30 @@
 
 project(TestNumPy LANGUAGES C)
 
-find_package (Python2 REQUIRED COMPONENTS Interpreter Development NumPy)
-find_package (Python3 REQUIRED COMPONENTS Interpreter Development NumPy)
+if(CMake_TEST_FindPython2_NumPy)
 
-Python2_add_library (arraytest2 MODULE arraytest.c)
-target_compile_definitions (arraytest2 PRIVATE PYTHON2)
-target_link_libraries (arraytest2 PRIVATE Python2::NumPy)
+  find_package (Python2 REQUIRED COMPONENTS Interpreter Development NumPy)
 
-Python3_add_library (arraytest3 MODULE arraytest.c)
-target_compile_definitions (arraytest3 PRIVATE PYTHON3)
-target_link_libraries (arraytest3 PRIVATE Python3::NumPy)
+  Python2_add_library (arraytest2 MODULE arraytest.c)
+  target_compile_definitions (arraytest2 PRIVATE PYTHON2)
+  target_link_libraries (arraytest2 PRIVATE Python2::NumPy)
 
-add_test (NAME python2_arraytest
-          COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:arraytest2>"
-          "${Python2_EXECUTABLE}" -c "import numpy; import arraytest2; arraytest2.vecsq(numpy.array([1, 2, 3]));")
+  add_test (NAME python2_arraytest
+    COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:arraytest2>"
+    "${Python2_EXECUTABLE}" -c "import numpy; import arraytest2; arraytest2.vecsq(numpy.array([1, 2, 3]));")
 
-add_test (NAME python3_arraytest
-          COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:arraytest3>"
-          "${Python3_EXECUTABLE}" -c "import numpy; import arraytest3; arraytest3.vecsq(numpy.array([1, 2, 3]));")
+endif()
+
+if(CMake_TEST_FindPython3_NumPy)
+
+  find_package (Python3 REQUIRED COMPONENTS Interpreter Development NumPy)
+
+  Python3_add_library (arraytest3 MODULE arraytest.c)
+  target_compile_definitions (arraytest3 PRIVATE PYTHON3)
+  target_link_libraries (arraytest3 PRIVATE Python3::NumPy)
+
+  add_test (NAME python3_arraytest
+    COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:arraytest3>"
+    "${Python3_EXECUTABLE}" -c "import numpy; import arraytest3; arraytest3.vecsq(numpy.array([1, 2, 3]));")
+
+endif()
diff --git a/Tests/FindPython/NumPyOnly/CMakeLists.txt b/Tests/FindPython/NumPyOnly/CMakeLists.txt
index 9aa1bcf..115cf2b 100644
--- a/Tests/FindPython/NumPyOnly/CMakeLists.txt
+++ b/Tests/FindPython/NumPyOnly/CMakeLists.txt
@@ -2,13 +2,23 @@
 
 project(TestNumPyOnly LANGUAGES C)
 
-find_package(Python2 REQUIRED COMPONENTS NumPy)
-find_package(Python3 REQUIRED COMPONENTS NumPy)
+if(CMake_TEST_FindPython2_NumPy)
 
-Python2_add_library (arraytest2 MODULE ../NumPy/arraytest.c)
-target_compile_definitions (arraytest2 PRIVATE PYTHON2)
-target_link_libraries (arraytest2 PRIVATE Python2::NumPy)
+  find_package(Python2 REQUIRED COMPONENTS NumPy)
+
+  Python2_add_library (arraytest2 MODULE ../NumPy/arraytest.c)
+  target_compile_definitions (arraytest2 PRIVATE PYTHON2)
+  target_link_libraries (arraytest2 PRIVATE Python2::NumPy)
+
+endif()
+
+
+if(CMake_TEST_FindPython3_NumPy)
+
+find_package(Python3 REQUIRED COMPONENTS NumPy)
 
 Python3_add_library (arraytest3 MODULE ../NumPy/arraytest.c)
 target_compile_definitions (arraytest3 PRIVATE PYTHON3)
 target_link_libraries (arraytest3 PRIVATE Python3::NumPy)
+
+endif()
diff --git a/Tests/FindPython/RequiredArtifacts/CMakeLists.txt b/Tests/FindPython/RequiredArtifacts/CMakeLists.txt
index cb9d4d3..eec28a5 100644
--- a/Tests/FindPython/RequiredArtifacts/CMakeLists.txt
+++ b/Tests/FindPython/RequiredArtifacts/CMakeLists.txt
@@ -4,13 +4,20 @@
 
 include(CTest)
 
-find_package(Python2 REQUIRED COMPONENTS Interpreter Development)
-if (NOT Python2_FOUND)
-  message (FATAL_ERROR "Failed to find Python 2")
+if(CMake_TEST_FindPython2)
+  find_package(Python2 REQUIRED COMPONENTS Interpreter Development)
+  if (NOT Python2_FOUND)
+    message (FATAL_ERROR "Failed to find Python 2")
+  endif()
+  set(USER_LIBRARY "${Python2_LIBRARY_RELEASE}")
+  set(USER_INCLUDE_DIR "${Python2_INCLUDE_DIRS}")
+else()
+  set(USER_LIBRARY "/path/to/invalid${CMAKE_C_LINK_LIBRARY_SUFFIX}")
+  set(USER_INCLUDE_DIR "/path/to/invalid/dir")
 endif()
 
 set(components Interpreter Development)
-if (CMake_TEST_FindPython_SABIModule AND WIN32)
+if (CMake_TEST_FindPython3_SABIModule AND WIN32)
   list (APPEND components Development.SABIModule)
 endif()
 find_package(Python3 REQUIRED COMPONENTS ${components})
@@ -61,7 +68,7 @@
   ${build_generator_args}
   --build-project TestRequiredArtifacts.Check
   --build-options -DPYTHON_IS_FOUND=FALSE -DCHECK_LIBRARY=ON
-                  "-DPython3_LIBRARY=${Python2_LIBRARY_RELEASE}"
+                  "-DPython3_LIBRARY=${USER_LIBRARY}"
   --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
   )
 
@@ -84,7 +91,7 @@
   ${build_generator_args}
   --build-project TestRequiredArtifacts.Check
   --build-options -DPYTHON_IS_FOUND=FALSE -DCHECK_INCLUDE=ON
-                  "-DPython3_INCLUDE_DIR=${Python2_INCLUDE_DIRS}"
+                  "-DPython3_INCLUDE_DIR=${USER_INCLUDE_DIR}"
   --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
   )
 
@@ -97,7 +104,7 @@
   --build-project TestRequiredArtifacts.Check
   --build-options -DPYTHON_IS_FOUND=FALSE -DCHECK_INTERPRETER=ON -DCHECK_LIBRARY=ON
                   "-DPython3_EXECUTABLE=${Python3_EXECUTABLE}"
-                  "-DPython3_LIBRARY=${Python2_LIBRARY_RELEASE}"
+                  "-DPython3_LIBRARY=${USER_LIBRARY}"
   --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
   )
 
@@ -110,11 +117,11 @@
   --build-project TestRequiredArtifacts.Check
   --build-options -DPYTHON_IS_FOUND=FALSE -DCHECK_LIBRARY=ON -DCHECK_INCLUDE=ON
                   "-DPython3_LIBRARY=${Python3_LIBRARY_RELEASE}"
-                  "-DPython3_INCLUDE_DIR=${Python2_INCLUDE_DIRS}"
+                  "-DPython3_INCLUDE_DIR=${USER_INCLUDE_DIR}"
   --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
   )
 
-if (CMake_TEST_FindPython_SABIModule AND WIN32)
+if (CMake_TEST_FindPython3_SABIModule AND WIN32)
   add_test(NAME FindPython.RequiredArtifacts.SABILibrary.VALID COMMAND
     ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
     --build-and-test
@@ -134,7 +141,7 @@
     ${build_generator_args}
     --build-project TestRequiredArtifacts.Check
     --build-options -DPYTHON_IS_FOUND=FALSE -DCHECK_SABI_LIBRARY=ON
-    "-DPython3_SABI_LIBRARY=${Python2_LIBRARY_RELEASE}"
+    "-DPython3_SABI_LIBRARY=${USER_LIBRARY}"
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
   )
 endif()
diff --git a/Tests/FindPython/SOABI/CMakeLists.txt b/Tests/FindPython/SOABI/CMakeLists.txt
index 60399d3..6c0e9a9 100644
--- a/Tests/FindPython/SOABI/CMakeLists.txt
+++ b/Tests/FindPython/SOABI/CMakeLists.txt
@@ -2,37 +2,40 @@
 
 project(TestSOABI LANGUAGES C)
 
-find_package(Python3 COMPONENTS ${CMake_TEST_FindPython_COMPONENT})
-if (NOT Python3_FOUND)
-  message (FATAL_ERROR "Failed to find Python 3")
-endif()
+if(CMake_TEST_FindPython3)
+  find_package(Python3 COMPONENTS ${CMake_TEST_FindPython_COMPONENT})
+  if (NOT Python3_FOUND)
+    message (FATAL_ERROR "Failed to find Python 3")
+  endif()
 
-if(NOT DEFINED Python3_SOABI)
-  message(FATAL_ERROR "Python3_SOABI for ${CMake_TEST_FindPython_COMPONENT} not found")
-endif()
+  if(NOT DEFINED Python3_SOABI)
+    message(FATAL_ERROR "Python3_SOABI for ${CMake_TEST_FindPython_COMPONENT} not found")
+  endif()
 
-if (Python3_Development_FOUND AND Python3_SOABI)
-  Python3_add_library (spam3 MODULE WITH_SOABI ../spam.c)
-  target_compile_definitions (spam3 PRIVATE PYTHON3)
+  if (Python3_Development_FOUND AND Python3_SOABI)
+    Python3_add_library (spam3 MODULE WITH_SOABI ../spam.c)
+    target_compile_definitions (spam3 PRIVATE PYTHON3)
 
-  get_property (suffix TARGET spam3 PROPERTY SUFFIX)
-  if (NOT suffix MATCHES "^.${Python3_SOABI}")
-    message(FATAL_ERROR "Module suffix do not include Python3_SOABI")
+    get_property (suffix TARGET spam3 PROPERTY SUFFIX)
+    if (NOT suffix MATCHES "^.${Python3_SOABI}")
+      message(FATAL_ERROR "Module suffix do not include Python3_SOABI")
+    endif()
   endif()
 endif()
 
+if(CMake_TEST_FindPython2)
+  find_package(Python2 COMPONENTS ${CMake_TEST_FindPython_COMPONENT})
+  if(NOT DEFINED Python2_SOABI)
+    message(FATAL_ERROR "Python2_SOABI for ${CMake_TEST_FindPython_COMPONENT} not found")
+  endif()
 
-find_package(Python2 COMPONENTS ${CMake_TEST_FindPython_COMPONENT})
-if(NOT DEFINED Python2_SOABI)
-  message(FATAL_ERROR "Python2_SOABI for ${CMake_TEST_FindPython_COMPONENT} not found")
-endif()
+  if (Python2_Development_FOUND AND Python2_SOABI)
+    Python2_add_library (spam2 MODULE WITH_SOABI ../spam.c)
+    target_compile_definitions (spam2 PRIVATE PYTHON2)
 
-if (Python2_Development_FOUND AND Python2_SOABI)
-  Python2_add_library (spam2 MODULE WITH_SOABI ../spam.c)
-  target_compile_definitions (spam2 PRIVATE PYTHON2)
-
-  get_property (suffix TARGET spam2 PROPERTY SUFFIX)
-  if (NOT suffix MATCHES "^.${Python2_SOABI}")
-    message(FATAL_ERROR "Module suffix do not include Python2_SOABI")
+    get_property (suffix TARGET spam2 PROPERTY SUFFIX)
+    if (NOT suffix MATCHES "^.${Python2_SOABI}")
+      message(FATAL_ERROR "Module suffix do not include Python2_SOABI")
+    endif()
   endif()
 endif()
diff --git a/Tests/FindPython/VirtualEnv/CMakeLists.txt b/Tests/FindPython/VirtualEnv/CMakeLists.txt
index e2e5bd2..ea742ea 100644
--- a/Tests/FindPython/VirtualEnv/CMakeLists.txt
+++ b/Tests/FindPython/VirtualEnv/CMakeLists.txt
@@ -27,21 +27,23 @@
                  "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
                  -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvDefault.cmake")
 
-add_test(NAME FindPython3.VirtualEnvOnly
-         COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
-                                           --unset=CONDA_PREFIX
-                                           "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
-                 "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
-                 -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
-add_test(NAME FindPython3.UnsetVirtualEnvOnly
-         COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
-                                           --unset=VIRTUAL_ENV
-                                           --unset=CONDA_PREFIX
-                 "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
-
 add_test(NAME FindPython3.VirtualEnvStandard
          COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
                                            --unset=CONDA_PREFIX
                                            "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
                  "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
                  -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvStandard.cmake")
+
+if(CMake_TEST_FindPython2)
+  add_test(NAME FindPython3.VirtualEnvOnly
+           COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+                                             --unset=CONDA_PREFIX
+                                             "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+                   "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+                   -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
+  add_test(NAME FindPython3.UnsetVirtualEnvOnly
+           COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+                                             --unset=VIRTUAL_ENV
+                                             --unset=CONDA_PREFIX
+                   "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
+endif()
diff --git a/Tests/FindPython/VirtualEnvConda/CMakeLists.txt b/Tests/FindPython/VirtualEnvConda/CMakeLists.txt
index 2f7c0db..3a64c31 100644
--- a/Tests/FindPython/VirtualEnvConda/CMakeLists.txt
+++ b/Tests/FindPython/VirtualEnvConda/CMakeLists.txt
@@ -26,21 +26,23 @@
                  "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
                  -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvDefault.cmake")
 
-add_test(NAME FindPython3.VirtualEnvOnlyConda
-         COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
-                                           --unset=VIRTUAL_ENV
-                                           "CONDA_PREFIX=${Python3_VIRTUAL_ENV}"
-                 "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
-                 -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
-add_test(NAME FindPython3.UnsetVirtualEnvOnlyConda
-         COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
-                                           --unset=CONDA_PREFIX
-                                           --unset=VIRTUAL_ENV
-                 "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
-
 add_test(NAME FindPython3.VirtualEnvStandardConda
          COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
                                            --unset=VIRTUAL_ENV
                                            "CONDA_PREFIX=${Python3_VIRTUAL_ENV}"
                  "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
                  -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvStandard.cmake")
+
+if(Cmake_TEST_FindPython2)
+  add_test(NAME FindPython3.VirtualEnvOnlyConda
+           COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+                                             --unset=VIRTUAL_ENV
+                                             "CONDA_PREFIX=${Python3_VIRTUAL_ENV}"
+                   "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+                   -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
+  add_test(NAME FindPython3.UnsetVirtualEnvOnlyConda
+           COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+                                             --unset=CONDA_PREFIX
+                                             --unset=VIRTUAL_ENV
+                   "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
+endif()
diff --git a/Tests/RunCMake/BuildDepends/LinkDependsCheck.cmake b/Tests/RunCMake/BuildDepends/LinkDependsCheck.cmake
index a21096b..596e1eb 100644
--- a/Tests/RunCMake/BuildDepends/LinkDependsCheck.cmake
+++ b/Tests/RunCMake/BuildDepends/LinkDependsCheck.cmake
@@ -2,7 +2,8 @@
 enable_language(C)
 
 file(WRITE "${CMAKE_BINARY_DIR}/LinkDependsUseLinker.cmake"
-     "set(CMAKE_C_LINK_DEPENDS_USE_LINKER \"${CMAKE_C_LINK_DEPENDS_USE_LINKER}\")\n")
+     "set(CMAKE_LINK_DEPENDS_USE_LINKER ${CMAKE_LINK_DEPENDS_USE_LINKER})
+set(CMAKE_C_LINK_DEPENDS_USE_LINKER ${CMAKE_C_LINK_DEPENDS_USE_LINKER})\n")
 
 
 file(GENERATE  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake"
diff --git a/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake b/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake
index dfa4f49..fada37a 100644
--- a/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake
+++ b/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake
@@ -199,12 +199,12 @@
 run_BuildDepends(CustomCommandUnityBuild)
 unset(run_BuildDepends_skip_step_2)
 
-#if (RunCMake_GENERATOR MATCHES "Make|Ninja" AND CMAKE_C_LINK_DEPENDS_USE_LINKER)
 if (RunCMake_GENERATOR MATCHES "Make|Ninja")
   set(run_BuildDepends_skip_step_2 1)
   run_BuildDepends(LinkDependsCheck)
   include("${RunCMake_BINARY_DIR}/LinkDependsCheck-build/LinkDependsUseLinker.cmake")
-  if (CMAKE_C_LINK_DEPENDS_USE_LINKER)
+  if ((NOT DEFINED CMAKE_LINK_DEPENDS_USE_LINKER OR CMAKE_LINK_DEPENDS_USE_LINKER)
+      AND CMAKE_C_LINK_DEPENDS_USE_LINKER)
     run_BuildDepends(LinkDependsExternalLibrary)
     unset(run_BuildDepends_skip_step_2)
     run_BuildDepends(LinkDepends)
diff --git a/Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt b/Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt
index 67d00f7..3472f33 100644
--- a/Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt
+++ b/Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt
@@ -1,4 +1,13 @@
-^CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
+^CMake Deprecation Warning at CMakeLists\.txt:[0-9]+ \(cmake_minimum_required\):
+  The OLD behavior for policy CMP0115 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\.
++
+CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\):
   Cannot find source file:
 
     noexist
diff --git a/Tests/RunCMake/CMP0116/CMP0116-Mixed-stderr.txt b/Tests/RunCMake/CMP0116/CMP0116-Mixed-stderr.txt
index 10e83a9..930dd3c 100644
--- a/Tests/RunCMake/CMP0116/CMP0116-Mixed-stderr.txt
+++ b/Tests/RunCMake/CMP0116/CMP0116-Mixed-stderr.txt
@@ -1,4 +1,15 @@
-^CMake Warning \(dev\) at CMP0116-Mixed\.cmake:1 \(add_custom_command\):
+^CMake Deprecation Warning at CMP0116-Mixed\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0116 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 Warning \(dev\) at CMP0116-Mixed\.cmake:1 \(add_custom_command\):
   Policy CMP0116 is not set: Ninja generators transform DEPFILEs from
   add_custom_command\(\)\.  Run "cmake --help-policy CMP0116" for policy
   details\.  Use the cmake_policy command to set the policy and suppress this
diff --git a/Tests/RunCMake/CMP0116/CMP0116-OLD-NOWARN-stderr.txt b/Tests/RunCMake/CMP0116/CMP0116-OLD-NOWARN-stderr.txt
new file mode 100644
index 0000000..887601c
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/CMP0116-OLD-NOWARN-stderr.txt
@@ -0,0 +1,8 @@
+^CMake Deprecation Warning at CMakeLists\.txt:[0-9]+ \(cmake_minimum_required\):
+  The OLD behavior for policy CMP0116 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/CMP0116/CMP0116-OLD-WARN-stderr.txt b/Tests/RunCMake/CMP0116/CMP0116-OLD-WARN-stderr.txt
new file mode 100644
index 0000000..887601c
--- /dev/null
+++ b/Tests/RunCMake/CMP0116/CMP0116-OLD-WARN-stderr.txt
@@ -0,0 +1,8 @@
+^CMake Deprecation Warning at CMakeLists\.txt:[0-9]+ \(cmake_minimum_required\):
+  The OLD behavior for policy CMP0116 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/CMP0118/CMP0118-OLD-Test1-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test1-stderr.txt
index 2af72a4..9285f9d 100644
--- a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test1-stderr.txt
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test1-stderr.txt
@@ -1,4 +1,15 @@
-^prop: `0`
+^CMake Deprecation Warning at CMP0118-OLD-Test1\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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\)
++
+prop: `0`
 CMake Error at CMP0118-Common-Test1\.cmake:[0-9]+ \(target_sources\):
   Cannot find source file:
 
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-stderr.txt
index 6109f65..9bd3d33 100644
--- a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-stderr.txt
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test10-stderr.txt
@@ -1,4 +1,15 @@
-^Generated_source0\.txt: # 1a # GENERATED = `1`
+^CMake Deprecation Warning at CMP0118-OLD-Test10\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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\)
++
+Generated_source0\.txt: # 1a # GENERATED = `1`
 Generated_source0\.txt: # 1b # GENERATED = `1`
 Generated_source0\.txt: # 2a # GENERATED = `1`
 Generated_source0\.txt: # 2b # GENERATED = `1`
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-stderr.txt
index e5e97de..4730caf 100644
--- a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-stderr.txt
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test11-stderr.txt
@@ -1,4 +1,15 @@
-^Generated_source0\.txt: # 1a # GENERATED = `1`
+^CMake Deprecation Warning at CMP0118-OLD-Test11\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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\)
++
+Generated_source0\.txt: # 1a # GENERATED = `1`
 Generated_source0\.txt: # 1b # GENERATED = `1`
 Generated_source0\.txt: # 2a # GENERATED = `1`
 Generated_source0\.txt: # 2b # GENERATED = `1`
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test12-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test12-stderr.txt
index e6c429c..69a07e1 100644
--- a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test12-stderr.txt
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test12-stderr.txt
@@ -1,4 +1,15 @@
-^CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+^CMake Deprecation Warning at CMP0118-OLD-Test12\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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 subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
   TARGET 'custom[4-6]' was not created in this directory\.
 +
 CMake Error at subdir-Common-Test12/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test13-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test13-stderr.txt
index 75dbf23..45c1dcb 100644
--- a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test13-stderr.txt
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test13-stderr.txt
@@ -1,4 +1,15 @@
-^CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
+^CMake Deprecation Warning at CMP0118-OLD-Test13\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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 subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
   TARGET 'custom[4-6]' was not created in this directory\.
 +
 CMake Error at subdir-Common-Test13/CMakeLists\.txt:[0-9]+ \(add_custom_command\):
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-stderr.txt
index f5b3d1a..7ade0cf 100644
--- a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-stderr.txt
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test14-stderr.txt
@@ -1,4 +1,15 @@
-^Generated_source0\.txt: # 1a # GENERATED = `1`
+^CMake Deprecation Warning at CMP0118-OLD-Test14\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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\)
++
+Generated_source0\.txt: # 1a # GENERATED = `1`
 Generated_source0\.txt: # 1b # GENERATED = `1`
 Generated_source0\.txt: # 2a # GENERATED = `1`
 Generated_source0\.txt: # 2b # GENERATED = `1`
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-stderr.txt
index a30bc84..5735539 100644
--- a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-stderr.txt
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test15-stderr.txt
@@ -1,4 +1,15 @@
-^Generated_source0\.txt: # 1a # GENERATED = `1`
+^CMake Deprecation Warning at CMP0118-OLD-Test15\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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\)
++
+Generated_source0\.txt: # 1a # GENERATED = `1`
 Generated_source0\.txt: # 1b # GENERATED = `1`
 Generated_source0\.txt: # 2a # GENERATED = `1`
 Generated_source0\.txt: # 2b # GENERATED = `1`
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test2-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test2-stderr.txt
index 403ce5a..74eb3e1 100644
--- a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test2-stderr.txt
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test2-stderr.txt
@@ -1 +1,12 @@
-^prop: `1`$
+^CMake Deprecation Warning at CMP0118-OLD-Test2\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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\)
++
+prop: `1`$
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3-stderr.txt
index 4f4fea3..cce5b19 100644
--- a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3-stderr.txt
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3-stderr.txt
@@ -1,4 +1,15 @@
-^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+^CMake Deprecation Warning at CMP0118-OLD-Test3\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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\)
++
+Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
 Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
 Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
 Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b-stderr.txt
index 3c80531..47eee2e 100644
--- a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b-stderr.txt
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test3b-stderr.txt
@@ -1,4 +1,15 @@
-^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+^CMake Deprecation Warning at CMP0118-OLD-Test3b\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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\)
++
+Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
 Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
 Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
 Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-stderr.txt
index 9600fee..f17c9be 100644
--- a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-stderr.txt
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4-stderr.txt
@@ -1,4 +1,15 @@
-^Generated_with_full_path1\.txt: # 1a # GENERATED = `0`
+^CMake Deprecation Warning at CMP0118-OLD-Test4\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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\)
++
+Generated_with_full_path1\.txt: # 1a # GENERATED = `0`
 Generated_with_full_path1\.txt: # 1b # GENERATED = `0`
 Generated_with_full_path1\.txt: # 2a # GENERATED = `0`
 Generated_with_full_path1\.txt: # 2b # GENERATED = `0`
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-stderr.txt
index e638660..388e90e 100644
--- a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-stderr.txt
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test4b-stderr.txt
@@ -1,4 +1,15 @@
-^Generated_with_full_path1\.txt: # 1a # GENERATED = `0`
+^CMake Deprecation Warning at CMP0118-OLD-Test4b\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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\)
++
+Generated_with_full_path1\.txt: # 1a # GENERATED = `0`
 Generated_with_full_path1\.txt: # 1b # GENERATED = `0`
 Generated_with_full_path1\.txt: # 2a # GENERATED = `0`
 Generated_with_full_path1\.txt: # 2b # GENERATED = `0`
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-stderr.txt
index 18e6a8c..4a67fa7 100644
--- a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-stderr.txt
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test5-stderr.txt
@@ -1,4 +1,15 @@
-^Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
+^CMake Deprecation Warning at CMP0118-OLD-Test5\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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\)
++
+Generated_with_full_path1\.txt: # 1a # GENERATED = `1`
 Generated_with_full_path1\.txt: # 1b # GENERATED = `1`
 Generated_with_full_path1\.txt: # 2a # GENERATED = `1`
 Generated_with_full_path1\.txt: # 2b # GENERATED = `1`
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-stderr.txt
index a60545f..0cad373 100644
--- a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-stderr.txt
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test6-stderr.txt
@@ -1,4 +1,15 @@
-^Generated_source1\.txt: # 1a # GENERATED = `1`
+^CMake Deprecation Warning at CMP0118-OLD-Test6\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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\)
++
+Generated_source1\.txt: # 1a # GENERATED = `1`
 Generated_source1\.txt: # 1b # GENERATED = `1`
 Generated_source1\.txt: # 2a # GENERATED = `1`
 Generated_source1\.txt: # 2b # GENERATED = `1`
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-stderr.txt
index fd496cb..7f232d5 100644
--- a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-stderr.txt
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test7-stderr.txt
@@ -1,4 +1,15 @@
-^Generated_source1\.txt: # 1a # GENERATED = `1`
+^CMake Deprecation Warning at CMP0118-OLD-Test7\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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\)
++
+Generated_source1\.txt: # 1a # GENERATED = `1`
 Generated_source1\.txt: # 1b # GENERATED = `1`
 Generated_source1\.txt: # 2a # GENERATED = `1`
 Generated_source1\.txt: # 2b # GENERATED = `1`
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-stderr.txt
index 3505242..dd9d2ef 100644
--- a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-stderr.txt
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test8-stderr.txt
@@ -1,4 +1,15 @@
-^Generated_source1\.txt: # 1a # GENERATED = `0`
+^CMake Deprecation Warning at CMP0118-OLD-Test8\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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\)
++
+Generated_source1\.txt: # 1a # GENERATED = `0`
 Generated_source1\.txt: # 1b # GENERATED = `0`
 Generated_source1\.txt: # 2a # GENERATED = `0`
 Generated_source1\.txt: # 2b # GENERATED = `0`
diff --git a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-stderr.txt b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-stderr.txt
index 63a9341..e01f782 100644
--- a/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-stderr.txt
+++ b/Tests/RunCMake/CMP0118/CMP0118-OLD-Test9-stderr.txt
@@ -1,4 +1,15 @@
-^Generated_source1\.txt: # 1a # GENERATED = `0`
+^CMake Deprecation Warning at CMP0118-OLD-Test9\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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\)
++
+Generated_source1\.txt: # 1a # GENERATED = `0`
 Generated_source1\.txt: # 1b # GENERATED = `0`
 Generated_source1\.txt: # 2a # GENERATED = `0`
 Generated_source1\.txt: # 2b # GENERATED = `0`
diff --git a/Tests/RunCMake/CMP0118/GenInSubdir-OLD-stderr.txt b/Tests/RunCMake/CMP0118/GenInSubdir-OLD-stderr.txt
index 5e9cf6c..2fc472b 100644
--- a/Tests/RunCMake/CMP0118/GenInSubdir-OLD-stderr.txt
+++ b/Tests/RunCMake/CMP0118/GenInSubdir-OLD-stderr.txt
@@ -1,4 +1,15 @@
-^CMake Error at GenInSubdir/CMakeLists\.txt:[0-9]+ \(target_sources\):
+^CMake Deprecation Warning at GenInSubdir-OLD\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0118 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 GenInSubdir/CMakeLists\.txt:[0-9]+ \(target_sources\):
   Cannot find source file:
 
     [^
diff --git a/Tests/RunCMake/CMP0119/CMP0119-OLD-stderr.txt b/Tests/RunCMake/CMP0119/CMP0119-OLD-stderr.txt
new file mode 100644
index 0000000..86eac41
--- /dev/null
+++ b/Tests/RunCMake/CMP0119/CMP0119-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0119-OLD\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0119 will be removed from a future version
+  of CMake\.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances\.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index f089a96..a62995a 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -363,7 +363,8 @@
 endif()
 if(CMake_TEST_UseSWIG)
   add_RunCMake_test(FindSWIG)
-  add_RunCMake_test(UseSWIG -DCMake_TEST_FindPython=${CMake_TEST_FindPython})
+  add_RunCMake_test(UseSWIG -DCMake_TEST_FindPython2=${CMake_TEST_FindPython2}
+                            -DCMake_TEST_FindPython3=${CMake_TEST_FindPython3})
 endif()
 if(NOT CMAKE_C_COMPILER_ID MATCHES "Watcom")
   add_RunCMake_test(GenerateExportHeader)
@@ -452,7 +453,7 @@
 add_RunCMake_test(add_dependencies)
 add_RunCMake_test(add_executable)
 add_RunCMake_test(add_library)
-add_RunCMake_test(add_subdirectory)
+add_RunCMake_test(add_subdirectory -DCMAKE_Fortran_COMPILER=${CMAKE_Fortran_COMPILER})
 add_RunCMake_test(add_test)
 add_RunCMake_test(build_command)
 add_executable(exit_code exit_code.c)
diff --git a/Tests/RunCMake/CommandLine/DeprecateVS11-WARN-ON-stderr.txt b/Tests/RunCMake/CommandLine/DeprecateVS11-WARN-ON-stderr.txt
deleted file mode 100644
index 9080942..0000000
--- a/Tests/RunCMake/CommandLine/DeprecateVS11-WARN-ON-stderr.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-^CMake Warning:
-  The "Visual Studio 11 2012" generator is deprecated and will be removed in
-  a future version of CMake.
-
-  Add CMAKE_WARN_VS11=OFF to the cache to disable this warning.$
diff --git a/Tests/RunCMake/CommandLine/DeprecateVS11-WARN-ON.cmake b/Tests/RunCMake/CommandLine/DeprecateVS11-WARN-ON.cmake
deleted file mode 100644
index e69de29..0000000
--- a/Tests/RunCMake/CommandLine/DeprecateVS11-WARN-ON.cmake
+++ /dev/null
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index 45b4c0e..53f13e4 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -1118,10 +1118,3 @@
   run_cmake(DeprecateVS9-WARN-ON)
   run_cmake_with_options(DeprecateVS9-WARN-OFF -DCMAKE_WARN_VS9=OFF)
 endif()
-
-if(RunCMake_GENERATOR MATCHES "^Visual Studio 11 2012")
-  run_cmake_with_options(DeprecateVS11-WARN-ON -DCMAKE_WARN_VS11=ON)
-  unset(ENV{CMAKE_WARN_VS11})
-  run_cmake(DeprecateVS11-WARN-ON)
-  run_cmake_with_options(DeprecateVS11-WARN-OFF -DCMAKE_WARN_VS11=OFF)
-endif()
diff --git a/Tests/RunCMake/CrosscompilingEmulator/EnvCrossCompilingEmulator-stdout.txt b/Tests/RunCMake/CrosscompilingEmulator/EnvCrossCompilingEmulator-stdout.txt
new file mode 100644
index 0000000..9a7d746
--- /dev/null
+++ b/Tests/RunCMake/CrosscompilingEmulator/EnvCrossCompilingEmulator-stdout.txt
@@ -0,0 +1,2 @@
+-- env_emulator='pseudo_emulator(\.exe)?'
+-- emulator='pseudo_emulator(\.exe)?'
diff --git a/Tests/RunCMake/CrosscompilingEmulator/EnvCrossCompilingEmulator.cmake b/Tests/RunCMake/CrosscompilingEmulator/EnvCrossCompilingEmulator.cmake
new file mode 100644
index 0000000..55fc483
--- /dev/null
+++ b/Tests/RunCMake/CrosscompilingEmulator/EnvCrossCompilingEmulator.cmake
@@ -0,0 +1,6 @@
+message(STATUS "ENV{CMAKE_CROSS_COMPILING_EMULATOR}='$ENV{CMAKE_CROSSCOMPILING_EMULATOR}'")
+message(STATUS "CMAKE_CROSSCOMPLING_EMULATOR='${CMAKE_CROSSCOMPILING_EMULATOR}'")
+get_filename_component(env_emulator "$ENV{CMAKE_CROSSCOMPILING_EMULATOR}" NAME)
+message(STATUS "env_emulator='${env_emulator}'")
+get_filename_component(emulator "${CMAKE_CROSSCOMPILING_EMULATOR}" NAME)
+message(STATUS "emulator='${emulator}'")
diff --git a/Tests/RunCMake/CrosscompilingEmulator/RunCMakeTest.cmake b/Tests/RunCMake/CrosscompilingEmulator/RunCMakeTest.cmake
index 97b7b5a..1ffd91c 100644
--- a/Tests/RunCMake/CrosscompilingEmulator/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CrosscompilingEmulator/RunCMakeTest.cmake
@@ -26,3 +26,11 @@
 "-DCMAKE_CROSSCOMPILING_EMULATOR=${PSEUDO_EMULATOR_CUSTOM_COMMAND_ARG}\;custom_argument")
 CustomCommandGenerator_run_and_build(AddCustomCommandWithArg)
 CustomCommandGenerator_run_and_build(AddCustomTargetWithArg)
+unset(RunCMake_TEST_OPTIONS)
+
+function(run_EnvCrossCompilingEmulator)
+  set(ENV{CMAKE_CROSSCOMPILING_EMULATOR} "${PSEUDO_EMULATOR}")
+  run_cmake(EnvCrossCompilingEmulator)
+  unset(ENV{CMAKE_CROSSCOMPILING_EMULATOR})
+endfunction()
+run_EnvCrossCompilingEmulator()
diff --git a/Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-OLD-stderr.txt b/Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-OLD-stderr.txt
new file mode 100644
index 0000000..4499d97
--- /dev/null
+++ b/Tests/RunCMake/MSVCRuntimeTypeInfo/CMP0117-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0117-OLD\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0117 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/Ninja/QtAutoMocDeps-stderr.txt b/Tests/RunCMake/Ninja/QtAutoMocDeps-stderr.txt
new file mode 100644
index 0000000..6024984
--- /dev/null
+++ b/Tests/RunCMake/Ninja/QtAutoMocDeps-stderr.txt
@@ -0,0 +1,8 @@
+^CMake Deprecation Warning at QtSubDir1/CMakeLists\.txt:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0116 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/UseSWIG/RunCMakeTest.cmake b/Tests/RunCMake/UseSWIG/RunCMakeTest.cmake
index c7a118f..537f67d 100644
--- a/Tests/RunCMake/UseSWIG/RunCMakeTest.cmake
+++ b/Tests/RunCMake/UseSWIG/RunCMakeTest.cmake
@@ -6,7 +6,7 @@
 
 run_cmake(CMP0086-WARN)
 
-if (CMake_TEST_FindPython)
+if (CMake_TEST_FindPython2 OR CMake_TEST_FindPython3)
 
   macro(run_cmake_target test subtest target)
     set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
diff --git a/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-OLD-Direct-stderr.txt b/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-OLD-Direct-stderr.txt
new file mode 100644
index 0000000..53f603e
--- /dev/null
+++ b/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-OLD-Direct-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0120-OLD-Direct\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0120 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/WriteCompilerDetectionHeader/CMP0120-OLD-stderr.txt b/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-OLD-stderr.txt
new file mode 100644
index 0000000..fea708f
--- /dev/null
+++ b/Tests/RunCMake/WriteCompilerDetectionHeader/CMP0120-OLD-stderr.txt
@@ -0,0 +1,10 @@
+^CMake Deprecation Warning at CMP0120-OLD\.cmake:[0-9]+ \(cmake_policy\):
+  The OLD behavior for policy CMP0120 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/add_subdirectory/RunCMakeTest.cmake b/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake
index ddf45af..3c70d07 100644
--- a/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake
+++ b/Tests/RunCMake/add_subdirectory/RunCMakeTest.cmake
@@ -3,7 +3,9 @@
 run_cmake(DoesNotExist)
 run_cmake(Missing)
 run_cmake(Function)
+set(RunCMake_TEST_OPTIONS -DCMAKE_Fortran_COMPILER=${CMAKE_Fortran_COMPILER})
 run_cmake(System)
+unset(RunCMake_TEST_OPTIONS)
 
 macro(run_cmake_install case)
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
diff --git a/Tests/RunCMake/add_subdirectory/System.cmake b/Tests/RunCMake/add_subdirectory/System.cmake
index 45d7d9a..1048a7a 100644
--- a/Tests/RunCMake/add_subdirectory/System.cmake
+++ b/Tests/RunCMake/add_subdirectory/System.cmake
@@ -1,4 +1,7 @@
 enable_language(CXX)
+if(CMAKE_Fortran_COMPILER)
+  enable_language(Fortran)
+endif()
 
 add_subdirectory(System SYSTEM)
 
diff --git a/Tests/RunCMake/add_subdirectory/System/CMakeLists.txt b/Tests/RunCMake/add_subdirectory/System/CMakeLists.txt
index ef74e80..8653b6f 100644
--- a/Tests/RunCMake/add_subdirectory/System/CMakeLists.txt
+++ b/Tests/RunCMake/add_subdirectory/System/CMakeLists.txt
@@ -4,6 +4,11 @@
 add_subdirectory(SubSub2)
 
 add_library(bar STATIC bar.cpp)
+if(CMAKE_Fortran_COMPILER)
+  target_sources(bar PRIVATE zap.f)
+endif()
+# Verify CMAKE_INCLUDE_SYSTEM_FLAG_<LANG> works
+target_link_libraries(bar PRIVATE subsub1bar)
 
 add_library(foo STATIC foo.cpp)
 set_target_properties(foo PROPERTIES SYSTEM OFF)
diff --git a/Tests/RunCMake/add_subdirectory/System/SubSub1/CMakeLists.txt b/Tests/RunCMake/add_subdirectory/System/SubSub1/CMakeLists.txt
index 291339b..24105b0 100644
--- a/Tests/RunCMake/add_subdirectory/System/SubSub1/CMakeLists.txt
+++ b/Tests/RunCMake/add_subdirectory/System/SubSub1/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_library(subsub1bar STATIC bar.cpp)
+target_include_directories(subsub1bar PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
 
 add_library(subsub1foo STATIC foo.cpp)
 set_target_properties(subsub1foo PROPERTIES SYSTEM OFF)
diff --git a/Tests/RunCMake/CommandLine/DeprecateVS11-WARN-OFF.cmake b/Tests/RunCMake/add_subdirectory/System/zap.f
similarity index 100%
rename from Tests/RunCMake/CommandLine/DeprecateVS11-WARN-OFF.cmake
rename to Tests/RunCMake/add_subdirectory/System/zap.f
diff --git a/Tests/RunCMake/target_sources/FileSetAbsoluteInstallIncludeDirExport.cmake b/Tests/RunCMake/target_sources/FileSetAbsoluteInstallIncludeDirExport.cmake
new file mode 100644
index 0000000..f049d91
--- /dev/null
+++ b/Tests/RunCMake/target_sources/FileSetAbsoluteInstallIncludeDirExport.cmake
@@ -0,0 +1,16 @@
+enable_language(C)
+
+# According to https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html#module:GNUInstallDirs
+# relative CMAKE_INSTALL_<dir> are encouraged, but absolute path's are also allowed.
+# Construct an absolute CMAKE_INSTALL_INCLUDEDIR.
+set(CMAKE_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include")
+
+add_library(lib1)
+target_sources(lib1
+    PRIVATE lib1.c
+    PUBLIC FILE_SET HEADERS BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} FILES h1.h)
+# Expect install(TARGETS) to respect absolute CMAKE_INSTALL_INCLUDEDIR
+# when installing the HEADERS.
+# Must not prepend the CMAKE_INSTALL_PREFIX in the <pkg>-config.cmake.
+install(TARGETS lib1 EXPORT lib1-config FILE_SET HEADERS)
+install(EXPORT lib1-config NAMESPACE lib1:: DESTINATION share/lib1)
diff --git a/Tests/RunCMake/target_sources/FileSetAbsoluteInstallIncludeDirImport.cmake b/Tests/RunCMake/target_sources/FileSetAbsoluteInstallIncludeDirImport.cmake
new file mode 100644
index 0000000..123d6ae
--- /dev/null
+++ b/Tests/RunCMake/target_sources/FileSetAbsoluteInstallIncludeDirImport.cmake
@@ -0,0 +1,9 @@
+enable_language(CXX)
+
+get_filename_component(CMAKE_PREFIX_PATH "${CMAKE_BINARY_DIR}" DIRECTORY)
+string(APPEND CMAKE_PREFIX_PATH "/FileSetAbsoluteInstallIncludeDirExport-build/install")
+
+find_package(lib1 REQUIRED)
+
+add_executable(exe main.cpp)
+target_link_libraries(exe PRIVATE lib1::lib1)
diff --git a/Tests/RunCMake/target_sources/RunCMakeTest.cmake b/Tests/RunCMake/target_sources/RunCMakeTest.cmake
index 90915cd..8505f71 100644
--- a/Tests/RunCMake/target_sources/RunCMakeTest.cmake
+++ b/Tests/RunCMake/target_sources/RunCMakeTest.cmake
@@ -99,3 +99,4 @@
 endfunction()
 
 run_export_import(FileSet)
+run_export_import(FileSetAbsoluteInstallIncludeDir)
diff --git a/Tests/UseSWIG/AlternateLibraryName/CMakeLists.txt b/Tests/UseSWIG/AlternateLibraryName/CMakeLists.txt
index a2c239c..f20593c 100644
--- a/Tests/UseSWIG/AlternateLibraryName/CMakeLists.txt
+++ b/Tests/UseSWIG/AlternateLibraryName/CMakeLists.txt
@@ -7,7 +7,7 @@
 find_package(SWIG REQUIRED)
 include(${SWIG_USE_FILE})
 
-find_package(Python2 REQUIRED COMPONENTS Interpreter Development)
+find_package(Python REQUIRED COMPONENTS Interpreter Development)
 
 # Path separator
 if (WIN32)
@@ -27,9 +27,9 @@
 set_target_properties (example_python PROPERTIES
   INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/.."
   SWIG_USE_TARGET_INCLUDE_DIRECTORIES TRUE)
-target_link_libraries(example_python PRIVATE Python2::Python)
+target_link_libraries(example_python PRIVATE Python::Python)
 
 
 add_test (NAME AlternateLibraryName.example1
   COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}${PS}$<TARGET_FILE_DIR:example_python>"
-  "${Python2_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/../runme.py")
+  "${Python_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/../runme.py")
diff --git a/Tests/UseSWIG/CMakeLists.txt b/Tests/UseSWIG/CMakeLists.txt
index 7c4925e..3d80270 100644
--- a/Tests/UseSWIG/CMakeLists.txt
+++ b/Tests/UseSWIG/CMakeLists.txt
@@ -147,16 +147,18 @@
   --build-options ${build_options}
   --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
   )
-add_test(NAME UseSWIG.MultiplePython COMMAND
-  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-  --build-and-test
-  "${CMake_SOURCE_DIR}/Tests/UseSWIG/MultiplePython"
-  "${CMake_BINARY_DIR}/Tests/UseSWIG/MultiplePython"
-  ${build_generator_args}
-  --build-project TestMultiplePython
-  --build-options ${build_options}
-  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+if(CMake_TEST_FindPython2 AND CMake_TEST_FindPython3)
+  add_test(NAME UseSWIG.MultiplePython COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/UseSWIG/MultiplePython"
+    "${CMake_BINARY_DIR}/Tests/UseSWIG/MultiplePython"
+    ${build_generator_args}
+    --build-project TestMultiplePython
+    --build-options ${build_options}
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
   )
+endif()
 add_test(NAME UseSWIG.MultipleFiles COMMAND
   ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
   --build-and-test
@@ -165,20 +167,20 @@
   ${build_generator_args}
   --build-project TestMultipleFiles
   --build-options ${build_options}
+)
+
+if(CMake_TEST_FindPython2 OR CMake_TEST_FindPython3)
+  add_test(NAME UseSWIG.ModuleVersion2 COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/UseSWIG/ModuleVersion2"
+    "${CMake_BINARY_DIR}/Tests/UseSWIG/ModuleVersion2"
+    ${build_generator_args}
+    --build-project TestModuleVersion2
+    --build-options ${build_options}
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
   )
-
-
-add_test(NAME UseSWIG.ModuleVersion2 COMMAND
-  ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
-  --build-and-test
-  "${CMake_SOURCE_DIR}/Tests/UseSWIG/ModuleVersion2"
-  "${CMake_BINARY_DIR}/Tests/UseSWIG/ModuleVersion2"
-  ${build_generator_args}
-  --build-project TestModuleVersion2
-  --build-options ${build_options}
-  --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
-  )
-
+endif()
 
 add_test(NAME UseSWIG.UseTargetINCLUDE_DIRECTORIES COMMAND
   ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
diff --git a/Tests/UseSWIG/ModuleName/CMakeLists.txt b/Tests/UseSWIG/ModuleName/CMakeLists.txt
index 435b441..c62319f 100644
--- a/Tests/UseSWIG/ModuleName/CMakeLists.txt
+++ b/Tests/UseSWIG/ModuleName/CMakeLists.txt
@@ -8,14 +8,7 @@
 cmake_policy(SET CMP0086 NEW)
 include(${SWIG_USE_FILE})
 
-find_package(Python2 REQUIRED COMPONENTS Interpreter Development)
-
-# Path separator
-if (WIN32)
-  set (PS "$<SEMICOLON>")
-else()
-  set (PS ":")
-endif()
+find_package(Python REQUIRED COMPONENTS Interpreter Development)
 
 unset(CMAKE_SWIG_FLAGS)
 
@@ -34,9 +27,9 @@
   LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example1"
   ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example1"
   RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example1")
-target_link_libraries(example1 PRIVATE Python2::Module)
+target_link_libraries(example1 PRIVATE Python::Module)
 
 
 add_test (NAME ModuleName.example1
-  COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}/Python2${PS}$<TARGET_FILE_DIR:example1>"
-  "${Python2_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/runme.py")
+  COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:example1>"
+  "${Python_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/runme.py")
diff --git a/Tests/UseSWIG/ModuleVersion2/CMakeLists.txt b/Tests/UseSWIG/ModuleVersion2/CMakeLists.txt
index 093e858..317ed47 100644
--- a/Tests/UseSWIG/ModuleVersion2/CMakeLists.txt
+++ b/Tests/UseSWIG/ModuleVersion2/CMakeLists.txt
@@ -7,9 +7,6 @@
 find_package(SWIG REQUIRED)
 include(${SWIG_USE_FILE})
 
-find_package(Python2 REQUIRED COMPONENTS Interpreter Development)
-find_package(Python3 REQUIRED COMPONENTS Interpreter Development)
-
 if (WIN32)
   set (PS $<SEMICOLON>)
 else()
@@ -25,32 +22,69 @@
 set_property(SOURCE "../example.i"
   PROPERTY GENERATED_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/..")
 
-swig_add_library(example1
-                 LANGUAGE python
-                 SOURCES ../example.i ../example.cxx)
-set_target_properties (example1 PROPERTIES
-  OUTPUT_NAME example
-  LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python2"
-  ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python2"
-  RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python2")
-target_link_libraries(example1 PRIVATE Python2::Module)
+if(CMake_TEST_FindPython2)
+  find_package(Python2 REQUIRED COMPONENTS Interpreter Development)
 
-# re-use sample interface file for another plugin
-swig_add_library(example2
-                 LANGUAGE python
-                 SOURCES ../example.i ../example.cxx)
-set_target_properties (example2 PROPERTIES
-  OUTPUT_NAME example
-  LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python3"
-  ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python3"
-  RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python3")
-target_link_libraries(example2 PRIVATE Python3::Module)
+  swig_add_library(example1
+                   LANGUAGE python
+                   SOURCES ../example.i ../example.cxx)
+  set_target_properties (example1 PROPERTIES
+    OUTPUT_NAME example
+    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python2-1"
+    ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python2-1"
+    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python2-1")
+  target_link_libraries(example1 PRIVATE Python2::Module)
+
+  add_test (NAME ModuleVersion2.example1
+    COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_PROPERTY:example1,SWIG_SUPPORT_FILES_DIRECTORY>${PS}$<TARGET_FILE_DIR:example1>"
+    "${Python2_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/../runme.py")
+
+  # re-use sample interface file for another plugin
+  swig_add_library(example2
+                   LANGUAGE python
+                   SOURCES ../example.i ../example.cxx)
+  set_target_properties (example2 PROPERTIES
+    OUTPUT_NAME example
+    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python2-2"
+    ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python2-2"
+    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python2-2")
+  target_link_libraries(example2 PRIVATE Python2::Module)
+
+  add_test (NAME ModuleVersion2.example2
+    COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_PROPERTY:example2,SWIG_SUPPORT_FILES_DIRECTORY>${PS}$<TARGET_FILE_DIR:example2>"
+    "${Python2_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/../runme.py")
+endif()
+
+if(CMake_TEST_FindPython3)
+  find_package(Python3 REQUIRED COMPONENTS Interpreter Development)
+
+  swig_add_library(example3
+                   LANGUAGE python
+                   SOURCES ../example.i ../example.cxx)
+  set_target_properties (example3 PROPERTIES
+    OUTPUT_NAME example
+    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python3-1"
+    ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python3-1"
+    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python3-1")
+  target_link_libraries(example3 PRIVATE Python3::Module)
+
+  add_test (NAME ModuleVersion2.example3
+    COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_PROPERTY:example3,SWIG_SUPPORT_FILES_DIRECTORY>${PS}$<TARGET_FILE_DIR:example3>"
+    "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/../runme.py")
 
 
-add_test (NAME ModuleVersion2.example1
-  COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_PROPERTY:example1,SWIG_SUPPORT_FILES_DIRECTORY>${PS}$<TARGET_FILE_DIR:example1>"
-  "${Python2_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/../runme.py")
+  # re-use sample interface file for another plugin
+  swig_add_library(example4
+                   LANGUAGE python
+                   SOURCES ../example.i ../example.cxx)
+  set_target_properties (example2 PROPERTIES
+    OUTPUT_NAME example
+    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python3-2"
+    ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python3-2"
+    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Python3-2")
+  target_link_libraries(example4 PRIVATE Python3::Module)
 
-add_test (NAME ModuleVersion2.example2
-  COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_PROPERTY:example2,SWIG_SUPPORT_FILES_DIRECTORY>${PS}$<TARGET_FILE_DIR:example2>"
-  "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/../runme.py")
+  add_test (NAME ModuleVersion2.example4
+    COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_PROPERTY:example4,SWIG_SUPPORT_FILES_DIRECTORY>${PS}$<TARGET_FILE_DIR:example4>"
+    "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/../runme.py")
+endif()
diff --git a/Tests/UseSWIG/MultipleFiles/CMakeLists.txt b/Tests/UseSWIG/MultipleFiles/CMakeLists.txt
index bf3d946..36734f9 100644
--- a/Tests/UseSWIG/MultipleFiles/CMakeLists.txt
+++ b/Tests/UseSWIG/MultipleFiles/CMakeLists.txt
@@ -11,7 +11,7 @@
 unset(SWIG_LANG_OPTIONS)
 unset(SWIG_LANG_LIBRARIES)
 
-find_package(Python3 REQUIRED COMPONENTS Development)
+find_package(Python REQUIRED COMPONENTS Development)
 
 set_property(SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/add.i" PROPERTY CPLUSPLUS ON)
 set_property(SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/sub.i" PROPERTY CPLUSPLUS ON)
@@ -27,4 +27,4 @@
                          "${CMAKE_CURRENT_SOURCE_DIR}/add.cxx"
                          "${CMAKE_CURRENT_SOURCE_DIR}/sub.cxx")
 target_include_directories(example PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
-target_link_libraries(example PRIVATE Python3::Module)
+target_link_libraries(example PRIVATE Python::Module)
diff --git a/Tests/UseSWIG/UseTargetINCLUDE_DIRECTORIES/CMakeLists.txt b/Tests/UseSWIG/UseTargetINCLUDE_DIRECTORIES/CMakeLists.txt
index 80a2e16..6cdf987 100644
--- a/Tests/UseSWIG/UseTargetINCLUDE_DIRECTORIES/CMakeLists.txt
+++ b/Tests/UseSWIG/UseTargetINCLUDE_DIRECTORIES/CMakeLists.txt
@@ -7,7 +7,7 @@
 find_package(SWIG REQUIRED)
 include(${SWIG_USE_FILE})
 
-find_package(Python3 REQUIRED COMPONENTS Interpreter Development)
+find_package(Python REQUIRED COMPONENTS Interpreter Development)
 
 unset(CMAKE_SWIG_FLAGS)
 
@@ -25,7 +25,7 @@
   LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example1"
   ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example1"
   RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example1")
-target_link_libraries(example1 PRIVATE Python3::Module)
+target_link_libraries(example1 PRIVATE Python::Module)
 
 
 # Check that source property override target property
@@ -42,4 +42,4 @@
   LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example2"
   ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example2"
   RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/example2")
-target_link_libraries(example2 PRIVATE Python3::Module)
+target_link_libraries(example2 PRIVATE Python::Module)
diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt
index fee21b6..12b5407 100644
--- a/Utilities/Doxygen/CMakeLists.txt
+++ b/Utilities/Doxygen/CMakeLists.txt
@@ -3,7 +3,7 @@
 
 if(NOT CMake_SOURCE_DIR)
   set(CMakeDeveloperReference_STANDALONE 1)
-  cmake_minimum_required(VERSION 3.13...3.25 FATAL_ERROR)
+  cmake_minimum_required(VERSION 3.13...3.26 FATAL_ERROR)
   get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
   get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
   include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt
index bde6c6b..694ba3c 100644
--- a/Utilities/Sphinx/CMakeLists.txt
+++ b/Utilities/Sphinx/CMakeLists.txt
@@ -3,7 +3,7 @@
 
 if(NOT CMake_SOURCE_DIR)
   set(CMakeHelp_STANDALONE 1)
-  cmake_minimum_required(VERSION 3.13...3.25 FATAL_ERROR)
+  cmake_minimum_required(VERSION 3.13...3.26 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/cmbzip2/CMakeLists.txt b/Utilities/cmbzip2/CMakeLists.txt
index 1d7b265..b52358e 100644
--- a/Utilities/cmbzip2/CMakeLists.txt
+++ b/Utilities/cmbzip2/CMakeLists.txt
@@ -19,3 +19,7 @@
 add_definitions(-D_FILE_OFFSET_BITS=64)
 add_library(cmbzip2
   blocksort.c huffman.c crctable.c randtable.c compress.c decompress.c bzlib.c)
+
+if(WIN32 AND CMake_BUILD_PCH)
+  target_precompile_headers(cmbzip2 PRIVATE "bzlib.h")
+endif()
diff --git a/Utilities/cmcppdap/CMakeLists.txt b/Utilities/cmcppdap/CMakeLists.txt
index 39f72a2..2aca681 100644
--- a/Utilities/cmcppdap/CMakeLists.txt
+++ b/Utilities/cmcppdap/CMakeLists.txt
@@ -34,4 +34,8 @@
   target_link_libraries(cmcppdap PRIVATE Threads::Threads)
 endif()
 
+if(CMake_BUILD_PCH)
+  target_precompile_headers(cmcppdap PRIVATE "include/dap/protocol.h")
+endif()
+
 install(FILES NOTICE DESTINATION ${CMAKE_DOC_DIR}/cmcppdap)
diff --git a/Utilities/cmcurl/lib/CMakeLists.txt b/Utilities/cmcurl/lib/CMakeLists.txt
index f1d0f76..ba75420 100644
--- a/Utilities/cmcurl/lib/CMakeLists.txt
+++ b/Utilities/cmcurl/lib/CMakeLists.txt
@@ -110,6 +110,10 @@
   OUTPUT_NAME ${LIBCURL_OUTPUT_NAME}
   )
 
+if(WIN32 AND CMake_BUILD_PCH)
+  target_precompile_headers(${LIB_NAME} PRIVATE "curl_setup.h" "curl_sspi.h" "${CURL_SOURCE_DIR}/include/curl/curl.h")
+endif()
+
 if(0) # This code not needed for building within CMake.
 if(CMAKE_SYSTEM_NAME STREQUAL "AIX" OR
   CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
diff --git a/Utilities/cmlibarchive/libarchive/CMakeLists.txt b/Utilities/cmlibarchive/libarchive/CMakeLists.txt
index bee69c2..e820853 100644
--- a/Utilities/cmlibarchive/libarchive/CMakeLists.txt
+++ b/Utilities/cmlibarchive/libarchive/CMakeLists.txt
@@ -246,6 +246,10 @@
 ADD_LIBRARY(cmlibarchive STATIC ${libarchive_SOURCES} ${include_HEADERS})
 TARGET_LINK_LIBRARIES(cmlibarchive ${ADDITIONAL_LIBS})
 
+if(WIN32 AND CMake_BUILD_PCH)
+  target_precompile_headers(cmlibarchive PRIVATE "archive_platform.h" "archive_entry.h" "<cm3p/bzlib.h>")
+endif()
+
 IF(0) # CMake does not build libarchive's full package.
 # Libarchive is a shared library
 ADD_LIBRARY(archive SHARED ${libarchive_SOURCES} ${include_HEADERS})
diff --git a/Utilities/cmliblzma/CMakeLists.txt b/Utilities/cmliblzma/CMakeLists.txt
index 3121fbe..3ba3ce9 100644
--- a/Utilities/cmliblzma/CMakeLists.txt
+++ b/Utilities/cmliblzma/CMakeLists.txt
@@ -186,4 +186,8 @@
   SET_PROPERTY(TARGET cmliblzma PROPERTY COMPILE_FLAGS "-O0")
 ENDIF()
 
+if(WIN32 AND CMake_BUILD_PCH)
+  target_precompile_headers(cmliblzma PRIVATE "common/mythread.h")
+endif()
+
 INSTALL(FILES COPYING DESTINATION ${CMAKE_DOC_DIR}/cmliblzma)
diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt
index ad3d433..9df0c7f 100644
--- a/Utilities/cmlibuv/CMakeLists.txt
+++ b/Utilities/cmlibuv/CMakeLists.txt
@@ -365,4 +365,8 @@
 target_link_libraries(cmlibuv ${uv_libraries})
 set_property(TARGET cmlibuv PROPERTY COMPILE_DEFINITIONS ${uv_defines})
 
+if(WIN32 AND CMake_BUILD_PCH)
+  target_precompile_headers(cmlibuv PRIVATE "include/uv.h" "src/win/internal.h")
+endif()
+
 install(FILES LICENSE DESTINATION ${CMAKE_DOC_DIR}/cmlibuv)
diff --git a/Utilities/std/cmext/algorithm b/Utilities/std/cmext/algorithm
index 11514fc..46377f4 100644
--- a/Utilities/std/cmext/algorithm
+++ b/Utilities/std/cmext/algorithm
@@ -16,6 +16,7 @@
 
 #if defined(__SUNPRO_CC) && defined(__sparc)
 #  include <list>
+#  include <string>
 #  include <vector>
 #endif
 
@@ -67,11 +68,15 @@
     APPEND_TWO(C1, C2)                                                        \
     APPEND_TWO(C2, C1)
 
-// For now, manage only support for std::vector and std::list.
-// Other sequential container support can be added if needed.
+// For now, manage only support for std::vector, std::list, and
+// std::basic_string. Other sequential container support can be added if
+// needed.
 APPEND(std::vector)
 APPEND(std::list)
+APPEND(std::basic_string)
 APPEND_MIX(std::vector, std::list)
+APPEND_MIX(std::vector, std::basic_string)
+APPEND_MIX(std::list, std::basic_string)
 
 #  undef APPEND
 #  undef APPEND_MIX
diff --git a/Utilities/std/cmext/iterator b/Utilities/std/cmext/iterator
index eba10dd..85a28fa 100644
--- a/Utilities/std/cmext/iterator
+++ b/Utilities/std/cmext/iterator
@@ -24,9 +24,18 @@
 
 // checks if a type is a range type: std::begin() and std::end() are supported
 template <typename Range>
-using is_range = cm::bool_constant<
-  cm::is_iterator<decltype(std::begin(std::declval<const Range>()))>::value &&
-  cm::is_iterator<decltype(std::end(std::declval<const Range>()))>::value>;
+using is_range =
+#if defined(_MSC_VER) && _MSC_VER < 1920
+  // MS C++ is not able to evaluate complex type introspection,
+  // so use a simplified version
+  cm::bool_constant<std::is_class<Range>::value ||
+                    std::is_array<Range>::value>;
+#else
+  cm::bool_constant<
+    cm::is_iterator<decltype(std::begin(
+      std::declval<const Range>()))>::value &&
+    cm::is_iterator<decltype(std::end(std::declval<const Range>()))>::value>;
+#endif
 
 // checks if a type is an input range type: std::begin() and std::end() are
 // returning an input iterator