Merge topic 'Qt4Macros-last-ext'

fd83dab339 Qt4Macros: Only cut last extension (".ts") and replace it with ".qm"

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !4211
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim
index 31ec1d0..0676f7e 100644
--- a/Auxiliary/vim/syntax/cmake.vim
+++ b/Auxiliary/vim/syntax/cmake.vim
@@ -221,6 +221,7 @@
             \ JOB_POOLS
             \ JOB_POOL_COMPILE
             \ JOB_POOL_LINK
+            \ JOB_POOL_PRECOMPILE_HEADER
             \ KEEP_EXTENSION
             \ LABELS
             \ LANGUAGE
@@ -1066,6 +1067,7 @@
             \ CMAKE_JOB_POOLS
             \ CMAKE_JOB_POOL_COMPILE
             \ CMAKE_JOB_POOL_LINK
+            \ CMAKE_JOB_POOL_PRECOMPILE_HEADER
             \ CMAKE_Java
             \ CMAKE_Java_ANDROID_TOOLCHAIN_MACHINE
             \ CMAKE_Java_ANDROID_TOOLCHAIN_PREFIX
@@ -2864,6 +2866,11 @@
             \ _LINKER_WRAPPER_FLAG
             \ _LINKER_WRAPPER_FLAG_SEP
 
+syn keyword cmakeKWtarget_precompile_headers contained
+            \ INTERFACE
+            \ PRIVATE
+            \ PUBLIC
+
 syn keyword cmakeKWtarget_sources contained
             \ ALIAS
             \ IMPORTED
@@ -3168,6 +3175,7 @@
             \ target_link_directories
             \ target_link_libraries
             \ target_link_options
+            \ target_precompile_headers
             \ target_sources
             \ try_compile
             \ try_run
@@ -3324,6 +3332,7 @@
 hi def link cmakeKWtarget_link_directories ModeMsg
 hi def link cmakeKWtarget_link_libraries ModeMsg
 hi def link cmakeKWtarget_link_options ModeMsg
+hi def link cmakeKWtarget_precompile_headers ModeMsg
 hi def link cmakeKWtarget_sources ModeMsg
 hi def link cmakeKWtry_compile ModeMsg
 hi def link cmakeKWtry_run ModeMsg
diff --git a/CMakeLists.txt b/CMakeLists.txt
index da99a6e..c7d139b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -264,7 +264,6 @@
       ${CMake_BINARY_DIR}/Testing/HTML/TestingResults/Icons/Logo.gif COPYONLY)
   endif()
   mark_as_advanced(DART_ROOT)
-  mark_as_advanced(CURL_TESTING)
 endmacro()
 
 
@@ -671,10 +670,6 @@
   set(LIBRARY_OUTPUT_PATH "" CACHE INTERNAL
     "Where to put the libraries for CMake")
 
-  # The CMake executables usually do not need any rpath to run in the build or
-  # install tree.
-  set(CMAKE_SKIP_RPATH ON CACHE INTERNAL "CMake does not need RPATHs.")
-
   # Load install destinations.
   include(Source/CMakeInstallDestinations.cmake)
 
@@ -714,19 +709,6 @@
   # build the utilities (a macro defined in this file)
   CMAKE_BUILD_UTILITIES()
 
-  # On NetBSD ncurses is required, since curses doesn't have the wsyncup()
-  # function. ncurses is installed via pkgsrc, so the library is in /usr/pkg/lib,
-  # which isn't in the default linker search path. So without RPATH ccmake
-  # doesn't run and the build doesn't succeed since ccmake is executed for
-  # generating the documentation.
-  if(BUILD_CursesDialog)
-    get_filename_component(_CURSES_DIR "${CURSES_LIBRARY}" PATH)
-    set(CURSES_NEED_RPATH FALSE)
-    if(NOT "${_CURSES_DIR}" STREQUAL "/lib" AND NOT "${_CURSES_DIR}" STREQUAL "/usr/lib" AND NOT "${_CURSES_DIR}" STREQUAL "/lib64" AND NOT "${_CURSES_DIR}" STREQUAL "/usr/lib64")
-      set(CURSES_NEED_RPATH TRUE)
-    endif()
-  endif()
-
   if(BUILD_QtDialog)
     if(APPLE)
       set(CMAKE_BUNDLE_VERSION
@@ -739,28 +721,15 @@
       set(CMAKE_INSTALL_PREFIX
         "${CMAKE_INSTALL_PREFIX}CMake.app/Contents")
     endif()
-
-    set(QT_NEED_RPATH FALSE)
-    if(NOT "${QT_LIBRARY_DIR}" STREQUAL "/lib" AND NOT "${QT_LIBRARY_DIR}" STREQUAL "/usr/lib" AND NOT "${QT_LIBRARY_DIR}" STREQUAL "/lib64" AND NOT "${QT_LIBRARY_DIR}" STREQUAL "/usr/lib64")
-      set(QT_NEED_RPATH TRUE)
-    endif()
   endif()
 
-
-  # The same might be true on other systems for other libraries.
-  # Then only enable RPATH if we have are building at least with cmake 2.4,
-  # since this one has much better RPATH features than cmake 2.2.
-  # The executables are then built with the RPATH for the libraries outside
-  # the build tree, which is both the build and the install RPATH.
-  if (UNIX)
-    if(   CMAKE_USE_SYSTEM_CURL   OR  CMAKE_USE_SYSTEM_ZLIB
-          OR  CMAKE_USE_SYSTEM_EXPAT  OR  CURSES_NEED_RPATH  OR  QT_NEED_RPATH)
-      set(CMAKE_SKIP_RPATH OFF CACHE INTERNAL "CMake built with RPATH.")
-      set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
-      set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
-    endif()
-  endif ()
-
+  if(UNIX)
+    # Install executables with the RPATH set for libraries outside the build tree.
+    # This is also suitable for binaries in the build tree.  Avoid re-link on install.
+    set(CMAKE_INSTALL_RPATH_USE_LINK_PATH ON CACHE BOOL "Install with RPATH set to find custom-built libraries.")
+    set(CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "Build with RPATH set to match install-tree RPATH.")
+    mark_as_advanced(CMAKE_INSTALL_RPATH_USE_LINK_PATH CMAKE_BUILD_WITH_INSTALL_RPATH)
+  endif()
 
   # add the uninstall support
   configure_file(
diff --git a/Help/command/mark_as_advanced.rst b/Help/command/mark_as_advanced.rst
index 5712fb4..e52e623 100644
--- a/Help/command/mark_as_advanced.rst
+++ b/Help/command/mark_as_advanced.rst
@@ -22,3 +22,9 @@
 new values will be marked as advanced, but if a
 variable already has an advanced/non-advanced state,
 it will not be changed.
+
+.. note::
+
+  Policy :policy:`CMP0102` affects the behavior of the ``mark_as_advanced``
+  call. When set to ``NEW``, variables passed to this command which are not
+  already in the cache are ignored. See policy :policy:`CMP0102`.
diff --git a/Help/cpack_gen/dmg.rst b/Help/cpack_gen/dmg.rst
index 1e37889..35320c2 100644
--- a/Help/cpack_gen/dmg.rst
+++ b/Help/cpack_gen/dmg.rst
@@ -81,6 +81,13 @@
   ``<language>.menu.txt`` and ``<language>.license.txt`` in the directory
   specified by the :variable:`CPACK_DMG_SLA_DIR` variable.
 
+.. variable:: CPACK_DMG_<component>_FILE_NAME
+
+ File name when packaging ``<component>`` as its own DMG
+ (``CPACK_COMPONENTS_GROUPING`` set to IGNORE).
+
+ - Default: ``CPACK_PACKAGE_FILE_NAME-<component>``
+
 .. variable:: CPACK_COMMAND_HDIUTIL
 
  Path to the ``hdiutil(1)`` command used to operate on disk image files on
diff --git a/Help/generator/Ninja Multi-Config.rst b/Help/generator/Ninja Multi-Config.rst
index 71cc392..e7f362e 100644
--- a/Help/generator/Ninja Multi-Config.rst
+++ b/Help/generator/Ninja Multi-Config.rst
@@ -19,9 +19,10 @@
 ``build-<Config>.ninja`` as the ``-f`` file and ``<target>`` as the build
 target.
 
-Executables and libraries of any configuration can be built regardless of which
+If :variable:`CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE` is turned on, executables
+and libraries of any configuration can be built regardless of which
 ``build-<Config>.ninja`` file is used, simply by specifying
-``<target>:<Config>`` as the Ninja target. You can also specify
+``<target>:<OtherConfig>`` as the Ninja target. You can also specify
 ``<target>:all`` to build a target in all configurations. Each
 ``build-<Config>.ninja`` file will additionally have ``<target>`` targets which
 are aliases for ``<target>:<Config>``. However, custom commands and custom
@@ -30,6 +31,17 @@
 Ninja for the same file to be output with different commands in the same build
 graph.
 
+You can additionally use :variable:`CMAKE_NINJA_MULTI_CROSS_CONFIGS` to limit
+the configurations that get cross-generated. If this variable is set, each
+``build-<Config>.ninja`` file will only contain rules for the configurations
+listed in the variable, plus their own configuration. This also affects which
+configurations are built by the ``<target>:all`` target.
+
+If :variable:`CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE` is not enabled, you can
+still build any target in ``build-<Config>.ninja`` by specifying
+``<target>:<Config>`` or ``<target>``, but not ``<target>:<OtherConfig>`` or
+``<target>:all``.
+
 Consider the following example:
 
 .. code-block:: cmake
@@ -54,7 +66,8 @@
 used to generate ``generated.c``, which would be used to build the ``Debug``
 configuration of ``generated``.
 
-But if you run the following instead:
+But if :variable:`CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE` is enabled, and you
+run the following instead:
 
 .. code-block:: shell
 
@@ -71,4 +84,13 @@
 As a convenience, ``Ninja Multi-Config`` offers a
 :variable:`CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE` setting. If this variable is
 specified, a ``build.ninja`` file will be generated which points to the
-specified ``build-<Config>.ninja`` file.
+specified ``build-<Config>.ninja`` file. In addition, if
+:variable:`CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE` is used in conjunction with
+:variable:`CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE`, you can also specify
+:variable:`CMAKE_NINJA_MULTI_DEFAULT_BUILD_ALIAS`, which changes the config
+of the ``<target>`` targets in ``build.ninja``. For example, if you set
+:variable:`CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE` to ``Release``, but set
+:variable:`CMAKE_NINJA_MULTI_DEFAULT_BUILD_ALIAS` to ``Debug`` or ``all``,
+all ``<target>`` aliases in ``build.ninja`` will resolve to ``<target>:Debug``
+or ``<target>:all``, but custom commands will still use the ``Release``
+configuration.
diff --git a/Help/guide/tutorial/Complete/CMakeLists.txt b/Help/guide/tutorial/Complete/CMakeLists.txt
index eca79d9..4d8a3ad 100644
--- a/Help/guide/tutorial/Complete/CMakeLists.txt
+++ b/Help/guide/tutorial/Complete/CMakeLists.txt
@@ -3,6 +3,8 @@
 # set the project name and version
 project(Tutorial VERSION 1.0)
 
+set(CMAKE_DEBUG_POSTFIX d)
+
 add_library(tutorial_compiler_flags INTERFACE)
 target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)
 
@@ -37,6 +39,8 @@
 
 # add the executable
 add_executable(Tutorial tutorial.cxx)
+set_target_properties(Tutorial PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
+
 target_link_libraries(Tutorial PUBLIC MathFunctions)
 
 # add the binary tree to the search path for include files
diff --git a/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt
index dfa84c9..c911625 100644
--- a/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt
@@ -17,7 +17,7 @@
 
   # first we add the executable that generates the table
   add_executable(MakeTable MakeTable.cxx)
-  target_link_libraries(MakeTable tutorial_compiler_flags)
+  target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags)
 
   # add the command to generate the source code
   add_custom_command(
diff --git a/Help/guide/tutorial/MultiPackage/MultiCPackConfig.cmake b/Help/guide/tutorial/Complete/MultiCPackConfig.cmake
similarity index 98%
rename from Help/guide/tutorial/MultiPackage/MultiCPackConfig.cmake
rename to Help/guide/tutorial/Complete/MultiCPackConfig.cmake
index 403b633..c2583df 100644
--- a/Help/guide/tutorial/MultiPackage/MultiCPackConfig.cmake
+++ b/Help/guide/tutorial/Complete/MultiCPackConfig.cmake
@@ -1,4 +1,3 @@
-
 include("release/CPackConfig.cmake")
 
 set(CPACK_INSTALL_CMAKE_PROJECTS
diff --git a/Help/guide/tutorial/Complete/tutorial.cxx b/Help/guide/tutorial/Complete/tutorial.cxx
index 586d183..a4f44d5 100644
--- a/Help/guide/tutorial/Complete/tutorial.cxx
+++ b/Help/guide/tutorial/Complete/tutorial.cxx
@@ -1,6 +1,5 @@
 // A simple program that computes the square root of a number
 #include <iostream>
-#include <sstream>
 #include <string>
 
 #include "MathFunctions.h"
@@ -9,6 +8,7 @@
 int main(int argc, char* argv[])
 {
   if (argc < 2) {
+    // report version
     std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
               << Tutorial_VERSION_MINOR << std::endl;
     std::cout << "Usage: " << argv[0] << " number" << std::endl;
@@ -18,8 +18,8 @@
   // convert input to double
   const double inputValue = std::stod(argv[1]);
 
-  // calculate square root
   const double outputValue = mathfunctions::sqrt(inputValue);
+
   std::cout << "The square root of " << inputValue << " is " << outputValue
             << std::endl;
   return 0;
diff --git a/Help/guide/tutorial/Consumer/CMakeLists.txt b/Help/guide/tutorial/Consumer/CMakeLists.txt
deleted file mode 100644
index a0e4598..0000000
--- a/Help/guide/tutorial/Consumer/CMakeLists.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-
-if(NOT DEFINED CMAKE_CXX_STANDARD)
-  set(CMAKE_CXX_STANDARD 11)
-  set(CMAKE_CXX_STANDARD_REQUIRED True)
-endif()
-
-
-function(find_external_dependency name)
-  set(${name}_ROOT ""  CACHE PATH "Root directory to find ${name}")
-  mark_as_advanced(${name}_DIR)
-  find_package(${name} PATHS ${${name}_ROOT} REQUIRED)
-endfunction()
-
-
-project(Consumer)
-
-find_external_dependency(MathFunctions)
-
-add_library(consumer consumer.cxx)
-target_link_libraries(consumer PUBLIC MathFunctions)
-
-# install the consumer library
-install(TARGETS consumer DESTINATION bin EXPORT ConsumerTargets)
-
-# install the configuration targets
-install(EXPORT ConsumerTargets
-  FILE ConsumerTargets.cmake
-  DESTINATION lib/cmake/Consumer
-)
-
-include(CMakePackageConfigHelpers)
-# generate the config file that is includes the exports
-configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
-  "${CMAKE_CURRENT_BINARY_DIR}/ConsumerConfig.cmake"
-  INSTALL_DESTINATION "lib/cmake/example"
-  NO_SET_AND_CHECK_MACRO
-  NO_CHECK_REQUIRED_COMPONENTS_MACRO
-  )
-
-# install the configuration file
-install(FILES
-  ${CMAKE_CURRENT_BINARY_DIR}/ConsumerConfig.cmake
-  DESTINATION lib/cmake/Consumer
-  )
-
-# generate the export targets for the build tree
-# needs to be after the install(TARGETS ) command
-export(EXPORT ConsumerTargets
-  FILE "${CMAKE_CURRENT_BINARY_DIR}/ConsumerTargets.cmake"
-)
diff --git a/Help/guide/tutorial/Consumer/Config.cmake.in b/Help/guide/tutorial/Consumer/Config.cmake.in
deleted file mode 100644
index 0b3f1e4..0000000
--- a/Help/guide/tutorial/Consumer/Config.cmake.in
+++ /dev/null
@@ -1,14 +0,0 @@
-
-@PACKAGE_INIT@
-
-include(CMakeFindDependencyMacro)
-
-function(find_external_dependency name)
-  set(${name}_ROOT ""  CACHE PATH "Root directory to find ${name}")
-  mark_as_advanced(${name}_DIR)
-  find_dependency(${name} PATHS ${${name}_ROOT} REQUIRED)
-endfunction()
-
-find_external_dependency(MathFunctions)
-
-include ( "${CMAKE_CURRENT_LIST_DIR}/ConsumerTargets.cmake" )
diff --git a/Help/guide/tutorial/Consumer/consumer.cxx b/Help/guide/tutorial/Consumer/consumer.cxx
deleted file mode 100644
index ae7877b..0000000
--- a/Help/guide/tutorial/Consumer/consumer.cxx
+++ /dev/null
@@ -1,11 +0,0 @@
-// A simple function that computes the square root of a number
-#include <iostream>
-#include <sstream>
-#include <string>
-
-#include "MathFunctions.h"
-
-double string_square_root(std::string const& value)
-{
-  return mathfunctions::sqrt(std::stod(value));
-}
diff --git a/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt
index e6cb8ba..32f5e08 100644
--- a/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt
@@ -15,7 +15,7 @@
 
   # first we add the executable that generates the table
   add_executable(MakeTable MakeTable.cxx)
-  target_link_libraries(MakeTable tutorial_compiler_flags)
+  target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags)
 
   # add the command to generate the source code
   add_custom_command(
diff --git a/Help/guide/tutorial/MultiPackage/CMakeLists.txt b/Help/guide/tutorial/Step12/CMakeLists.txt
similarity index 85%
rename from Help/guide/tutorial/MultiPackage/CMakeLists.txt
rename to Help/guide/tutorial/Step12/CMakeLists.txt
index 01d417a..eca79d9 100644
--- a/Help/guide/tutorial/MultiPackage/CMakeLists.txt
+++ b/Help/guide/tutorial/Step12/CMakeLists.txt
@@ -1,11 +1,19 @@
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.15)
 
 # set the project name and version
 project(Tutorial VERSION 1.0)
 
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED True)
+add_library(tutorial_compiler_flags INTERFACE)
+target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)
 
+# add compiler warning flags just when building this project via
+# the BUILD_INTERFACE genex
+set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU>")
+set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
+target_compile_options(tutorial_compiler_flags INTERFACE
+  "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>"
+  "$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>"
+)
 
 # control where the static and shared libraries are built so that on windows
 # we don't need to tinker with the path to run the executable
diff --git a/Help/guide/tutorial/Step12/CTestConfig.cmake b/Help/guide/tutorial/Step12/CTestConfig.cmake
new file mode 100644
index 0000000..73efdb1
--- /dev/null
+++ b/Help/guide/tutorial/Step12/CTestConfig.cmake
@@ -0,0 +1,7 @@
+set(CTEST_PROJECT_NAME "CMakeTutorial")
+set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
+
+set(CTEST_DROP_METHOD "http")
+set(CTEST_DROP_SITE "my.cdash.org")
+set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial")
+set(CTEST_DROP_SITE_CDASH TRUE)
diff --git a/Help/guide/tutorial/MultiPackage/Config.cmake.in b/Help/guide/tutorial/Step12/Config.cmake.in
similarity index 100%
rename from Help/guide/tutorial/MultiPackage/Config.cmake.in
rename to Help/guide/tutorial/Step12/Config.cmake.in
diff --git a/Help/guide/tutorial/MultiPackage/License.txt b/Help/guide/tutorial/Step12/License.txt
similarity index 100%
rename from Help/guide/tutorial/MultiPackage/License.txt
rename to Help/guide/tutorial/Step12/License.txt
diff --git a/Help/guide/tutorial/MultiPackage/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt
similarity index 87%
rename from Help/guide/tutorial/MultiPackage/MathFunctions/CMakeLists.txt
rename to Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt
index a2df2a7..720ee64 100644
--- a/Help/guide/tutorial/MultiPackage/MathFunctions/CMakeLists.txt
+++ b/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt
@@ -17,6 +17,7 @@
 
   # first we add the executable that generates the table
   add_executable(MakeTable MakeTable.cxx)
+  target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags)
 
   # add the command to generate the source code
   add_custom_command(
@@ -41,19 +42,18 @@
                         POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
                         )
 
+  target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
   target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
 endif()
 
+target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
+
 # define the symbol stating we are using the declspec(dllexport) when
 # building on windows
 target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH")
 
-# setup the version numbering
-set_property(TARGET MathFunctions PROPERTY VERSION "1.0.0")
-set_property(TARGET MathFunctions PROPERTY SOVERSION "1")
-
 # install rules
-install(TARGETS MathFunctions
+install(TARGETS MathFunctions tutorial_compiler_flags
         DESTINATION lib
         EXPORT MathFunctionsTargets)
 install(FILES MathFunctions.h DESTINATION include)
diff --git a/Help/guide/tutorial/MultiPackage/MathFunctions/MakeTable.cxx b/Help/guide/tutorial/Step12/MathFunctions/MakeTable.cxx
similarity index 100%
rename from Help/guide/tutorial/MultiPackage/MathFunctions/MakeTable.cxx
rename to Help/guide/tutorial/Step12/MathFunctions/MakeTable.cxx
diff --git a/Help/guide/tutorial/MultiPackage/MathFunctions/MathFunctions.cxx b/Help/guide/tutorial/Step12/MathFunctions/MathFunctions.cxx
similarity index 100%
rename from Help/guide/tutorial/MultiPackage/MathFunctions/MathFunctions.cxx
rename to Help/guide/tutorial/Step12/MathFunctions/MathFunctions.cxx
diff --git a/Help/guide/tutorial/MultiPackage/MathFunctions/MathFunctions.h b/Help/guide/tutorial/Step12/MathFunctions/MathFunctions.h
similarity index 100%
rename from Help/guide/tutorial/MultiPackage/MathFunctions/MathFunctions.h
rename to Help/guide/tutorial/Step12/MathFunctions/MathFunctions.h
diff --git a/Help/guide/tutorial/MultiPackage/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step12/MathFunctions/mysqrt.cxx
similarity index 89%
rename from Help/guide/tutorial/MultiPackage/MathFunctions/mysqrt.cxx
rename to Help/guide/tutorial/Step12/MathFunctions/mysqrt.cxx
index 5e622be..8153f18 100644
--- a/Help/guide/tutorial/MultiPackage/MathFunctions/mysqrt.cxx
+++ b/Help/guide/tutorial/Step12/MathFunctions/mysqrt.cxx
@@ -17,11 +17,10 @@
   // use the table to help find an initial value
   double result = x;
   if (x >= 1 && x < 10) {
+    std::cout << "Use the table to help find an initial value " << std::endl;
     result = sqrtTable[static_cast<int>(x)];
   }
 
-  // if we have both log and exp then use them
-
   // do ten iterations
   for (int i = 0; i < 10; ++i) {
     if (result <= 0) {
diff --git a/Help/guide/tutorial/MultiPackage/MathFunctions/mysqrt.h b/Help/guide/tutorial/Step12/MathFunctions/mysqrt.h
similarity index 100%
rename from Help/guide/tutorial/MultiPackage/MathFunctions/mysqrt.h
rename to Help/guide/tutorial/Step12/MathFunctions/mysqrt.h
diff --git a/Help/guide/tutorial/MultiPackage/TutorialConfig.h.in b/Help/guide/tutorial/Step12/TutorialConfig.h.in
similarity index 68%
rename from Help/guide/tutorial/MultiPackage/TutorialConfig.h.in
rename to Help/guide/tutorial/Step12/TutorialConfig.h.in
index 8cd2fc9..7e4d7fa 100644
--- a/Help/guide/tutorial/MultiPackage/TutorialConfig.h.in
+++ b/Help/guide/tutorial/Step12/TutorialConfig.h.in
@@ -1,3 +1,3 @@
-// the configured version number
+// the configured options and settings for Tutorial
 #define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
 #define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
diff --git a/Help/guide/tutorial/MultiPackage/tutorial.cxx b/Help/guide/tutorial/Step12/tutorial.cxx
similarity index 89%
rename from Help/guide/tutorial/MultiPackage/tutorial.cxx
rename to Help/guide/tutorial/Step12/tutorial.cxx
index f97805b..a4f44d5 100644
--- a/Help/guide/tutorial/MultiPackage/tutorial.cxx
+++ b/Help/guide/tutorial/Step12/tutorial.cxx
@@ -8,6 +8,7 @@
 int main(int argc, char* argv[])
 {
   if (argc < 2) {
+    // report version
     std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
               << Tutorial_VERSION_MINOR << std::endl;
     std::cout << "Usage: " << argv[0] << " number" << std::endl;
@@ -15,7 +16,7 @@
   }
 
   // convert input to double
-  double inputValue = std::stod(argv[1]);
+  const double inputValue = std::stod(argv[1]);
 
   const double outputValue = mathfunctions::sqrt(inputValue);
 
diff --git a/Help/guide/tutorial/index.rst b/Help/guide/tutorial/index.rst
index d74d160..96f0486 100644
--- a/Help/guide/tutorial/index.rst
+++ b/Help/guide/tutorial/index.rst
@@ -45,7 +45,8 @@
 version number. While we could do this exclusively in the source code, using
 ``CMakeLists.txt`` provides more flexibility.
 
-First, modify the ``CMakeLists.txt`` file to set the version number.
+First, modify the ``CMakeLists.txt`` file to use the :command:`project` command
+to set the project name and version number.
 
 .. literalinclude:: Step2/CMakeLists.txt
   :language: cmake
@@ -102,9 +103,10 @@
 
 We will need to explicitly state in the CMake code that it should use the
 correct flags. The easiest way to enable support for a specific C++ standard
-in CMake is by using the ``CMAKE_CXX_STANDARD`` variable. For this tutorial,
-set the ``CMAKE_CXX_STANDARD`` variable in the ``CMakeLists.txt`` file to 11
-and ``CMAKE_CXX_STANDARD_REQUIRED`` to True:
+in CMake is by using the :variable:`CMAKE_CXX_STANDARD` variable. For this
+tutorial, set the :variable:`CMAKE_CXX_STANDARD` variable in the
+``CMakeLists.txt`` file to 11 and :variable:`CMAKE_CXX_STANDARD_REQUIRED` to
+True:
 
 .. literalinclude:: Step2/CMakeLists.txt
   :language: cmake
@@ -113,7 +115,8 @@
 Build and Test
 --------------
 
-Run **cmake** or **cmake-gui** to configure the project and then build it
+Run the :manual:`cmake <cmake(1)>` executable or the
+:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
 with your chosen build tool.
 
 For example, from the command line we could navigate to the
@@ -156,11 +159,11 @@
 .. literalinclude:: Step3/MathFunctions/CMakeLists.txt
   :language: cmake
 
-To make use of the new library we will add an ``add_subdirectory`` call in the
-top-level ``CMakeLists.txt`` file so that the library will get built. We add
-the new library to the executable, and add ``MathFunctions`` as an include
-directory so that the ``mqsqrt.h`` header file can be found. The last few lines
-of the top-level ``CMakeLists.txt`` file should now look like:
+To make use of the new library we will add an :command:`add_subdirectory`
+call in the top-level ``CMakeLists.txt`` file so that the library will get
+built. We add the new library to the executable, and add ``MathFunctions`` as
+an include directory so that the ``mqsqrt.h`` header file can be found. The
+last few lines of the top-level ``CMakeLists.txt`` file should now look like:
 
 .. code-block:: cmake
 
@@ -189,10 +192,11 @@
   :start-after: # should we use our own math functions
   :end-before: # add the MathFunctions library
 
-This option will be displayed in the CMake GUI and ccmake with a default
-value of ON that can be changed by the user. This setting will be stored in
-the cache so that the user does not need to set the value each time they run
-CMake on a build directory.
+This option will be displayed in the :manual:`cmake-gui <cmake-gui(1)>` and
+:manual:`ccmake <ccmake(1)>`
+with a default value of ON that can be changed by the user. This setting will
+be stored in the cache so that the user does not need to set the value each
+time they run CMake on a build directory.
 
 The next change is to make building and linking the MathFunctions library
 conditional. To do this we change the end of the top-level ``CMakeLists.txt``
@@ -234,11 +238,13 @@
 **Exercise**: Why is it important that we configure ``TutorialConfig.h.in``
 after the option for ``USE_MYMATH``? What would happen if we inverted the two?
 
-Run **cmake** or **cmake-gui** to configure the project and then build it
+Run the :manual:`cmake  <cmake(1)>` executable or the
+:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
 with your chosen build tool. Then run the built Tutorial executable.
 
-Use ccmake or the CMake GUI to update the value of ``USE_MYMATH``. Rebuild and
-run the tutorial again. Which function gives better results, sqrt or mysqrt?
+Use the :manual:`ccmake <ccmake(1)>` executable or the :manual:`cmake-gui <cmake-gui(1)>`
+to update the value of ``USE_MYMATH``. Rebuild and run the tutorial again.
+Which function gives better results, sqrt or mysqrt?
 
 Adding Usage Requirements for Library (Step 3)
 ==============================================
@@ -248,19 +254,20 @@
 property of targets inside CMake. The primary commands that leverage usage
 requirements are:
 
-  - ``target_compile_definitions``
-  - ``target_compile_options``
-  - ``target_include_directories``
-  - ``target_link_libraries``
+  - :command:`target_compile_definitions`
+  - :command:`target_compile_options`
+  - :command:`target_include_directories`
+  - :command:`target_link_libraries`
 
 Let's refactor our code from `Adding a Library (Step 2)`_ to use the modern
 CMake approach of usage requirements. We first state that anybody linking to
 MathFunctions needs to include the current source directory, while
-MathFunctions itself doesn't. So  this can become an ``INTERFACE`` usage
+MathFunctions itself doesn't. So this can become an ``INTERFACE`` usage
 requirement.
 
 Remember ``INTERFACE`` means things that consumers require but the producer
-doesn't. Add the following lines to the end of ``MathFunctions/CMakeLists.txt``:
+doesn't. Add the following lines to the end of
+``MathFunctions/CMakeLists.txt``:
 
 .. literalinclude:: Step4/MathFunctions/CMakeLists.txt
   :language: cmake
@@ -281,9 +288,10 @@
   :language: cmake
   :start-after: # so that we will find TutorialConfig.h
 
-Once this is done, run **cmake** or **cmake-gui** to configure the project
-and then build it with your chosen build tool or by using ``cmake --build .``
-from the build directory.
+Once this is done, run the :manual:`cmake  <cmake(1)>` executable or the
+:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
+with your chosen build tool or by using ``cmake --build .`` from the build
+directory.
 
 Installing and Testing (Step 4)
 ===============================
@@ -312,16 +320,17 @@
 
 That is all that is needed to create a basic local install of the tutorial.
 
-Run **cmake** or **cmake-gui** to configure the project and then build it
-with your chosen build tool. Run the install step by typing
-``cmake --install .`` (introduced in 3.15, older versions of CMake must use
-``make install``) from the command line, or build the ``INSTALL`` target from
-an IDE. This will install the appropriate header files, libraries, and
-executables.
+Run the :manual:`cmake  <cmake(1)>` executable or the
+:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
+with your chosen build tool. Run the install step by using the ``install``
+option of the :manual:`cmake  <cmake(1)>` command (introduced in 3.15, older
+versions of CMake must use ``make install``) from the command line, or build
+the ``INSTALL`` target from an IDE. This will install the appropriate header
+files, libraries, and executables.
 
-The CMake variable ``CMAKE_INSTALL_PREFIX`` is used to determine the root of
-where the files will be installed. If using ``cmake --install`` a custom
-installation directory can be given via ``--prefix`` argument. For
+The CMake variable :variable:`CMAKE_INSTALL_PREFIX` is used to determine the
+root of where the files will be installed. If using ``cmake --install`` a
+custom installation directory can be given via the ``--prefix`` argument. For
 multi-configuration tools, use the ``--config`` argument to specify the
 configuration.
 
@@ -339,25 +348,25 @@
   :start-after: # enable testing
 
 The first test simply verifies that the application runs, does not segfault or
-otherwise crash, and has a zero return value. This is the basic form of a CTest
-test.
+otherwise crash, and has a zero return value. This is the basic form of a
+CTest test.
 
-The next test makes use of the ``PASS_REGULAR_EXPRESSION`` test property to
-verify that the output of the test contains certain strings. In this case,
-verifying that the usage message is printed when an incorrect number of
-arguments are provided.
+The next test makes use of the :prop_test:`PASS_REGULAR_EXPRESSION` test
+property to verify that the output of the test contains certain strings. In
+this case, verifying that the usage message is printed when an incorrect number
+of arguments are provided.
 
 Lastly, we have a function called ``do_test`` that runs the application and
 verifies that the computed square root is correct for given input. For each
 invocation of ``do_test``, another test is added to the project with a name,
 input, and expected results based on the passed arguments.
 
-Rebuild the application and then cd to the binary directory and run
-``ctest -N`` and ``ctest -VV``. For multi-config generators (e.g. Visual
-Studio), the configuration type must be specified. To run tests in Debug mode,
-for example, use ``ctest -C Debug -VV`` from the build directory (not the
-Debug subdirectory!). Alternatively, build the ``RUN_TESTS`` target from the
-IDE.
+Rebuild the application and then cd to the binary directory and run the
+:manual:`ctest <ctest(1)>` executable: ``ctest -N`` and ``ctest -VV``. For
+multi-config generators (e.g. Visual Studio), the configuration type must be
+specified. To run tests in Debug mode, for example, use ``ctest -C Debug -VV``
+from the build directory (not the Debug subdirectory!). Alternatively, build
+the ``RUN_TESTS`` target from the IDE.
 
 Adding System Introspection (Step 5)
 ====================================
@@ -370,7 +379,7 @@
 
 If the platform has ``log`` and ``exp`` then we will use them to compute the
 square root in the ``mysqrt`` function. We first test for the availability of
-these functions using the ``CheckSymbolExists`` module in the top-level
+these functions using the :module:`CheckSymbolExists` module in the top-level
 ``CMakeLists.txt``. We're going to use the new defines in
 ``TutorialConfig.h.in``, so be sure to set them before that file is configured.
 
@@ -388,22 +397,29 @@
   #cmakedefine HAVE_LOG
   #cmakedefine HAVE_EXP
 
-Modify ``mysqrt.cxx`` to include cmath. Next, in that same file in the
-``mysqrt`` function we can provide an alternate implementation based on
-``log`` and ``exp`` if they are available on the system using the following
-code (don't forget the ``#endif`` before returning the result!):
+If ``log`` and ``exp`` are available on the system, then we will use them to
+compute the square root in the ``mysqrt`` function. Add the following code to
+the ``mysqrt`` function in ``MathFunctions/mysqrt.cxx`` (don't forget the
+``#endif`` before returning the result!):
 
 .. literalinclude:: Step6/MathFunctions/mysqrt.cxx
   :language: c++
   :start-after: // if we have both log and exp then use them
   :end-before: // do ten iterations
 
-Run **cmake** or **cmake-gui** to configure the project and then build it
+We will also need to modify ``mysqrt.cxx`` to include ``cmath``.
+
+.. literalinclude:: Step6/MathFunctions/mysqrt.cxx
+  :language: c++
+  :end-before: #include <iostream>
+
+Run the :manual:`cmake  <cmake(1)>` executable or the
+:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
 with your chosen build tool and run the Tutorial executable.
 
 You will notice that we're not using ``log`` and ``exp``, even if we think they
-should be available. We should realize quickly that we have forgotten to include
-``TutorialConfig.h`` in ``mysqrt.cxx``.
+should be available. We should realize quickly that we have forgotten to
+include ``TutorialConfig.h`` in ``mysqrt.cxx``.
 
 We will also need to update ``MathFunctions/CMakeLists.txt`` so ``mysqrt.cxx``
 knows where this file is located:
@@ -415,10 +431,10 @@
             PRIVATE ${CMAKE_BINARY_DIR}
             )
 
-After making this update, go ahead and build the project again and run the built
-Tutorial executable. If ``log`` and ``exp`` are still not being used, open the
-generated ``TutorialConfig.h`` file from the build directory. Maybe they aren't
-available on the current system?
+After making this update, go ahead and build the project again and run the
+built Tutorial executable. If ``log`` and ``exp`` are still not being used,
+open the generated ``TutorialConfig.h`` file from the build directory. Maybe
+they aren't available on the current system?
 
 Which function gives better results now, sqrt or mysqrt?
 
@@ -427,7 +443,7 @@
 
 Is there a better place for us to save the ``HAVE_LOG`` and ``HAVE_EXP`` values
 other than in ``TutorialConfig.h``? Let's try to use
-``target_compile_definitions``.
+:command:`target_compile_definitions`.
 
 First, remove the defines from ``TutorialConfig.h.in``. We no longer need to
 include ``TutorialConfig.h`` from ``mysqrt.cxx`` or the extra include in
@@ -460,8 +476,8 @@
 ``HAVE_EXP`` from ``mysqrt.cxx``. At the same time, we can remove
 :code:`#include <cmath>`.
 
-In the ``MathFunctions`` subdirectory, a new source file named ``MakeTable.cxx``
-has been provided to generate the table.
+In the ``MathFunctions`` subdirectory, a new source file named
+``MakeTable.cxx`` has been provided to generate the table.
 
 After reviewing the file, we can see that the table is produced as valid C++
 code and that the output filename is passed in as an argument.
@@ -510,7 +526,8 @@
   :language: c++
   :start-after: // a hack square root calculation using simple operations
 
-Run **cmake** or **cmake-gui** to configure the project and then build it
+Run the :manual:`cmake  <cmake(1)>` executable or the
+:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
 with your chosen build tool.
 
 When this project is built it will first build the ``MakeTable`` executable.
@@ -530,26 +547,28 @@
 installing the binaries that we had built from the source code. In this
 example we will be building installation packages that support binary
 installations and package management features. To accomplish this we will use
-CPack to create platform specific installers. Specifically we need to add
-a few lines to the bottom of our top-level ``CMakeLists.txt`` file.
+CPack to create platform specific installers. Specifically we need to add a
+few lines to the bottom of our top-level ``CMakeLists.txt`` file.
 
 .. literalinclude:: Step8/CMakeLists.txt
   :language: cmake
   :start-after: # setup installer
 
 That is all there is to it. We start by including
-``InstallRequiredSystemLibraries``. This module will include any runtime
-libraries that are needed by the project for the current platform. Next we
-set some CPack variables to where we have stored the license and version
+:module:`InstallRequiredSystemLibraries`. This module will include any runtime
+libraries that are needed by the project for the current platform. Next we set
+some CPack variables to where we have stored the license and version
 information for this project. The version information was set earlier in this
 tutorial and the ``license.txt`` has been included in the top-level source
 directory for this step.
 
-Finally we include the CPack module which will use these variables and some
-other properties of the current system to setup an installer.
+Finally we include the :module:`CPack module <CPack>` which will use these
+variables and some other properties of the current system to setup an
+installer.
 
-The next step is to build the project in the usual manner and then run
-CPack on it. To build a binary distribution, from the binary directory run:
+The next step is to build the project in the usual manner and then run the
+:manual:`cpack <cpack(1)>` executable. To build a binary distribution, from the
+binary directory run:
 
 .. code-block:: console
 
@@ -571,16 +590,17 @@
 Alternatively, run ``make package`` or right click the ``Package`` target and
 ``Build Project`` from an IDE.
 
-Run the installer found in the binary directory. Then run the
-installed executable and verify that it works.
+Run the installer found in the binary directory. Then run the installed
+executable and verify that it works.
 
 Adding Support for a Dashboard (Step 8)
 =======================================
 
-Adding support for submitting our test results to a dashboard is very easy. We
+Adding support for submitting our test results to a dashboard is simple. We
 already defined a number of tests for our project in `Testing Support`_. Now we
 just have to run those tests and submit them to a dashboard. To include support
-for dashboards we include the CTest module in our top-level ``CMakeLists.txt``.
+for dashboards we include the :module:`CTest` module in our top-level
+``CMakeLists.txt``.
 
 Replace:
 
@@ -596,8 +616,8 @@
   # enable dashboard scripting
   include(CTest)
 
-The CTest module will automatically call ``enable_testing()``, so
-we can remove it from our CMake files.
+The :module:`CTest` module will automatically call ``enable_testing()``, so we
+can remove it from our CMake files.
 
 We will also need to create a ``CTestConfig.cmake`` file in the top-level
 directory where we can specify the name of the project and where to submit the
@@ -606,9 +626,11 @@
 .. literalinclude:: Step9/CTestConfig.cmake
   :language: cmake
 
-CTest will read in this file when it runs. To create a simple dashboard you can
-run **cmake** or **cmake-gui** to configure the project, but do not build it
-yet. Instead, change directory to the binary tree, and then run::
+The :manual:`ctest <ctest(1)>` executable will read in this file when it runs.
+To create a simple dashboard you can run the :manual:`cmake <cmake(1)>`
+executable or the :manual:`cmake-gui <cmake-gui(1)>` to configure the project,
+but do not build it yet. Instead, change directory to the binary tree, and then
+run:
 
   ctest [-VV] -D Experimental
 
@@ -619,26 +641,26 @@
 
 Or, from an IDE, build the ``Experimental`` target.
 
-``ctest`` will build and test the project and submit the results to the Kitware
-public dashboard. The results of your dashboard will be uploaded to Kitware's
-public dashboard here: https://my.cdash.org/index.php?project=CMakeTutorial.
+The :manual:`ctest <ctest(1)>` executable will build and test the project and
+submit the results to Kitware's public dashboard:
+https://my.cdash.org/index.php?project=CMakeTutorial.
 
 Mixing Static and Shared (Step 9)
 =================================
 
-In this section we will show how by using the ``BUILD_SHARED_LIBS`` variable
-we can control the default behavior of ``add_library``, and allow control
-over how libraries without an explicit type (``STATIC``, ``SHARED``, ``MODULE``
-or ``OBJECT``) are built.
+In this section we will show how the :variable:`BUILD_SHARED_LIBS` variable can
+be used to control the default behavior of :command:`add_library`,
+and allow control over how libraries without an explicit type (``STATIC``,
+``SHARED``, ``MODULE`` or ``OBJECT``) are built.
 
-To accomplish this we need to add ``BUILD_SHARED_LIBS`` to the top-level
-``CMakeLists.txt``. We use the ``option`` command as it allows users to
-optionally select if the value should be On or Off.
+To accomplish this we need to add :variable:`BUILD_SHARED_LIBS` to the
+top-level ``CMakeLists.txt``. We use the :command:`option` command as it allows
+users to optionally select if the value should be ON or OFF.
 
 Next we are going to refactor MathFunctions to become a real library that
 encapsulates using ``mysqrt`` or ``sqrt``, instead of requiring the calling
 code to do this logic. This will also mean that ``USE_MYMATH`` will not control
-building MathFuctions, but instead will control the behavior of this library.
+building MathFunctions, but instead will control the behavior of this library.
 
 The first step is to update the starting section of the top-level
 ``CMakeLists.txt`` to look like:
@@ -680,8 +702,8 @@
 At this point, if you build everything, you will notice that linking fails
 as we are combining a static library without position independent code with a
 library that has position independent code. The solution to this is to
-explicitly set the ``POSITION_INDEPENDENT_CODE`` target property of SqrtLibrary
-to be True no matter the build type.
+explicitly set the :prop_tgt:`POSITION_INDEPENDENT_CODE` target property of
+SqrtLibrary to be True no matter the build type.
 
 .. literalinclude:: Step10/MathFunctions/CMakeLists.txt
   :language: cmake
@@ -694,35 +716,39 @@
 Adding Generator Expressions (Step 10)
 ======================================
 
-Generator expressions are evaluated during build system generation to produce
-information specific to each build configuration.
+:manual:`Generator expressions <cmake-generator-expressions(7)>` are evaluated
+during build system generation to produce information specific to each build
+configuration.
 
-Generator expressions are allowed in the context of many target properties,
-such as ``LINK_LIBRARIES``, ``INCLUDE_DIRECTORIES``, ``COMPILE_DEFINITIONS``
-and others. They may also be used when using commands to populate those
-properties, such as ``target_link_libraries()``,
-``target_include_directories()``,
-``target_compile_definitions()`` and others.
+:manual:`Generator expressions <cmake-generator-expressions(7)>` are allowed in
+the context of many target properties, such as :prop_tgt:`LINK_LIBRARIES`,
+:prop_tgt:`INCLUDE_DIRECTORIES`, :prop_tgt:`COMPILE_DEFINITIONS` and others.
+They may also be used when using commands to populate those properties, such as
+:command:`target_link_libraries`, :command:`target_include_directories`,
+:command:`target_compile_definitions` and others.
 
-Generator expressions may be used to enable conditional linking, conditional
-definitions used when compiling, conditional include directories and more.
-The conditions may be based on the build configuration, target properties,
-platform information or any other queryable information.
+:manual:`Generator expressions <cmake-generator-expressions(7)>`  may be used
+to enable conditional linking, conditional definitions used when compiling,
+conditional include directories and more. The conditions may be based on the
+build configuration, target properties, platform information or any other
+queryable information.
 
-There are different types of generator expressions including Logical,
-Informational, and Output expressions.
+There are different types of
+:manual:`generator expressions <cmake-generator-expressions(7)>` including
+Logical, Informational, and Output expressions.
 
 Logical expressions are used to create conditional output. The basic
 expressions are the 0 and 1 expressions. A ``$<0:...>`` results in the empty
 string, and ``<1:...>`` results in the content of "...".  They can also be
 nested.
 
-A common usage of generator expressions is to conditionally add compiler
-flags, such as those for language levels or warnings. A nice pattern is
-to associate this information to an ``INTERFACE`` target allowing this
-information to propagate. Lets start by constructing an ``INTERFACE``
-target and specifying the required C++ standard level of ``11`` instead
-of using ``CMAKE_CXX_STANDARD``.
+A common usage of
+:manual:`generator expressions <cmake-generator-expressions(7)>` is to
+conditionally add compiler flags, such as those for language levels or
+warnings. A nice pattern is to associate this information to an ``INTERFACE``
+target allowing this information to propagate. Lets start by constructing an
+``INTERFACE`` target and specifying the required C++ standard level of ``11``
+instead of using :variable:`CMAKE_CXX_STANDARD`.
 
 So the following code:
 
@@ -739,11 +765,10 @@
   :end-before: # add compiler warning flags just when building this project via
 
 
-Next we add the desired compiler warning flags that we want for our
-project. As warning flags vary based on the compiler we use
-the ``COMPILE_LANG_AND_ID`` generator expression to control which
-flags to apply given a language and a set of compiler ids as seen
-below:
+Next we add the desired compiler warning flags that we want for our project. As
+warning flags vary based on the compiler we use the ``COMPILE_LANG_AND_ID``
+generator expression to control which flags to apply given a language and a set
+of compiler ids as seen below:
 
 .. literalinclude:: Step11/CMakeLists.txt
   :language: cmake
@@ -755,8 +780,8 @@
 project will not inherit our warning flags.
 
 
-**Exercise**: Modify ``MathFunctions/CMakeLists.txt`` so that
-all targets have a ``target_link_libraries()`` call to ``tutorial_compiler_flags``.
+**Exercise**: Modify ``MathFunctions/CMakeLists.txt`` so that all targets have
+a :command:`target_link_libraries` call to ``tutorial_compiler_flags``.
 
 
 Adding Export Configuration (Step 11)
@@ -771,12 +796,12 @@
 can use our project, be it from a build directory, a local install or when
 packaged.
 
-The first step is to update our ``install(TARGETS)`` commands to not only
-specify a ``DESTINATION`` but also an ``EXPORT``. The ``EXPORT`` keyword
+The first step is to update our :command:`install(TARGETS)` commands to not
+only specify a ``DESTINATION`` but also an ``EXPORT``. The ``EXPORT`` keyword
 generates and installs a CMake file containing code to import all targets
-listed in the install command from the installation tree. So let's go ahead
-and explicitly ``EXPORT`` the MathFunctions library by updating the
-``install`` command in ``MathFunctions/CMakeLists.txt`` to look like:
+listed in the install command from the installation tree. So let's go ahead and
+explicitly ``EXPORT`` the MathFunctions library by updating the ``install``
+command in ``MathFunctions/CMakeLists.txt`` to look like:
 
 .. literalinclude:: Complete/MathFunctions/CMakeLists.txt
   :language: cmake
@@ -806,12 +831,12 @@
 What CMake is trying to say is that during generating the export information
 it will export a path that is intrinsically tied to the current machine and
 will not be valid on other machines. The solution to this is to update the
-MathFunctions ``target_include_directories`` to understand that it needs
+MathFunctions :command:`target_include_directories` to understand that it needs
 different ``INTERFACE`` locations when being used from within the build
 directory and from an install / package. This means converting the
-``target_include_directories`` call for MathFunctions to look like:
+:command:`target_include_directories` call for MathFunctions to look like:
 
-.. literalinclude:: Complete/MathFunctions/CMakeLists.txt
+.. literalinclude:: Step12/MathFunctions/CMakeLists.txt
   :language: cmake
   :start-after: # to find MathFunctions.h, while we don't.
   :end-before: # should we use our own math functions
@@ -821,16 +846,16 @@
 
 At this point, we have CMake properly packaging the target information that is
 required but we will still need to generate a ``MathFunctionsConfig.cmake`` so
-that the CMake ``find_package`` command can find our project. So let's go
+that the CMake :command:`find_package` command can find our project. So let's go
 ahead and add a new file to the top-level of the project called
 ``Config.cmake.in`` with the following contents:
 
-.. literalinclude:: Complete/Config.cmake.in
+.. literalinclude:: Step12/Config.cmake.in
 
 Then, to properly configure and install that file, add the following to the
 bottom of the top-level ``CMakeLists.txt``:
 
-.. literalinclude:: Complete/CMakeLists.txt
+.. literalinclude:: Step12/CMakeLists.txt
   :language: cmake
   :start-after: # install the configuration targets
   :end-before: # generate the export
@@ -840,7 +865,7 @@
 we want our project to also be used from a build directory we only have to add
 the following to the bottom of the top level ``CMakeLists.txt``:
 
-.. literalinclude:: Complete/CMakeLists.txt
+.. literalinclude:: Step12/CMakeLists.txt
   :language: cmake
   :start-after: # needs to be after the install(TARGETS ) command
 
@@ -848,55 +873,81 @@
 configured ``MathFunctionsConfig.cmake`` in the build directory to be used by
 other projects, without needing it to be installed.
 
-Import a CMake Project (Consumer)
-=================================
+Packaging Debug and Release (Step 12)
+=====================================
 
-This example shows how a project can find other CMake packages that
-generate ``Config.cmake`` files.
+**Note:** This example is valid for single-configuration generators and will
+not work for multi-configuration generators (e.g. Visual Studio).
 
-It also shows how to state a project's external dependencies when generating
-a ``Config.cmake``.
+By default, CMake's model is that a build directory only contains a single
+configuration, be it Debug, Release, MinSizeRel, or RelWithDebInfo. It is
+possible, however, to setup CPack to bundle multiple build directories and
+construct a package that contains multiple configurations of the same project.
 
-Packaging Debug and Release (MultiPackage)
-==========================================
+First, we want to ensure that the debug and release builds use different names
+for the executables and libraries that will be installed. Let's use `d` as the
+postfix for the debug executable and libraries.
 
-By default CMake's model is that a build directory only contains a single
-configuration, be it Debug, Release, MinSizeRel, or RelWithDebInfo.
+Set :variable:`CMAKE_DEBUG_POSTFIX` near the beginning of the top-level
+``CMakeLists.txt`` file:
 
-But it is possible to setup CPack to bundle multiple build directories at the
-same time to build a package that contains multiple configurations of the
-same project.
+.. literalinclude:: Complete/CMakeLists.txt
+  :language: cmake
+  :start-after: project(Tutorial VERSION 1.0)
+  :end-before: target_compile_features(tutorial_compiler_flags
 
-First we need to construct a directory called ``multi_config``, which
-will contain all the builds that we want to package together.
+And the :prop_tgt:`DEBUG_POSTFIX` property on the tutorial executable:
 
-Second create a ``debug`` and ``release`` directory underneath
-``multi_config``. At the end you should have a layout that looks like:
+.. literalinclude:: Complete/CMakeLists.txt
+  :language: cmake
+  :start-after: # add the executable
+  :end-before: # add the binary tree to the search path for include files
+
+Let's also add version numbering to the MathFunctions library. In
+``MathFunctions/CMakeLists.txt``, set the :prop_tgt:`VERSION` and
+:prop_tgt:`SOVERSION` properties:
+
+.. literalinclude:: Complete/MathFunctions/CMakeLists.txt
+  :language: cmake
+  :start-after: # setup the version numbering
+  :end-before: # install rules
+
+From the ``Step12`` directory, create ``debug`` and ``release``
+subbdirectories. The layout will look like:
 
 .. code-block:: none
 
-  ─ multi_config
-      ├── debug
-      └── release
+  - Step12
+     └── debug
+     └── release
 
-Now we need to setup debug and release builds, which would roughly entail
-the following:
+Now we need to setup debug and release builds. We can use
+:variable:`CMAKE_BUILD_TYPE` to set the configuration type:
 
 .. code-block:: console
 
   cd debug
-  cmake -DCMAKE_BUILD_TYPE=Debug ../../MultiPackage/
+  cmake -DCMAKE_BUILD_TYPE=Debug ..
   cmake --build .
   cd ../release
-  cmake -DCMAKE_BUILD_TYPE=Release ../../MultiPackage/
+  cmake -DCMAKE_BUILD_TYPE=Release ..
   cmake --build .
-  cd ..
 
+Now that both the debug and release builds are complete, we can use a custom
+configuration file to package both builds into a single release. In the
+``Step12`` directory, create a file called ``MultiCPackConfig.cmake``. In this
+file, first include the default configuration file that was created by the
+:manual:`cmake  <cmake(1)>` executable.
 
-Now that both the debug and release builds are complete, we can use
-a custom ``MultiCPackConfig.cmake`` file to package both builds into a single
-release.
+Next, use the ``CPACK_INSTALL_CMAKE_PROJECTS`` variable to specify which
+projects to install. In this case, we want to install both debug and release.
+
+.. literalinclude:: Complete/MultiCPackConfig.cmake
+  :language: cmake
+
+From the ``Step12`` directory, run :manual:`cpack <cpack(1)>` specifying our
+custom configuration file with the ``config`` option:
 
 .. code-block:: console
 
-  cpack --config ../../MultiPackage/MultiCPackConfig.cmake
+  cpack --config MultiCPackConfig.cmake
diff --git a/Help/guide/user-interaction/GUI-Add-Entry.png b/Help/guide/user-interaction/GUI-Add-Entry.png
new file mode 100644
index 0000000..1e9be7e
--- /dev/null
+++ b/Help/guide/user-interaction/GUI-Add-Entry.png
Binary files differ
diff --git a/Help/guide/user-interaction/GUI-Choose-Generator.png b/Help/guide/user-interaction/GUI-Choose-Generator.png
new file mode 100644
index 0000000..19ad2c0
--- /dev/null
+++ b/Help/guide/user-interaction/GUI-Choose-Generator.png
Binary files differ
diff --git a/Help/guide/user-interaction/GUI-Configure-Dialog.png b/Help/guide/user-interaction/GUI-Configure-Dialog.png
new file mode 100644
index 0000000..9839cac
--- /dev/null
+++ b/Help/guide/user-interaction/GUI-Configure-Dialog.png
Binary files differ
diff --git a/Help/guide/user-interaction/GUI-Source-Binary.png b/Help/guide/user-interaction/GUI-Source-Binary.png
new file mode 100644
index 0000000..e338354
--- /dev/null
+++ b/Help/guide/user-interaction/GUI-Source-Binary.png
Binary files differ
diff --git a/Help/guide/user-interaction/index.rst b/Help/guide/user-interaction/index.rst
new file mode 100644
index 0000000..3a1038f
--- /dev/null
+++ b/Help/guide/user-interaction/index.rst
@@ -0,0 +1,686 @@
+User Interaction Guide
+**********************
+
+.. only:: html
+
+   .. contents::
+
+Introduction
+============
+
+Where a software package supplies a CMake-based buildsystem
+with the source of their software, the consumer of the
+software is required to run a CMake user interaction tool
+in order to build it.
+
+Well-behaved CMake-based buildsystems do not create any
+output in the source directory, so typically, the user
+performs an out-of-source build and performs the build
+there.  First, CMake must be instructed to generate a
+suitable buildsystem, then the user invokes a build tool
+to process that generated buildsystem.  The generated
+buildsystem is specific to the machine used to generate
+it and is not redistributable.  Each consumer of a provided
+source software package is required to use CMake to
+generate a buildsystem specific to their system.
+
+Generated buildsystems should generally be treated as
+read-only. The CMake files as a primary artifact should
+completely specify the buildsystem and there should be no
+reason to populate properties manually in an IDE for
+example after generating the buildsystem.  CMake will
+periodically rewrite the generated buildsystem, so
+modifications by users will be overwritten.
+
+The features and user interfaces described in this manual
+are available for all CMake-based build systems by virtue
+of providing CMake files.
+
+The CMake tooling may report errors to the user when
+processing provided CMake files, such as reporting that
+the compiler is not supported, or the compiler does not
+support a required compile option, or a dependency can
+not be found.  These errors must be resolved by the user
+by choosing a different compiler,
+:guide:`installing dependencies <Using Dependencies Guide>`,
+or instructing CMake where to find them, etc.
+
+Command Line cmake tool
+-----------------------
+
+A simple but typical use of :manual:`cmake(1)` with a fresh
+copy of software source code is to create a build directory
+and invoke cmake there:
+
+.. code-block:: console
+
+  $ cd some_software-1.4.2
+  $ mkdir build
+  $ cd build
+  $ cmake .. -DCMAKE_INSTALL_PREFIX=/opt/the/prefix
+  $ cmake --build .
+  $ cmake --build . --target install
+
+It is recommended to build in a separate directory to the
+source because that keeps the source directory pristine,
+allows for building a single source with multiple
+toolchains, and allows easy clearing of build artifacts by
+simply deleting the build directory.
+
+The CMake tooling may report warnings which are intended
+for the provider of the software, not intended for the
+consumer of the software.  Such warnings end with "This
+warning is for project developers".  Users may disable
+such warnings by passing the ``-Wno-dev`` flag to
+:manual:`cmake(1)`.
+
+cmake-gui tool
+--------------
+
+Users more accustomed to GUI interfaces may use the
+:manual:`cmake-gui(1)` tool to invoke CMake and generate
+a buildsystem.
+
+The source and binary directories must first be
+populated.  It is always advised to use different
+directories for the source and the build.
+
+.. image:: /guide/user-interaction/GUI-Source-Binary.png
+
+Generating a Buildsystem
+========================
+
+There are several user interface tools which may be used
+to generate a buildsystem from CMake files.  The
+:manual:`ccmake(1)` and :manual:`cmake-gui(1)` tools guide
+the user through setting the various necessary options.
+The :manual:`cmake(1)` tool can be invoked to specify
+options on the command line.  This manual describes options
+which may be set using any of the user interface tools,
+though the mode of setting an option is different for each
+tool.
+
+Command line environment
+------------------------
+
+When invoking :manual:`cmake(1)` with a command line
+buildsystem such as ``Makefiles`` or ``Ninja``, it is
+necessary to use the correct build environment to
+ensure that build tools are available. CMake must be
+able to find the appropriate
+:variable:`build tool <CMAKE_MAKE_PROGRAM>`,
+compiler, linker and other tools as needed.
+
+On Linux systems, the appropriate tools are often
+provided in system-wide locations and may be readily
+installed through the system package manager. Other
+toolchains provided by the user or installed in
+non-default locations can also be used.
+
+When cross-compiling, some platforms may require
+environment variables to be set or may provide
+scripts to set the environment.
+
+Visual Studio ships multiple command prompts and
+``vcvarsall.bat`` scripts for setting up the
+correct environments for command line buildsystems. While
+not strictly necessary to use a corresponding
+command line environment when using a Visual Studio
+generator, doing so has no disadvantages.
+
+When using Xcode, there can be more than one Xcode
+version installed.  Which one to use can be selected
+in a number of different ways, but the most common
+methods are:
+
+* Setting the default version in the preferences
+  of the Xcode IDE.
+* Setting the default version via the ``xcode-select``
+  command line tool.
+* Overriding the default version by setting the
+  ``DEVELOPER_DIR`` environment variable when running
+  CMake and the build tool.
+
+Command line ``-G`` option
+--------------------------
+
+CMake chooses a generator by default based on the
+platform.  Usually, the default generator is sufficient
+to allow the user to proceed to build the software.
+
+The user may override the default generator with
+the ``-G`` option:
+
+.. code-block:: console
+
+  $ cmake .. -G Ninja
+
+The output of ``cmake --help`` includes a list of
+:manual:`generators <cmake-generators(7)>` available
+for the user to choose from.  Note that generator
+names are case sensitive.
+
+On Unix-like systems (including Mac OS X), the
+:generator:`Unix Makefiles` generator is used by
+default.  A variant of that generator can also be used
+on Windows in various environments, such as the
+:generator:`NMake Makefiles` and
+:generator:`MinGW Makefiles` generator.  These generators
+generate a ``Makefile`` variant which can be executed
+with ``make``, ``gmake``, ``nmake`` or similar tools.
+See the individual generator documentation for more
+information on targeted environments and tools.
+
+The :generator:`Ninja` generator is available on all
+major platforms. ``ninja`` is a build tool similar
+in use-cases to ``make``, but with a focus on
+performance and efficiency.
+
+On Windows, :manual:`cmake(1)` can be used to generate
+solutions for the Visual Studio IDE.  Visual Studio
+versions may be specified by the product name of the
+IDE, which includes a four-digit year.  Aliases are
+provided for other means by which Visual Studio
+versions are sometimes referred to, such as two
+digits which correspond to the product version of the
+VisualC++ compiler, or a combination of the two:
+
+.. code-block:: console
+
+  $ cmake .. -G "Visual Studio 2019"
+  $ cmake .. -G "Visual Studio 16"
+  $ cmake .. -G "Visual Studio 16 2019"
+
+Visual Studio generators can target different architectures.
+One can specify the target architecture using the `-A` option:
+
+.. code-block:: console
+
+  cmake .. -G "Visual Studio 2019" -A x64
+  cmake .. -G "Visual Studio 16" -A ARM
+  cmake .. -G "Visual Studio 16 2019" -A ARM64
+
+On Apple, the :generator:`Xcode` generator may be used to
+generate project files for the Xcode IDE.
+
+Some IDEs such as KDevelop4, QtCreator and CLion have
+native support for CMake-based buildsystems.  Those IDEs
+provide user interface for selecting an underlying
+generator to use, typically a choice between a ``Makefile``
+or a ``Ninja`` based generator.
+
+Note that it is not possible to change the generator
+with ``-G`` after the first invocation of CMake.  To
+change the generator, the build directory must be
+deleted and the build must be started from scratch.
+
+When generating Visual Studio project and solutions
+files several other options are available to use when
+initially running :manual:`cmake(1)`.
+
+The Visual Studio toolset can be specified with the
+``-T`` option:
+
+.. code-block:: console
+
+    $ # Build with the clang-cl toolset
+    $ cmake.exe .. -G "Visual Studio 16 2019" -A x64 -T LLVM
+    $ # Build targeting Windows XP
+    $ cmake.exe .. -G "Visual Studio 16 2019" -A x64 -T v120_xp
+
+Whereas the ``-A`` option specifies the _target_
+architecture, the ``-T`` option can be used to specify
+details of the toolchain used.  For example, `-Thost=x64`
+can be given to select the 64-bit version of the host
+tools.  The following demonstrates how to use 64-bit
+tools and also build for a 64-bit target architecture:
+
+.. code-block:: console
+
+    $ cmake .. -G "Visual Studio 16 2019" -A x64 -Thost=x64
+
+Choosing a generator in cmake-gui
+---------------------------------
+
+The "Configure" button triggers a new dialog to
+select the CMake generator to use.
+
+.. image:: /guide/user-interaction/GUI-Configure-Dialog.png
+
+All generators available on the command line are also
+available in :manual:`cmake-gui(1)`.
+
+.. image:: /guide/user-interaction/GUI-Choose-Generator.png
+
+When choosing a Visual Studio generator, further options
+are available to set an architecture to generate for.
+
+.. image:: /manual/VS-Choose-Arch.png
+
+.. _`Setting Build Variables`:
+
+Setting Build Variables
+=======================
+
+Software projects often require variables to be
+set on the command line when invoking CMake.  Some of
+the most commonly used CMake variables are listed in
+the table below:
+
+========================================== ============================================================
+ Variable                                   Meaning
+========================================== ============================================================
+ :variable:`CMAKE_PREFIX_PATH`              Path to search for
+                                            :guide:`dependent packages <Using Dependencies Guide>`
+ :variable:`CMAKE_MODULE_PATH`              Path to search for additional CMake modules
+ :variable:`CMAKE_BUILD_TYPE`               Build configuration, such as
+                                            ``Debug`` or ``Release``, determining
+                                            debug/optimization flags.  This is only
+                                            relevant for single-configuration buildsystems such
+                                            as ``Makefile`` and ``Ninja``.  Multi-configuration
+                                            buildsystems such as those for Visual Studio and Xcode
+                                            ignore this setting.
+ :variable:`CMAKE_INSTALL_PREFIX`           Location to install the
+                                            software to with the
+                                            ``install`` build target
+ :variable:`CMAKE_TOOLCHAIN_FILE`           File containing cross-compiling
+                                            data such as
+                                            :manual:`toolchains and sysroots <cmake-toolchains(7)>`.
+ :variable:`BUILD_SHARED_LIBS`              Whether to build shared
+                                            instead of static libraries
+                                            for :command:`add_library`
+                                            commands used without a type
+ :variable:`CMAKE_EXPORT_COMPILE_COMMANDS`  Generate a ``compile_commands.json``
+                                            file for use with clang-based tools
+========================================== ============================================================
+
+Other project-specific variables may be available
+to control builds, such as enabling or disabling
+components of the project.
+
+There is no convention provided by CMake for how
+such variables are named between different
+provided buildsystems, except that variables with
+the prefix ``CMAKE_`` usually refer to options
+provided by CMake itself and should not be used
+in third-party options, which should use
+their own prefix instead.  The
+:manual:`cmake-gui(1)` tool can display options
+in groups defined by their prefix, so it makes
+sense for third parties to ensure that they use a
+self-consistent prefix.
+
+Setting variables on the command line
+-------------------------------------
+
+CMake variables can be set on the command line either
+when creating the initial build:
+
+.. code-block:: console
+
+    $ mkdir build
+    $ cd build
+    $ cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug
+
+or later on a subsequent invocation of
+:manual:`cmake(1)`:
+
+.. code-block:: console
+
+    $ cd build
+    $ cmake . -DCMAKE_BUILD_TYPE=Debug
+
+The ``-U`` flag may be used to unset variables
+on the :manual:`cmake(1)` command line:
+
+.. code-block:: console
+
+    $ cd build
+    $ cmake . -UMyPackage_DIR
+
+A CMake buildsystem which was initially created
+on the command line can be modified using the
+:manual:`cmake-gui(1)` and vice-versa.
+
+The :manual:`cmake(1)` tool allows specifying a
+file to use to populate the initial cache using
+the ``-C`` option.  This can be useful to simplify
+commands and scripts which repeatedly require the
+same cache entries.
+
+Setting variables with cmake-gui
+--------------------------------
+
+Variables may be set in the cmake-gui using the "Add Entry"
+button.  This triggers a new dialog to set the value of
+the variable.
+
+.. image:: /guide/user-interaction/GUI-Add-Entry.png
+
+The main view of the :manual:`cmake-gui(1)` user interface
+can be used to edit existing variables.
+
+The CMake Cache
+---------------
+
+When CMake is executed, it needs to find the locations of
+compilers, tools and dependencies.  It also needs to be
+able to consistently re-generate a buildsystem to use the
+same compile/link flags and paths to dependencies.  Such
+parameters are also required to be configurable by the
+user because they are paths and options specific to the
+users system.
+
+When it is first executed, CMake generates a
+``CMakeCache.txt`` file in the build directory containing
+key-value pairs for such artifacts.  The cache file can be
+viewed or edited by the user by running the
+:manual:`cmake-gui(1)` or :manual:`ccmake(1)` tool.  The
+tools provide an interactive interface for re-configuring
+the provided software and re-generating the buildsystem,
+as is needed after editing cached values.  Each cache
+entry may have an associated short help text which is
+displayed in the user interface tools.
+
+The cache entries may also have a type to signify how it
+should be presented in the user interface.  For example,
+a cache entry of type ``BOOL`` can be edited by a
+checkbox in a user interface, a ``STRING`` can be edited
+in a text field, and a ``FILEPATH`` while similar to a
+``STRING`` should also provide a way to locate filesystem
+paths using a file dialog.  An entry of type ``STRING``
+may provide a restricted list of allowed values which are
+then provided in a drop-down menu in the
+:manual:`cmake-gui(1)` user interface (see the
+:prop_cache:`STRINGS` cache property).
+
+The CMake files shipped with a software package may also
+define boolean toggle options using the :command:`option`
+command.  The command creates a cache entry which has a
+help text and a default value.  Such cache entries are
+typically specific to the provided software and affect
+the configuration of the build, such as whether tests
+and examples are built, whether to build with exceptions
+enabled etc.
+
+Invoking the Buildsystem
+========================
+
+After generating the buildsystem, the software can be
+built by invoking the particular build tool.  In the
+case of the IDE generators, this can involve loading
+the generated project file into the IDE to invoke the
+build.
+
+CMake is aware of the specific build tool needed to invoke
+a build so in general, to build a buildsystem or project
+from the command line after generating, the following
+command may be invoked in the build directory:
+
+.. code-block:: console
+
+  $ cmake --build .
+
+The ``--build`` flag enables a particular mode of
+operation for the :manual:`cmake(1)` tool.  It invokes
+the  :variable:`CMAKE_MAKE_PROGRAM` command associated
+with the :manual:`generator <cmake-generators(7)>`, or
+the build tool configured by the user.
+
+The ``--build`` mode also accepts the parameter
+``--target`` to specify a particular target to build,
+for example a particular library, executable or
+custom target, or a particular special target like
+``install``:
+
+.. code-block:: console
+
+  $ cmake --build . --target myexe
+
+The ``--build`` mode also accepts a ``--config`` parameter
+in the case of multi-config generators to specify which
+particular configuration to build:
+
+.. code-block:: console
+
+  $ cmake --build . --target myexe --config Release
+
+The ``--config`` option has no effect if the generator
+generates a buildsystem specific to a configuration which
+is chosen when invoking cmake with the
+:variable:`CMAKE_BUILD_TYPE` variable.
+
+Some buildsystems omit details of command lines invoked
+during the build.  The ``--verbose`` flag can be used to
+cause those command lines to be shown:
+
+.. code-block:: console
+
+  $ cmake --build . --target myexe --verbose
+
+The ``--build`` mode can also pass particular command
+line options to the underlying build tool by listing
+them after ``--``.  This can be useful to specify
+options to the build tool, such as to continue the
+build after a failed job, where CMake does not
+provide a high-level user interface.
+
+For all generators, it is possible to run the underlying
+build tool after invoking CMake.  For example, ``make``
+may be executed after generating with the
+:generator:`Unix Makefiles` generator to invoke the build,
+or ``ninja`` after generating with the :generator:`Ninja`
+generator etc.  The IDE buildsystems usually provide
+command line tooling for building a project which can
+also be invoked.
+
+Selecting a Target
+------------------
+
+Each executable and library described in the CMake files
+is a build target, and the buildsystem may describe
+custom targets, either for internal use, or for user
+consumption, for example to create documentation.
+
+CMake provides some built-in targets for all buildsystems
+providing CMake files.
+
+``all``
+  The default target used by ``Makefile`` and ``Ninja``
+  generators.  Builds all targets in the buildsystem,
+  except those which are excluded by their
+  :prop_tgt:`EXCLUDE_FROM_ALL` target property or
+  :prop_dir:`EXCLUDE_FROM_ALL` directory property.  The
+  name ``ALL_BUILD`` is used for this purpose for the
+  Xcode and Visual Studio generators.
+``help``
+  Lists the targets available for build.  This target is
+  available when using the :generator:`Unix Makefiles` or
+  :generator:`Ninja` generator, and the exact output is
+  tool-specific.
+``clean``
+  Delete built object files and other output files.  The
+  ``Makefile`` based generators create a ``clean`` target
+  per directory, so that an individual directory can be
+  cleaned.  The ``Ninja`` tool provides its own granular
+  ``-t clean`` system.
+``test``
+  Runs tests.  This target is only automatically available
+  if the CMake files provide CTest-based tests.  See also
+  `Running Tests`_.
+``install``
+  Installs the software.  This target is only automatically
+  available if the software defines install rules with the
+  :command:`install` command.  See also
+  `Software Installation`_.
+``package``
+  Creates a binary package.  This target is only
+  automatically available if the CMake files provide
+  CPack-based packages.
+``package_source``
+  Creates a source package.  This target is only
+  automatically available if the CMake files provide
+  CPack-based packages.
+
+For ``Makefile`` based systems, ``/fast`` variants of binary
+build targets are provided. The ``/fast`` variants are used
+to build the specified target without regard for its
+dependencies.  The dependencies are not checked and
+are not rebuilt if out of date.  The :generator:`Ninja`
+generator is sufficiently fast at dependency checking that
+such targets are not provided for that generator.
+
+``Makefile`` based systems also provide build-targets to
+preprocess, assemble and compile individual files in a
+particular directory.
+
+.. code-block:: console
+
+  $ make foo.cpp.i
+  $ make foo.cpp.s
+  $ make foo.cpp.o
+
+The file extension is built into the name of the target
+because another file with the same name but a different
+extension may exist.  However, build-targets without the
+file extension are also provided.
+
+.. code-block:: console
+
+  $ make foo.i
+  $ make foo.s
+  $ make foo.o
+
+In buildsystems which contain ``foo.c`` and ``foo.cpp``,
+building the ``foo.i`` target will preprocess both files.
+
+Specifying a Build Program
+--------------------------
+
+The program invoked by the ``--build`` mode is determined
+by the :variable:`CMAKE_MAKE_PROGRAM` variable.  For most
+generators, the particular program does not need to be
+configured.
+
+===================== =========================== ===========================
+      Generator           Default make program           Alternatives
+===================== =========================== ===========================
+ XCode                 ``xcodebuild``
+ Unix Makefiles        ``make``
+ NMake Makefiles       ``nmake``                   ``jom``
+ NMake Makefiles JOM   ``jom``                     ``nmake``
+ MinGW Makefiles       ``mingw32-make``
+ MSYS Makefiles        ``make``
+ Ninja                 ``ninja``
+ Visual Studio         ``msbuild``
+ Watcom WMake          ``wmake``
+===================== =========================== ===========================
+
+The ``jom`` tool is capable of reading makefiles of the
+``NMake`` flavor and building in parallel, while the
+``nmake`` tool always builds serially.  After generating
+with the :generator:`NMake Makefiles` generator a user
+can run ``jom`` instead of ``nmake``.  The ``--build``
+mode would also use ``jom`` if the
+:variable:`CMAKE_MAKE_PROGRAM` was set to ``jom`` while
+using the :generator:`NMake Makefiles` generator, and
+as a convenience, the :generator:`NMake Makefiles JOM`
+generator is provided to find ``jom`` in the normal way
+and use it as the :variable:`CMAKE_MAKE_PROGRAM`. For
+completeness, ``nmake`` is an alternative tool which
+can process the output of the
+:generator:`NMake Makefiles JOM` generator, but doing
+so would be a pessimisation.
+
+Software Installation
+=====================
+
+The :variable:`CMAKE_INSTALL_PREFIX` variable can be
+set in the CMake cache to specify where to install the
+provided software.  If the provided software has install
+rules, specified using the :command:`install` command,
+they will install artifacts into that prefix.  On Windows,
+the default installation location corresponds to the
+``ProgramFiles`` system directory which may be
+architecture specific.  On Unix hosts, ``/usr/local`` is
+the default installation location.
+
+The :variable:`CMAKE_INSTALL_PREFIX` variable always
+refers to the installation prefix on the target
+filesystem.
+
+In cross-compiling or packaging scenarios where the
+sysroot is read-only or where the sysroot should otherwise
+remain pristine, the :variable:`CMAKE_STAGING_PREFIX`
+variable can be set to a location to actually install
+the files.
+
+The commands:
+
+.. code-block:: console
+
+  $ cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local \
+    -DCMAKE_SYSROOT=$HOME/root \
+    -DCMAKE_STAGING_PREFIX=/tmp/package
+  $ cmake --build .
+  $ cmake --build . --target install
+
+result in files being installed to paths such
+as ``/tmp/package/lib/libfoo.so`` on the host machine.
+The ``/usr/local`` location on the host machine is
+not affected.
+
+Some provided software may specify ``uninstall`` rules,
+but CMake does not generate such rules by default itself.
+
+Running Tests
+=============
+
+The :manual:`ctest(1)` tool is shipped with the CMake
+distribution to execute provided tests and report
+results.  The ``test`` build-target is provided to run
+all available tests, but the :manual:`ctest(1)` tool
+allows granular control over which tests to run, how to
+run them, and how to report results.  Executing
+:manual:`ctest(1)` in the build directory is equivalent
+to running the ``test`` target:
+
+.. code-block:: console
+
+  $ ctest
+
+A regular expression can be passed to run only tests
+which match the expression.  To run only tests with
+``Qt`` in their name:
+
+.. code-block:: console
+
+  $ ctest -R Qt
+
+Tests can be excluded by regular expression too.  To
+run only tests without ``Qt`` in their name:
+
+.. code-block:: console
+
+  $ ctest -E Qt
+
+Tests can be run in parallel by passing ``-j`` arguments
+to :manual:`ctest(1)`:
+
+.. code-block:: console
+
+  $ ctest -R Qt -j8
+
+The environment variable :envvar:`CTEST_PARALLEL_LEVEL`
+can alternatively be set to avoid the need to pass
+``-j``.
+
+By default :manual:`ctest(1)` does not print the output
+from the tests. The command line argument ``-V`` (or
+``--verbose``) enables verbose mode to print the
+output from all tests.
+The ``--output-on-failure`` option prints the test
+output for failing tests only.  The environment variable
+:envvar:`CTEST_OUTPUT_ON_FAILURE`
+can be set to ``1`` as an alternative to passing the
+``--output-on-failure`` option to :manual:`ctest(1)`.
diff --git a/Help/guide/using-dependencies/index.rst b/Help/guide/using-dependencies/index.rst
new file mode 100644
index 0000000..6fdcc55
--- /dev/null
+++ b/Help/guide/using-dependencies/index.rst
@@ -0,0 +1,200 @@
+Using Dependencies Guide
+************************
+
+.. only:: html
+
+   .. contents::
+
+Introduction
+============
+
+For developers wishing to use CMake to consume a third
+party binary package, there are multiple possibilities
+regarding how to optimally do so, depending on how
+CMake-aware the third-party library is.
+
+CMake files provided with a software package contain
+instructions for finding each build dependency.  Some
+build dependencies are optional in that the build may
+succeed with a different feature set if the dependency
+is missing, and some dependencies are required.  CMake
+searches well-known locations for each dependency, and
+the provided software may supply additional hints or
+locations to CMake to find each dependency.
+
+If a required dependency is not found by
+:manual:`cmake(1)`, the cache is populated with an entry
+which contains a ``NOTFOUND`` value.  This value can be
+replaced by specifying it on the command line, or in
+the :manual:`ccmake(1)` or :manual:`cmake-gui(1)` tool.
+See the :guide:`User Interaction Guide` for
+more about setting cache entries.
+
+Libraries providing Config-file packages
+----------------------------------------
+
+The most convenient way for a third-party to provide library
+binaries for use with CMake is to provide
+:ref:`Config File Packages`.  These packages are text files
+shipped with the library which instruct CMake how to use the
+library binaries and associated headers, helper tools and
+CMake macros provided by the library.
+
+The config files can usually be found in a directory whose
+name matches the pattern ``lib/cmake/<PackageName>``, though
+they may be in other locations instead.  The
+``<PackageName>`` corresponds to use in CMake code with the
+:command:`find_package` command such as
+``find_package(PackageName REQUIRED)``.
+
+The ``lib/cmake/<PackageName>`` directory will contain a
+file which is either named ``<PackageName>Config.cmake``
+or ``<PackageName>-config.cmake``.  This is the entry point
+to the package for CMake.  A separate optional file named
+``<PackageName>ConfigVersion.cmake`` may also exist in the
+directory.  This file is used by CMake to determine whether
+the version of the third party package satisfies uses of the
+:command:`find_package` command which specify version
+constraints.  It is optional to specify a version when using
+:command:`find_package`, even if a ``ConfigVersion`` file is
+present.
+
+If the ``Config.cmake`` file is found and the
+optionally-specified version is satisfied, then the CMake
+:command:`find_package` command considers the package to be
+found and the entire library package is assumed to be
+complete as designed.
+
+There may be additional files providing CMake macros or
+:ref:`imported targets` for you to use.  CMake does not
+enforce any naming convention for these
+files.  They are related to the primary ``Config`` file by
+use of the CMake :command:`include` command.
+
+:guide:`Invoking CMake <User Interaction Guide>` with the
+intent of using a package of third party binaries requires
+that cmake :command:`find_package` commands succeed in finding
+the package.  If the location of the package is in a directory
+known to CMake, the :command:`find_package` call should
+succeed.  The directories known to cmake are platform-specific.
+For example, packages installed on Linux with a standard
+system package manager will be found in the ``/usr`` prefix
+automatically.  Packages installed in ``Program Files`` on
+Windows will similarly be found automatically.
+
+Packages which are not found automatically are in locations
+not predictable to CMake such as ``/opt/mylib`` or
+``$HOME/dev/prefix``.  This is a normal situation and CMake
+provides several ways for users to specify where to find
+such libraries.
+
+The :variable:`CMAKE_PREFIX_PATH` variable may be
+:ref:`set when invoking CMake <Setting Build Variables>`.
+It is treated as a list of paths to search for
+:ref:`Config File Packages`.  A package installed in
+``/opt/somepackage`` will typically install config files
+such as
+``/opt/somepackage/lib/cmake/somePackage/SomePackageConfig.cmake``.
+In that case, ``/opt/somepackage`` should be added to
+:variable:`CMAKE_PREFIX_PATH`.
+
+The environment variable ``CMAKE_PREFIX_PATH`` may also be
+populated with prefixes to search for packages.  Like the
+``PATH`` environment variable, this is a list and needs to use
+the platform-specific environment variable list item separator
+(``:`` on Unix and ``;`` on Windows).
+
+The :variable:`CMAKE_PREFIX_PATH` variable provides convenience
+in cases where multiple prefixes need to be specified, or when
+multiple different package binaries are available in the same
+prefix.  Paths to packages may also be specified by setting
+variables matching ``<PackageName>_DIR``, such as
+``SomePackage_DIR``.  Note that this is not a prefix but should
+be a full path to a directory containing a config-style package
+file, such as ``/opt/somepackage/lib/cmake/SomePackage/`` in
+the above example.
+
+Imported Targets from Packages
+------------------------------
+
+A third-party package which provides config-file packages may
+also provide :ref:`Imported targets`. These will be
+specified in files containing configuration-specific file
+paths relevant to the package, such as debug and release
+versions of libraries.
+
+Often the third-party package documentation will point out the
+names of imported targets available after a successful
+``find_package`` for a library.  Those imported target names
+can be used with the :command:`target_link_libraries` command.
+
+A complete example which makes a simple use of a third party
+library might look like:
+
+.. code-block:: cmake
+
+    cmake_minimum_required(VERSION 3.10)
+    project(MyExeProject VERSION 1.0.0)
+
+    find_package(SomePackage REQUIRED)
+    add_executable(MyExe main.cpp)
+    target_link_libraries(MyExe PRIVATE SomePrefix::LibName)
+
+See :manual:`cmake-buildsystem(7)` for further information
+about developing a CMake buildsystem.
+
+Libraries not Providing Config-file Packages
+--------------------------------------------
+
+Third-party libraries which do not provide config-file packages
+can still be found with the :command:`find_package` command, if
+a ``FindSomePackage.cmake`` file is available.
+
+These module-file packages are different to config-file packages
+in that:
+
+#. They should not be provided by the third party, except
+   perhaps in the form of documentation
+#. The availability of a ``Find<PackageName>.cmake`` file does
+   not indicate the availability of the binaries themselves.
+#. CMake does not search the :variable:`CMAKE_PREFIX_PATH` for
+   ``Find<PackageName>.cmake`` files.  Instead CMake searches
+   for such files in the :variable:`CMAKE_MODULE_PATH`
+   variable. It is common for users to set the
+   :variable:`CMAKE_MODULE_PATH` when running CMake, and it is
+   common for CMake projects to append to
+   :variable:`CMAKE_MODULE_PATH` to allow use of local
+   module-file packages.
+#. CMake ships ``Find<PackageName>.cmake`` files for some
+   :manual:`third party packages <cmake-modules(7)>`
+   for convenience in cases where the third party does
+   not provide config-file packages directly.  These files are
+   a maintenance burden for CMake, so new Find modules are
+   generally not added to CMake anymore.  Third-parties should
+   provide config file packages instead of relying on a Find
+   module to be provided by CMake.
+
+Module-file packages may also provide :ref:`Imported targets`.
+A complete example which finds such a package might look
+like:
+
+.. code-block:: cmake
+
+    cmake_minimum_required(VERSION 3.10)
+    project(MyExeProject VERSION 1.0.0)
+
+    find_package(PNG REQUIRED)
+
+    # Add path to a FindSomePackage.cmake file
+    list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+    find_package(SomePackage REQUIRED)
+
+    add_executable(MyExe main.cpp)
+    target_link_libraries(MyExe PRIVATE
+        PNG::PNG
+        SomePrefix::LibName
+    )
+
+The :variable:`<PackageName>_ROOT` variable is also
+searched as a prefix for :command:`find_package` calls using
+module-file packages such as ``FindSomePackage``.
diff --git a/Help/index.rst b/Help/index.rst
index cc6cee6..4d9a9c8 100644
--- a/Help/index.rst
+++ b/Help/index.rst
@@ -1,5 +1,34 @@
 .. title:: CMake Reference Documentation
 
+Introduction
+############
+
+CMake is a tool to manage building of source code.  Originally, CMake was
+designed as a generator for various dialects of ``Makefile``, today
+CMake generates modern buildsystems such as ``Ninja`` as well as project
+files for IDEs such as Visual Studio and Xcode.
+
+CMake is widely used for the C and C++ languages, but it may be used to
+build source code of other languages too.
+
+People encountering CMake for the first time may have different initial
+goals.  To learn how to build a source code package downloaded from the
+internet, start with the :guide:`User Interaction Guide`.
+This will detail the steps needed to run the :manual:`cmake(1)` or
+:manual:`cmake-gui(1)` executable and how to choose a generator, and
+how to complete the build.
+
+The :guide:`Using Dependencies Guide` is aimed at developers
+wishing to get started using a third-party library.
+
+For developers starting a project using CMake, the :guide:`CMake Tutorial`
+is a suitable starting point.  The :manual:`cmake-buildsystem(7)`
+manual is aimed at developers expanding their knowledge of maintaining
+a buildsystem and becoming familiar with the build targets that
+can be represented in CMake.  The :manual:`cmake-packages(7)` manual
+explains how to create packages which can easily be consumed by
+third-party CMake-based buildsystems.
+
 Command-Line Tools
 ##################
 
@@ -53,6 +82,8 @@
     :maxdepth: 1
 
     /guide/tutorial/index
+    /guide/user-interaction/index
+    /guide/using-dependencies/index
 
 .. only:: html or text
 
diff --git a/Help/manual/VS-Choose-Arch.png b/Help/manual/VS-Choose-Arch.png
new file mode 100644
index 0000000..816b0f4
--- /dev/null
+++ b/Help/manual/VS-Choose-Arch.png
Binary files differ
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index 1fd49ed..c256250 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -57,6 +57,8 @@
 .. toctree::
    :maxdepth: 1
 
+   CMP0102: mark_as_advanced() does nothing if a cache entry does not exist. </policy/CMP0102>
+   CMP0101: target_compile_options honors BEFORE keyword in all scopes. </policy/CMP0101>
    CMP0100: Let AUTOMOC and AUTOUIC process .hh header files. </policy/CMP0100>
    CMP0099: Link properties are transitive over private dependency on static libraries. </policy/CMP0099>
    CMP0098: FindFLEX runs flex in CMAKE_CURRENT_BINARY_DIR when executing. </policy/CMP0098>
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index b3802d1..3a62371 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -185,6 +185,7 @@
    /prop_tgt/DEPLOYMENT_ADDITIONAL_FILES
    /prop_tgt/DEPRECATION
    /prop_tgt/DISABLE_PRECOMPILE_HEADERS
+   /prop_tgt/DOTNET_TARGET_FRAMEWORK
    /prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION
    /prop_tgt/EchoString
    /prop_tgt/ENABLE_EXPORTS
@@ -253,6 +254,7 @@
    /prop_tgt/IOS_INSTALL_COMBINED
    /prop_tgt/JOB_POOL_COMPILE
    /prop_tgt/JOB_POOL_LINK
+   /prop_tgt/JOB_POOL_PRECOMPILE_HEADER
    /prop_tgt/LABELS
    /prop_tgt/LANG_CLANG_TIDY
    /prop_tgt/LANG_COMPILER_LAUNCHER
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 74dd1fb..1f5b39c 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -48,6 +48,7 @@
    /variable/CMAKE_DEBUG_TARGET_PROPERTIES
    /variable/CMAKE_DIRECTORY_LABELS
    /variable/CMAKE_DL_LIBS
+   /variable/CMAKE_DOTNET_TARGET_FRAMEWORK
    /variable/CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION
    /variable/CMAKE_EDIT_COMMAND
    /variable/CMAKE_EXECUTABLE_SUFFIX
@@ -65,6 +66,7 @@
    /variable/CMAKE_IMPORT_LIBRARY_SUFFIX
    /variable/CMAKE_JOB_POOL_COMPILE
    /variable/CMAKE_JOB_POOL_LINK
+   /variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER
    /variable/CMAKE_JOB_POOLS
    /variable/CMAKE_LANG_COMPILER_AR
    /variable/CMAKE_LANG_COMPILER_RANLIB
@@ -215,7 +217,6 @@
    /variable/CMAKE_MESSAGE_INDENT
    /variable/CMAKE_MESSAGE_LOG_LEVEL
    /variable/CMAKE_MODULE_PATH
-   /variable/CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE
    /variable/CMAKE_POLICY_DEFAULT_CMPNNNN
    /variable/CMAKE_POLICY_WARNING_CMPNNNN
    /variable/CMAKE_PREFIX_PATH
@@ -369,6 +370,7 @@
    /variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY
    /variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG
    /variable/CMAKE_CONFIG_POSTFIX
+   /variable/CMAKE_CTEST_ARGUMENTS
    /variable/CMAKE_CUDA_SEPARABLE_COMPILATION
    /variable/CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS
    /variable/CMAKE_DEBUG_POSTFIX
@@ -423,6 +425,10 @@
    /variable/CMAKE_MODULE_LINKER_FLAGS_INIT
    /variable/CMAKE_MSVCIDE_RUN_PATH
    /variable/CMAKE_MSVC_RUNTIME_LIBRARY
+   /variable/CMAKE_NINJA_MULTI_CROSS_CONFIGS
+   /variable/CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE
+   /variable/CMAKE_NINJA_MULTI_DEFAULT_BUILD_ALIAS
+   /variable/CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE
    /variable/CMAKE_NINJA_OUTPUT_PATH_PREFIX
    /variable/CMAKE_NO_BUILTIN_CHRPATH
    /variable/CMAKE_NO_SYSTEM_FROM_IMPORTED
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index 4315f0a..44b1f2f 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -279,7 +279,9 @@
          "file": "/full/path/to/the/CMake/file.txt",
          "line": 0,
          "cmd": "add_executable",
-         "args": ["foo", "bar"]
+         "args": ["foo", "bar"],
+         "time": 1579512535.9687231,
+         "frame": 2
        }
 
      The members are:
@@ -288,8 +290,8 @@
        The full path to the CMake source file where the function
        was called.
 
-      ``line``
-       The line in `file` of the function call.
+     ``line``
+       The line in ``file`` of the function call.
 
      ``cmd``
        The name of the function that was called.
@@ -297,6 +299,12 @@
      ``args``
        A string list of all function parameters.
 
+     ``time``
+       Timestamp (seconds since epoch) of the function call.
+
+     ``frame``
+       Stack frame depth of the function that was called.
+
      Additionally, the first JSON document outputted contains the
      ``version`` key for the current major and minor version of the
 
diff --git a/Help/policy/CMP0101.rst b/Help/policy/CMP0101.rst
new file mode 100644
index 0000000..9941acf
--- /dev/null
+++ b/Help/policy/CMP0101.rst
@@ -0,0 +1,20 @@
+CMP0101
+-------
+
+:command:`target_compile_options` now honors ``BEFORE`` keyword in all scopes.
+
+In CMake 3.16 and below the :command:`target_compile_options` ignores the
+``BEFORE`` keyword in private scope. CMake 3.17 and later honors
+``BEFORE`` keyword in all scopes. This policy provides compatibility for
+projects that have not been updated to expect the new behavior.
+
+The ``OLD`` behavior for this policy is to not honor ``BEFORE`` keyword in
+private scope. The ``NEW`` behavior of this policy is to honor
+``BEFORE`` keyword in all scopes.
+
+This policy was introduced in CMake version 3.17.  Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/policy/CMP0102.rst b/Help/policy/CMP0102.rst
new file mode 100644
index 0000000..9859006
--- /dev/null
+++ b/Help/policy/CMP0102.rst
@@ -0,0 +1,25 @@
+CMP0102
+-------
+
+The :command:`mark_as_advanced` command no longer creates a cache entry if one
+does not already exist.
+
+In CMake 3.16 and below, if a variable was not defined at all or just defined
+locally, the :command:`mark_as_advanced` command would create a new cache
+entry with an ``UNINITIALIZED`` type and no value. When a :command:`find_path`
+(or other similar ``find_`` command) would next run, it would find this
+undefined cache entry and set it up with an empty string value. This process
+would end up deleting the local variable in the process (due to the way the
+cache works), effectively clearing any stored ``find_`` results that were only
+available in the local scope.
+
+The ``OLD`` behavior for this policy is to create the empty cache definition.
+The ``NEW`` behavior of this policy is to ignore variables which do not
+already exist in the cache.
+
+This policy was introduced in CMake version 3.17.  Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike many policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK.rst b/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK.rst
new file mode 100644
index 0000000..8698eb6
--- /dev/null
+++ b/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK.rst
@@ -0,0 +1,13 @@
+DOTNET_TARGET_FRAMEWORK
+-----------------------
+
+Specify the .NET target framework.
+
+Used to specify the .NET target framework for C++/CLI and C#.  For
+example: ``netcoreapp2.1``.
+
+This property is only evaluated for :ref:`Visual Studio Generators`
+VS 2010 and above.
+
+Can be initialized for all targets using the variable
+:variable:`CMAKE_DOTNET_TARGET_FRAMEWORK`.
diff --git a/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst b/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst
index c100326..b33f4fb 100644
--- a/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst
+++ b/Help/prop_tgt/DOTNET_TARGET_FRAMEWORK_VERSION.rst
@@ -3,11 +3,13 @@
 
 Specify the .NET target framework version.
 
-Used to specify the .NET target framework version for C++/CLI.  For
-example: ``v4.5``.
+Used to specify the .NET target framework version for C++/CLI and C#.
+For example: ``v4.5``.
 
 This property is only evaluated for :ref:`Visual Studio Generators`
 VS 2010 and above.
 
-Can be initialized for all targets using the variable
-:variable:`CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION`.
+To initialize this variable for all targets set
+:variable:`CMAKE_DOTNET_TARGET_FRAMEWORK` or
+:variable:`CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION`. If both are set,
+the latter is ignored.
diff --git a/Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst b/Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst
new file mode 100644
index 0000000..ece28a4
--- /dev/null
+++ b/Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst
@@ -0,0 +1,21 @@
+JOB_POOL_PRECOMPILE_HEADER
+--------------------------
+
+Ninja only: Pool used for generating pre-compiled headers.
+
+The number of parallel compile processes could be limited by defining
+pools with the global :prop_gbl:`JOB_POOLS`
+property and then specifying here the pool name.
+
+For instance:
+
+.. code-block:: cmake
+
+  set_property(TARGET myexe PROPERTY JOB_POOL_PRECOMPILE_HEADER two_jobs)
+
+This property is initialized by the value of
+:variable:`CMAKE_JOB_POOL_PRECOMPILE_HEADER`.
+
+If neither :prop_tgt:`JOB_POOL_PRECOMPILE_HEADER` nor
+:variable:`CMAKE_JOB_POOL_PRECOMPILE_HEADER` are set then
+:prop_tgt:`JOB_POOL_COMPILE` will be used for this task.
diff --git a/Help/prop_tgt/LINK_LIBRARIES_INDIRECTION.txt b/Help/prop_tgt/LINK_LIBRARIES_INDIRECTION.txt
index 1fdb6ad..476e4a6 100644
--- a/Help/prop_tgt/LINK_LIBRARIES_INDIRECTION.txt
+++ b/Help/prop_tgt/LINK_LIBRARIES_INDIRECTION.txt
@@ -1,9 +1,9 @@
 .. note::
   A call to :command:`target_link_libraries(<target> ...)` may update this
   property on ``<target>``.  If ``<target>`` was not created in the same
-  directory as the call then :command:`target_link_libraries` will add a
-  suffix of the form ``::@<directory-id>`` to each entry, where the
-  ``::@`` is a separator and the ``<directory-id>`` is unspecified.
+  directory as the call then :command:`target_link_libraries` will wrap each
+  entry with the form ``::@(directory-id);...;::@``, where the ``::@`` is
+  literal and the ``(directory-id)`` is unspecified.
   This tells the generators that the named libraries must be looked up in
   the scope of the caller rather than in the scope in which the
   ``<target>`` was created.  Valid directory ids are stripped on export
diff --git a/Help/prop_tgt/VS_DOTNET_TARGET_FRAMEWORK_VERSION.rst b/Help/prop_tgt/VS_DOTNET_TARGET_FRAMEWORK_VERSION.rst
index 9f5a313..6cb8f86 100644
--- a/Help/prop_tgt/VS_DOTNET_TARGET_FRAMEWORK_VERSION.rst
+++ b/Help/prop_tgt/VS_DOTNET_TARGET_FRAMEWORK_VERSION.rst
@@ -3,8 +3,9 @@
 
 Specify the .NET target framework version.
 
-Used to specify the .NET target framework version for C++/CLI.  For
+Used to specify the .NET target framework version for C++/CLI. For
 example, "v4.5".
 
 This property is deprecated and should not be used anymore. Use
+:prop_tgt:`DOTNET_TARGET_FRAMEWORK` or
 :prop_tgt:`DOTNET_TARGET_FRAMEWORK_VERSION` instead.
diff --git a/Help/release/dev/cmake-ctest-arguments.rst b/Help/release/dev/cmake-ctest-arguments.rst
new file mode 100644
index 0000000..72a264a
--- /dev/null
+++ b/Help/release/dev/cmake-ctest-arguments.rst
@@ -0,0 +1,6 @@
+cmake-ctest-arguments
+---------------------
+
+* A :variable:`CMAKE_CTEST_ARGUMENTS` variable was added to specify a list
+  of command-line arguments passed to CTest when running through the
+  ``test`` (or ``RUN_TESTS``) target of the generated build system.
diff --git a/Help/release/dev/custom-dmg-names.rst b/Help/release/dev/custom-dmg-names.rst
new file mode 100644
index 0000000..73a70a1
--- /dev/null
+++ b/Help/release/dev/custom-dmg-names.rst
@@ -0,0 +1,7 @@
+custom-dmg-names
+----------------
+
+* The :cpack_gen:`CPack DragNDrop Generator` learned to use
+  the :variable:`CPACK_DMG_<component>_FILE_NAME` variable
+  to set a custom filename when packaging components into
+  their own DMGs.
diff --git a/Help/release/dev/fphsa-detect-name-mismatch.rst b/Help/release/dev/fphsa-detect-name-mismatch.rst
new file mode 100644
index 0000000..be51a43
--- /dev/null
+++ b/Help/release/dev/fphsa-detect-name-mismatch.rst
@@ -0,0 +1,5 @@
+fphsa-name-mismatch
+-------------------
+
+* The :module:`FindPackageHandleStandardArgs` module learned to check the
+  package name passed in for typo mistakes.
diff --git a/Help/release/dev/mingw-find-no-dll.rst b/Help/release/dev/mingw-find-no-dll.rst
new file mode 100644
index 0000000..84e7431
--- /dev/null
+++ b/Help/release/dev/mingw-find-no-dll.rst
@@ -0,0 +1,6 @@
+mingw-find-no-dll
+-----------------
+
+* When using MinGW tools, the :command:`find_library` command no longer
+  finds ``.dll`` files by default.  Instead it expects ``.dll.a`` import
+  libraries to be available.
diff --git a/Help/release/dev/target_compile_options-BEFORE-keyword.rst b/Help/release/dev/target_compile_options-BEFORE-keyword.rst
new file mode 100644
index 0000000..8dafddd
--- /dev/null
+++ b/Help/release/dev/target_compile_options-BEFORE-keyword.rst
@@ -0,0 +1,5 @@
+target_compile_options-BEFORE-keyword
+-------------------------------------
+
+* :command:`target_compile_options` command learns to honor ``BEFORE`` keyword
+  in all scopes. See policy :policy:`CMP0101`.
diff --git a/Help/release/dev/vs-dotnet-standard-core.rst b/Help/release/dev/vs-dotnet-standard-core.rst
new file mode 100644
index 0000000..9bb292e
--- /dev/null
+++ b/Help/release/dev/vs-dotnet-standard-core.rst
@@ -0,0 +1,7 @@
+vs-dotnet-standard-core
+-----------------------
+
+* :ref:`Visual Studio Generators` for VS 2010 and above learned to
+  support .NET Standard and .NET Core.  See the
+  :prop_tgt:`DOTNET_TARGET_FRAMEWORK` target property and
+  associated :variable:`CMAKE_DOTNET_TARGET_FRAMEWORK` variable.
diff --git a/Help/release/dev/xcode-default-warnings.rst b/Help/release/dev/xcode-default-warnings.rst
new file mode 100644
index 0000000..a9a2e49
--- /dev/null
+++ b/Help/release/dev/xcode-default-warnings.rst
@@ -0,0 +1,5 @@
+xcode-default-warnings
+----------------------
+
+* The :generator:`Xcode` generator no longer hard-codes ``-Wmost``,
+  ``-Wno-four-char-constants``, and ``-Wno-unknown-pragmas`` warning flags.
diff --git a/Help/variable/CMAKE_CTEST_ARGUMENTS.rst b/Help/variable/CMAKE_CTEST_ARGUMENTS.rst
new file mode 100644
index 0000000..0940b46
--- /dev/null
+++ b/Help/variable/CMAKE_CTEST_ARGUMENTS.rst
@@ -0,0 +1,6 @@
+CMAKE_CTEST_ARGUMENTS
+---------------------
+
+Set this to a :ref:`semicolon-separated list <CMake Language Lists>` of
+command-line arguments to pass to :manual:`ctest(1)` when running tests
+through the ``test`` (or ``RUN_TESTS``) target of the generated build system.
diff --git a/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK.rst b/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK.rst
new file mode 100644
index 0000000..8edcd1e
--- /dev/null
+++ b/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK.rst
@@ -0,0 +1,16 @@
+CMAKE_DOTNET_TARGET_FRAMEWORK
+-----------------------------
+
+Default value for :prop_tgt:`DOTNET_TARGET_FRAMEWORK` property	of
+targets.
+
+This variable is used to initialize the
+:prop_tgt:`DOTNET_TARGET_FRAMEWORK` property on all targets. See that
+target property for additional information.
+
+Setting ``CMAKE_DOTNET_TARGET_FRAMEWORK`` may be necessary
+when working with ``C#`` and newer .NET framework versions to
+avoid referencing errors with the ``ALL_BUILD`` CMake target.
+
+This variable is only evaluated for :ref:`Visual Studio Generators`
+VS 2010 and above.
diff --git a/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION.rst b/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION.rst
index 124fefe..c2eef9e 100644
--- a/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION.rst
+++ b/Help/variable/CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION.rst
@@ -6,7 +6,11 @@
 
 This variable is used to initialize the
 :prop_tgt:`DOTNET_TARGET_FRAMEWORK_VERSION` property on all
-targets. See that target property for additional information.
+targets. See that target property for additional information. When set,
+:variable:`CMAKE_DOTNET_TARGET_FRAMEWORK` takes precednece over this
+variable. See that variable or the associated target property
+:prop_tgt:`DOTNET_TARGET_FRAMEWORK` for additional information.
+
 
 Setting ``CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION`` may be necessary
 when working with ``C#`` and newer .NET framework versions to
diff --git a/Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET.rst b/Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET.rst
index e82867d..8587742 100644
--- a/Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET.rst
+++ b/Help/variable/CMAKE_GLOBAL_AUTOGEN_TARGET.rst
@@ -3,7 +3,7 @@
 
 Switch to enable generation of a global ``autogen`` target.
 
-When :variable:`CMAKE_GLOBAL_AUTORCC_TARGET` is enabled, a custom target
+When :variable:`CMAKE_GLOBAL_AUTOGEN_TARGET` is enabled, a custom target
 ``autogen`` is generated.  This target depends on all :prop_tgt:`AUTOMOC` and
 :prop_tgt:`AUTOUIC` generated ``<ORIGIN>_autogen`` targets in the project.
 By building the global ``autogen`` target, all :prop_tgt:`AUTOMOC` and
diff --git a/Help/variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER.rst b/Help/variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER.rst
new file mode 100644
index 0000000..f9467b3
--- /dev/null
+++ b/Help/variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER.rst
@@ -0,0 +1,6 @@
+CMAKE_JOB_POOL_PRECOMPILE_HEADER
+--------------------------------
+
+This variable is used to initialize the :prop_tgt:`JOB_POOL_PRECOMPILE_HEADER`
+property on all the targets. See :prop_tgt:`JOB_POOL_PRECOMPILE_HEADER`
+for additional information.
diff --git a/Help/variable/CMAKE_NINJA_MULTI_CROSS_CONFIGS.rst b/Help/variable/CMAKE_NINJA_MULTI_CROSS_CONFIGS.rst
new file mode 100644
index 0000000..48f6985
--- /dev/null
+++ b/Help/variable/CMAKE_NINJA_MULTI_CROSS_CONFIGS.rst
@@ -0,0 +1,7 @@
+CMAKE_NINJA_MULTI_CROSS_CONFIGS
+-------------------------------
+
+Set which configurations get cross-built if
+:variable:`CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE` is set. See the
+documentation for the :generator:`Ninja Multi-Config` generator for more
+information.
diff --git a/Help/variable/CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE.rst b/Help/variable/CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE.rst
new file mode 100644
index 0000000..0571d52
--- /dev/null
+++ b/Help/variable/CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE.rst
@@ -0,0 +1,10 @@
+CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE
+-------------------------------------
+
+If this variable is enabled, cross-configuration building is enabled in the
+:generator:`Ninja Multi-Config` generator. See the generator's description for
+more details. This variable is ``OFF`` by default.
+
+This variable is meant to be set from the command line (via
+``-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE:BOOL=ON``) and should not be set from
+project code.
diff --git a/Help/variable/CMAKE_NINJA_MULTI_DEFAULT_BUILD_ALIAS.rst b/Help/variable/CMAKE_NINJA_MULTI_DEFAULT_BUILD_ALIAS.rst
new file mode 100644
index 0000000..a997e9b
--- /dev/null
+++ b/Help/variable/CMAKE_NINJA_MULTI_DEFAULT_BUILD_ALIAS.rst
@@ -0,0 +1,6 @@
+CMAKE_NINJA_MULTI_DEFAULT_BUILD_ALIAS
+-------------------------------------
+
+Controls the config of ``<target>`` aliases in ``build.ninja`` for the
+:generator:`Ninja Multi-Config` generator. See the generator's documentation
+for more details.
diff --git a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
index fc52e7b..de71d0e 100644
--- a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
+++ b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst
@@ -23,6 +23,8 @@
   policy :policy:`CMP0082`.
 * ``CMAKE_POLICY_WARNING_CMP0089`` controls the warning for
   policy :policy:`CMP0089`.
+* ``CMAKE_POLICY_WARNING_CMP0102`` controls the warning for
+  policy :policy:`CMP0102`.
 
 This variable should not be set by a project in CMake code.  Project
 developers running CMake may set this variable in their cache to
diff --git a/Modules/CMakeASM_MASMInformation.cmake b/Modules/CMakeASM_MASMInformation.cmake
index a38c114..9f7e934 100644
--- a/Modules/CMakeASM_MASMInformation.cmake
+++ b/Modules/CMakeASM_MASMInformation.cmake
@@ -10,5 +10,11 @@
 
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> /c  /Fo <OBJECT> <SOURCE>")
 
+# The ASM_MASM compiler id for this compiler is "MSVC", so fill out the runtime library table.
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         "")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL      "")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug    "")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL "")
+
 include(CMakeASMInformation)
 set(ASM_DIALECT)
diff --git a/Modules/CMakeCSharpInformation.cmake b/Modules/CMakeCSharpInformation.cmake
index 48e1a1e..41cd449 100644
--- a/Modules/CMakeCSharpInformation.cmake
+++ b/Modules/CMakeCSharpInformation.cmake
@@ -10,7 +10,7 @@
 
 set(CMAKE_BUILD_TYPE_INIT Debug)
 
-set(CMAKE_CSharp_FLAGS_INIT "/define:TRACE /langversion:3")
+set(CMAKE_CSharp_FLAGS_INIT "/define:TRACE")
 set(CMAKE_CSharp_FLAGS_DEBUG_INIT "/debug:full /optimize- /warn:3 /errorreport:prompt /define:DEBUG")
 set(CMAKE_CSharp_FLAGS_RELEASE_INIT "/debug:none /optimize  /warn:1  /errorreport:queue")
 set(CMAKE_CSharp_FLAGS_RELWITHDEBINFO_INIT "/debug:full /optimize-")
diff --git a/Modules/CMakeDetermineCUDACompiler.cmake b/Modules/CMakeDetermineCUDACompiler.cmake
index 490d659..7d7fb9a 100644
--- a/Modules/CMakeDetermineCUDACompiler.cmake
+++ b/Modules/CMakeDetermineCUDACompiler.cmake
@@ -186,33 +186,32 @@
       "Failed to parsed CUDA nvcc implicit link information:\n${_nvcc_log}\n\n")
     message(FATAL_ERROR "Failed to extract nvcc implicit link line.")
   endif()
+endif()
 
-  set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES )
-  if(_nvcc_output_orig MATCHES "#\\\$ +INCLUDES= *([^\n]*)\n")
-    set(_nvcc_includes "${CMAKE_MATCH_1}")
-    string(APPEND _nvcc_log "  found 'INCLUDES=' string: [${_nvcc_includes}]\n")
-  else()
-    set(_nvcc_includes "")
-    string(REPLACE "\n" "\n    " _nvcc_output_log "\n${_nvcc_output_orig}")
-    string(APPEND _nvcc_log "  no 'INCLUDES=' string found in nvcc output:${_nvcc_output_log}\n")
-  endif()
-  if(_nvcc_includes)
-    # across all operating system each include directory is prefixed with -I
-    separate_arguments(_nvcc_output UNIX_COMMAND "${_nvcc_includes}")
-    foreach(line IN LISTS _nvcc_output)
-      string(REGEX REPLACE "^-I" "" line "${line}")
-      get_filename_component(line "${line}" ABSOLUTE)
-      list(APPEND CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES "${line}")
-    endforeach()
+set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES )
+string(REPLACE "\r" "" _nvcc_output_orig "${CMAKE_CUDA_COMPILER_PRODUCED_OUTPUT}")
+if(_nvcc_output_orig MATCHES "#\\\$ +INCLUDES= *([^\n]*)\n")
+  set(_nvcc_includes "${CMAKE_MATCH_1}")
+  string(APPEND _nvcc_log "  found 'INCLUDES=' string: [${_nvcc_includes}]\n")
+else()
+  set(_nvcc_includes "")
+  string(REPLACE "\n" "\n    " _nvcc_output_log "\n${_nvcc_output_orig}")
+  string(APPEND _nvcc_log "  no 'INCLUDES=' string found in nvcc output:${_nvcc_output_log}\n")
+endif()
+if(_nvcc_includes)
+  # across all operating system each include directory is prefixed with -I
+  separate_arguments(_nvcc_output NATIVE_COMMAND "${_nvcc_includes}")
+  foreach(line IN LISTS _nvcc_output)
+    string(REGEX REPLACE "^-I" "" line "${line}")
+    get_filename_component(line "${line}" ABSOLUTE)
+    list(APPEND CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES "${line}")
+  endforeach()
 
-    file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
-      "Parsed CUDA nvcc include information from above output:\n${_nvcc_log}\n${log}\n\n")
-  else()
-    file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
-      "Failed to detect CUDA nvcc include information:\n${_nvcc_log}\n\n")
-  endif()
-
-
+  file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+    "Parsed CUDA nvcc include information from above output:\n${_nvcc_log}\n${log}\n\n")
+else()
+  file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+    "Failed to detect CUDA nvcc include information:\n${_nvcc_log}\n\n")
 endif()
 
 # configure all variables set in this file
diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake
index 52d8976..d125791 100644
--- a/Modules/CMakeDetermineCompilerId.cmake
+++ b/Modules/CMakeDetermineCompilerId.cmake
@@ -366,6 +366,7 @@
       endif()
       set(cuda_tools "CUDA ${CMAKE_VS_PLATFORM_TOOLSET_CUDA}")
       set(id_compile "CudaCompile")
+      set(id_ItemDefinitionGroup_entry "<CudaCompile><AdditionalOptions>%(AdditionalOptions)-v</AdditionalOptions></CudaCompile>")
       set(id_PostBuildEvent_Command [[echo CMAKE_CUDA_COMPILER=$(CudaToolkitBinDir)\nvcc.exe]])
       if(CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR)
         set(id_CudaToolkitCustomDir "<CudaToolkitCustomDir>${CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR}nvcc</CudaToolkitCustomDir>")
@@ -376,7 +377,7 @@
         string(CONCAT id_Import_targets [[<Import Project="$(VCTargetsPath)\BuildCustomizations\]] "${cuda_tools}" [[.targets" />]])
       endif()
       if(CMAKE_VS_PLATFORM_NAME STREQUAL x64)
-        set(id_ItemDefinitionGroup_entry "<CudaCompile><TargetMachinePlatform>64</TargetMachinePlatform></CudaCompile>")
+        set(id_ItemDefinitionGroup_entry "<CudaCompile><TargetMachinePlatform>64</TargetMachinePlatform><AdditionalOptions>%(AdditionalOptions)-v</AdditionalOptions></CudaCompile>")
       endif()
       set(id_Link_AdditionalDependencies "<AdditionalDependencies>cudart.lib</AdditionalDependencies>")
     endif()
diff --git a/Modules/CPack.cmake b/Modules/CPack.cmake
index cbb5323..3b46ca5 100644
--- a/Modules/CPack.cmake
+++ b/Modules/CPack.cmake
@@ -470,8 +470,10 @@
     "${CMAKE_PROJECT_HOMEPAGE_URL}")
 endif()
 
-_cpack_set_default(CPACK_PACKAGE_DESCRIPTION_FILE
+set(CPACK_DEFAULT_PACKAGE_DESCRIPTION_FILE
   "${CMAKE_ROOT}/Templates/CPack.GenericDescription.txt")
+_cpack_set_default(CPACK_PACKAGE_DESCRIPTION_FILE
+  "${CPACK_DEFAULT_PACKAGE_DESCRIPTION_FILE}")
 _cpack_set_default(CPACK_RESOURCE_FILE_LICENSE
   "${CMAKE_ROOT}/Templates/CPack.GenericLicense.txt")
 _cpack_set_default(CPACK_RESOURCE_FILE_README
@@ -563,8 +565,16 @@
         option(CPACK_BINARY_OSXX11       "Enable to build OSX X11 packages"      OFF)
         option(CPACK_BINARY_PACKAGEMAKER "Enable to build PackageMaker packages" OFF)
         option(CPACK_BINARY_PRODUCTBUILD "Enable to build productbuild packages" OFF)
+        mark_as_advanced(
+          CPACK_BINARY_BUNDLE
+          CPACK_BINARY_DRAGNDROP
+          CPACK_BINARY_OSXX11
+          CPACK_BINARY_PACKAGEMAKER
+          CPACK_BINARY_PRODUCTBUILD
+          )
       else()
         option(CPACK_BINARY_TZ  "Enable to build TZ packages"     ON)
+        mark_as_advanced(CPACK_BINARY_TZ)
       endif()
       option(CPACK_BINARY_DEB  "Enable to build Debian packages"  OFF)
       option(CPACK_BINARY_FREEBSD  "Enable to build FreeBSD packages"  OFF)
@@ -574,6 +584,16 @@
       option(CPACK_BINARY_TBZ2 "Enable to build TBZ2 packages"    OFF)
       option(CPACK_BINARY_TGZ  "Enable to build TGZ packages"     ON)
       option(CPACK_BINARY_TXZ  "Enable to build TXZ packages"     OFF)
+      mark_as_advanced(
+        CPACK_BINARY_DEB
+        CPACK_BINARY_FREEBSD
+        CPACK_BINARY_NSIS
+        CPACK_BINARY_RPM
+        CPACK_BINARY_STGZ
+        CPACK_BINARY_TBZ2
+        CPACK_BINARY_TGZ
+        CPACK_BINARY_TXZ
+        )
     endif()
   else()
     option(CPACK_BINARY_7Z    "Enable to build 7-Zip packages" OFF)
@@ -581,8 +601,16 @@
     option(CPACK_BINARY_NUGET "Enable to build NuGet packages" OFF)
     option(CPACK_BINARY_WIX   "Enable to build WiX packages" OFF)
     option(CPACK_BINARY_ZIP   "Enable to build ZIP packages" OFF)
+    mark_as_advanced(
+      CPACK_BINARY_7Z
+      CPACK_BINARY_NSIS
+      CPACK_BINARY_NUGET
+      CPACK_BINARY_WIX
+      CPACK_BINARY_ZIP
+      )
   endif()
   option(CPACK_BINARY_IFW "Enable to build IFW packages" OFF)
+  mark_as_advanced(CPACK_BINARY_IFW)
 
   cpack_optional_append(CPACK_GENERATOR  CPACK_BINARY_7Z           7Z)
   cpack_optional_append(CPACK_GENERATOR  CPACK_BINARY_BUNDLE       Bundle)
@@ -612,6 +640,7 @@
   if(UNIX)
     if(CYGWIN)
       option(CPACK_SOURCE_CYGWIN "Enable to build Cygwin source packages" ON)
+      mark_as_advanced(CPACK_SOURCE_CYGWIN)
     else()
       option(CPACK_SOURCE_RPM  "Enable to build RPM source packages"  OFF)
       option(CPACK_SOURCE_TBZ2 "Enable to build TBZ2 source packages" ON)
@@ -619,10 +648,22 @@
       option(CPACK_SOURCE_TXZ  "Enable to build TXZ source packages"  ON)
       option(CPACK_SOURCE_TZ   "Enable to build TZ source packages"   ON)
       option(CPACK_SOURCE_ZIP  "Enable to build ZIP source packages"  OFF)
+      mark_as_advanced(
+        CPACK_SOURCE_RPM
+        CPACK_SOURCE_TBZ2
+        CPACK_SOURCE_TGZ
+        CPACK_SOURCE_TXZ
+        CPACK_SOURCE_TZ
+        CPACK_SOURCE_ZIP
+        )
     endif()
   else()
     option(CPACK_SOURCE_7Z  "Enable to build 7-Zip source packages" ON)
     option(CPACK_SOURCE_ZIP "Enable to build ZIP source packages" ON)
+    mark_as_advanced(
+      CPACK_SOURCE_7Z
+      CPACK_SOURCE_ZIP
+      )
   endif()
 
   cpack_optional_append(CPACK_SOURCE_GENERATOR  CPACK_SOURCE_7Z      7Z)
@@ -635,38 +676,6 @@
   cpack_optional_append(CPACK_SOURCE_GENERATOR  CPACK_SOURCE_ZIP     ZIP)
 endif()
 
-# mark the above options as advanced
-mark_as_advanced(
-  CPACK_BINARY_7Z
-  CPACK_BINARY_BUNDLE
-  CPACK_BINARY_CYGWIN
-  CPACK_BINARY_DEB
-  CPACK_BINARY_DRAGNDROP
-  CPACK_BINARY_FREEBSD
-  CPACK_BINARY_IFW
-  CPACK_BINARY_NSIS
-  CPACK_BINARY_NUGET
-  CPACK_BINARY_OSXX11
-  CPACK_BINARY_PACKAGEMAKER
-  CPACK_BINARY_PRODUCTBUILD
-  CPACK_BINARY_RPM
-  CPACK_BINARY_STGZ
-  CPACK_BINARY_TBZ2
-  CPACK_BINARY_TGZ
-  CPACK_BINARY_TXZ
-  CPACK_BINARY_TZ
-  CPACK_BINARY_WIX
-  CPACK_BINARY_ZIP
-  CPACK_SOURCE_7Z
-  CPACK_SOURCE_CYGWIN
-  CPACK_SOURCE_RPM
-  CPACK_SOURCE_TBZ2
-  CPACK_SOURCE_TGZ
-  CPACK_SOURCE_TXZ
-  CPACK_SOURCE_TZ
-  CPACK_SOURCE_ZIP
-  )
-
 # Set some other variables
 _cpack_set_default(CPACK_INSTALL_CMAKE_PROJECTS
   "${CMAKE_BINARY_DIR};${CMAKE_PROJECT_NAME};ALL;/")
diff --git a/Modules/CTest.cmake b/Modules/CTest.cmake
index 1a51bc8..8109108 100644
--- a/Modules/CTest.cmake
+++ b/Modules/CTest.cmake
@@ -243,7 +243,6 @@
 
   mark_as_advanced(
     BZRCOMMAND
-    BZR_UPDATE_OPTIONS
     COVERAGE_COMMAND
     COVERAGE_EXTRA_FLAGS
     CTEST_SUBMIT_RETRY_DELAY
@@ -257,13 +256,10 @@
     MAKECOMMAND
     MEMORYCHECK_COMMAND
     MEMORYCHECK_SUPPRESSIONS_FILE
-    PURIFYCOMMAND
-    SCPCOMMAND
     SLURM_SBATCH_COMMAND
     SLURM_SRUN_COMMAND
     SITE
     SVNCOMMAND
-    SVN_UPDATE_OPTIONS
     )
   if(NOT RUN_FROM_DART)
     set(RUN_FROM_CTEST_OR_DART 1)
diff --git a/Modules/Compiler/AppleClang-OBJCXX.cmake b/Modules/Compiler/AppleClang-OBJCXX.cmake
index 7c6f763..2c084af 100644
--- a/Modules/Compiler/AppleClang-OBJCXX.cmake
+++ b/Modules/Compiler/AppleClang-OBJCXX.cmake
@@ -1,5 +1,7 @@
 include(Compiler/Clang-OBJCXX)
 
+set(CMAKE_OBJCXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
+
 if(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 4.0)
   set(CMAKE_OBJCXX98_STANDARD_COMPILE_OPTION "-std=c++98")
   set(CMAKE_OBJCXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
diff --git a/Modules/Compiler/GNU-OBJC.cmake b/Modules/Compiler/GNU-OBJC.cmake
index 5fba801..fb9b0b2 100644
--- a/Modules/Compiler/GNU-OBJC.cmake
+++ b/Modules/Compiler/GNU-OBJC.cmake
@@ -1,6 +1,2 @@
 include(Compiler/GNU)
 __compiler_gnu(OBJC)
-
-if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.2)
-  set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
-endif()
diff --git a/Modules/Compiler/GNU-OBJCXX.cmake b/Modules/Compiler/GNU-OBJCXX.cmake
index 66a547e..06f0244 100644
--- a/Modules/Compiler/GNU-OBJCXX.cmake
+++ b/Modules/Compiler/GNU-OBJCXX.cmake
@@ -1,8 +1,8 @@
 include(Compiler/GNU)
-__compiler_gnu(OBJC)
+__compiler_gnu(OBJCXX)
 
-if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.2)
-  set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
+if(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 4.2)
+  set(CMAKE_OBJCXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
 endif()
 
 if(NOT CMAKE_OBJCXX_LINK_FLAGS)
diff --git a/Modules/Compiler/NAG-Fortran.cmake b/Modules/Compiler/NAG-Fortran.cmake
index c54ab9d..2111c65 100644
--- a/Modules/Compiler/NAG-Fortran.cmake
+++ b/Modules/Compiler/NAG-Fortran.cmake
@@ -28,6 +28,8 @@
   endif()
 endif()
 
+set(CMAKE_Fortran_SUBMODULE_SEP ".")
+set(CMAKE_Fortran_SUBMODULE_EXT ".sub")
 set(CMAKE_Fortran_MODDIR_FLAG "-mdir ")
 set(CMAKE_SHARED_LIBRARY_Fortran_FLAGS "-PIC")
 set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-fixed")
diff --git a/Modules/FindBLAS.cmake b/Modules/FindBLAS.cmake
index dc73f16..23b5fa7 100644
--- a/Modules/FindBLAS.cmake
+++ b/Modules/FindBLAS.cmake
@@ -8,8 +8,9 @@
 Find Basic Linear Algebra Subprograms (BLAS) library
 
 This module finds an installed Fortran library that implements the
-BLAS linear-algebra interface (see http://www.netlib.org/blas/).  The
-list of libraries searched for is taken from the ``autoconf`` macro file,
+BLAS linear-algebra interface (see http://www.netlib.org/blas/).
+
+The approach follows that taken for the ``autoconf`` macro file,
 ``acx_blas.m4`` (distributed at
 http://ac-archive.sourceforge.net/ac-archive/acx_blas.html).
 
@@ -25,28 +26,28 @@
   If set, checks only the specified vendor, if not set checks all the
   possibilities.  List of vendors valid in this module:
 
-  * Goto
-  * OpenBLAS
-  * FLAME
-  * ATLAS PhiPACK
-  * CXML
-  * DXML
-  * SunPerf
-  * SCSL
-  * SGIMATH
-  * IBMESSL
-  * Intel10_32 (intel mkl v10 32 bit)
-  * Intel10_64lp (intel mkl v10+ 64 bit, threaded code, lp64 model)
-  * Intel10_64lp_seq (intel mkl v10+ 64 bit, sequential code, lp64 model)
-  * Intel10_64ilp (intel mkl v10+ 64 bit, threaded code, ilp64 model)
-  * Intel10_64ilp_seq (intel mkl v10+ 64 bit, sequential code, ilp64 model)
-  * Intel (obsolete versions of mkl 32 and 64 bit)
-  * ACML
-  * ACML_MP
-  * ACML_GPU
-  * Apple
-  * NAS
-  * Generic
+  * ``Goto``
+  * ``OpenBLAS``
+  * ``FLAME``
+  * ``ATLAS PhiPACK``
+  * ``CXML``
+  * ``DXML``
+  * ``SunPerf``
+  * ``SCSL``
+  * ``SGIMATH``
+  * ``IBMESSL``
+  * ``Intel10_32`` (intel mkl v10 32 bit)
+  * ``Intel10_64lp`` (intel mkl v10+ 64 bit, threaded code, lp64 model)
+  * ``Intel10_64lp_seq`` (intel mkl v10+ 64 bit, sequential code, lp64 model)
+  * ``Intel10_64ilp`` (intel mkl v10+ 64 bit, threaded code, ilp64 model)
+  * ``Intel10_64ilp_seq`` (intel mkl v10+ 64 bit, sequential code, ilp64 model)
+  * ``Intel`` (obsolete versions of mkl 32 and 64 bit)
+  * ``ACML``
+  * ``ACML_MP``
+  * ``ACML_GPU``
+  * ``Apple``
+  * ``NAS``
+  * ``Generic``
 
 ``BLA_F95``
   if ``ON`` tries to find the BLAS95 interfaces
@@ -92,17 +93,8 @@
 
 #]=======================================================================]
 
-include(${CMAKE_CURRENT_LIST_DIR}/CheckFunctionExists.cmake)
-include(${CMAKE_CURRENT_LIST_DIR}/CheckFortranFunctionExists.cmake)
-include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
-include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
-cmake_push_check_state()
-set(CMAKE_REQUIRED_QUIET ${BLAS_FIND_QUIETLY})
-
-set(_blas_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
-
 # Check the language being used
-if( NOT (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED) )
+if(NOT (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED))
   if(BLAS_FIND_REQUIRED)
     message(FATAL_ERROR "FindBLAS requires Fortran, C, or C++ to be enabled.")
   else()
@@ -111,6 +103,18 @@
   endif()
 endif()
 
+if(CMAKE_Fortran_COMPILER_LOADED)
+  include(${CMAKE_CURRENT_LIST_DIR}/CheckFortranFunctionExists.cmake)
+else()
+  include(${CMAKE_CURRENT_LIST_DIR}/CheckFunctionExists.cmake)
+endif()
+include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+cmake_push_check_state()
+set(CMAKE_REQUIRED_QUIET ${BLAS_FIND_QUIETLY})
+
+set(_blas_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+
 if(BLA_PREFER_PKGCONFIG)
   find_package(PkgConfig)
   pkg_check_modules(PKGC_BLAS blas)
@@ -121,7 +125,9 @@
   endif()
 endif()
 
-macro(Check_Fortran_Libraries LIBRARIES _prefix _name _flags _list _thread)
+# TODO: move this stuff to a separate module
+
+macro(CHECK_BLAS_LIBRARIES LIBRARIES _prefix _name _flags _list _threadlibs)
   # This macro checks for the existence of the combination of fortran libraries
   # given by _list.  If the combination is found, this macro checks (using the
   # Check_Fortran_Function_Exists macro) whether can link against that library
@@ -138,53 +144,54 @@
   set(_libraries_work TRUE)
   set(${LIBRARIES})
   set(_combined_name)
-  if (NOT _libdir)
-    if (WIN32)
+  if(NOT _libdir)
+    if(WIN32)
       set(_libdir ENV LIB)
-    elseif (APPLE)
+    elseif(APPLE)
       set(_libdir ENV DYLD_LIBRARY_PATH)
-    else ()
+    else()
       set(_libdir ENV LD_LIBRARY_PATH)
-    endif ()
-  endif ()
+    endif()
+  endif()
 
   list(APPEND _libdir "${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}")
 
   foreach(_library ${_list})
     set(_combined_name ${_combined_name}_${_library})
-    if(NOT "${_thread}" STREQUAL "")
-      set(_combined_name ${_combined_name}_thread)
+    if(NOT "${_threadlibs}" STREQUAL "")
+      set(_combined_name ${_combined_name}_threadlibs)
     endif()
     if(_libraries_work)
-      if (BLA_STATIC)
-        if (WIN32)
+      if(BLA_STATIC)
+        if(WIN32)
           set(CMAKE_FIND_LIBRARY_SUFFIXES .lib ${CMAKE_FIND_LIBRARY_SUFFIXES})
-        endif ()
-        if (APPLE)
+        endif()
+        if(APPLE)
           set(CMAKE_FIND_LIBRARY_SUFFIXES .lib ${CMAKE_FIND_LIBRARY_SUFFIXES})
-        else ()
+        else()
           set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
-        endif ()
-      else ()
-        if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
+        endif()
+      else()
+        if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
           # for ubuntu's libblas3gf and liblapack3gf packages
           set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES} .so.3gf)
-        endif ()
-      endif ()
+        endif()
+      endif()
       find_library(${_prefix}_${_library}_LIBRARY
         NAMES ${_library}
         PATHS ${_libdir}
-        )
+      )
       mark_as_advanced(${_prefix}_${_library}_LIBRARY)
       set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_library}_LIBRARY})
       set(_libraries_work ${${_prefix}_${_library}_LIBRARY})
     endif()
   endforeach()
+
   if(_libraries_work)
     # Test this combination of libraries.
-    set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}} ${_thread})
-    #  message("DEBUG: CMAKE_REQUIRED_LIBRARIES = ${CMAKE_REQUIRED_LIBRARIES}")
-    if (CMAKE_Fortran_COMPILER_LOADED)
+    set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}} ${_threadlibs})
+    #message("DEBUG: CMAKE_REQUIRED_LIBRARIES = ${CMAKE_REQUIRED_LIBRARIES}")
+    if(CMAKE_Fortran_COMPILER_LOADED)
       check_fortran_function_exists("${_name}" ${_prefix}${_combined_name}_WORKS)
     else()
       check_function_exists("${_name}_" ${_prefix}${_combined_name}_WORKS)
@@ -192,11 +199,12 @@
     set(CMAKE_REQUIRED_LIBRARIES)
     set(_libraries_work ${${_prefix}${_combined_name}_WORKS})
   endif()
+
   if(_libraries_work)
     if("${_list}" STREQUAL "")
       set(${LIBRARIES} "${LIBRARIES}-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
     else()
-      set(${LIBRARIES} ${${LIBRARIES}} ${_thread})  # for static link
+      set(${LIBRARIES} ${${LIBRARIES}} ${_threadlibs})
     endif()
   else()
     set(${LIBRARIES} FALSE)
@@ -207,18 +215,18 @@
 set(BLAS_LINKER_FLAGS)
 set(BLAS_LIBRARIES)
 set(BLAS95_LIBRARIES)
-if (NOT $ENV{BLA_VENDOR} STREQUAL "")
+if(NOT $ENV{BLA_VENDOR} STREQUAL "")
   set(BLA_VENDOR $ENV{BLA_VENDOR})
-else ()
+else()
   if(NOT BLA_VENDOR)
     set(BLA_VENDOR "All")
   endif()
-endif ()
+endif()
 
-if (BLA_VENDOR STREQUAL "All")
+# Implicitly linked BLAS libraries?
+if(BLA_VENDOR STREQUAL "All")
   if(NOT BLAS_LIBRARIES)
-    # Implicitly linked BLAS libraries
-    check_fortran_libraries(
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
@@ -227,71 +235,70 @@
       ""
       )
   endif()
-endif ()
+endif()
 
-#BLAS in intel mkl 10+ library? (em64t 64bit)
-if (BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
-  if (NOT BLAS_LIBRARIES)
-
-    # System-specific settings
-    if (WIN32)
-      if (BLA_STATIC)
-        set(BLAS_mkl_DLL_SUFFIX "")
+# BLAS in the Intel MKL 10+ library?
+if(BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
+  if(NOT BLAS_LIBRARIES)
+    if(CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED)
+      # System-specific settings
+      if(WIN32)
+        if(BLA_STATIC)
+          set(BLAS_mkl_DLL_SUFFIX "")
+        else()
+          set(BLAS_mkl_DLL_SUFFIX "_dll")
+        endif()
       else()
-        set(BLAS_mkl_DLL_SUFFIX "_dll")
+        # Switch to GNU Fortran support layer if needed (but not on Apple, where MKL does not provide it)
+        if(CMAKE_Fortran_COMPILER_LOADED AND CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND NOT APPLE)
+            set(BLAS_mkl_INTFACE "gf")
+            set(BLAS_mkl_THREADING "gnu")
+            set(BLAS_mkl_OMP "gomp")
+        else()
+            set(BLAS_mkl_INTFACE "intel")
+            set(BLAS_mkl_THREADING "intel")
+            set(BLAS_mkl_OMP "iomp5")
+        endif()
+        set(BLAS_mkl_LM "-lm")
+        set(BLAS_mkl_LDL "-ldl")
       endif()
-    else()
-      # Switch to GNU Fortran support layer if needed (but not on Apple, where MKL does not provide it)
-      if(CMAKE_Fortran_COMPILER_LOADED AND CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND NOT APPLE)
-          set(BLAS_mkl_INTFACE "gf")
-          set(BLAS_mkl_THREADING "gnu")
-          set(BLAS_mkl_OMP "gomp")
-      else()
-          set(BLAS_mkl_INTFACE "intel")
-          set(BLAS_mkl_THREADING "intel")
-          set(BLAS_mkl_OMP "iomp5")
-      endif()
-      set(BLAS_mkl_LM "-lm")
-      set(BLAS_mkl_LDL "-ldl")
-    endif()
 
-    if (BLA_VENDOR MATCHES "_64ilp")
-      set(BLAS_mkl_ILP_MODE "ilp64")
-    else ()
-      set(BLAS_mkl_ILP_MODE "lp64")
-    endif ()
-
-    if (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED)
       if(BLAS_FIND_QUIETLY OR NOT BLAS_FIND_REQUIRED)
         find_package(Threads)
       else()
         find_package(Threads REQUIRED)
       endif()
 
+      if(BLA_VENDOR MATCHES "_64ilp")
+        set(BLAS_mkl_ILP_MODE "ilp64")
+      else()
+        set(BLAS_mkl_ILP_MODE "lp64")
+      endif()
+
       set(BLAS_SEARCH_LIBS "")
 
       if(BLA_F95)
-        set(BLAS_mkl_SEARCH_SYMBOL sgemm_f95)
+        set(BLAS_mkl_SEARCH_SYMBOL "sgemm_f95")
         set(_LIBRARIES BLAS95_LIBRARIES)
-        if (WIN32)
+        if(WIN32)
           # Find the main file (32-bit or 64-bit)
           set(BLAS_SEARCH_LIBS_WIN_MAIN "")
-          if (BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All")
+          if(BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All")
             list(APPEND BLAS_SEARCH_LIBS_WIN_MAIN
               "mkl_blas95${BLAS_mkl_DLL_SUFFIX} mkl_intel_c${BLAS_mkl_DLL_SUFFIX}")
           endif()
-          if (BLA_VENDOR MATCHES "^Intel10_64i?lp" OR BLA_VENDOR STREQUAL "All")
+          if(BLA_VENDOR MATCHES "^Intel10_64i?lp" OR BLA_VENDOR STREQUAL "All")
             list(APPEND BLAS_SEARCH_LIBS_WIN_MAIN
               "mkl_blas95_${BLAS_mkl_ILP_MODE}${BLAS_mkl_DLL_SUFFIX} mkl_intel_${BLAS_mkl_ILP_MODE}${BLAS_mkl_DLL_SUFFIX}")
-          endif ()
+          endif()
 
           # Add threading/sequential libs
           set(BLAS_SEARCH_LIBS_WIN_THREAD "")
-          if (BLA_VENDOR MATCHES "_seq$" OR BLA_VENDOR STREQUAL "All")
+          if(BLA_VENDOR MATCHES "_seq$" OR BLA_VENDOR STREQUAL "All")
             list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
               "mkl_sequential${BLAS_mkl_DLL_SUFFIX}")
           endif()
-          if (NOT BLA_VENDOR MATCHES "_seq$" OR BLA_VENDOR STREQUAL "All")
+          if(NOT BLA_VENDOR MATCHES "_seq$" OR BLA_VENDOR STREQUAL "All")
             # old version
             list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
               "libguide40 mkl_intel_thread${BLAS_mkl_DLL_SUFFIX}")
@@ -301,14 +308,14 @@
           endif()
 
           # Cartesian product of the above
-          foreach (MAIN ${BLAS_SEARCH_LIBS_WIN_MAIN})
-            foreach (THREAD ${BLAS_SEARCH_LIBS_WIN_THREAD})
+          foreach(MAIN ${BLAS_SEARCH_LIBS_WIN_MAIN})
+            foreach(THREAD ${BLAS_SEARCH_LIBS_WIN_THREAD})
               list(APPEND BLAS_SEARCH_LIBS
                 "${MAIN} ${THREAD} mkl_core${BLAS_mkl_DLL_SUFFIX}")
             endforeach()
           endforeach()
-        else ()
-          if (BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All")
+        else()
+          if(BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All")
             # old version
             list(APPEND BLAS_SEARCH_LIBS
               "mkl_blas95 mkl_${BLAS_mkl_INTFACE} mkl_${BLAS_mkl_THREADING}_thread mkl_core guide")
@@ -316,8 +323,8 @@
             # mkl >= 10.3
             list(APPEND BLAS_SEARCH_LIBS
               "mkl_blas95 mkl_${BLAS_mkl_INTFACE} mkl_${BLAS_mkl_THREADING}_thread mkl_core ${BLAS_mkl_OMP}")
-          endif ()
-          if (BLA_VENDOR MATCHES "^Intel10_64i?lp$" OR BLA_VENDOR STREQUAL "All")
+          endif()
+          if(BLA_VENDOR MATCHES "^Intel10_64i?lp$" OR BLA_VENDOR STREQUAL "All")
             # old version
             list(APPEND BLAS_SEARCH_LIBS
               "mkl_blas95 mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_THREADING}_thread mkl_core guide")
@@ -325,30 +332,30 @@
             # mkl >= 10.3
             list(APPEND BLAS_SEARCH_LIBS
               "mkl_blas95_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_THREADING}_thread mkl_core ${BLAS_mkl_OMP}")
-          endif ()
-          if (BLA_VENDOR MATCHES "^Intel10_64i?lp_seq$" OR BLA_VENDOR STREQUAL "All")
+          endif()
+          if(BLA_VENDOR MATCHES "^Intel10_64i?lp_seq$" OR BLA_VENDOR STREQUAL "All")
             list(APPEND BLAS_SEARCH_LIBS
               "mkl_blas95_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_sequential mkl_core")
-          endif ()
-        endif ()
-      else ()
+          endif()
+        endif()
+      else()
         set(BLAS_mkl_SEARCH_SYMBOL sgemm)
         set(_LIBRARIES BLAS_LIBRARIES)
-        if (WIN32)
+        if(WIN32)
           # Find the main file (32-bit or 64-bit)
           set(BLAS_SEARCH_LIBS_WIN_MAIN "")
-          if (BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All")
+          if(BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All")
             list(APPEND BLAS_SEARCH_LIBS_WIN_MAIN
               "mkl_intel_c${BLAS_mkl_DLL_SUFFIX}")
           endif()
-          if (BLA_VENDOR MATCHES "^Intel10_64i?lp" OR BLA_VENDOR STREQUAL "All")
+          if(BLA_VENDOR MATCHES "^Intel10_64i?lp" OR BLA_VENDOR STREQUAL "All")
             list(APPEND BLAS_SEARCH_LIBS_WIN_MAIN
               "mkl_intel_${BLAS_mkl_ILP_MODE}${BLAS_mkl_DLL_SUFFIX}")
-          endif ()
+          endif()
 
           # Add threading/sequential libs
           set(BLAS_SEARCH_LIBS_WIN_THREAD "")
-          if (NOT BLA_VENDOR MATCHES "_seq$" OR BLA_VENDOR STREQUAL "All")
+          if(NOT BLA_VENDOR MATCHES "_seq$" OR BLA_VENDOR STREQUAL "All")
             # old version
             list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
               "libguide40 mkl_intel_thread${BLAS_mkl_DLL_SUFFIX}")
@@ -356,20 +363,20 @@
             list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
               "libiomp5md mkl_intel_thread${BLAS_mkl_DLL_SUFFIX}")
           endif()
-          if (BLA_VENDOR MATCHES "_seq$" OR BLA_VENDOR STREQUAL "All")
+          if(BLA_VENDOR MATCHES "_seq$" OR BLA_VENDOR STREQUAL "All")
             list(APPEND BLAS_SEARCH_LIBS_WIN_THREAD
               "mkl_sequential${BLAS_mkl_DLL_SUFFIX}")
           endif()
 
           # Cartesian product of the above
-          foreach (MAIN ${BLAS_SEARCH_LIBS_WIN_MAIN})
-            foreach (THREAD ${BLAS_SEARCH_LIBS_WIN_THREAD})
+          foreach(MAIN ${BLAS_SEARCH_LIBS_WIN_MAIN})
+            foreach(THREAD ${BLAS_SEARCH_LIBS_WIN_THREAD})
               list(APPEND BLAS_SEARCH_LIBS
                 "${MAIN} ${THREAD} mkl_core${BLAS_mkl_DLL_SUFFIX}")
             endforeach()
           endforeach()
-        else ()
-          if (BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All")
+        else()
+          if(BLA_VENDOR STREQUAL "Intel10_32" OR BLA_VENDOR STREQUAL "All")
             # old version
             list(APPEND BLAS_SEARCH_LIBS
               "mkl_${BLAS_mkl_INTFACE} mkl_${BLAS_mkl_THREADING}_thread mkl_core guide")
@@ -377,8 +384,8 @@
             # mkl >= 10.3
             list(APPEND BLAS_SEARCH_LIBS
               "mkl_${BLAS_mkl_INTFACE} mkl_${BLAS_mkl_THREADING}_thread mkl_core ${BLAS_mkl_OMP}")
-          endif ()
-          if (BLA_VENDOR MATCHES "^Intel10_64i?lp$" OR BLA_VENDOR STREQUAL "All")
+          endif()
+          if(BLA_VENDOR MATCHES "^Intel10_64i?lp$" OR BLA_VENDOR STREQUAL "All")
             # old version
             list(APPEND BLAS_SEARCH_LIBS
               "mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_THREADING}_thread mkl_core guide")
@@ -386,45 +393,45 @@
             # mkl >= 10.3
             list(APPEND BLAS_SEARCH_LIBS
               "mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_${BLAS_mkl_THREADING}_thread mkl_core ${BLAS_mkl_OMP}")
-          endif ()
-          if (BLA_VENDOR MATCHES "^Intel10_64i?lp_seq$" OR BLA_VENDOR STREQUAL "All")
+          endif()
+          if(BLA_VENDOR MATCHES "^Intel10_64i?lp_seq$" OR BLA_VENDOR STREQUAL "All")
             list(APPEND BLAS_SEARCH_LIBS
               "mkl_${BLAS_mkl_INTFACE}_${BLAS_mkl_ILP_MODE} mkl_sequential mkl_core")
-          endif ()
+          endif()
 
           #older vesions of intel mkl libs
-          if (BLA_VENDOR STREQUAL "Intel" OR BLA_VENDOR STREQUAL "All")
+          if(BLA_VENDOR STREQUAL "Intel" OR BLA_VENDOR STREQUAL "All")
             list(APPEND BLAS_SEARCH_LIBS
               "mkl")
             list(APPEND BLAS_SEARCH_LIBS
               "mkl_ia32")
             list(APPEND BLAS_SEARCH_LIBS
               "mkl_em64t")
-          endif ()
-        endif ()
-      endif ()
+          endif()
+        endif()
+      endif()
 
-      if (DEFINED ENV{MKLROOT})
-        if (BLA_VENDOR STREQUAL "Intel10_32")
+      if(DEFINED ENV{MKLROOT})
+        if(BLA_VENDOR STREQUAL "Intel10_32")
           set(_BLAS_MKLROOT_LIB_DIR "$ENV{MKLROOT}/lib/ia32")
-        elseif (BLA_VENDOR MATCHES "^Intel10_64i?lp$" OR BLA_VENDOR MATCHES "^Intel10_64i?lp_seq$")
+        elseif(BLA_VENDOR MATCHES "^Intel10_64i?lp$" OR BLA_VENDOR MATCHES "^Intel10_64i?lp_seq$")
           set(_BLAS_MKLROOT_LIB_DIR "$ENV{MKLROOT}/lib/intel64")
-        endif ()
-      endif ()
-      if (_BLAS_MKLROOT_LIB_DIR)
-        if (WIN32)
+        endif()
+      endif()
+      if(_BLAS_MKLROOT_LIB_DIR)
+        if(WIN32)
           string(APPEND _BLAS_MKLROOT_LIB_DIR "_win")
-        elseif (APPLE)
+        elseif(APPLE)
           string(APPEND _BLAS_MKLROOT_LIB_DIR "_mac")
-        else ()
+        else()
           string(APPEND _BLAS_MKLROOT_LIB_DIR "_lin")
-        endif ()
-      endif ()
+        endif()
+      endif()
 
-      foreach (IT ${BLAS_SEARCH_LIBS})
+      foreach(IT ${BLAS_SEARCH_LIBS})
         string(REPLACE " " ";" SEARCH_LIBS ${IT})
-        if (NOT ${_LIBRARIES})
-          check_fortran_libraries(
+        if(NOT ${_LIBRARIES})
+          check_blas_libraries(
             ${_LIBRARIES}
             BLAS
             ${BLAS_mkl_SEARCH_SYMBOL}
@@ -433,19 +440,19 @@
             "${CMAKE_THREAD_LIBS_INIT};${BLAS_mkl_LM};${BLAS_mkl_LDL}"
             "${_BLAS_MKLROOT_LIB_DIR}"
             )
-        endif ()
-      endforeach ()
+        endif()
+      endforeach()
 
-    endif ()
-    unset(BLAS_mkl_ILP_MODE)
-    unset(BLAS_mkl_INTFACE)
-    unset(BLAS_mkl_THREADING)
-    unset(BLAS_mkl_OMP)
-    unset(BLAS_mkl_DLL_SUFFIX)
-    unset(BLAS_mkl_LM)
-    unset(BLAS_mkl_LDL)
-  endif ()
-endif ()
+      unset(BLAS_mkl_ILP_MODE)
+      unset(BLAS_mkl_INTFACE)
+      unset(BLAS_mkl_THREADING)
+      unset(BLAS_mkl_OMP)
+      unset(BLAS_mkl_DLL_SUFFIX)
+      unset(BLAS_mkl_LM)
+      unset(BLAS_mkl_LDL)
+    endif()
+  endif()
+endif()
 
 if(BLA_F95)
   find_package_handle_standard_args(BLAS REQUIRED_VARS BLAS95_LIBRARIES)
@@ -455,10 +462,10 @@
   endif()
 endif()
 
-if (BLA_VENDOR STREQUAL "Goto" OR BLA_VENDOR STREQUAL "All")
+# gotoblas? (http://www.tacc.utexas.edu/tacc-projects/gotoblas2)
+if(BLA_VENDOR STREQUAL "Goto" OR BLA_VENDOR STREQUAL "All")
   if(NOT BLAS_LIBRARIES)
-    # gotoblas (http://www.tacc.utexas.edu/tacc-projects/gotoblas2)
-    check_fortran_libraries(
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
@@ -467,12 +474,12 @@
       ""
       )
   endif()
-endif ()
+endif()
 
-if (BLA_VENDOR STREQUAL "OpenBLAS" OR BLA_VENDOR STREQUAL "All")
+# OpenBLAS? (http://www.openblas.net)
+if(BLA_VENDOR STREQUAL "OpenBLAS" OR BLA_VENDOR STREQUAL "All")
   if(NOT BLAS_LIBRARIES)
-    # OpenBLAS (http://www.openblas.net)
-    check_fortran_libraries(
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
@@ -487,8 +494,7 @@
     else()
       find_package(Threads REQUIRED)
     endif()
-    # OpenBLAS (http://www.openblas.net)
-    check_fortran_libraries(
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
@@ -497,12 +503,12 @@
       "${CMAKE_THREAD_LIBS_INIT}"
       )
   endif()
-endif ()
+endif()
 
-if (BLA_VENDOR STREQUAL "FLAME" OR BLA_VENDOR STREQUAL "All")
+# FLAME's blis library? (https://github.com/flame/blis)
+if(BLA_VENDOR STREQUAL "FLAME" OR BLA_VENDOR STREQUAL "All")
   if(NOT BLAS_LIBRARIES)
-    # FLAME's blis library (https://github.com/flame/blis)
-    check_fortran_libraries(
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
@@ -511,12 +517,12 @@
       ""
       )
   endif()
-endif ()
+endif()
 
-if (BLA_VENDOR STREQUAL "ATLAS" OR BLA_VENDOR STREQUAL "All")
+# BLAS in the ATLAS library? (http://math-atlas.sourceforge.net/)
+if(BLA_VENDOR STREQUAL "ATLAS" OR BLA_VENDOR STREQUAL "All")
   if(NOT BLAS_LIBRARIES)
-    # BLAS in ATLAS library? (http://math-atlas.sourceforge.net/)
-    check_fortran_libraries(
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       dgemm
@@ -525,12 +531,12 @@
       ""
       )
   endif()
-endif ()
+endif()
 
 # BLAS in PhiPACK libraries? (requires generic BLAS lib, too)
-if (BLA_VENDOR STREQUAL "PhiPACK" OR BLA_VENDOR STREQUAL "All")
+if(BLA_VENDOR STREQUAL "PhiPACK" OR BLA_VENDOR STREQUAL "All")
   if(NOT BLAS_LIBRARIES)
-    check_fortran_libraries(
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
@@ -539,12 +545,12 @@
       ""
       )
   endif()
-endif ()
+endif()
 
 # BLAS in Alpha CXML library?
-if (BLA_VENDOR STREQUAL "CXML" OR BLA_VENDOR STREQUAL "All")
+if(BLA_VENDOR STREQUAL "CXML" OR BLA_VENDOR STREQUAL "All")
   if(NOT BLAS_LIBRARIES)
-    check_fortran_libraries(
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
@@ -553,12 +559,12 @@
       ""
       )
   endif()
-endif ()
+endif()
 
 # BLAS in Alpha DXML library? (now called CXML, see above)
-if (BLA_VENDOR STREQUAL "DXML" OR BLA_VENDOR STREQUAL "All")
+if(BLA_VENDOR STREQUAL "DXML" OR BLA_VENDOR STREQUAL "All")
   if(NOT BLAS_LIBRARIES)
-    check_fortran_libraries(
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
@@ -567,12 +573,12 @@
       ""
       )
   endif()
-endif ()
+endif()
 
 # BLAS in Sun Performance library?
-if (BLA_VENDOR STREQUAL "SunPerf" OR BLA_VENDOR STREQUAL "All")
+if(BLA_VENDOR STREQUAL "SunPerf" OR BLA_VENDOR STREQUAL "All")
   if(NOT BLAS_LIBRARIES)
-    check_fortran_libraries(
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
@@ -584,12 +590,12 @@
       set(BLAS_LINKER_FLAGS "-xlic_lib=sunperf")
     endif()
   endif()
-endif ()
+endif()
 
 # BLAS in SCSL library?  (SGI/Cray Scientific Library)
-if (BLA_VENDOR STREQUAL "SCSL" OR BLA_VENDOR STREQUAL "All")
+if(BLA_VENDOR STREQUAL "SCSL" OR BLA_VENDOR STREQUAL "All")
   if(NOT BLAS_LIBRARIES)
-    check_fortran_libraries(
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
@@ -598,12 +604,12 @@
       ""
       )
   endif()
-endif ()
+endif()
 
 # BLAS in SGIMATH library?
-if (BLA_VENDOR STREQUAL "SGIMATH" OR BLA_VENDOR STREQUAL "All")
+if(BLA_VENDOR STREQUAL "SGIMATH" OR BLA_VENDOR STREQUAL "All")
   if(NOT BLAS_LIBRARIES)
-    check_fortran_libraries(
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
@@ -612,12 +618,12 @@
       ""
       )
   endif()
-endif ()
+endif()
 
 # BLAS in IBM ESSL library? (requires generic BLAS lib, too)
-if (BLA_VENDOR STREQUAL "IBMESSL" OR BLA_VENDOR STREQUAL "All")
+if(BLA_VENDOR STREQUAL "IBMESSL" OR BLA_VENDOR STREQUAL "All")
   if(NOT BLAS_LIBRARIES)
-    check_fortran_libraries(
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
@@ -626,107 +632,107 @@
       ""
       )
   endif()
-endif ()
+endif()
 
-#BLAS in acml library?
-if (BLA_VENDOR MATCHES "ACML" OR BLA_VENDOR STREQUAL "All")
-  if( ((BLA_VENDOR STREQUAL "ACML") AND (NOT BLAS_ACML_LIB_DIRS)) OR
+# BLAS in acml library?
+if(BLA_VENDOR MATCHES "ACML" OR BLA_VENDOR STREQUAL "All")
+  if(((BLA_VENDOR STREQUAL "ACML") AND (NOT BLAS_ACML_LIB_DIRS)) OR
     ((BLA_VENDOR STREQUAL "ACML_MP") AND (NOT BLAS_ACML_MP_LIB_DIRS)) OR
     ((BLA_VENDOR STREQUAL "ACML_GPU") AND (NOT BLAS_ACML_GPU_LIB_DIRS))
     )
   # try to find acml in "standard" paths
-  if( WIN32 )
-    file( GLOB _ACML_ROOT "C:/AMD/acml*/ACML-EULA.txt" )
+  if(WIN32)
+    file(GLOB _ACML_ROOT "C:/AMD/acml*/ACML-EULA.txt")
   else()
-    file( GLOB _ACML_ROOT "/opt/acml*/ACML-EULA.txt" )
+    file(GLOB _ACML_ROOT "/opt/acml*/ACML-EULA.txt")
   endif()
-  if( WIN32 )
-    file( GLOB _ACML_GPU_ROOT "C:/AMD/acml*/GPGPUexamples" )
+  if(WIN32)
+    file(GLOB _ACML_GPU_ROOT "C:/AMD/acml*/GPGPUexamples")
   else()
-    file( GLOB _ACML_GPU_ROOT "/opt/acml*/GPGPUexamples" )
+    file(GLOB _ACML_GPU_ROOT "/opt/acml*/GPGPUexamples")
   endif()
   list(GET _ACML_ROOT 0 _ACML_ROOT)
   list(GET _ACML_GPU_ROOT 0 _ACML_GPU_ROOT)
-  if( _ACML_ROOT )
-    get_filename_component( _ACML_ROOT ${_ACML_ROOT} PATH )
-    if( SIZEOF_INTEGER EQUAL 8 )
-      set( _ACML_PATH_SUFFIX "_int64" )
+  if(_ACML_ROOT)
+    get_filename_component(_ACML_ROOT ${_ACML_ROOT} PATH)
+    if(SIZEOF_INTEGER EQUAL 8)
+      set(_ACML_PATH_SUFFIX "_int64")
     else()
-      set( _ACML_PATH_SUFFIX "" )
+      set(_ACML_PATH_SUFFIX "")
     endif()
-    if( CMAKE_Fortran_COMPILER_ID STREQUAL "Intel" )
-      set( _ACML_COMPILER32 "ifort32" )
-      set( _ACML_COMPILER64 "ifort64" )
-    elseif( CMAKE_Fortran_COMPILER_ID STREQUAL "SunPro" )
-      set( _ACML_COMPILER32 "sun32" )
-      set( _ACML_COMPILER64 "sun64" )
-    elseif( CMAKE_Fortran_COMPILER_ID STREQUAL "PGI" )
-      set( _ACML_COMPILER32 "pgi32" )
-      if( WIN32 )
-        set( _ACML_COMPILER64 "win64" )
+    if(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel")
+      set(_ACML_COMPILER32 "ifort32")
+      set(_ACML_COMPILER64 "ifort64")
+    elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "SunPro")
+      set(_ACML_COMPILER32 "sun32")
+      set(_ACML_COMPILER64 "sun64")
+    elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "PGI")
+      set(_ACML_COMPILER32 "pgi32")
+      if(WIN32)
+        set(_ACML_COMPILER64 "win64")
       else()
-        set( _ACML_COMPILER64 "pgi64" )
+        set(_ACML_COMPILER64 "pgi64")
       endif()
-    elseif( CMAKE_Fortran_COMPILER_ID STREQUAL "Open64" )
+    elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Open64")
       # 32 bit builds not supported on Open64 but for code simplicity
       # We'll just use the same directory twice
-      set( _ACML_COMPILER32 "open64_64" )
-      set( _ACML_COMPILER64 "open64_64" )
-    elseif( CMAKE_Fortran_COMPILER_ID STREQUAL "NAG" )
-      set( _ACML_COMPILER32 "nag32" )
-      set( _ACML_COMPILER64 "nag64" )
+      set(_ACML_COMPILER32 "open64_64")
+      set(_ACML_COMPILER64 "open64_64")
+    elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "NAG")
+      set(_ACML_COMPILER32 "nag32")
+      set(_ACML_COMPILER64 "nag64")
     else()
-      set( _ACML_COMPILER32 "gfortran32" )
-      set( _ACML_COMPILER64 "gfortran64" )
+      set(_ACML_COMPILER32 "gfortran32")
+      set(_ACML_COMPILER64 "gfortran64")
     endif()
 
-    if( BLA_VENDOR STREQUAL "ACML_MP" )
+    if(BLA_VENDOR STREQUAL "ACML_MP")
       set(_ACML_MP_LIB_DIRS
         "${_ACML_ROOT}/${_ACML_COMPILER32}_mp${_ACML_PATH_SUFFIX}/lib"
-        "${_ACML_ROOT}/${_ACML_COMPILER64}_mp${_ACML_PATH_SUFFIX}/lib" )
+        "${_ACML_ROOT}/${_ACML_COMPILER64}_mp${_ACML_PATH_SUFFIX}/lib")
     else()
       set(_ACML_LIB_DIRS
         "${_ACML_ROOT}/${_ACML_COMPILER32}${_ACML_PATH_SUFFIX}/lib"
-        "${_ACML_ROOT}/${_ACML_COMPILER64}${_ACML_PATH_SUFFIX}/lib" )
+        "${_ACML_ROOT}/${_ACML_COMPILER64}${_ACML_PATH_SUFFIX}/lib")
     endif()
   endif()
 elseif(BLAS_${BLA_VENDOR}_LIB_DIRS)
   set(_${BLA_VENDOR}_LIB_DIRS ${BLAS_${BLA_VENDOR}_LIB_DIRS})
 endif()
 
-if( BLA_VENDOR STREQUAL "ACML_MP" )
-  foreach( BLAS_ACML_MP_LIB_DIRS ${_ACML_MP_LIB_DIRS})
-    check_fortran_libraries (
+if(BLA_VENDOR STREQUAL "ACML_MP")
+  foreach(BLAS_ACML_MP_LIB_DIRS ${_ACML_MP_LIB_DIRS})
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
       "" "acml_mp;acml_mv" "" ${BLAS_ACML_MP_LIB_DIRS}
       )
-    if( BLAS_LIBRARIES )
+    if(BLAS_LIBRARIES)
       break()
     endif()
   endforeach()
-elseif( BLA_VENDOR STREQUAL "ACML_GPU" )
-  foreach( BLAS_ACML_GPU_LIB_DIRS ${_ACML_GPU_LIB_DIRS})
-    check_fortran_libraries (
+elseif(BLA_VENDOR STREQUAL "ACML_GPU")
+  foreach(BLAS_ACML_GPU_LIB_DIRS ${_ACML_GPU_LIB_DIRS})
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
       "" "acml;acml_mv;CALBLAS" "" ${BLAS_ACML_GPU_LIB_DIRS}
       )
-    if( BLAS_LIBRARIES )
+    if(BLAS_LIBRARIES)
       break()
     endif()
   endforeach()
 else()
-  foreach( BLAS_ACML_LIB_DIRS ${_ACML_LIB_DIRS} )
-    check_fortran_libraries (
+  foreach(BLAS_ACML_LIB_DIRS ${_ACML_LIB_DIRS})
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
       "" "acml;acml_mv" "" ${BLAS_ACML_LIB_DIRS}
       )
-    if( BLAS_LIBRARIES )
+    if(BLAS_LIBRARIES)
       break()
     endif()
   endforeach()
@@ -734,7 +740,7 @@
 
 # Either acml or acml_mp should be in LD_LIBRARY_PATH but not both
 if(NOT BLAS_LIBRARIES)
-  check_fortran_libraries(
+  check_blas_libraries(
     BLAS_LIBRARIES
     BLAS
     sgemm
@@ -744,7 +750,7 @@
     )
 endif()
 if(NOT BLAS_LIBRARIES)
-  check_fortran_libraries(
+  check_blas_libraries(
     BLAS_LIBRARIES
     BLAS
     sgemm
@@ -754,7 +760,7 @@
     )
 endif()
 if(NOT BLAS_LIBRARIES)
-  check_fortran_libraries(
+  check_blas_libraries(
     BLAS_LIBRARIES
     BLAS
     sgemm
@@ -763,12 +769,12 @@
     ""
     )
 endif()
-endif () # ACML
+endif() # ACML
 
 # Apple BLAS library?
-if (BLA_VENDOR STREQUAL "Apple" OR BLA_VENDOR STREQUAL "All")
+if(BLA_VENDOR STREQUAL "Apple" OR BLA_VENDOR STREQUAL "All")
   if(NOT BLAS_LIBRARIES)
-    check_fortran_libraries(
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       dgemm
@@ -777,11 +783,12 @@
       ""
       )
   endif()
-endif ()
+endif()
 
-if (BLA_VENDOR STREQUAL "NAS" OR BLA_VENDOR STREQUAL "All")
-  if ( NOT BLAS_LIBRARIES )
-    check_fortran_libraries(
+# Apple NAS (vecLib) library?
+if(BLA_VENDOR STREQUAL "NAS" OR BLA_VENDOR STREQUAL "All")
+  if(NOT BLAS_LIBRARIES)
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       dgemm
@@ -789,13 +796,13 @@
       "vecLib"
       ""
       )
-  endif ()
-endif ()
+  endif()
+endif()
 
 # Generic BLAS library?
-if (BLA_VENDOR STREQUAL "Generic" OR BLA_VENDOR STREQUAL "All")
+if(BLA_VENDOR STREQUAL "Generic" OR BLA_VENDOR STREQUAL "All")
   if(NOT BLAS_LIBRARIES)
-    check_fortran_libraries(
+    check_blas_libraries(
       BLAS_LIBRARIES
       BLAS
       sgemm
@@ -804,7 +811,7 @@
       ""
       )
   endif()
-endif ()
+endif()
 
 if(NOT BLA_F95)
   find_package_handle_standard_args(BLAS REQUIRED_VARS BLAS_LIBRARIES)
@@ -812,7 +819,7 @@
 
 # On compilers that implicitly link BLAS (such as ftn, cc, and CC on Cray HPC machines)
 # we used a placeholder for empty BLAS_LIBRARIES to get through our logic above.
-if (BLAS_LIBRARIES STREQUAL "BLAS_LIBRARIES-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
+if(BLAS_LIBRARIES STREQUAL "BLAS_LIBRARIES-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
   set(BLAS_LIBRARIES "")
 endif()
 
diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake
index 0e84fab..deac9ef 100644
--- a/Modules/FindBoost.cmake
+++ b/Modules/FindBoost.cmake
@@ -248,6 +248,7 @@
 # Save project's policies
 cmake_policy(PUSH)
 cmake_policy(SET CMP0057 NEW) # if IN_LIST
+cmake_policy(SET CMP0102 NEW) # if mark_as_advanced(non_cache_var)
 
 function(_boost_get_existing_target component target_var)
   set(names "${component}")
@@ -441,7 +442,9 @@
   # Note that args are passed in the Boost_FIND_xxxxx variables, so there is no
   # need to delegate them to this find_package call.
   find_package(Boost QUIET NO_MODULE)
-  mark_as_advanced(Boost_DIR)
+  if (DEFINED Boost_DIR)
+    mark_as_advanced(Boost_DIR)
+  endif ()
 
   # If we found a boost cmake package, then we're done. Print out what we found.
   # Otherwise let the rest of the module try to find it.
diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake
index 1837694..6a40ace 100644
--- a/Modules/FindCUDAToolkit.cmake
+++ b/Modules/FindCUDAToolkit.cmake
@@ -122,7 +122,6 @@
 
 The CUDA Runtime library (cudart) are what most applications will typically
 need to link against to make any calls such as `cudaMalloc`, and `cudaFree`.
-They are an explicit dependency of almost every library.
 
 Targets Created:
 
@@ -409,6 +408,11 @@
     The path to the CUDA Toolkit library directory that contains the CUDA
     Runtime library ``cudart``.
 
+``CUDAToolkit_TARGET_DIR``
+    The path to the CUDA Toolkit directory including the target architecture
+    when cross-compiling. When not cross-compiling this will be equivalant to
+    ``CUDAToolkit_ROOT_DIR``.
+
 ``CUDAToolkit_NVCC_EXECUTABLE``
     The path to the NVIDIA CUDA compiler ``nvcc``.  Note that this path may
     **not** be the same as
@@ -642,8 +646,37 @@
 
 get_filename_component(CUDAToolkit_ROOT_DIR ${CUDAToolkit_BIN_DIR} DIRECTORY ABSOLUTE)
 
-# Now that we have the real ROOT_DIR, find components inside it.
-list(APPEND CMAKE_PREFIX_PATH ${CUDAToolkit_ROOT_DIR})
+# Handle cross compilation
+if(CMAKE_CROSSCOMPILING)
+  if(CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7-a")
+    # Support for NVPACK
+    set (CUDAToolkit_TARGET_NAME "armv7-linux-androideabi")
+  elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
+    # Support for arm cross compilation
+    set(CUDAToolkit_TARGET_NAME "armv7-linux-gnueabihf")
+  elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
+    # Support for aarch64 cross compilation
+    if (ANDROID_ARCH_NAME STREQUAL "arm64")
+      set(CUDAToolkit_TARGET_NAME "aarch64-linux-androideabi")
+    else()
+      set(CUDAToolkit_TARGET_NAME "aarch64-linux")
+    endif (ANDROID_ARCH_NAME STREQUAL "arm64")
+  elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
+      set(CUDAToolkit_TARGET_NAME "x86_64-linux")
+  endif()
+
+  if (EXISTS "${CUDAToolkit_ROOT_DIR}/targets/${CUDAToolkit_TARGET_NAME}")
+    set(CUDAToolkit_TARGET_DIR "${CUDAToolkit_ROOT_DIR}/targets/${CUDAToolkit_TARGET_NAME}")
+    # add known CUDA target root path to the set of directories we search for programs, libraries and headers
+    list(APPEND CMAKE_FIND_ROOT_PATH "${CUDAToolkit_TARGET_DIR}")
+  endif()
+else()
+  # Not cross compiling
+  set(CUDAToolkit_TARGET_DIR "${CUDAToolkit_ROOT_DIR}")
+  # Now that we have the real ROOT_DIR, find components inside it.
+  list(APPEND CMAKE_PREFIX_PATH ${CUDAToolkit_ROOT_DIR})
+endif()
+
 
 # Find the include/ directory
 find_path(CUDAToolkit_INCLUDE_DIR
@@ -653,14 +686,20 @@
 # And find the CUDA Runtime Library libcudart
 find_library(CUDA_CUDART
   NAMES cudart
-  PATH_SUFFIXES lib64 lib/x64
+  PATH_SUFFIXES lib64 lib64/stubs lib/x64
 )
 if (NOT CUDA_CUDART AND NOT CUDAToolkit_FIND_QUIETLY)
   message(STATUS "Unable to find cudart library.")
 endif()
 
 unset(CUDAToolkit_ROOT_DIR)
-list(REMOVE_AT CMAKE_PREFIX_PATH -1)
+if(CMAKE_CROSSCOMPILING)
+  if(CUDAToolkit_TARGET_DIR)
+    list(REMOVE_AT CMAKE_FIND_ROOT_PATH -1)
+  endif()
+else()
+  list(REMOVE_AT CMAKE_PREFIX_PATH -1)
+endif()
 
 #-----------------------------------------------------------------------------
 # Perform version comparison and validate all required variables are set.
@@ -697,7 +736,7 @@
       NAMES ${search_names}
       PATHS ${CUDAToolkit_LIBRARY_DIR}
             ENV CUDA_PATH
-      PATH_SUFFIXES nvidia/current lib64 lib/x64 lib
+      PATH_SUFFIXES nvidia/current lib64 lib64/stubs lib/x64 lib lib/stubs
     )
 
     if (NOT CUDA::${lib_name} AND CUDA_${lib_name}_LIBRARY)
@@ -708,9 +747,13 @@
   endfunction()
 
   function(add_cuda_link_dependency lib_name)
-    foreach(dependency IN LISTS ${ARGN})
-      target_link_libraries(CUDA::${lib_name} INTERFACE CUDA::${dependency})
-    endforeach()
+    if(TARGET CUDA::${lib_name})
+      foreach(dependency IN LISTS ARGN)
+        if(TARGET CUDA::${dependency})
+          target_link_libraries(CUDA::${lib_name} INTERFACE CUDA::${dependency})
+        endif()
+      endforeach()
+    endif()
   endfunction()
 
   add_library(CUDA::toolkit IMPORTED INTERFACE)
@@ -725,10 +768,8 @@
 
   foreach (cuda_lib cublas cufft cufftw curand cusolver cusparse nvgraph nvjpeg)
     find_and_add_cuda_import_lib(${cuda_lib})
-    add_cuda_link_dependency(${cuda_lib} cudart)
 
     find_and_add_cuda_import_lib(${cuda_lib}_static)
-    add_cuda_link_dependency(${cuda_lib}_static cudart_static)
   endforeach()
 
   # cuSOLVER depends on cuBLAS, and cuSPARSE
@@ -742,9 +783,6 @@
   find_and_add_cuda_import_lib(nppc)
   find_and_add_cuda_import_lib(nppc_static)
 
-  add_cuda_link_dependency(nppc cudart)
-  add_cuda_link_dependency(nppc_static cudart_static culibos)
-
   # Process the majority of the NPP libraries.
   foreach (cuda_lib nppial nppicc nppidei nppif nppig nppim nppist nppitc npps nppicom nppisu)
     find_and_add_cuda_import_lib(${cuda_lib})
@@ -771,13 +809,11 @@
   endif()
   find_and_add_cuda_import_lib(nvToolsExt nvToolsExt nvToolsExt64)
 
-  add_cuda_link_dependency(nvToolsExt cudart)
-
   find_and_add_cuda_import_lib(OpenCL)
 
   find_and_add_cuda_import_lib(culibos)
   if(TARGET CUDA::culibos)
-    foreach (cuda_lib cublas cufft cusparse curand nvjpeg)
+    foreach (cuda_lib cublas cufft cusparse curand nppc nvjpeg)
       add_cuda_link_dependency(${cuda_lib}_static culibos)
     endforeach()
   endif()
diff --git a/Modules/FindCurses.cmake b/Modules/FindCurses.cmake
index e3e7273..ba56078 100644
--- a/Modules/FindCurses.cmake
+++ b/Modules/FindCurses.cmake
@@ -159,6 +159,10 @@
   if(NOT CURSES_NCURSES_HAS_CBREAK)
     find_library(CURSES_EXTRA_LIBRARY "${CURSES_TINFO_LIBRARY_NAME}" HINTS "${_cursesLibDir}")
     find_library(CURSES_EXTRA_LIBRARY "${CURSES_TINFO_LIBRARY_NAME}" )
+
+    mark_as_advanced(
+      CURSES_EXTRA_LIBRARY
+      )
   endif()
 else()
   get_filename_component(_cursesLibDir "${CURSES_CURSES_LIBRARY}" PATH)
@@ -262,6 +266,5 @@
   CURSES_INCLUDE_PATH
   CURSES_CURSES_LIBRARY
   CURSES_NCURSES_LIBRARY
-  CURSES_EXTRA_LIBRARY
   CURSES_FORM_LIBRARY
   )
diff --git a/Modules/FindGTK2.cmake b/Modules/FindGTK2.cmake
index 83091f3..565763d 100644
--- a/Modules/FindGTK2.cmake
+++ b/Modules/FindGTK2.cmake
@@ -5,96 +5,83 @@
 FindGTK2
 --------
 
-Find the GTK2 widget libraries and several of its
-other optional components like ``gtkmm``, ``glade``, and ``glademm``.
-
-NOTE: If you intend to use version checking, CMake 2.6.2 or later is
-
-::
-
-       required.
-
-
+Find the GTK2 widget libraries and several of its other optional components
+like ``gtkmm``, ``glade``, and ``glademm``.
 
 Specify one or more of the following components as you call this find
 module.  See example below.
 
-::
+* ``gtk``
+* ``gtkmm``
+* ``glade``
+* ``glademm``
 
-   gtk
-   gtkmm
-   glade
-   glademm
-
-
+Result Variables
+^^^^^^^^^^^^^^^^
 
 The following variables will be defined for your use
 
-::
+``GTK2_FOUND``
+  Were all of your specified components found?
+``GTK2_INCLUDE_DIRS``
+  All include directories
+``GTK2_LIBRARIES``
+  All libraries
+``GTK2_TARGETS``
+  All imported targets
+``GTK2_DEFINITIONS``
+  Additional compiler flags
+``GTK2_VERSION``
+  The version of GTK2 found (x.y.z)
+``GTK2_MAJOR_VERSION``
+  The major version of GTK2
+``GTK2_MINOR_VERSION``
+  The minor version of GTK2
+``GTK2_PATCH_VERSION``
+  The patch version of GTK2
 
-   GTK2_FOUND - Were all of your specified components found?
-   GTK2_INCLUDE_DIRS - All include directories
-   GTK2_LIBRARIES - All libraries
-   GTK2_TARGETS - All imported targets
-   GTK2_DEFINITIONS - Additional compiler flags
-
-
-
-::
-
-   GTK2_VERSION - The version of GTK2 found (x.y.z)
-   GTK2_MAJOR_VERSION - The major version of GTK2
-   GTK2_MINOR_VERSION - The minor version of GTK2
-   GTK2_PATCH_VERSION - The patch version of GTK2
-
-
+Input Variables
+^^^^^^^^^^^^^^^
 
 Optional variables you can define prior to calling this module:
 
-::
+``GTK2_DEBUG``
+  Enables verbose debugging of the module
+``GTK2_ADDITIONAL_SUFFIXES``
+  Allows defining additional directories to search for include files
 
-   GTK2_DEBUG - Enables verbose debugging of the module
-   GTK2_ADDITIONAL_SUFFIXES - Allows defining additional directories to
-                              search for include files
+Example Usage
+^^^^^^^^^^^^^
 
+Call :command:`find_package` once.  Here are some examples to pick from:
 
+Require GTK 2.6 or later:
 
-================= Example Usage:
+.. code-block:: cmake
 
-::
+  find_package(GTK2 2.6 REQUIRED gtk)
 
-   Call find_package() once, here are some examples to pick from:
+Require GTK 2.10 or later and Glade:
 
+.. code-block:: cmake
 
+  find_package(GTK2 2.10 REQUIRED gtk glade)
 
-::
+Search for GTK/GTKMM 2.8 or later:
 
-   Require GTK 2.6 or later
-       find_package(GTK2 2.6 REQUIRED gtk)
+.. code-block:: cmake
 
+  find_package(GTK2 2.8 COMPONENTS gtk gtkmm)
 
+Use the results:
 
-::
+.. code-block:: cmake
 
-   Require GTK 2.10 or later and Glade
-       find_package(GTK2 2.10 REQUIRED gtk glade)
-
-
-
-::
-
-   Search for GTK/GTKMM 2.8 or later
-       find_package(GTK2 2.8 COMPONENTS gtk gtkmm)
-
-
-
-::
-
-   if(GTK2_FOUND)
-      include_directories(${GTK2_INCLUDE_DIRS})
-      add_executable(mygui mygui.cc)
-      target_link_libraries(mygui ${GTK2_LIBRARIES})
-   endif()
+  if(GTK2_FOUND)
+    include_directories(${GTK2_INCLUDE_DIRS})
+    add_executable(mygui mygui.cc)
+    target_link_libraries(mygui ${GTK2_LIBRARIES})
+  endif()
 #]=======================================================================]
 
 # Version 1.6 (CMake 3.0)
@@ -881,6 +868,7 @@
 
     set(GTK2_${_COMPONENT_UPPER}_FIND_QUIETLY ${GTK2_FIND_QUIETLY})
 
+    set(FPHSA_NAME_MISMATCHED 1)
     if(_GTK2_component STREQUAL "gtk")
         FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTK2_${_COMPONENT_UPPER} "Some or all of the gtk libraries were not found."
             GTK2_GTK_LIBRARY
@@ -923,6 +911,7 @@
             GTK2_GLADEMMCONFIG_INCLUDE_DIR
         )
     endif()
+    unset(FPHSA_NAME_MISMATCHED)
 
     if(NOT GTK2_${_COMPONENT_UPPER}_FOUND)
         set(_GTK2_did_we_find_everything false)
diff --git a/Modules/FindLAPACK.cmake b/Modules/FindLAPACK.cmake
index 3cb3653..3aa3de4 100644
--- a/Modules/FindLAPACK.cmake
+++ b/Modules/FindLAPACK.cmake
@@ -7,10 +7,10 @@
 
 Find Linear Algebra PACKage (LAPACK) library
 
-This module finds an installed fortran library that implements the
+This module finds an installed Fortran library that implements the
 LAPACK linear-algebra interface (see http://www.netlib.org/lapack/).
 
-The approach follows that taken for the autoconf macro file,
+The approach follows that taken for the ``autoconf`` macro file,
 ``acx_lapack.m4`` (distributed at
 http://ac-archive.sourceforge.net/ac-archive/acx_lapack.html).
 
@@ -26,21 +26,21 @@
   If set, checks only the specified vendor, if not set checks all the
   possibilities.  List of vendors valid in this module:
 
+  * ``OpenBLAS``
+  * ``FLAME``
   * ``Intel10_32`` (intel mkl v10 32 bit)
   * ``Intel10_64lp`` (intel mkl v10+ 64 bit, threaded code, lp64 model)
   * ``Intel10_64lp_seq`` (intel mkl v10+ 64 bit, sequential code, lp64 model)
   * ``Intel10_64ilp`` (intel mkl v10+ 64 bit, threaded code, ilp64 model)
   * ``Intel10_64ilp_seq`` (intel mkl v10+ 64 bit, sequential code, ilp64 model)
   * ``Intel`` (obsolete versions of mkl 32 and 64 bit)
-  * ``OpenBLAS``
-  * ``FLAME``
   * ``ACML``
   * ``Apple``
   * ``NAS``
   * ``Generic``
 
 ``BLA_F95``
-  if ``ON`` tries to find BLAS95/LAPACK95
+  if ``ON`` tries to find the BLAS95/LAPACK95 interfaces
 
 Result Variables
 ^^^^^^^^^^^^^^^^
@@ -50,7 +50,7 @@
 ``LAPACK_FOUND``
   library implementing the LAPACK interface is found
 ``LAPACK_LINKER_FLAGS``
-  uncached list of required linker flags (excluding -l and -L).
+  uncached list of required linker flags (excluding ``-l`` and ``-L``).
 ``LAPACK_LIBRARIES``
   uncached list of libraries (using full path name) to link against
   to use LAPACK
@@ -62,7 +62,7 @@
 
 .. note::
 
-  C or CXX must be enabled to use Intel MKL
+  C or CXX must be enabled to use Intel Math Kernel Library (MKL)
 
   For example, to use Intel MKL libraries and/or Intel compiler:
 
@@ -72,10 +72,8 @@
     find_package(LAPACK)
 #]=======================================================================]
 
-set(_lapack_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
-
 # Check the language being used
-if( NOT (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED) )
+if(NOT (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED OR CMAKE_Fortran_COMPILER_LOADED))
   if(LAPACK_FIND_REQUIRED)
     message(FATAL_ERROR "FindLAPACK requires Fortran, C, or C++ to be enabled.")
   else()
@@ -84,303 +82,308 @@
   endif()
 endif()
 
-if (CMAKE_Fortran_COMPILER_LOADED)
-include(${CMAKE_CURRENT_LIST_DIR}/CheckFortranFunctionExists.cmake)
-else ()
-include(${CMAKE_CURRENT_LIST_DIR}/CheckFunctionExists.cmake)
-endif ()
+if(CMAKE_Fortran_COMPILER_LOADED)
+  include(${CMAKE_CURRENT_LIST_DIR}/CheckFortranFunctionExists.cmake)
+else()
+  include(${CMAKE_CURRENT_LIST_DIR}/CheckFunctionExists.cmake)
+endif()
 include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake)
 
 cmake_push_check_state()
 set(CMAKE_REQUIRED_QUIET ${LAPACK_FIND_QUIETLY})
 
+set(_lapack_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+
 set(LAPACK_FOUND FALSE)
 set(LAPACK95_FOUND FALSE)
 
-# TODO: move this stuff to separate module
+# TODO: move this stuff to a separate module
 
-macro(Check_Lapack_Libraries LIBRARIES _prefix _name _flags _list _blas _threads)
-# This macro checks for the existence of the combination of fortran libraries
-# given by _list.  If the combination is found, this macro checks (using the
-# Check_Fortran_Function_Exists macro) whether can link against that library
-# combination using the name of a routine given by _name using the linker
-# flags given by _flags.  If the combination of libraries is found and passes
-# the link test, LIBRARIES is set to the list of complete library paths that
-# have been found.  Otherwise, LIBRARIES is set to FALSE.
+macro(CHECK_LAPACK_LIBRARIES LIBRARIES _prefix _name _flags _list _threadlibs _blas)
+  # This macro checks for the existence of the combination of fortran libraries
+  # given by _list.  If the combination is found, this macro checks (using the
+  # Check_Fortran_Function_Exists macro) whether can link against that library
+  # combination using the name of a routine given by _name using the linker
+  # flags given by _flags.  If the combination of libraries is found and passes
+  # the link test, LIBRARIES is set to the list of complete library paths that
+  # have been found.  Otherwise, LIBRARIES is set to FALSE.
 
-# N.B. _prefix is the prefix applied to the names of all cached variables that
-# are generated internally and marked advanced by this macro.
+  # N.B. _prefix is the prefix applied to the names of all cached variables that
+  # are generated internally and marked advanced by this macro.
 
-set(_libraries_work TRUE)
-set(${LIBRARIES})
-set(_combined_name)
-if (NOT _libdir)
-  if (WIN32)
-    set(_libdir ENV LIB)
-  elseif (APPLE)
-    set(_libdir ENV DYLD_LIBRARY_PATH)
-  else ()
-    set(_libdir ENV LD_LIBRARY_PATH)
-  endif ()
-endif ()
+  set(_libraries_work TRUE)
+  set(${LIBRARIES})
+  set(_combined_name)
+  if(NOT _libdir)
+    if(WIN32)
+      set(_libdir ENV LIB)
+    elseif(APPLE)
+      set(_libdir ENV DYLD_LIBRARY_PATH)
+    else()
+      set(_libdir ENV LD_LIBRARY_PATH)
+    endif()
+  endif()
 
-list(APPEND _libdir "${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}")
+  list(APPEND _libdir "${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}")
 
-foreach(_library ${_list})
-  set(_combined_name ${_combined_name}_${_library})
+  foreach(_library ${_list})
+    set(_combined_name ${_combined_name}_${_library})
+
+    if(_libraries_work)
+      if(BLA_STATIC)
+        if(WIN32)
+          set(CMAKE_FIND_LIBRARY_SUFFIXES .lib ${CMAKE_FIND_LIBRARY_SUFFIXES})
+        endif()
+        if(APPLE)
+          set(CMAKE_FIND_LIBRARY_SUFFIXES .lib ${CMAKE_FIND_LIBRARY_SUFFIXES})
+        else()
+          set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
+        endif()
+      else()
+        if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+          # for ubuntu's libblas3gf and liblapack3gf packages
+          set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES} .so.3gf)
+        endif()
+      endif()
+      find_library(${_prefix}_${_library}_LIBRARY
+        NAMES ${_library}
+        PATHS ${_libdir}
+      )
+      mark_as_advanced(${_prefix}_${_library}_LIBRARY)
+      set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_library}_LIBRARY})
+      set(_libraries_work ${${_prefix}_${_library}_LIBRARY})
+    endif()
+  endforeach()
 
   if(_libraries_work)
-    if (BLA_STATIC)
-      if (WIN32)
-        set(CMAKE_FIND_LIBRARY_SUFFIXES .lib ${CMAKE_FIND_LIBRARY_SUFFIXES})
-      endif ()
-      if (APPLE)
-        set(CMAKE_FIND_LIBRARY_SUFFIXES .lib ${CMAKE_FIND_LIBRARY_SUFFIXES})
-      else ()
-        set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
-      endif ()
-    else ()
-      if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
-        # for ubuntu's libblas3gf and liblapack3gf packages
-        set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES} .so.3gf)
-      endif ()
-    endif ()
-    find_library(${_prefix}_${_library}_LIBRARY
-      NAMES ${_library}
-      PATHS ${_libdir}
-      )
-    mark_as_advanced(${_prefix}_${_library}_LIBRARY)
-    set(${LIBRARIES} ${${LIBRARIES}} ${${_prefix}_${_library}_LIBRARY})
-    set(_libraries_work ${${_prefix}_${_library}_LIBRARY})
+    # Test this combination of libraries.
+    if(UNIX AND BLA_STATIC)
+      set(CMAKE_REQUIRED_LIBRARIES ${_flags} "-Wl,--start-group" ${${LIBRARIES}} ${_blas} "-Wl,--end-group" ${_threadlibs})
+    else()
+      set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}} ${_blas} ${_threadlibs})
+    endif()
+    #message("DEBUG: CMAKE_REQUIRED_LIBRARIES = ${CMAKE_REQUIRED_LIBRARIES}")
+    if(CMAKE_Fortran_COMPILER_LOADED)
+      check_fortran_function_exists("${_name}" ${_prefix}${_combined_name}_WORKS)
+    else()
+      check_function_exists("${_name}_" ${_prefix}${_combined_name}_WORKS)
+    endif()
+    set(CMAKE_REQUIRED_LIBRARIES)
+    set(_libraries_work ${${_prefix}${_combined_name}_WORKS})
   endif()
-endforeach()
 
-if(_libraries_work)
-  # Test this combination of libraries.
-  if(UNIX AND BLA_STATIC)
-    set(CMAKE_REQUIRED_LIBRARIES ${_flags} "-Wl,--start-group" ${${LIBRARIES}} ${_blas} "-Wl,--end-group" ${_threads})
+  if(_libraries_work)
+    if("${_list}${_blas}" STREQUAL "")
+      set(${LIBRARIES} "${LIBRARIES}-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
+    else()
+      set(${LIBRARIES} ${${LIBRARIES}} ${_blas} ${_threadlibs})
+    endif()
   else()
-    set(CMAKE_REQUIRED_LIBRARIES ${_flags} ${${LIBRARIES}} ${_blas} ${_threads})
-  endif()
-#  message("DEBUG: CMAKE_REQUIRED_LIBRARIES = ${CMAKE_REQUIRED_LIBRARIES}")
-  if (NOT CMAKE_Fortran_COMPILER_LOADED)
-    check_function_exists("${_name}_" ${_prefix}${_combined_name}_WORKS)
-  else ()
-    check_fortran_function_exists(${_name} ${_prefix}${_combined_name}_WORKS)
-  endif ()
-  set(CMAKE_REQUIRED_LIBRARIES)
-  set(_libraries_work ${${_prefix}${_combined_name}_WORKS})
-  #message("DEBUG: ${LIBRARIES} = ${${LIBRARIES}}")
-endif()
-
- if(_libraries_work)
-   if("${_list}${_blas}" STREQUAL "")
-     set(${LIBRARIES} "${LIBRARIES}-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
-   else()
-     set(${LIBRARIES} ${${LIBRARIES}} ${_blas} ${_threads})
-   endif()
- else()
     set(${LIBRARIES} FALSE)
- endif()
-
+  endif()
+  #message("DEBUG: ${LIBRARIES} = ${${LIBRARIES}}")
 endmacro()
 
-
 set(LAPACK_LINKER_FLAGS)
 set(LAPACK_LIBRARIES)
 set(LAPACK95_LIBRARIES)
 
-
 if(LAPACK_FIND_QUIETLY OR NOT LAPACK_FIND_REQUIRED)
   find_package(BLAS)
 else()
   find_package(BLAS REQUIRED)
 endif()
 
-
 if(BLAS_FOUND)
   set(LAPACK_LINKER_FLAGS ${BLAS_LINKER_FLAGS})
-  if (NOT $ENV{BLA_VENDOR} STREQUAL "")
+  if(NOT $ENV{BLA_VENDOR} STREQUAL "")
     set(BLA_VENDOR $ENV{BLA_VENDOR})
-  else ()
+  else()
     if(NOT BLA_VENDOR)
       set(BLA_VENDOR "All")
     endif()
-  endif ()
+  endif()
 
-#intel lapack
-if (BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
-  if(NOT LAPACK_LIBRARIES)
-  if (NOT WIN32)
-    set(LAPACK_mkl_LM "-lm")
-    set(LAPACK_mkl_LDL "-ldl")
-  endif ()
-  if (CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED)
-    if(LAPACK_FIND_QUIETLY OR NOT LAPACK_FIND_REQUIRED)
-      find_PACKAGE(Threads)
-    else()
-      find_package(Threads REQUIRED)
-    endif()
+  # LAPACK in the Intel MKL 10+ library?
+  if(BLA_VENDOR MATCHES "Intel" OR BLA_VENDOR STREQUAL "All")
+    if(NOT LAPACK_LIBRARIES)
+      if(CMAKE_C_COMPILER_LOADED OR CMAKE_CXX_COMPILER_LOADED)
+        # System-specific settings
+        if(NOT WIN32)
+          set(LAPACK_mkl_LM "-lm")
+          set(LAPACK_mkl_LDL "-ldl")
+        endif()
 
-    if (BLA_VENDOR MATCHES "_64ilp")
-      set(LAPACK_mkl_ILP_MODE "ilp64")
-    else ()
-      set(LAPACK_mkl_ILP_MODE "lp64")
-    endif ()
+        if(LAPACK_FIND_QUIETLY OR NOT LAPACK_FIND_REQUIRED)
+          find_package(Threads)
+        else()
+          find_package(Threads REQUIRED)
+        endif()
 
-    set(LAPACK_SEARCH_LIBS "")
+        if(BLA_VENDOR MATCHES "_64ilp")
+          set(LAPACK_mkl_ILP_MODE "ilp64")
+        else()
+          set(LAPACK_mkl_ILP_MODE "lp64")
+        endif()
 
-    if (BLA_F95)
-      set(LAPACK_mkl_SEARCH_SYMBOL "cheev_f95")
-      set(_LIBRARIES LAPACK95_LIBRARIES)
-      set(_BLAS_LIBRARIES ${BLAS95_LIBRARIES})
+        set(LAPACK_SEARCH_LIBS "")
 
-      # old
-      list(APPEND LAPACK_SEARCH_LIBS
-        "mkl_lapack95")
-      # new >= 10.3
-      list(APPEND LAPACK_SEARCH_LIBS
-        "mkl_intel_c")
-      list(APPEND LAPACK_SEARCH_LIBS
-        "mkl_lapack95_${LAPACK_mkl_ILP_MODE}")
-    else()
-      set(LAPACK_mkl_SEARCH_SYMBOL "cheev")
-      set(_LIBRARIES LAPACK_LIBRARIES)
-      set(_BLAS_LIBRARIES ${BLAS_LIBRARIES})
+        if(BLA_F95)
+          set(LAPACK_mkl_SEARCH_SYMBOL "cheev_f95")
+          set(_LIBRARIES LAPACK95_LIBRARIES)
+          set(_BLAS_LIBRARIES ${BLAS95_LIBRARIES})
 
-      # old
-      list(APPEND LAPACK_SEARCH_LIBS
-        "mkl_lapack")
-    endif()
+          # old
+          list(APPEND LAPACK_SEARCH_LIBS
+            "mkl_lapack95")
+          # new >= 10.3
+          list(APPEND LAPACK_SEARCH_LIBS
+            "mkl_intel_c")
+          list(APPEND LAPACK_SEARCH_LIBS
+            "mkl_lapack95_${LAPACK_mkl_ILP_MODE}")
+        else()
+          set(LAPACK_mkl_SEARCH_SYMBOL "cheev")
+          set(_LIBRARIES LAPACK_LIBRARIES)
+          set(_BLAS_LIBRARIES ${BLAS_LIBRARIES})
 
-    # First try empty lapack libs
-    if (NOT ${_LIBRARIES})
-      check_lapack_libraries(
-        ${_LIBRARIES}
-        LAPACK
-        ${LAPACK_mkl_SEARCH_SYMBOL}
-        ""
-        ""
-        "${_BLAS_LIBRARIES}"
-        ""
-        )
-    endif ()
-    # Then try the search libs
-    foreach (IT ${LAPACK_SEARCH_LIBS})
-      if (NOT ${_LIBRARIES})
-        check_lapack_libraries(
-          ${_LIBRARIES}
-          LAPACK
-          ${LAPACK_mkl_SEARCH_SYMBOL}
-          ""
-          "${IT}"
-          "${_BLAS_LIBRARIES}"
-          "${CMAKE_THREAD_LIBS_INIT};${LAPACK_mkl_LM};${LAPACK_mkl_LDL}"
+          # old
+          list(APPEND LAPACK_SEARCH_LIBS
+            "mkl_lapack")
+        endif()
+
+        # First try empty lapack libs
+        if(NOT ${_LIBRARIES})
+          check_lapack_libraries(
+            ${_LIBRARIES}
+            LAPACK
+            ${LAPACK_mkl_SEARCH_SYMBOL}
+            ""
+            ""
+            ""
+            "${_BLAS_LIBRARIES}"
           )
-      endif ()
-    endforeach ()
+        endif()
+        # Then try the search libs
+        foreach(IT ${LAPACK_SEARCH_LIBS})
+          if(NOT ${_LIBRARIES})
+            check_lapack_libraries(
+              ${_LIBRARIES}
+              LAPACK
+              ${LAPACK_mkl_SEARCH_SYMBOL}
+              ""
+              "${IT}"
+              "${CMAKE_THREAD_LIBS_INIT};${LAPACK_mkl_LM};${LAPACK_mkl_LDL}"
+              "${_BLAS_LIBRARIES}"
+            )
+          endif()
+        endforeach()
 
-    unset(LAPACK_mkl_ILP_MODE)
-    unset(LAPACK_mkl_SEARCH_SYMBOL)
-    unset(LAPACK_mkl_LM)
-    unset(LAPACK_mkl_LDL)
-  endif ()
+        unset(LAPACK_mkl_ILP_MODE)
+        unset(LAPACK_mkl_SEARCH_SYMBOL)
+        unset(LAPACK_mkl_LM)
+        unset(LAPACK_mkl_LDL)
+      endif()
+    endif()
   endif()
-endif()
 
-if (BLA_VENDOR STREQUAL "Goto" OR BLA_VENDOR STREQUAL "All")
- if(NOT LAPACK_LIBRARIES)
-  check_lapack_libraries(
-  LAPACK_LIBRARIES
-  LAPACK
-  cheev
-  ""
-  "goto2"
-  "${BLAS_LIBRARIES}"
-  ""
-  )
- endif()
-endif ()
-
-if (BLA_VENDOR STREQUAL "OpenBLAS" OR BLA_VENDOR STREQUAL "All")
- if(NOT LAPACK_LIBRARIES)
-  check_lapack_libraries(
-  LAPACK_LIBRARIES
-  LAPACK
-  cheev
-  ""
-  "openblas"
-  "${BLAS_LIBRARIES}"
-  ""
-  )
- endif()
-endif ()
-
-if (BLA_VENDOR STREQUAL "FLAME" OR BLA_VENDOR STREQUAL "All")
- if(NOT LAPACK_LIBRARIES)
-  check_lapack_libraries(
-  LAPACK_LIBRARIES
-  LAPACK
-  cheev
-  ""
-  "flame"
-  "${BLAS_LIBRARIES}"
-  ""
-  )
- endif()
-endif ()
-
-#acml lapack
-if (BLA_VENDOR MATCHES "ACML" OR BLA_VENDOR STREQUAL "All")
-  if (BLAS_LIBRARIES MATCHES ".+acml.+")
-    set (LAPACK_LIBRARIES ${BLAS_LIBRARIES})
-  endif ()
-endif ()
-
-# Apple LAPACK library?
-if (BLA_VENDOR STREQUAL "Apple" OR BLA_VENDOR STREQUAL "All")
-  if(NOT LAPACK_LIBRARIES)
-    check_lapack_libraries(
-    LAPACK_LIBRARIES
-    LAPACK
-    cheev
-    ""
-    "Accelerate"
-    "${BLAS_LIBRARIES}"
-    ""
-    )
+  # gotoblas? (http://www.tacc.utexas.edu/tacc-projects/gotoblas2)
+  if(BLA_VENDOR STREQUAL "Goto" OR BLA_VENDOR STREQUAL "All")
+    if(NOT LAPACK_LIBRARIES)
+      check_lapack_libraries(
+        LAPACK_LIBRARIES
+        LAPACK
+        cheev
+        ""
+        "goto2"
+        ""
+        "${BLAS_LIBRARIES}"
+      )
+    endif()
   endif()
-endif ()
-if (BLA_VENDOR STREQUAL "NAS" OR BLA_VENDOR STREQUAL "All")
-  if ( NOT LAPACK_LIBRARIES )
-    check_lapack_libraries(
-    LAPACK_LIBRARIES
-    LAPACK
-    cheev
-    ""
-    "vecLib"
-    "${BLAS_LIBRARIES}"
-    ""
-    )
-  endif ()
-endif ()
-# Generic LAPACK library?
-if (BLA_VENDOR STREQUAL "Generic" OR
-    BLA_VENDOR STREQUAL "ATLAS" OR
-    BLA_VENDOR STREQUAL "All")
-  if ( NOT LAPACK_LIBRARIES )
-    check_lapack_libraries(
-    LAPACK_LIBRARIES
-    LAPACK
-    cheev
-    ""
-    "lapack"
-    "${BLAS_LIBRARIES}"
-    ""
-    )
-  endif ()
-endif ()
 
+  # OpenBLAS? (http://www.openblas.net)
+  if(BLA_VENDOR STREQUAL "OpenBLAS" OR BLA_VENDOR STREQUAL "All")
+    if(NOT LAPACK_LIBRARIES)
+      check_lapack_libraries(
+        LAPACK_LIBRARIES
+        LAPACK
+        cheev
+        ""
+        "openblas"
+        ""
+        "${BLAS_LIBRARIES}"
+      )
+    endif()
+  endif()
+
+  # FLAME's blis library? (https://github.com/flame/blis)
+  if(BLA_VENDOR STREQUAL "FLAME" OR BLA_VENDOR STREQUAL "All")
+    if(NOT LAPACK_LIBRARIES)
+      check_lapack_libraries(
+        LAPACK_LIBRARIES
+        LAPACK
+        cheev
+        ""
+        "flame"
+        ""
+        "${BLAS_LIBRARIES}"
+      )
+    endif()
+  endif()
+
+  # BLAS in acml library?
+  if(BLA_VENDOR MATCHES "ACML" OR BLA_VENDOR STREQUAL "All")
+    if(BLAS_LIBRARIES MATCHES ".+acml.+")
+      set(LAPACK_LIBRARIES ${BLAS_LIBRARIES})
+    endif()
+  endif()
+
+  # Apple LAPACK library?
+  if(BLA_VENDOR STREQUAL "Apple" OR BLA_VENDOR STREQUAL "All")
+    if(NOT LAPACK_LIBRARIES)
+      check_lapack_libraries(
+        LAPACK_LIBRARIES
+        LAPACK
+        cheev
+        ""
+        "Accelerate"
+        ""
+        "${BLAS_LIBRARIES}"
+      )
+    endif()
+  endif()
+
+  # Apple NAS (vecLib) library?
+  if(BLA_VENDOR STREQUAL "NAS" OR BLA_VENDOR STREQUAL "All")
+    if(NOT LAPACK_LIBRARIES)
+      check_lapack_libraries(
+        LAPACK_LIBRARIES
+        LAPACK
+        cheev
+        ""
+        "vecLib"
+        ""
+        "${BLAS_LIBRARIES}"
+      )
+    endif()
+  endif()
+
+  # Generic LAPACK library?
+  if(BLA_VENDOR STREQUAL "Generic" OR
+      BLA_VENDOR STREQUAL "ATLAS" OR
+      BLA_VENDOR STREQUAL "All")
+    if(NOT LAPACK_LIBRARIES)
+      check_lapack_libraries(
+        LAPACK_LIBRARIES
+        LAPACK
+        cheev
+        ""
+        "lapack"
+        ""
+        "${BLAS_LIBRARIES}"
+      )
+    endif()
+  endif()
 else()
   message(STATUS "LAPACK requires BLAS")
 endif()
@@ -397,11 +400,11 @@
     else()
       if(LAPACK_FIND_REQUIRED)
         message(FATAL_ERROR
-        "A required library with LAPACK95 API not found. Please specify library location."
+          "A required library with LAPACK95 API not found. Please specify library location."
         )
       else()
         message(STATUS
-        "A library with LAPACK95 API not found. Please specify library location."
+          "A library with LAPACK95 API not found. Please specify library location."
         )
       endif()
     endif()
@@ -421,11 +424,11 @@
     else()
       if(LAPACK_FIND_REQUIRED)
         message(FATAL_ERROR
-        "A required library with LAPACK API not found. Please specify library location."
+          "A required library with LAPACK API not found. Please specify library location."
         )
       else()
         message(STATUS
-        "A library with LAPACK API not found. Please specify library location."
+          "A library with LAPACK API not found. Please specify library location."
         )
       endif()
     endif()
@@ -434,7 +437,7 @@
 
 # On compilers that implicitly link LAPACK (such as ftn, cc, and CC on Cray HPC machines)
 # we used a placeholder for empty LAPACK_LIBRARIES to get through our logic above.
-if (LAPACK_LIBRARIES STREQUAL "LAPACK_LIBRARIES-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
+if(LAPACK_LIBRARIES STREQUAL "LAPACK_LIBRARIES-PLACEHOLDER-FOR-EMPTY-LIBRARIES")
   set(LAPACK_LIBRARIES "")
 endif()
 
diff --git a/Modules/FindLua.cmake b/Modules/FindLua.cmake
index caf9d69..0b0c970 100644
--- a/Modules/FindLua.cmake
+++ b/Modules/FindLua.cmake
@@ -211,6 +211,7 @@
   # include the math library for Unix
   if (UNIX AND NOT APPLE AND NOT BEOS)
     find_library(LUA_MATH_LIBRARY m)
+    mark_as_advanced(LUA_MATH_LIBRARY)
     set(LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}")
 
     # include dl library for statically-linked Lua library
@@ -232,6 +233,6 @@
                                   REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR
                                   VERSION_VAR LUA_VERSION_STRING)
 
-mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARY LUA_MATH_LIBRARY)
+mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARY)
 
 cmake_policy(POP)
diff --git a/Modules/FindMPI.cmake b/Modules/FindMPI.cmake
index 6b1da4b..3e42386 100644
--- a/Modules/FindMPI.cmake
+++ b/Modules/FindMPI.cmake
@@ -96,15 +96,27 @@
 Variables for locating MPI
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-This module performs a three step search for an MPI implementation:
+This module performs a four step search for an MPI implementation:
 
-1. Check if the compiler has MPI support built-in. This is the case if the user passed a
+1. Search for ``MPIEXEC_EXECUTABLE`` and, if found, use its base directory.
+2. Check if the compiler has MPI support built-in. This is the case if the user passed a
    compiler wrapper as ``CMAKE_<LANG>_COMPILER`` or if they're on a Cray system.
-2. Attempt to find an MPI compiler wrapper and determine the compiler information from it.
-3. Try to find an MPI implementation that does not ship such a wrapper by guessing settings.
+3. Attempt to find an MPI compiler wrapper and determine the compiler information from it.
+4. Try to find an MPI implementation that does not ship such a wrapper by guessing settings.
    Currently, only Microsoft MPI and MPICH2 on Windows are supported.
 
-For controlling the second step, the following variables may be set:
+For controlling the ``MPIEXEC_EXECUTABLE`` step, the following variables may be set:
+
+``MPIEXEC_EXECUTABLE``
+  Manually specify the location of ``mpiexec``.
+``MPI_HOME``
+  Specify the base directory of the MPI installation.
+``ENV{MPI_HOME}``
+  Environment variable to specify the base directory of the MPI installation.
+``ENV{I_MPI_ROOT}``
+  Environment variable to specify the base directory of the MPI installation.
+
+For controlling the compiler wrapper step, the following variables may be set:
 
 ``MPI_<lang>_COMPILER``
   Search for the specified compiler wrapper and use it.
@@ -1059,40 +1071,15 @@
   endif()
 endmacro()
 
-macro(_MPI_assemble_include_dirs LANG)
-  if("${MPI_${LANG}_COMPILER}" STREQUAL "${CMAKE_${LANG}_COMPILER}")
-    set(MPI_${LANG}_INCLUDE_DIRS "")
-  else()
-    set(MPI_${LANG}_INCLUDE_DIRS "${MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS}")
-    if("${LANG}" MATCHES "(C|CXX)")
-      if(MPI_${LANG}_HEADER_DIR)
-        list(APPEND MPI_${LANG}_INCLUDE_DIRS "${MPI_${LANG}_HEADER_DIR}")
-      endif()
-    else() # Fortran
-      if(MPI_${LANG}_F77_HEADER_DIR)
-        list(APPEND MPI_${LANG}_INCLUDE_DIRS "${MPI_${LANG}_F77_HEADER_DIR}")
-      endif()
-      if(MPI_${LANG}_MODULE_DIR AND NOT "${MPI_${LANG}_MODULE_DIR}" IN_LIST MPI_${LANG}_INCLUDE_DIRS)
-        list(APPEND MPI_${LANG}_INCLUDE_DIRS "${MPI_${LANG}_MODULE_DIR}")
-      endif()
-    endif()
-    if(MPI_${LANG}_ADDITIONAL_INCLUDE_VARS)
-      foreach(MPI_ADDITIONAL_INC_DIR IN LISTS MPI_${LANG}_ADDITIONAL_INCLUDE_VARS)
-        list(APPEND MPI_${LANG}_INCLUDE_DIRS "${MPI_${MPI_ADDITIONAL_INC_DIR}_INCLUDE_DIR}")
-      endforeach()
-    endif()
-  endif()
-endmacro()
-
-function(_MPI_split_include_dirs LANG)
-  if("${MPI_${LANG}_COMPILER}" STREQUAL "${CMAKE_${LANG}_COMPILER}")
-    return()
-  endif()
+macro(_MPI_split_include_dirs LANG)
   # Backwards compatibility: Search INCLUDE_PATH if given.
   if(MPI_${LANG}_INCLUDE_PATH)
     list(APPEND MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS "${MPI_${LANG}_INCLUDE_PATH}")
   endif()
 
+  # Preserve the include dirs before stripping out the components
+  set(MPI_${LANG}_INCLUDE_DIRS ${MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS})
+
   # We try to find the headers/modules among those paths (and system paths)
   # For C/C++, we just need to have a look for mpi.h.
   if("${LANG}" MATCHES "(C|CXX)")
@@ -1103,6 +1090,7 @@
     if(MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS)
       list(REMOVE_ITEM MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS "${MPI_${LANG}_HEADER_DIR}")
     endif()
+
   # Fortran is more complicated here: An implementation could provide
   # any of the Fortran 77/90/2008 APIs for MPI. For example, MSMPI
   # only provides Fortran 77 and - if mpi.f90 is built - potentially
@@ -1123,6 +1111,7 @@
     endif()
     mark_as_advanced(MPI_${LANG}_F77_HEADER_DIR MPI_${LANG}_MODULE_DIR)
   endif()
+
   # Remove duplicates and default system directories from the list.
   if(MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS)
     list(REMOVE_DUPLICATES MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS)
@@ -1130,8 +1119,9 @@
       list(REMOVE_ITEM MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS ${MPI_IMPLICIT_INC_DIR})
     endforeach()
   endif()
+
   set(MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS ${MPI_${LANG}_ADDITIONAL_INCLUDE_DIRS} CACHE STRING "MPI ${LANG} additional include directories" FORCE)
-endfunction()
+endmacro()
 
 macro(_MPI_create_imported_target LANG)
   if(NOT TARGET MPI::MPI_${LANG})
@@ -1494,8 +1484,9 @@
       endif()
     endif()
 
-    _MPI_split_include_dirs(${LANG})
-    _MPI_assemble_include_dirs(${LANG})
+    if(NOT "${MPI_${LANG}_COMPILER}" STREQUAL "${CMAKE_${LANG}_COMPILER}")
+      _MPI_split_include_dirs(${LANG})
+    endif()
     _MPI_assemble_libraries(${LANG})
 
     _MPI_adjust_compile_definitions(${LANG})
@@ -1664,7 +1655,8 @@
         list(APPEND MPI_${LANG}_REQUIRED_VARS "MPI_${LANG}_WORKS")
       endif()
     endif()
-    find_package_handle_standard_args(MPI_${LANG} REQUIRED_VARS ${MPI_${LANG}_REQUIRED_VARS}
+    find_package_handle_standard_args(MPI_${LANG} NAME_MISMATCHED
+      REQUIRED_VARS ${MPI_${LANG}_REQUIRED_VARS}
       VERSION_VAR MPI_${LANG}_VERSION)
 
     if(DEFINED MPI_${LANG}_VERSION)
diff --git a/Modules/FindMatlab.cmake b/Modules/FindMatlab.cmake
index c8cae2e..92ee729 100644
--- a/Modules/FindMatlab.cmake
+++ b/Modules/FindMatlab.cmake
@@ -241,6 +241,8 @@
 endif()
 
 set(MATLAB_VERSIONS_MAPPING
+  "R2019b=9.7"
+  "R2019a=9.6"
   "R2018b=9.5"
   "R2018a=9.4"
   "R2017b=9.3"
@@ -974,10 +976,19 @@
   endif()
 
   if(NOT Matlab_VERSION_STRING VERSION_LESS "9.1") # For 9.1 (R2016b) and newer, add version source file
-    # TODO: check the file extensions in ${${prefix}_SRC} to see if they're C or C++ files
-    # Currently, the C and C++ versions of the version files are identical, so this doesn't matter.
-    set(MEX_VERSION_FILE "${Matlab_ROOT_DIR}/extern/version/c_mexapi_version.c")
-    #set(MEX_VERSION_FILE "${Matlab_ROOT_DIR}/extern/version/cpp_mexapi_version.cpp")
+    # Add the correct version file depending on which languages are enabled in the project
+    if(CMAKE_C_COMPILER_LOADED)
+      # If C is enabled, use the .c file as it will work fine also with C++
+      set(MEX_VERSION_FILE "${Matlab_ROOT_DIR}/extern/version/c_mexapi_version.c")
+    elseif(CMAKE_CXX_COMPILER_LOADED)
+      # If C is not enabled, check if CXX is enabled and use the .cpp file
+      # to avoid that the .c file is silently ignored
+      set(MEX_VERSION_FILE "${Matlab_ROOT_DIR}/extern/version/cpp_mexapi_version.cpp")
+    else()
+      # If neither C or CXX is enabled, warn because we cannot add the source.
+      # TODO: add support for fortran mex files
+      message(WARNING "[MATLAB] matlab_add_mex requires that at least C or CXX are enabled languages")
+    endif()
   endif()
 
   if(NOT Matlab_VERSION_STRING VERSION_LESS "9.4") # For 9.4 (R2018a) and newer, add API macro
diff --git a/Modules/FindOpenACC.cmake b/Modules/FindOpenACC.cmake
index 743e0e2..398dcf5 100644
--- a/Modules/FindOpenACC.cmake
+++ b/Modules/FindOpenACC.cmake
@@ -254,6 +254,7 @@
     _OPENACC_SET_VERSION_BY_SPEC_DATE("${LANG}")
 
     find_package_handle_standard_args(OpenACC_${LANG}
+      NAME_MISMATCHED
       REQUIRED_VARS OpenACC_${LANG}_FLAGS
       VERSION_VAR OpenACC_${LANG}_VERSION
     )
diff --git a/Modules/FindOpenGL.cmake b/Modules/FindOpenGL.cmake
index 23bb001d..74392da 100644
--- a/Modules/FindOpenGL.cmake
+++ b/Modules/FindOpenGL.cmake
@@ -130,6 +130,8 @@
   set(OPENGL_USE_${_COMPONENT} 1)
 endforeach()
 
+set(_OpenGL_CACHE_VARS)
+
 if (CYGWIN)
   find_path(OPENGL_INCLUDE_DIR GL/gl.h )
   list(APPEND _OpenGL_REQUIRED_VARS OPENGL_INCLUDE_DIR)
@@ -137,6 +139,11 @@
   find_library(OPENGL_gl_LIBRARY opengl32 )
   find_library(OPENGL_glu_LIBRARY glu32 )
 
+  list(APPEND _OpenGL_CACHE_VARS
+    OPENGL_INCLUDE_DIR
+    OPENGL_gl_LIBRARY
+    OPENGL_glu_LIBRARY
+    )
 elseif (WIN32)
 
   if(BORLAND)
@@ -147,6 +154,10 @@
     set (OPENGL_glu_LIBRARY glu32 CACHE STRING "GLU library for win32")
   endif()
 
+  list(APPEND _OpenGL_CACHE_VARS
+    OPENGL_gl_LIBRARY
+    OPENGL_glu_LIBRARY
+    )
 elseif (APPLE)
   # The OpenGL.framework provides both gl and glu
   find_library(OPENGL_gl_LIBRARY OpenGL DOC "OpenGL library for OS X")
@@ -155,6 +166,11 @@
   find_path(OPENGL_INCLUDE_DIR OpenGL/gl.h DOC "Include for OpenGL on OS X")
   list(APPEND _OpenGL_REQUIRED_VARS OPENGL_INCLUDE_DIR)
 
+  list(APPEND _OpenGL_CACHE_VARS
+    OPENGL_INCLUDE_DIR
+    OPENGL_gl_LIBRARY
+    OPENGL_glu_LIBRARY
+    )
 else()
   if (CMAKE_SYSTEM_NAME MATCHES "HP-UX")
     # Handle HP-UX cases where we only want to find OpenGL in either hpux64
@@ -194,6 +210,12 @@
     /usr/openwin/share/include
     /opt/graphics/OpenGL/include
   )
+  list(APPEND _OpenGL_CACHE_VARS
+    OPENGL_INCLUDE_DIR
+    OPENGL_GLX_INCLUDE_DIR
+    OPENGL_EGL_INCLUDE_DIR
+    OPENGL_xmesa_INCLUDE_DIR
+    )
 
   # Search for the GLVND libraries.  We do this regardless of COMPONENTS; we'll
   # take into account the COMPONENTS logic later.
@@ -222,6 +244,13 @@
           /usr/shlib
   )
 
+  list(APPEND _OpenGL_CACHE_VARS
+    OPENGL_opengl_LIBRARY
+    OPENGL_glx_LIBRARY
+    OPENGL_egl_LIBRARY
+    OPENGL_glu_LIBRARY
+    )
+
   set(_OpenGL_GL_POLICY_WARN 0)
   if(NOT DEFINED OpenGL_GL_PREFERENCE)
     set(OpenGL_GL_PREFERENCE "")
@@ -268,6 +297,7 @@
             ${_OPENGL_LIB_PATH}
       PATH_SUFFIXES libglvnd
       )
+    list(APPEND _OpenGL_CACHE_VARS OPENGL_gl_LIBRARY)
   endif()
 
   if(_OpenGL_GL_POLICY_WARN AND OPENGL_gl_LIBRARY AND OPENGL_opengl_LIBRARY AND OPENGL_glx_LIBRARY)
@@ -532,14 +562,5 @@
 # This deprecated setting is for backward compatibility with CMake1.4
 set(OPENGL_INCLUDE_PATH ${OPENGL_INCLUDE_DIR})
 
-mark_as_advanced(
-  OPENGL_INCLUDE_DIR
-  OPENGL_xmesa_INCLUDE_DIR
-  OPENGL_egl_LIBRARY
-  OPENGL_glu_LIBRARY
-  OPENGL_glx_LIBRARY
-  OPENGL_gl_LIBRARY
-  OPENGL_opengl_LIBRARY
-  OPENGL_EGL_INCLUDE_DIR
-  OPENGL_GLX_INCLUDE_DIR
-)
+mark_as_advanced(${_OpenGL_CACHE_VARS})
+unset(_OpenGL_CACHE_VARS)
diff --git a/Modules/FindOpenMP.cmake b/Modules/FindOpenMP.cmake
index 90d1c3e..26fed41 100644
--- a/Modules/FindOpenMP.cmake
+++ b/Modules/FindOpenMP.cmake
@@ -509,6 +509,7 @@
     endif()
 
     find_package_handle_standard_args(OpenMP_${LANG}
+      NAME_MISMATCHED
       REQUIRED_VARS OpenMP_${LANG}_FLAGS ${_OPENMP_${LANG}_REQUIRED_LIB_VARS}
       VERSION_VAR OpenMP_${LANG}_VERSION
     )
diff --git a/Modules/FindOpenSSL.cmake b/Modules/FindOpenSSL.cmake
index 043fc6c..af713d6 100644
--- a/Modules/FindOpenSSL.cmake
+++ b/Modules/FindOpenSSL.cmake
@@ -458,7 +458,7 @@
     "Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system variable OPENSSL_ROOT_DIR"
 )
 
-mark_as_advanced(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES)
+mark_as_advanced(OPENSSL_INCLUDE_DIR)
 
 if(OPENSSL_FOUND)
   if(NOT TARGET OpenSSL::Crypto AND
diff --git a/Modules/FindPackageHandleStandardArgs.cmake b/Modules/FindPackageHandleStandardArgs.cmake
index d824ee8..a078049 100644
--- a/Modules/FindPackageHandleStandardArgs.cmake
+++ b/Modules/FindPackageHandleStandardArgs.cmake
@@ -27,6 +27,7 @@
       [VERSION_VAR <version-var>]
       [HANDLE_COMPONENTS]
       [CONFIG_MODE]
+      [NAME_MISMATCHED]
       [REASON_FAILURE_MESSAGE <reason-failure-message>]
       [FAIL_MESSAGE <custom-failure-message>]
       )
@@ -90,6 +91,12 @@
     Specify a custom failure message instead of using the default
     generated message.  Not recommended.
 
+  ``NAME_MISMATCHED``
+    Indicate that the ``<PackageName>`` does not match
+    ``${CMAKE_FIND_PACKAGE_NAME}``. This is usually a mistake and raises a
+    warning, but it may be intentional for usage of the command for components
+    of a larger package.
+
 Example for the simple signature:
 
 .. code-block:: cmake
@@ -106,6 +113,17 @@
 the content of the first ``<required-var>``.  On repeated CMake runs,
 the same message will not be printed again.
 
+.. note::
+
+  If ``<PackageName>`` does not match ``CMAKE_FIND_PACKAGE_NAME`` for the
+  calling module, a warning that there is a mismatch is given. The
+  ``FPHSA_NAME_MISMATCHED`` variable may be set to bypass the warning if using
+  the old signature and the ``NAME_MISMATCHED`` argument using the new
+  signature. To avoid forcing the caller to require newer versions of CMake for
+  usage, the variable's value will be used if defined when the
+  ``NAME_MISMATCHED`` argument is not passed for the new signature (but using
+  both is an error)..
+
 Example for the full signature:
 
 .. code-block:: cmake
@@ -190,15 +208,32 @@
 
 function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)
 
-# Set up the arguments for `cmake_parse_arguments`.
-  set(options  CONFIG_MODE  HANDLE_COMPONENTS)
+  # Set up the arguments for `cmake_parse_arguments`.
+  set(options  CONFIG_MODE  HANDLE_COMPONENTS NAME_MISMATCHED)
   set(oneValueArgs  FAIL_MESSAGE  REASON_FAILURE_MESSAGE VERSION_VAR  FOUND_VAR)
   set(multiValueArgs REQUIRED_VARS)
 
-# Check whether we are in 'simple' or 'extended' mode:
+  # Check whether we are in 'simple' or 'extended' mode:
   set(_KEYWORDS_FOR_EXTENDED_MODE  ${options} ${oneValueArgs} ${multiValueArgs} )
   list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX)
 
+  unset(FPHSA_NAME_MISMATCHED_override)
+  if (DEFINED FPHSA_NAME_MISMATCHED)
+    # If the variable NAME_MISMATCHED variable is set, error if it is passed as
+    # an argument. The former is for old signatures, the latter is for new
+    # signatures.
+    list(FIND ARGN "NAME_MISMATCHED" name_mismatched_idx)
+    if (NOT name_mismatched_idx EQUAL "-1")
+      message(FATAL_ERROR
+        "The `NAME_MISMATCHED` argument may only be specified by the argument or "
+        "the variable, not both.")
+    endif ()
+
+    # But use the variable if it is not an argument to avoid forcing minimum
+    # CMake version bumps for calling modules.
+    set(FPHSA_NAME_MISMATCHED_override "${FPHSA_NAME_MISMATCHED}")
+  endif ()
+
   if(${INDEX} EQUAL -1)
     set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG})
     set(FPHSA_REQUIRED_VARS ${ARGN})
@@ -227,6 +262,21 @@
     endif()
   endif()
 
+  if (DEFINED FPHSA_NAME_MISMATCHED_override)
+    set(FPHSA_NAME_MISMATCHED "${FPHSA_NAME_MISMATCHED_override}")
+  endif ()
+
+  if (DEFINED CMAKE_FIND_PACKAGE_NAME
+      AND NOT FPHSA_NAME_MISMATCHED
+      AND NOT _NAME STREQUAL CMAKE_FIND_PACKAGE_NAME)
+    message(AUTHOR_WARNING
+      "The package name passed to `find_package_handle_standard_args` "
+      "(${_NAME}) does not match the name of the calling package "
+      "(${CMAKE_FIND_PACKAGE_NAME}). This can lead to problems in calling "
+      "code that expects `find_package` result variables (e.g., `_FOUND`) "
+      "to follow a certain pattern.")
+  endif ()
+
 # now that we collected all arguments, process them
 
   if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG")
@@ -239,10 +289,12 @@
   string(TOLOWER ${_NAME} _NAME_LOWER)
 
   if(FPHSA_FOUND_VAR)
-    if(FPHSA_FOUND_VAR MATCHES "^${_NAME}_FOUND$"  OR  FPHSA_FOUND_VAR MATCHES "^${_NAME_UPPER}_FOUND$")
+    set(_FOUND_VAR_UPPER ${_NAME_UPPER}_FOUND)
+    set(_FOUND_VAR_MIXED ${_NAME}_FOUND)
+    if(FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_MIXED  OR  FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_UPPER)
       set(_FOUND_VAR ${FPHSA_FOUND_VAR})
     else()
-      message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_NAME}_FOUND\" and \"${_NAME_UPPER}_FOUND\" are valid names.")
+      message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_FOUND_VAR_MIXED}\" and \"${_FOUND_VAR_UPPER}\" are valid names.")
     endif()
   else()
     set(_FOUND_VAR ${_NAME_UPPER}_FOUND)
diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake
index 086b229..7483d72 100644
--- a/Modules/FindPython/Support.cmake
+++ b/Modules/FindPython/Support.cmake
@@ -23,7 +23,7 @@
   message (FATAL_ERROR "FindPython: INTERNAL ERROR")
 endif()
 if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL 3)
-  set(_${_PYTHON_PREFIX}_VERSIONS 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
+  set(_${_PYTHON_PREFIX}_VERSIONS 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
 elseif (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL 2)
   set(_${_PYTHON_PREFIX}_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0)
 else()
@@ -62,6 +62,9 @@
                     ${CMAKE_SYSTEM_FRAMEWORK_PATH})
     list (REMOVE_DUPLICATES _pff_frameworks)
     foreach (_pff_framework IN LISTS _pff_frameworks)
+      if (EXISTS ${_pff_framework}/Python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}.framework)
+        list (APPEND ${_PYTHON_PREFIX}_FRAMEWORKS ${_pff_framework}/Python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}.framework)
+      endif()
       if (EXISTS ${_pff_framework}/Python.framework)
         list (APPEND ${_PYTHON_PREFIX}_FRAMEWORKS ${_pff_framework}/Python.framework)
       endif()
diff --git a/Modules/FindPythonInterp.cmake b/Modules/FindPythonInterp.cmake
index ccc7d5b..1e01a99 100644
--- a/Modules/FindPythonInterp.cmake
+++ b/Modules/FindPythonInterp.cmake
@@ -54,7 +54,7 @@
 
 set(_PYTHON1_VERSIONS 1.6 1.5)
 set(_PYTHON2_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0)
-set(_PYTHON3_VERSIONS 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
+set(_PYTHON3_VERSIONS 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
 
 if(PythonInterp_FIND_VERSION)
     if(PythonInterp_FIND_VERSION_COUNT GREATER 1)
diff --git a/Modules/FindPythonLibs.cmake b/Modules/FindPythonLibs.cmake
index 1d62ac4..d3ec7be 100644
--- a/Modules/FindPythonLibs.cmake
+++ b/Modules/FindPythonLibs.cmake
@@ -79,7 +79,7 @@
 
 set(_PYTHON1_VERSIONS 1.6 1.5)
 set(_PYTHON2_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0)
-set(_PYTHON3_VERSIONS 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
+set(_PYTHON3_VERSIONS 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
 
 if(PythonLibs_FIND_VERSION)
     if(PythonLibs_FIND_VERSION_COUNT GREATER 1)
diff --git a/Modules/FindTCL.cmake b/Modules/FindTCL.cmake
index be47c39..960265f 100644
--- a/Modules/FindTCL.cmake
+++ b/Modules/FindTCL.cmake
@@ -224,12 +224,14 @@
 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
 
 FIND_PACKAGE_HANDLE_STANDARD_ARGS(TCL DEFAULT_MSG TCL_LIBRARY TCL_INCLUDE_PATH)
+set(FPHSA_NAME_MISMATCHED 1)
 set(TCLTK_FIND_REQUIRED ${TCL_FIND_REQUIRED})
 set(TCLTK_FIND_QUIETLY  ${TCL_FIND_QUIETLY})
 FIND_PACKAGE_HANDLE_STANDARD_ARGS(TCLTK DEFAULT_MSG TCL_LIBRARY TCL_INCLUDE_PATH TK_LIBRARY TK_INCLUDE_PATH)
 set(TK_FIND_REQUIRED ${TCL_FIND_REQUIRED})
 set(TK_FIND_QUIETLY  ${TCL_FIND_QUIETLY})
 FIND_PACKAGE_HANDLE_STANDARD_ARGS(TK DEFAULT_MSG TK_LIBRARY TK_INCLUDE_PATH)
+unset(FPHSA_NAME_MISMATCHED)
 
 mark_as_advanced(
   TCL_INCLUDE_PATH
diff --git a/Modules/InstallRequiredSystemLibraries.cmake b/Modules/InstallRequiredSystemLibraries.cmake
index 0e1429d..04687b9 100644
--- a/Modules/InstallRequiredSystemLibraries.cmake
+++ b/Modules/InstallRequiredSystemLibraries.cmake
@@ -288,9 +288,16 @@
         "${MSVC_CRT_DIR}/msvcp${v}.dll"
         )
       if(NOT vs VERSION_LESS 14)
-        if(EXISTS "${MSVC_CRT_DIR}/vcruntime${v}_1.dll")
-          list(APPEND __install__libs "${MSVC_CRT_DIR}/vcruntime${v}_1.dll")
-        endif()
+        foreach(crt
+            "${MSVC_CRT_DIR}/msvcp${v}_1.dll"
+            "${MSVC_CRT_DIR}/msvcp${v}_2.dll"
+            "${MSVC_CRT_DIR}/msvcp${v}_codecvt_ids.dll"
+            "${MSVC_CRT_DIR}/vcruntime${v}_1.dll"
+            )
+          if(EXISTS "${crt}")
+            list(APPEND __install__libs "${crt}")
+          endif()
+        endforeach()
         list(APPEND __install__libs
             "${MSVC_CRT_DIR}/vcruntime${v}.dll"
             "${MSVC_CRT_DIR}/concrt${v}.dll"
@@ -309,9 +316,16 @@
         "${MSVC_CRT_DIR}/msvcp${v}d.dll"
         )
       if(NOT vs VERSION_LESS 14)
-        if(EXISTS "${MSVC_CRT_DIR}/vcruntime${v}_1d.dll")
-          list(APPEND __install__libs "${MSVC_CRT_DIR}/vcruntime${v}_1d.dll")
-        endif()
+        foreach(crt
+            "${MSVC_CRT_DIR}/msvcp${v}_1d.dll"
+            "${MSVC_CRT_DIR}/msvcp${v}_2d.dll"
+            "${MSVC_CRT_DIR}/msvcp${v}d_codecvt_ids.dll"
+            "${MSVC_CRT_DIR}/vcruntime${v}_1d.dll"
+            )
+          if(EXISTS "${crt}")
+            list(APPEND __install__libs "${crt}")
+          endif()
+        endforeach()
         list(APPEND __install__libs
             "${MSVC_CRT_DIR}/vcruntime${v}d.dll"
             "${MSVC_CRT_DIR}/concrt${v}d.dll"
diff --git a/Modules/Internal/CPack/CPackDeb.cmake b/Modules/Internal/CPack/CPackDeb.cmake
index fe0fe09..c74c324 100644
--- a/Modules/Internal/CPack/CPackDeb.cmake
+++ b/Modules/Internal/CPack/CPackDeb.cmake
@@ -498,6 +498,11 @@
 
   # Description: (mandatory)
   # Try package description first
+  if(CPACK_USED_DEFAULT_PACKAGE_DESCRIPTION_FILE)
+    set(_desc_fallback)
+  else()
+    set(_desc_fallback "CPACK_PACKAGE_DESCRIPTION")
+  endif()
   if(CPACK_DEB_PACKAGE_COMPONENT)
     cpack_deb_variable_fallback("CPACK_DEBIAN_PACKAGE_DESCRIPTION"
       "CPACK_DEBIAN_${_local_component_name}_DESCRIPTION"
@@ -505,11 +510,13 @@
   else()
     cpack_deb_variable_fallback("CPACK_DEBIAN_PACKAGE_DESCRIPTION"
       "CPACK_DEBIAN_PACKAGE_DESCRIPTION"
-      "CPACK_PACKAGE_DESCRIPTION")
+      ${_desc_fallback})
   endif()
 
   # Still no description? ... and description file has set ...
-  if(NOT CPACK_DEBIAN_PACKAGE_DESCRIPTION AND CPACK_PACKAGE_DESCRIPTION_FILE)
+  if(NOT CPACK_DEBIAN_PACKAGE_DESCRIPTION
+     AND CPACK_PACKAGE_DESCRIPTION_FILE
+     AND NOT CPACK_PACKAGE_DESCRIPTION_FILE STREQUAL CPACK_DEFAULT_PACKAGE_DESCRIPTION_FILE)
     # Read `CPACK_PACKAGE_DESCRIPTION_FILE` then...
     file(READ ${CPACK_PACKAGE_DESCRIPTION_FILE} CPACK_DEBIAN_PACKAGE_DESCRIPTION)
   endif()
diff --git a/Modules/Platform/Darwin.cmake b/Modules/Platform/Darwin.cmake
index 1482d76..e5a57b5 100644
--- a/Modules/Platform/Darwin.cmake
+++ b/Modules/Platform/Darwin.cmake
@@ -157,6 +157,10 @@
     endif()
   endforeach()
 endif()
+if (OSX_DEVELOPER_ROOT AND EXISTS "${OSX_DEVELOPER_ROOT}/Library/Frameworks")
+  list(APPEND CMAKE_SYSTEM_FRAMEWORK_PATH
+    ${OSX_DEVELOPER_ROOT}/Library/Frameworks)
+endif()
 list(APPEND CMAKE_SYSTEM_FRAMEWORK_PATH
   /Library/Frameworks
   /Network/Library/Frameworks
diff --git a/Modules/Platform/Windows-Clang.cmake b/Modules/Platform/Windows-Clang.cmake
index 02864c6..c17cf6d 100644
--- a/Modules/Platform/Windows-Clang.cmake
+++ b/Modules/Platform/Windows-Clang.cmake
@@ -24,7 +24,7 @@
   set(CMAKE_DEPFILE_FLAGS_${lang} "-MD -MT <OBJECT> -MF <DEPFILE>")
 
   set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "")
-  set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll" ".dll.a" ".a" ".lib")
+  set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll.a" ".a" ".lib")
   set(CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS 1)
   set (CMAKE_LINK_DEF_FILE_FLAG "-Xlinker /DEF:")
 
diff --git a/Modules/Platform/Windows-GNU.cmake b/Modules/Platform/Windows-GNU.cmake
index 235d9ce..38a8cf4 100644
--- a/Modules/Platform/Windows-GNU.cmake
+++ b/Modules/Platform/Windows-GNU.cmake
@@ -25,7 +25,7 @@
 
 if(MINGW)
   set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "")
-  set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll" ".dll.a" ".a" ".lib")
+  set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll.a" ".a" ".lib")
   set(CMAKE_C_STANDARD_LIBRARIES_INIT "-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32")
   set(CMAKE_CXX_STANDARD_LIBRARIES_INIT "${CMAKE_C_STANDARD_LIBRARIES_INIT}")
 endif()
diff --git a/Modules/Platform/Windows-PGI.cmake b/Modules/Platform/Windows-PGI.cmake
index ad77e8a..8166240 100644
--- a/Modules/Platform/Windows-PGI.cmake
+++ b/Modules/Platform/Windows-PGI.cmake
@@ -9,9 +9,10 @@
 set(__WINDOWS_COMPILER_PGI 1)
 
 # PGI on Windows doesn't support parallel compile processes
-if(NOT DEFINED CMAKE_JOB_POOL_LINK OR NOT DEFINED CMAKE_JOB_POOL_COMPILE)
+if(NOT DEFINED CMAKE_JOB_POOL_LINK OR NOT DEFINED CMAKE_JOB_POOL_COMPILE OR NOT DEFINED CMAKE_JOB_POOL_PRECOMPILE_HEADER)
   set(CMAKE_JOB_POOL_LINK PGITaskPool)
   set(CMAKE_JOB_POOL_COMPILE PGITaskPool)
+  set(CMAKE_JOB_POOL_PRECOMPILE_HEADER PGITaskPool)
   get_property(_pgijp GLOBAL PROPERTY JOB_POOLS)
   if(NOT _pgijp MATCHES "PGITaskPool=")
       set_property(GLOBAL APPEND PROPERTY JOB_POOLS PGITaskPool=1)
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index fe896b0..257b171 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 16)
-set(CMake_VERSION_PATCH 20200113)
+set(CMake_VERSION_PATCH 20200125)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx
index ea71007..3516235 100644
--- a/Source/CPack/cmCPackDragNDropGenerator.cxx
+++ b/Source/CPack/cmCPackDragNDropGenerator.cxx
@@ -775,6 +775,11 @@
     }
   }
 
+  std::string componentFileName =
+    "CPACK_DMG_" + cmSystemTools::UpperCase(componentName) + "_FILE_NAME";
+  if (this->IsSet(componentFileName)) {
+    return this->GetOption(componentFileName);
+  }
   return GetComponentPackageFileName(package_file_name, componentName, false);
 }
 
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
index 6003493..712eb77 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -125,7 +125,7 @@
   cmCPackLogger(cmCPackLog::LOG_DEBUG,
                 "Look for: CPACK_PACKAGE_DESCRIPTION_FILE" << std::endl);
   const char* descFileName = this->GetOption("CPACK_PACKAGE_DESCRIPTION_FILE");
-  if (descFileName) {
+  if (descFileName && !this->GetOption("CPACK_PACKAGE_DESCRIPTION")) {
     cmCPackLogger(cmCPackLog::LOG_DEBUG,
                   "Look for: " << descFileName << std::endl);
     if (!cmSystemTools::FileExists(descFileName)) {
@@ -149,7 +149,12 @@
     while (ifs && cmSystemTools::GetLineFromStream(ifs, line)) {
       ostr << cmXMLSafe(line) << std::endl;
     }
-    this->SetOptionIfNotSet("CPACK_PACKAGE_DESCRIPTION", ostr.str().c_str());
+    this->SetOption("CPACK_PACKAGE_DESCRIPTION", ostr.str().c_str());
+    const char* defFileName =
+      this->GetOption("CPACK_DEFAULT_PACKAGE_DESCRIPTION_FILE");
+    if (defFileName && !strcmp(defFileName, descFileName)) {
+      this->SetOption("CPACK_USED_DEFAULT_PACKAGE_DESCRIPTION_FILE", "ON");
+    }
   }
   if (!this->GetOption("CPACK_PACKAGE_DESCRIPTION")) {
     cmCPackLogger(
diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx
index 46b00b1..acb75b2 100644
--- a/Source/CTest/cmCTestSubmitCommand.cxx
+++ b/Source/CTest/cmCTestSubmitCommand.cxx
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include <cm/memory>
+#include <cm/vector>
 
 #include "cm_static_string_view.hxx"
 
@@ -174,7 +175,7 @@
   this->PartsMentioned = !this->Parts.empty() || cmContains(keywords, "PARTS");
   this->FilesMentioned = !this->Files.empty() || cmContains(keywords, "FILES");
 
-  cmEraseIf(this->Parts, [this](std::string const& arg) -> bool {
+  cm::erase_if(this->Parts, [this](std::string const& arg) -> bool {
     cmCTest::Part p = this->CTest->GetPartFromName(arg.c_str());
     if (p == cmCTest::PartCount) {
       std::ostringstream e;
@@ -185,7 +186,7 @@
     return false;
   });
 
-  cmEraseIf(this->Files, [this](std::string const& arg) -> bool {
+  cm::erase_if(this->Files, [this](std::string const& arg) -> bool {
     if (!cmSystemTools::FileExists(arg)) {
       std::ostringstream e;
       e << "File \"" << arg << "\" does not exist. Cannot submit "
diff --git a/Source/CTest/cmCTestUploadCommand.cxx b/Source/CTest/cmCTestUploadCommand.cxx
index d0e3848..eaef1ca 100644
--- a/Source/CTest/cmCTestUploadCommand.cxx
+++ b/Source/CTest/cmCTestUploadCommand.cxx
@@ -4,11 +4,11 @@
 
 #include <set>
 #include <sstream>
-#include <vector>
+
+#include <cm/vector>
 
 #include "cm_static_string_view.hxx"
 
-#include "cmAlgorithms.h"
 #include "cmCTest.h"
 #include "cmCTestUploadHandler.h"
 #include "cmMakefile.h"
@@ -24,7 +24,7 @@
 
 void cmCTestUploadCommand::CheckArguments(std::vector<std::string> const&)
 {
-  cmEraseIf(this->Files, [this](std::string const& arg) -> bool {
+  cm::erase_if(this->Files, [this](std::string const& arg) -> bool {
     if (!cmSystemTools::FileExists(arg)) {
       std::ostringstream e;
       e << "File \"" << arg << "\" does not exist. Cannot submit "
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
index 2ec9622..cdf899c 100644
--- a/Source/CTest/cmProcess.cxx
+++ b/Source/CTest/cmProcess.cxx
@@ -278,9 +278,6 @@
 
 void cmProcess::OnTimeout()
 {
-  if (this->ProcessState != cmProcess::State::Executing) {
-    return;
-  }
   this->ProcessState = cmProcess::State::Expired;
   bool const was_still_reading = !this->ReadHandleClosed;
   if (!this->ReadHandleClosed) {
diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx
index 995088c..5deba8b 100644
--- a/Source/cmAddCustomCommandCommand.cxx
+++ b/Source/cmAddCustomCommandCommand.cxx
@@ -215,7 +215,8 @@
       }
 
       if (cmSystemTools::FileIsFullPath(filename)) {
-        filename = cmSystemTools::CollapseFullPath(filename);
+        filename = cmSystemTools::CollapseFullPath(
+          filename, status.GetMakefile().GetHomeOutputDirectory());
       }
       switch (doing) {
         case doing_depfile:
diff --git a/Source/cmAddSubDirectoryCommand.cxx b/Source/cmAddSubDirectoryCommand.cxx
index 6a1a514..35eabaf 100644
--- a/Source/cmAddSubDirectoryCommand.cxx
+++ b/Source/cmAddSubDirectoryCommand.cxx
@@ -53,7 +53,8 @@
     status.SetError(error);
     return false;
   }
-  srcPath = cmSystemTools::CollapseFullPath(srcPath);
+  srcPath =
+    cmSystemTools::CollapseFullPath(srcPath, mf.GetHomeOutputDirectory());
 
   // Compute the full path to the binary directory.
   std::string binPath;
diff --git a/Source/cmAddTestCommand.cxx b/Source/cmAddTestCommand.cxx
index 8942113..205c1c7 100644
--- a/Source/cmAddTestCommand.cxx
+++ b/Source/cmAddTestCommand.cxx
@@ -2,6 +2,8 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmAddTestCommand.h"
 
+#include <cm/memory>
+
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmStringAlgorithms.h"
@@ -44,7 +46,7 @@
   } else {
     test = mf.CreateTest(args[0]);
     test->SetOldStyle(true);
-    mf.AddTestGenerator(new cmTestGenerator(test));
+    mf.AddTestGenerator(cm::make_unique<cmTestGenerator>(test));
   }
   test->SetCommand(command);
 
@@ -141,7 +143,7 @@
     test->SetProperty("WORKING_DIRECTORY", working_directory.c_str());
   }
   test->SetCommandExpandLists(command_expand_lists);
-  mf.AddTestGenerator(new cmTestGenerator(test, configurations));
+  mf.AddTestGenerator(cm::make_unique<cmTestGenerator>(test, configurations));
 
   return true;
 }
diff --git a/Source/cmAlgorithms.h b/Source/cmAlgorithms.h
index a179acb..19da2a0 100644
--- a/Source/cmAlgorithms.h
+++ b/Source/cmAlgorithms.h
@@ -37,12 +37,6 @@
   return first;
 }
 
-template <typename Container, typename Predicate>
-void cmEraseIf(Container& cont, Predicate pred)
-{
-  cont.erase(std::remove_if(cont.begin(), cont.end(), pred), cont.end());
-}
-
 template <typename Range, typename Key>
 auto cmContainsImpl(Range const& range, Key const& key, cmOverloadPriority<2>)
   -> decltype(range.exists(key))
@@ -73,40 +67,6 @@
 
 namespace ContainerAlgorithms {
 
-template <typename T>
-struct cmIsPair
-{
-  enum
-  {
-    value = false
-  };
-};
-
-template <typename K, typename V>
-struct cmIsPair<std::pair<K, V>>
-{
-  enum
-  {
-    value = true
-  };
-};
-
-template <typename Range,
-          bool valueTypeIsPair = cmIsPair<typename Range::value_type>::value>
-struct DefaultDeleter
-{
-  void operator()(typename Range::value_type value) const { delete value; }
-};
-
-template <typename Range>
-struct DefaultDeleter<Range, /* valueTypeIsPair = */ true>
-{
-  void operator()(typename Range::value_type value) const
-  {
-    delete value.second;
-  }
-};
-
 template <typename FwdIt>
 FwdIt RemoveN(FwdIt i1, FwdIt i2, size_t n)
 {
@@ -139,13 +99,6 @@
   cmRange<std::vector<cmListFileBacktrace>::const_iterator>;
 
 template <typename Range>
-void cmDeleteAll(Range const& r)
-{
-  std::for_each(r.begin(), r.end(),
-                ContainerAlgorithms::DefaultDeleter<Range>());
-}
-
-template <typename Range>
 typename Range::const_iterator cmRemoveN(Range& r, size_t n)
 {
   return ContainerAlgorithms::RemoveN(r.begin(), r.end(), n);
diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx
index e3536d5..265941a 100644
--- a/Source/cmCacheManager.cxx
+++ b/Source/cmCacheManager.cxx
@@ -190,7 +190,7 @@
     if (entryKey.size() > plen && *(end - plen) == '-' &&
         strcmp(end - plen + 1, *p) == 0) {
       std::string key = entryKey.substr(0, entryKey.size() - plen);
-      cmCacheManager::CacheIterator it = this->GetCacheIterator(key.c_str());
+      cmCacheManager::CacheIterator it = this->GetCacheIterator(key);
       if (it.IsAtEnd()) {
         // Create an entry and store the property.
         CacheEntry& ne = this->Cache[key];
@@ -497,9 +497,15 @@
   return nullptr;
 }
 
-cmCacheManager::CacheIterator cmCacheManager::GetCacheIterator(const char* key)
+cmCacheManager::CacheIterator cmCacheManager::GetCacheIterator(
+  const std::string& key)
 {
-  return { *this, key };
+  return { *this, key.c_str() };
+}
+
+cmCacheManager::CacheIterator cmCacheManager::GetCacheIterator()
+{
+  return { *this, nullptr };
 }
 
 const std::string* cmCacheManager::GetInitializedCacheValue(
@@ -638,20 +644,21 @@
 }
 
 void cmCacheManager::CacheEntry::AppendProperty(const std::string& prop,
-                                                const char* value,
+                                                const std::string& value,
                                                 bool asString)
 {
   if (prop == "TYPE") {
-    this->Type = cmState::StringToCacheEntryType(value ? value : "STRING");
+    this->Type = cmState::StringToCacheEntryType(!value.empty() ? value.c_str()
+                                                                : "STRING");
   } else if (prop == "VALUE") {
-    if (value) {
-      if (!this->Value.empty() && *value && !asString) {
+    if (!value.empty()) {
+      if (!this->Value.empty() && !asString) {
         this->Value += ";";
       }
       this->Value += value;
     }
   } else {
-    this->Properties.AppendProperty(prop, value, asString);
+    this->Properties.AppendProperty(prop, value.c_str(), asString);
   }
 }
 
@@ -673,7 +680,7 @@
 }
 
 void cmCacheManager::CacheIterator::AppendProperty(const std::string& p,
-                                                   const char* v,
+                                                   const std::string& v,
                                                    bool asString)
 {
   if (!this->IsAtEnd()) {
diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h
index faa60c5..d8be991 100644
--- a/Source/cmCacheManager.h
+++ b/Source/cmCacheManager.h
@@ -39,7 +39,7 @@
     std::vector<std::string> GetPropertyList() const;
     const char* GetProperty(const std::string&) const;
     void SetProperty(const std::string& property, const char* value);
-    void AppendProperty(const std::string& property, const char* value,
+    void AppendProperty(const std::string& property, const std::string& value,
                         bool asString = false);
     bool Initialized = false;
   };
@@ -58,10 +58,10 @@
     bool GetPropertyAsBool(const std::string&) const;
     bool PropertyExists(const std::string&) const;
     void SetProperty(const std::string& property, const char* value);
-    void AppendProperty(const std::string& property, const char* value,
+    void AppendProperty(const std::string& property, const std::string& value,
                         bool asString = false);
     void SetProperty(const std::string& property, bool value);
-    const char* GetValue() const { return this->GetEntry().Value.c_str(); }
+    const std::string& GetValue() const { return this->GetEntry().Value; }
     bool GetValueAsBool() const;
     void SetValue(const char*);
     cmStateEnums::CacheEntryType GetType() const
@@ -111,7 +111,8 @@
   void PrintCache(std::ostream&) const;
 
   //! Get the iterator for an entry with a given key.
-  cmCacheManager::CacheIterator GetCacheIterator(const char* key = nullptr);
+  cmCacheManager::CacheIterator GetCacheIterator(const std::string& key);
+  cmCacheManager::CacheIterator GetCacheIterator();
 
   //! Remove an entry from the cache
   void RemoveCacheEntry(const std::string& key);
@@ -124,52 +125,52 @@
 
   const char* GetCacheEntryValue(const std::string& key)
   {
-    cmCacheManager::CacheIterator it = this->GetCacheIterator(key.c_str());
+    cmCacheManager::CacheIterator it = this->GetCacheIterator(key);
     if (it.IsAtEnd()) {
       return nullptr;
     }
-    return it.GetValue();
+    return it.GetValue().c_str();
   }
 
   const char* GetCacheEntryProperty(std::string const& key,
                                     std::string const& propName)
   {
-    return this->GetCacheIterator(key.c_str()).GetProperty(propName);
+    return this->GetCacheIterator(key).GetProperty(propName);
   }
 
   cmStateEnums::CacheEntryType GetCacheEntryType(std::string const& key)
   {
-    return this->GetCacheIterator(key.c_str()).GetType();
+    return this->GetCacheIterator(key).GetType();
   }
 
   bool GetCacheEntryPropertyAsBool(std::string const& key,
                                    std::string const& propName)
   {
-    return this->GetCacheIterator(key.c_str()).GetPropertyAsBool(propName);
+    return this->GetCacheIterator(key).GetPropertyAsBool(propName);
   }
 
   void SetCacheEntryProperty(std::string const& key,
                              std::string const& propName,
                              std::string const& value)
   {
-    this->GetCacheIterator(key.c_str()).SetProperty(propName, value.c_str());
+    this->GetCacheIterator(key).SetProperty(propName, value.c_str());
   }
 
   void SetCacheEntryBoolProperty(std::string const& key,
                                  std::string const& propName, bool value)
   {
-    this->GetCacheIterator(key.c_str()).SetProperty(propName, value);
+    this->GetCacheIterator(key).SetProperty(propName, value);
   }
 
   void SetCacheEntryValue(std::string const& key, std::string const& value)
   {
-    this->GetCacheIterator(key.c_str()).SetValue(value.c_str());
+    this->GetCacheIterator(key).SetValue(value.c_str());
   }
 
   void RemoveCacheEntryProperty(std::string const& key,
                                 std::string const& propName)
   {
-    this->GetCacheIterator(key.c_str()).SetProperty(propName, nullptr);
+    this->GetCacheIterator(key).SetProperty(propName, nullptr);
   }
 
   void AppendCacheEntryProperty(std::string const& key,
@@ -177,8 +178,7 @@
                                 std::string const& value,
                                 bool asString = false)
   {
-    this->GetCacheIterator(key.c_str())
-      .AppendProperty(propName, value.c_str(), asString);
+    this->GetCacheIterator(key).AppendProperty(propName, value, asString);
   }
 
   std::vector<std::string> GetCacheEntryKeys()
diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx
index c568253..34f815f 100644
--- a/Source/cmCustomCommandGenerator.cxx
+++ b/Source/cmCustomCommandGenerator.cxx
@@ -8,7 +8,6 @@
 
 #include <cmext/algorithm>
 
-#include "cmAlgorithms.h"
 #include "cmCustomCommand.h"
 #include "cmCustomCommandLines.h"
 #include "cmGeneratorExpression.h"
@@ -30,11 +29,9 @@
       cmExpandedList(cge->Evaluate(lg, config));
     for (std::string& it : result) {
       cmSystemTools::ConvertToUnixSlashes(it);
-      if (cmContains(it, '/') && !cmSystemTools::FileIsFullPath(it)) {
-        it = cmStrCat(lg->GetMakefile()->GetCurrentBinaryDirectory(), '/', it);
-      }
       if (cmSystemTools::FileIsFullPath(it)) {
-        it = cmSystemTools::CollapseFullPath(it);
+        it = cmSystemTools::CollapseFullPath(
+          it, lg->GetMakefile()->GetHomeOutputDirectory());
       }
     }
     cm::append(output, result);
diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx
index ee43587..3692202 100644
--- a/Source/cmDependsFortran.cxx
+++ b/Source/cmDependsFortran.cxx
@@ -33,6 +33,8 @@
     ext_len = 4;
   } else if (cmHasLiteralSuffix(mod, ".smod")) {
     ext_len = 5;
+  } else if (cmHasLiteralSuffix(mod, ".sub")) {
+    ext_len = 4;
   }
   std::string const& name = mod.substr(0, mod.size() - ext_len);
   std::string const& ext = mod.substr(mod.size() - ext_len);
@@ -284,7 +286,8 @@
       if (doing_provides) {
         std::string mod = line;
         if (!cmHasLiteralSuffix(mod, ".mod") &&
-            !cmHasLiteralSuffix(mod, ".smod")) {
+            !cmHasLiteralSuffix(mod, ".smod") &&
+            !cmHasLiteralSuffix(mod, ".sub")) {
           // Support fortran.internal files left by older versions of CMake.
           // They do not include the ".mod" extension.
           mod += ".mod";
@@ -470,7 +473,8 @@
   if (args.size() >= 5) {
     compilerId = args[4];
   }
-  if (!cmHasLiteralSuffix(mod, ".mod") && !cmHasLiteralSuffix(mod, ".smod")) {
+  if (!cmHasLiteralSuffix(mod, ".mod") && !cmHasLiteralSuffix(mod, ".smod") &&
+      !cmHasLiteralSuffix(mod, ".sub")) {
     // Support depend.make files left by older versions of CMake.
     // They do not include the ".mod" extension.
     mod += ".mod";
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 7a4b887..27e9906 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -14,6 +14,7 @@
 #include "cmComputeLinkInformation.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
 #include "cmLinkItem.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
@@ -640,6 +641,9 @@
   std::string sep;
   input.clear();
   for (std::string& li : parts) {
+    if (cmHasLiteralPrefix(li, CMAKE_DIRECTORY_ID_SEP)) {
+      continue;
+    }
     if (cmGeneratorExpression::Find(li) == std::string::npos) {
       this->AddTargetNamespace(li, target, missingTargets);
     } else {
diff --git a/Source/cmExtraKateGenerator.cxx b/Source/cmExtraKateGenerator.cxx
index e463420..3a22846 100644
--- a/Source/cmExtraKateGenerator.cxx
+++ b/Source/cmExtraKateGenerator.cxx
@@ -246,8 +246,7 @@
       }
     }
 
-    const std::vector<cmSourceFile*>& sources = makefile->GetSourceFiles();
-    for (cmSourceFile* sf : sources) {
+    for (const auto& sf : makefile->GetSourceFiles()) {
       if (sf->GetIsGenerated()) {
         continue;
       }
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index d13e8ec..955195f 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -493,8 +493,9 @@
     Directory& d = *di;
 
     // Accumulate the presence of install rules on the way up.
-    for (auto gen : d.LocalGenerator->GetMakefile()->GetInstallGenerators()) {
-      if (!dynamic_cast<cmInstallSubdirectoryGenerator*>(gen)) {
+    for (const auto& gen :
+         d.LocalGenerator->GetMakefile()->GetInstallGenerators()) {
+      if (!dynamic_cast<cmInstallSubdirectoryGenerator*>(gen.get())) {
         d.HasInstallRule = true;
         break;
       }
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 1fdfa87..79110ab 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -25,6 +25,7 @@
 #include "cm_static_string_view.hxx"
 #include "cm_sys_stat.h"
 
+#include "cmAlgorithms.h"
 #include "cmArgumentParser.h"
 #include "cmCryptoHash.h"
 #include "cmExecutionStatus.h"
@@ -1707,7 +1708,8 @@
   // as we receive downloaded bits from curl...
   //
   std::string dir = cmSystemTools::GetFilenamePath(file);
-  if (!cmSystemTools::FileExists(dir) && !cmSystemTools::MakeDirectory(dir)) {
+  if (!dir.empty() && !cmSystemTools::FileExists(dir) &&
+      !cmSystemTools::MakeDirectory(dir)) {
     std::string errstring = "DOWNLOAD error: cannot create directory '" + dir +
       "' - Specify file by full path name and verify that you "
       "have directory creation and file write privileges.";
@@ -2673,9 +2675,20 @@
     cmSystemTools::SetFatalErrorOccured();
     return false;
   }
-  argIt = keywordsMissingValues.begin();
-  if (argIt != keywordsMissingValues.end()) {
-    status.SetError(cmStrCat("Keyword missing value: ", *argIt));
+
+  const std::vector<std::string> LIST_ARGS = { "DIRECTORIES",
+                                               "EXECUTABLES",
+                                               "LIBRARIES",
+                                               "MODULES",
+                                               "POST_EXCLUDE_REGEXES",
+                                               "POST_INCLUDE_REGEXES",
+                                               "PRE_EXCLUDE_REGEXES",
+                                               "PRE_INCLUDE_REGEXES" };
+  auto kwbegin = keywordsMissingValues.cbegin();
+  auto kwend = cmRemoveMatching(keywordsMissingValues, LIST_ARGS);
+  if (kwend != kwbegin) {
+    status.SetError(cmStrCat("Keywords missing values:\n  ",
+                             cmJoin(cmMakeRange(kwbegin, kwend), "\n  ")));
     cmSystemTools::SetFatalErrorOccured();
     return false;
   }
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 523083a..792cd4d 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -2713,6 +2713,17 @@
   if (i == this->NameMap.end() || i->first != name) {
     // Check if we know how to generate this file.
     cmSourcesWithOutput sources = this->Makefile->GetSourcesWithOutput(name);
+    // If we failed to find a target or source and we have a relative path, it
+    // might be a valid source if made relative to the current binary
+    // directory.
+    if (!sources.Target && !sources.Source &&
+        !cmSystemTools::FileIsFullPath(name)) {
+      auto fullname =
+        cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/', name);
+      fullname = cmSystemTools::CollapseFullPath(
+        fullname, this->Makefile->GetHomeOutputDirectory());
+      sources = this->Makefile->GetSourcesWithOutput(fullname);
+    }
     i = this->NameMap.emplace_hint(i, name, sources);
   }
   if (cmTarget* t = i->second.Target) {
@@ -3086,7 +3097,8 @@
     cmLinkImplementationLibraries const* impl =
       this->GetLinkImplementationLibraries(config);
     for (cmLinkImplItem const& lib : impl->Libraries) {
-      std::string libDir = cmSystemTools::CollapseFullPath(lib.AsStr());
+      std::string libDir = cmSystemTools::CollapseFullPath(
+        lib.AsStr(), this->Makefile->GetHomeOutputDirectory());
 
       static cmsys::RegularExpression frameworkCheck(
         "(.*\\.framework)(/Versions/[^/]+)?/[^/]+$");
@@ -3395,8 +3407,15 @@
       { "OBJCXX", ".objcxx.hxx" }
     };
 
-    filename = cmStrCat(filename, "CMakeFiles/", generatorTarget->GetName(),
-                        ".dir/cmake_pch", languageToExtension.at(language));
+    filename =
+      cmStrCat(filename, "CMakeFiles/", generatorTarget->GetName(), ".dir");
+
+    if (this->GetGlobalGenerator()->IsMultiConfig()) {
+      filename = cmStrCat(filename, "/", config);
+    }
+
+    filename =
+      cmStrCat(filename, "/cmake_pch", languageToExtension.at(language));
 
     const std::string filename_tmp = cmStrCat(filename, ".tmp");
     if (!pchReuseFrom) {
@@ -5406,16 +5425,39 @@
                                                          areport);
 }
 
+bool cmGeneratorTarget::IsLinkLookupScope(std::string const& n,
+                                          cmLocalGenerator const*& lg) const
+{
+  if (cmHasLiteralPrefix(n, CMAKE_DIRECTORY_ID_SEP)) {
+    cmDirectoryId const dirId = n.substr(sizeof(CMAKE_DIRECTORY_ID_SEP) - 1);
+    if (dirId.String.empty()) {
+      lg = this->LocalGenerator;
+      return true;
+    }
+    if (cmLocalGenerator const* otherLG =
+          this->GlobalGenerator->FindLocalGenerator(dirId)) {
+      lg = otherLG;
+      return true;
+    }
+  }
+  return false;
+}
+
 void cmGeneratorTarget::LookupLinkItems(std::vector<std::string> const& names,
                                         cmListFileBacktrace const& bt,
                                         std::vector<cmLinkItem>& items) const
 {
+  cmLocalGenerator const* lg = this->LocalGenerator;
   for (std::string const& n : names) {
+    if (this->IsLinkLookupScope(n, lg)) {
+      continue;
+    }
+
     std::string name = this->CheckCMP0004(n);
     if (name == this->GetName() || name.empty()) {
       continue;
     }
-    items.push_back(this->ResolveLinkItem(name, bt));
+    items.push_back(this->ResolveLinkItem(name, bt, lg));
   }
 }
 
@@ -5424,6 +5466,7 @@
   cmGeneratorTarget const* headTarget, bool usage_requirements_only,
   std::vector<cmLinkItem>& items, bool& hadHeadSensitiveCondition) const
 {
+  // Keep this logic in sync with ComputeLinkImplementationLibraries.
   cmGeneratorExpression ge;
   cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr);
   // The $<LINK_ONLY> expression may be in a link interface to specify private
@@ -6499,6 +6542,7 @@
   const std::string& config, cmOptionalLinkImplementation& impl,
   cmGeneratorTarget const* head) const
 {
+  cmLocalGenerator const* lg = this->LocalGenerator;
   cmStringRange entryRange = this->Target->GetLinkImplementationEntries();
   cmBacktraceRange btRange = this->Target->GetLinkImplementationBacktraces();
   cmBacktraceRange::const_iterator btIt = btRange.begin();
@@ -6507,6 +6551,7 @@
                                      end = entryRange.end();
        le != end; ++le, ++btIt) {
     std::vector<std::string> llibs;
+    // Keep this logic in sync with ExpandLinkItems.
     cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_LIBRARIES", nullptr,
                                                nullptr);
     cmGeneratorExpression ge(*btIt);
@@ -6519,6 +6564,10 @@
     }
 
     for (std::string const& lib : llibs) {
+      if (this->IsLinkLookupScope(lib, lg)) {
+        continue;
+      }
+
       // Skip entries that resolve to the target itself or are empty.
       std::string name = this->CheckCMP0004(lib);
       if (name == this->GetName() || name.empty()) {
@@ -6553,7 +6602,7 @@
       }
 
       // The entry is meant for this configuration.
-      impl.Libraries.emplace_back(this->ResolveLinkItem(name, *btIt),
+      impl.Libraries.emplace_back(this->ResolveLinkItem(name, *btIt, lg),
                                   evaluated != *le);
     }
 
@@ -6590,38 +6639,16 @@
 cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference(
   std::string const& name) const
 {
-  cmLocalGenerator const* lg = this->LocalGenerator;
-  std::string const* lookupName = &name;
+  return this->ResolveTargetReference(name, this->LocalGenerator);
+}
 
-  // When target_link_libraries() is called with a LHS target that is
-  // not created in the calling directory it adds a directory id suffix
-  // that we can use to look up the calling directory.  It is that scope
-  // in which the item name is meaningful.  This case is relatively rare
-  // so we allocate a separate string only when the directory id is present.
-  std::string::size_type pos = name.find(CMAKE_DIRECTORY_ID_SEP);
-  std::string plainName;
-  if (pos != std::string::npos) {
-    // We will look up the plain name without the directory id suffix.
-    plainName = name.substr(0, pos);
-
-    // We will look up in the scope of the directory id.
-    // If we do not recognize the id then leave the original
-    // syntax in place to produce an indicative error later.
-    cmDirectoryId const dirId =
-      name.substr(pos + sizeof(CMAKE_DIRECTORY_ID_SEP) - 1);
-    if (cmLocalGenerator const* otherLG =
-          this->GlobalGenerator->FindLocalGenerator(dirId)) {
-      lg = otherLG;
-      lookupName = &plainName;
-    }
-  }
-
+cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference(
+  std::string const& name, cmLocalGenerator const* lg) const
+{
   TargetOrString resolved;
 
-  if (cmGeneratorTarget* tgt = lg->FindGeneratorTargetToUse(*lookupName)) {
+  if (cmGeneratorTarget* tgt = lg->FindGeneratorTargetToUse(name)) {
     resolved.Target = tgt;
-  } else if (lookupName == &plainName) {
-    resolved.String = std::move(plainName);
   } else {
     resolved.String = name;
   }
@@ -6632,7 +6659,14 @@
 cmLinkItem cmGeneratorTarget::ResolveLinkItem(
   std::string const& name, cmListFileBacktrace const& bt) const
 {
-  TargetOrString resolved = this->ResolveTargetReference(name);
+  return this->ResolveLinkItem(name, bt, this->LocalGenerator);
+}
+
+cmLinkItem cmGeneratorTarget::ResolveLinkItem(std::string const& name,
+                                              cmListFileBacktrace const& bt,
+                                              cmLocalGenerator const* lg) const
+{
+  TargetOrString resolved = this->ResolveTargetReference(name, lg);
 
   if (!resolved.Target) {
     return cmLinkItem(resolved.String, bt);
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 0a72cbe..9d06104 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -378,9 +378,14 @@
     cmGeneratorTarget* Target = nullptr;
   };
   TargetOrString ResolveTargetReference(std::string const& name) const;
+  TargetOrString ResolveTargetReference(std::string const& name,
+                                        cmLocalGenerator const* lg) const;
 
   cmLinkItem ResolveLinkItem(std::string const& name,
                              cmListFileBacktrace const& bt) const;
+  cmLinkItem ResolveLinkItem(std::string const& name,
+                             cmListFileBacktrace const& bt,
+                             cmLocalGenerator const* lg) const;
 
   // Compute the set of languages compiled by the target.  This is
   // computed every time it is called because the languages can change
@@ -919,6 +924,9 @@
 
   std::unordered_set<std::string> UnityBatchedSourceFiles;
 
+  bool IsLinkLookupScope(std::string const& n,
+                         cmLocalGenerator const*& lg) const;
+
   void ExpandLinkItems(std::string const& prop, std::string const& value,
                        std::string const& config,
                        const cmGeneratorTarget* headTarget,
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 4cbcda0..38ff3ae 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -7,6 +7,7 @@
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
+#include <functional>
 #include <initializer_list>
 #include <iterator>
 #include <sstream>
@@ -1412,7 +1413,7 @@
 
   for (const auto& localGen : this->LocalGenerators) {
     cmMakefile* mf = localGen->GetMakefile();
-    for (cmInstallGenerator* g : mf->GetInstallGenerators()) {
+    for (const auto& g : mf->GetInstallGenerators()) {
       if (!g->Compute(localGen.get())) {
         return false;
       }
@@ -1687,10 +1688,10 @@
   std::map<cmTarget*, cmGeneratorTarget*> importedMap;
   for (unsigned int i = 0; i < this->Makefiles.size(); ++i) {
     auto& mf = this->Makefiles[i];
-    for (cmTarget* ownedImpTgt : mf->GetOwnedImportedTargets()) {
+    for (const auto& ownedImpTgt : mf->GetOwnedImportedTargets()) {
       cmLocalGenerator* lg = this->LocalGenerators[i].get();
-      auto gt = cm::make_unique<cmGeneratorTarget>(ownedImpTgt, lg);
-      importedMap[ownedImpTgt] = gt.get();
+      auto gt = cm::make_unique<cmGeneratorTarget>(ownedImpTgt.get(), lg);
+      importedMap[ownedImpTgt.get()] = gt.get();
       lg->AddOwnedImportedGeneratorTarget(std::move(gt));
     }
   }
@@ -2458,6 +2459,13 @@
   cmCustomCommandLine singleLine;
   singleLine.push_back(cmSystemTools::GetCTestCommand());
   singleLine.push_back("--force-new-ctest-process");
+  if (auto testArgs = mf->GetDefinition("CMAKE_CTEST_ARGUMENTS")) {
+    std::vector<std::string> args;
+    cmExpandList(testArgs, args);
+    for (auto const& arg : args) {
+      singleLine.push_back(arg);
+    }
+  }
   if (cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.') {
     singleLine.push_back("-C");
     singleLine.push_back(cmakeCfgIntDir);
@@ -3113,6 +3121,16 @@
   return this->FilenameTargetDepends[sf];
 }
 
+const std::string& cmGlobalGenerator::GetRealPath(const std::string& dir)
+{
+  auto i = this->RealPaths.lower_bound(dir);
+  if (i == this->RealPaths.end() ||
+      this->RealPaths.key_comp()(dir, i->first)) {
+    i = this->RealPaths.emplace_hint(i, dir, cmSystemTools::GetRealPath(dir));
+  }
+  return i->second;
+}
+
 void cmGlobalGenerator::ProcessEvaluationFiles()
 {
   std::vector<std::string> generatedFiles;
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index b427992..f6ed10f 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -415,6 +415,8 @@
 
   virtual bool IsXcode() const { return false; }
 
+  virtual bool IsVisualStudio() const { return false; }
+
   /** Return true if we know the exact location of object files.
       If false, store the reason in the given string.
       This is meaningful only after EnableLanguage has been called.  */
@@ -486,6 +488,8 @@
     configs.emplace_back("$<CONFIG>");
   }
 
+  std::string const& GetRealPath(std::string const& dir);
+
 protected:
   // for a project collect all its targets by following depend
   // information, and also collect all the targets
@@ -678,6 +682,8 @@
   mutable std::map<cmSourceFile*, std::set<cmGeneratorTarget const*>>
     FilenameTargetDepends;
 
+  std::map<std::string, std::string> RealPaths;
+
 #if !defined(CMAKE_BOOTSTRAP)
   // Pool of file locks
   cmFileLockPool FileLockPool;
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 35b4f91..2dd89e3 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -293,7 +293,7 @@
     if (config.empty()) {
       this->WriteBuild(*this->GetCommonFileStream(), build);
     } else {
-      this->WriteBuild(*this->GetConfigFileStream(config), build);
+      this->WriteBuild(*this->GetImplFileStream(config), build);
     }
   }
 
@@ -324,7 +324,7 @@
     cmNinjaBuild build("COPY_OSX_CONTENT");
     build.Outputs.push_back(std::move(output));
     build.ExplicitDeps.push_back(std::move(input));
-    this->WriteBuild(*this->GetConfigFileStream(config), build);
+    this->WriteBuild(*this->GetImplFileStream(config), build);
   }
 }
 
@@ -518,6 +518,7 @@
   if (cmSystemTools::GetErrorOccuredFlag()) {
     this->RulesFileStream->setstate(std::ios::failbit);
     for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs()) {
+      this->GetImplFileStream(config)->setstate(std::ios::failbit);
       this->GetConfigFileStream(config)->setstate(std::ios::failbit);
     }
     this->GetCommonFileStream()->setstate(std::ios::failbit);
@@ -527,15 +528,13 @@
   this->CloseRulesFileStream();
   this->CloseBuildFileStreams();
 
-  if (!this->WriteDefaultBuildFile()) {
-    return;
-  }
-
-  auto run_ninja_tool = [this](char const* tool) {
+  auto run_ninja_tool = [this](std::vector<char const*> const& args) {
     std::vector<std::string> command;
     command.push_back(this->NinjaCommand);
     command.emplace_back("-t");
-    command.emplace_back(tool);
+    for (auto const& arg : args) {
+      command.emplace_back(arg);
+    }
     std::string error;
     if (!cmSystemTools::RunSingleCommand(command, nullptr, &error, nullptr,
                                          nullptr,
@@ -550,14 +549,35 @@
     }
   };
 
-  if (this->NinjaSupportsCleanDeadTool) {
-    run_ninja_tool("cleandead");
+  // The `cleandead` tool needs to know about all outputs in the build we just
+  // wrote out. Ninja-Multi doesn't have a single `build.ninja` we can use that
+  // is the union of all generated configurations, so we can't run it reliably
+  // in that case.
+  if (this->NinjaSupportsCleanDeadTool && !this->IsMultiConfig()) {
+    run_ninja_tool({ "cleandead" });
   }
-  if (this->NinjaSupportsUnconditionalRecompactTool) {
-    run_ninja_tool("recompact");
+  // The `recompact` tool loads the manifest. As above, we don't have a single
+  // `build.ninja` to load for this in Ninja-Multi. This may be relaxed in the
+  // future pending further investigation into how Ninja works upstream
+  // (ninja#1721).
+  if (this->NinjaSupportsUnconditionalRecompactTool &&
+      !this->IsMultiConfig()) {
+    run_ninja_tool({ "recompact" });
   }
   if (this->NinjaSupportsRestatTool) {
-    run_ninja_tool("restat");
+    // XXX(ninja): We only list `build.ninja` entry files here because CMake
+    // *always* rewrites these files on a reconfigure. If CMake ever gets
+    // smarter about this, all CMake-time created/edited files listed as
+    // outputs for the reconfigure build statement will need to be listed here.
+    cmNinjaDeps outputs;
+    this->AddRebuildManifestOutputs(outputs);
+    std::vector<const char*> args;
+    args.reserve(outputs.size() + 1);
+    args.push_back("restat");
+    for (auto const& output : outputs) {
+      args.push_back(output.c_str());
+    }
+    run_ninja_tool(args);
   }
 }
 
@@ -1150,14 +1170,11 @@
       newAliasGlobal.first->second.GeneratorTarget != target) {
     newAliasGlobal.first->second.GeneratorTarget = nullptr;
   }
-  if (config != "all") {
-    std::pair<TargetAliasMap::iterator, bool> newAliasConfig =
-      this->Configs[config].TargetAliases.insert(
-        std::make_pair(outputPath, ta));
-    if (newAliasConfig.second &&
-        newAliasConfig.first->second.GeneratorTarget != target) {
-      newAliasConfig.first->second.GeneratorTarget = nullptr;
-    }
+  std::pair<TargetAliasMap::iterator, bool> newAliasConfig =
+    this->Configs[config].TargetAliases.insert(std::make_pair(outputPath, ta));
+  if (newAliasConfig.second &&
+      newAliasConfig.first->second.GeneratorTarget != target) {
+    newAliasConfig.first->second.GeneratorTarget = nullptr;
   }
 }
 
@@ -1183,8 +1200,7 @@
     build.Outputs.front() = ta.first;
     build.ExplicitDeps.clear();
     if (ta.second.Config == "all") {
-      for (auto const& config :
-           ta.second.GeneratorTarget->Makefile->GetGeneratorConfigs()) {
+      for (auto const& config : this->GetCrossConfigs("")) {
         this->AppendTargetOutputs(ta.second.GeneratorTarget,
                                   build.ExplicitDeps, config);
       }
@@ -1192,7 +1208,12 @@
       this->AppendTargetOutputs(ta.second.GeneratorTarget, build.ExplicitDeps,
                                 ta.second.Config);
     }
-    this->WriteBuild(os, build);
+    this->WriteBuild(this->EnableCrossConfigBuild() &&
+                         (ta.second.Config == "all" ||
+                          this->GetCrossConfigs("").count(ta.second.Config))
+                       ? os
+                       : *this->GetImplFileStream(ta.second.Config),
+                     build);
   }
 
   if (this->IsMultiConfig()) {
@@ -1216,6 +1237,37 @@
         this->WriteBuild(*this->GetConfigFileStream(config), build);
       }
     }
+
+    auto const* defaultConfig = this->GetDefaultBuildAlias();
+    if (defaultConfig) {
+      std::string config = defaultConfig;
+      for (auto const& ta : this->Configs[config].TargetAliases) {
+        // Don't write ambiguous aliases.
+        if (!ta.second.GeneratorTarget) {
+          continue;
+        }
+
+        // Don't write alias if there is a already a custom command with
+        // matching output
+        if (this->HasCustomCommandOutput(ta.first)) {
+          continue;
+        }
+
+        build.Outputs.front() = ta.first;
+        build.ExplicitDeps.clear();
+        if (config == "all") {
+          for (auto const& config2 :
+               this->Makefiles.front()->GetGeneratorConfigs()) {
+            this->AppendTargetOutputs(ta.second.GeneratorTarget,
+                                      build.ExplicitDeps, config2);
+          }
+        } else {
+          this->AppendTargetOutputs(ta.second.GeneratorTarget,
+                                    build.ExplicitDeps, config);
+        }
+        this->WriteBuild(*this->GetDefaultFileStream(), build);
+      }
+    }
   }
 }
 
@@ -1259,7 +1311,11 @@
         }
       }
       // Write target
-      this->WriteBuild(os, build);
+      this->WriteBuild(this->EnableCrossConfigBuild() &&
+                           this->GetCrossConfigs("").count(config)
+                         ? os
+                         : *this->GetImplFileStream(config),
+                       build);
     }
 
     // Add shortcut target
@@ -1271,18 +1327,28 @@
           this->ConvertToNinjaPath(currentBinaryDir + "/all");
         this->WriteBuild(*this->GetConfigFileStream(config), build);
       }
+
+      auto const* defaultConfig = this->GetDefaultBuildAlias();
+      if (defaultConfig) {
+        std::string config = defaultConfig;
+        build.ExplicitDeps = { this->BuildAlias(
+          this->ConvertToNinjaPath(currentBinaryDir + "/all"), config) };
+        build.Outputs.front() =
+          this->ConvertToNinjaPath(currentBinaryDir + "/all");
+        this->WriteBuild(*this->GetDefaultFileStream(), build);
+      }
     }
 
     // Add target for all configs
-    if (this->IsMultiConfig()) {
+    if (this->EnableCrossConfigBuild()) {
       build.ExplicitDeps.clear();
-      for (auto const& config : configs) {
+      for (auto const& config : this->GetCrossConfigs("")) {
         build.ExplicitDeps.push_back(this->BuildAlias(
           this->ConvertToNinjaPath(currentBinaryDir + "/all"), config));
       }
       build.Outputs.front() = this->BuildAlias(
         this->ConvertToNinjaPath(currentBinaryDir + "/all"), "all");
-      this->WriteBuild(*this->GetCommonFileStream(), build);
+      this->WriteBuild(os, build);
     }
   }
 }
@@ -1330,8 +1396,7 @@
         knownDependencies.insert(this->ConvertToNinjaPath(j));
       }
     }
-    for (cmGeneratorExpressionEvaluationFile* li :
-         lg->GetMakefile()->GetEvaluationFiles()) {
+    for (const auto& li : lg->GetMakefile()->GetEvaluationFiles()) {
       // get all the files created by generator expressions and convert them
       // to ninja paths
       for (std::string const& evaluationFile : li->GetFiles()) {
@@ -1423,6 +1488,10 @@
   for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs()) {
     this->WriteTargetDefault(*this->GetConfigFileStream(config));
   }
+
+  if (this->GetDefaultBuildType()) {
+    this->WriteTargetDefault(*this->GetDefaultFileStream());
+  }
 }
 
 void cmGlobalNinjaGenerator::WriteTargetDefault(std::ostream& os)
@@ -1710,30 +1779,43 @@
           config));
       }
       for (auto const& fileConfig : configs) {
+        if (fileConfig != config && !this->EnableCrossConfigBuild()) {
+          continue;
+        }
         if (this->IsMultiConfig()) {
           build.Variables["FILE_ARG"] = cmStrCat(
-            "-f ", cmGlobalNinjaMultiGenerator::GetNinjaFilename(fileConfig));
+            "-f ",
+            cmGlobalNinjaMultiGenerator::GetNinjaImplFilename(fileConfig));
         }
-        this->WriteBuild(*this->GetConfigFileStream(fileConfig), build);
+        this->WriteBuild(*this->GetImplFileStream(fileConfig), build);
       }
     }
 
-    if (this->IsMultiConfig()) {
+    if (this->EnableCrossConfigBuild()) {
       build.Outputs.front() = this->BuildAlias(
         this->NinjaOutputPath(this->GetCleanTargetName()), "all");
       build.ExplicitDeps.clear();
 
       if (additionalFiles) {
-        build.ExplicitDeps.push_back(
-          this->NinjaOutputPath(this->GetAdditionalCleanTargetName()));
+        for (auto const& config : this->GetCrossConfigs("")) {
+          build.ExplicitDeps.push_back(this->BuildAlias(
+            this->NinjaOutputPath(this->GetAdditionalCleanTargetName()),
+            config));
+        }
       }
 
-      build.Variables["TARGETS"] = "";
+      std::vector<std::string> byproducts;
+      for (auto const& config : this->GetCrossConfigs("")) {
+        byproducts.push_back(
+          this->BuildAlias(GetByproductsForCleanTargetName(), config));
+      }
+      build.Variables["TARGETS"] = cmJoin(byproducts, " ");
 
       for (auto const& fileConfig : configs) {
         build.Variables["FILE_ARG"] = cmStrCat(
-          "-f ", cmGlobalNinjaMultiGenerator::GetNinjaFilename(fileConfig));
-        this->WriteBuild(*this->GetConfigFileStream(fileConfig), build);
+          "-f ",
+          cmGlobalNinjaMultiGenerator::GetNinjaImplFilename(fileConfig));
+        this->WriteBuild(*this->GetImplFileStream(fileConfig), build);
       }
     }
   }
@@ -1749,6 +1831,14 @@
         this->NinjaOutputPath(this->GetCleanTargetName()), config);
       this->WriteBuild(*this->GetConfigFileStream(config), build);
     }
+
+    auto const* defaultConfig = this->GetDefaultBuildAlias();
+    if (defaultConfig) {
+      std::string config = defaultConfig;
+      build.ExplicitDeps.front() = this->BuildAlias(
+        this->NinjaOutputPath(this->GetCleanTargetName()), config);
+      this->WriteBuild(*this->GetDefaultFileStream(), build);
+    }
   }
 
   // Write byproducts
@@ -2192,6 +2282,12 @@
   return true;
 }
 
+bool cmGlobalNinjaGenerator::EnableCrossConfigBuild() const
+{
+  return this->IsMultiConfig() &&
+    this->Makefiles.front()->IsOn("CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE");
+}
+
 int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
                              std::vector<std::string>::const_iterator argEnd)
 {
@@ -2283,7 +2379,17 @@
   }
 }
 
-const char* cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE = "common.ninja";
+std::set<std::string> cmGlobalNinjaGenerator::GetCrossConfigs(
+  const std::string& /*fileConfig*/) const
+{
+  std::set<std::string> result;
+  result.insert(
+    this->Makefiles.front()->GetSafeDefinition("CMAKE_BUILD_TYPE"));
+  return result;
+}
+
+const char* cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE =
+  "CMakeFiles/common.ninja";
 const char* cmGlobalNinjaMultiGenerator::NINJA_FILE_EXTENSION = ".ninja";
 
 cmGlobalNinjaMultiGenerator::cmGlobalNinjaMultiGenerator(cmake* cm)
@@ -2314,21 +2420,45 @@
     return false;
   }
 
+  auto const* defaultConfig = this->GetDefaultBuildType();
+  if (defaultConfig) {
+    if (!this->OpenFileStream(this->DefaultFileStream, NINJA_BUILD_FILE)) {
+      return false;
+    }
+    *this->DefaultFileStream
+      << "# This file is a convenience file generated by\n"
+      << "# CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE.\n\n"
+      << "include " << GetNinjaImplFilename(defaultConfig) << "\n\n";
+  }
+
   // Write a comment about this file.
   *this->CommonFileStream
     << "# This file contains build statements common to all "
        "configurations.\n\n";
 
   for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs()) {
+    // Open impl file.
+    if (!this->OpenFileStream(this->ImplFileStreams[config],
+                              GetNinjaImplFilename(config))) {
+      return false;
+    }
+
+    // Write a comment about this file.
+    *this->ImplFileStreams[config]
+      << "# This file contains build statements specific to the \"" << config
+      << "\"\n# configuration.\n\n";
+
+    // Open config file.
     if (!this->OpenFileStream(this->ConfigFileStreams[config],
-                              GetNinjaFilename(config))) {
+                              GetNinjaConfigFilename(config))) {
       return false;
     }
 
     // Write a comment about this file.
     *this->ConfigFileStreams[config]
-      << "# This file contains build statements specific to the \"" << config
-      << "\"\n# configuration.\n\n";
+      << "# This file contains aliases specific to the \"" << config
+      << "\"\n# configuration.\n\n"
+      << "include " << GetNinjaImplFilename(config) << "\n\n";
   }
 
   return true;
@@ -2342,7 +2472,17 @@
     cmSystemTools::Error("Common file stream was not open.");
   }
 
+  if (this->DefaultFileStream) {
+    this->DefaultFileStream.reset();
+  } // No error if it wasn't open
+
   for (auto const& config : this->Makefiles[0]->GetGeneratorConfigs()) {
+    if (this->ImplFileStreams[config]) {
+      this->ImplFileStreams[config].reset();
+    } else {
+      cmSystemTools::Error(
+        cmStrCat("Impl file stream for \"", config, "\" was not open."));
+    }
     if (this->ConfigFileStreams[config]) {
       this->ConfigFileStreams[config].reset();
     } else {
@@ -2356,10 +2496,17 @@
   GeneratedMakeCommand& command, const std::string& config) const
 {
   command.Add("-f");
-  command.Add(GetNinjaFilename(config));
+  command.Add(GetNinjaConfigFilename(config));
 }
 
-std::string cmGlobalNinjaMultiGenerator::GetNinjaFilename(
+std::string cmGlobalNinjaMultiGenerator::GetNinjaImplFilename(
+  const std::string& config)
+{
+  return cmStrCat("CMakeFiles/impl-", config,
+                  cmGlobalNinjaMultiGenerator::NINJA_FILE_EXTENSION);
+}
+
+std::string cmGlobalNinjaMultiGenerator::GetNinjaConfigFilename(
   const std::string& config)
 {
   return cmStrCat("build-", config,
@@ -2370,7 +2517,8 @@
   cmNinjaDeps& outputs) const
 {
   for (auto const& config : this->Makefiles.front()->GetGeneratorConfigs()) {
-    outputs.push_back(this->NinjaOutputPath(GetNinjaFilename(config)));
+    outputs.push_back(this->NinjaOutputPath(GetNinjaImplFilename(config)));
+    outputs.push_back(this->NinjaOutputPath(GetNinjaConfigFilename(config)));
   }
   if (this->Makefiles.front()->GetDefinition(
         "CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE")) {
@@ -2388,20 +2536,43 @@
   }
 }
 
-bool cmGlobalNinjaMultiGenerator::WriteDefaultBuildFile()
+const char* cmGlobalNinjaMultiGenerator::GetDefaultBuildType() const
 {
-  auto const* defaultConfig = this->Makefiles.front()->GetDefinition(
+  return this->Makefiles.front()->GetDefinition(
     "CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE");
-  if (defaultConfig) {
-    std::unique_ptr<cmGeneratedFileStream> defaultStream;
-    if (!this->OpenFileStream(defaultStream, NINJA_BUILD_FILE)) {
-      return false;
+}
+
+const char* cmGlobalNinjaMultiGenerator::GetDefaultBuildAlias() const
+{
+  if (this->EnableCrossConfigBuild()) {
+    auto const* alias = this->Makefiles.front()->GetDefinition(
+      "CMAKE_NINJA_MULTI_DEFAULT_BUILD_ALIAS");
+    if (alias) {
+      return alias;
     }
-    *defaultStream << "# This file is a convenience file generated by\n"
-                   << "# CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE.\n\n"
-                   << "include " << this->GetNinjaFilename(defaultConfig)
-                   << "\n";
   }
 
-  return true;
+  return this->GetDefaultBuildType();
+}
+
+std::set<std::string> cmGlobalNinjaMultiGenerator::GetCrossConfigs(
+  const std::string& fileConfig) const
+{
+  std::vector<std::string> configs;
+  if (this->EnableCrossConfigBuild()) {
+    auto configsValue = this->Makefiles.front()->GetSafeDefinition(
+      "CMAKE_NINJA_MULTI_CROSS_CONFIGS");
+    if (!configsValue.empty()) {
+      cmExpandList(configsValue, configs);
+    } else {
+      configs = this->Makefiles.front()->GetGeneratorConfigs();
+    }
+  }
+
+  std::set<std::string> result(configs.cbegin(), configs.cend());
+  if (!fileConfig.empty()) {
+    result.insert(fileConfig);
+  }
+
+  return result;
 }
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index fdd9dda..d00a061 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -208,12 +208,23 @@
   }
   const char* GetCleanTargetName() const override { return "clean"; }
 
+  virtual cmGeneratedFileStream* GetImplFileStream(
+    const std::string& /*config*/) const
+  {
+    return this->BuildFileStream.get();
+  }
+
   virtual cmGeneratedFileStream* GetConfigFileStream(
     const std::string& /*config*/) const
   {
     return this->BuildFileStream.get();
   }
 
+  virtual cmGeneratedFileStream* GetDefaultFileStream() const
+  {
+    return this->BuildFileStream.get();
+  }
+
   virtual cmGeneratedFileStream* GetCommonFileStream() const
   {
     return this->BuildFileStream.get();
@@ -395,6 +406,15 @@
     return this->Configs[config].ByproductsForCleanTarget;
   }
 
+  bool EnableCrossConfigBuild() const;
+
+  virtual const char* GetDefaultBuildType() const { return nullptr; }
+
+  virtual const char* GetDefaultBuildAlias() const { return nullptr; }
+
+  virtual std::set<std::string> GetCrossConfigs(
+    const std::string& fileConfig) const;
+
 protected:
   void Generate() override;
 
@@ -402,7 +422,6 @@
 
   virtual bool OpenBuildFileStreams();
   virtual void CloseBuildFileStreams();
-  virtual bool WriteDefaultBuildFile() { return true; }
 
   bool OpenFileStream(std::unique_ptr<cmGeneratedFileStream>& stream,
                       const std::string& name);
@@ -571,12 +590,23 @@
   std::string ExpandCFGIntDir(const std::string& str,
                               const std::string& config) const override;
 
+  cmGeneratedFileStream* GetImplFileStream(
+    const std::string& config) const override
+  {
+    return this->ImplFileStreams.at(config).get();
+  }
+
   cmGeneratedFileStream* GetConfigFileStream(
     const std::string& config) const override
   {
     return this->ConfigFileStreams.at(config).get();
   }
 
+  cmGeneratedFileStream* GetDefaultFileStream() const override
+  {
+    return this->DefaultFileStream.get();
+  }
+
   cmGeneratedFileStream* GetCommonFileStream() const override
   {
     return this->CommonFileStream.get();
@@ -585,13 +615,19 @@
   void AppendNinjaFileArgument(GeneratedMakeCommand& command,
                                const std::string& config) const override;
 
-  static std::string GetNinjaFilename(const std::string& config);
+  static std::string GetNinjaImplFilename(const std::string& config);
+  static std::string GetNinjaConfigFilename(const std::string& config);
 
   void AddRebuildManifestOutputs(cmNinjaDeps& outputs) const override;
 
   void GetQtAutoGenConfigs(std::vector<std::string>& configs) const override;
 
-  bool WriteDefaultBuildFile() override;
+  const char* GetDefaultBuildType() const override;
+
+  const char* GetDefaultBuildAlias() const override;
+
+  std::set<std::string> GetCrossConfigs(
+    const std::string& fileConfig) const override;
 
 protected:
   bool OpenBuildFileStreams() override;
@@ -599,8 +635,11 @@
 
 private:
   std::map<std::string, std::unique_ptr<cmGeneratedFileStream>>
+    ImplFileStreams;
+  std::map<std::string, std::unique_ptr<cmGeneratedFileStream>>
     ConfigFileStreams;
   std::unique_ptr<cmGeneratedFileStream> CommonFileStream;
+  std::unique_ptr<cmGeneratedFileStream> DefaultFileStream;
 };
 
 #endif // ! cmGlobalNinjaGenerator_h
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index 0591758..90c9ef0 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -892,6 +892,9 @@
 
   // Keep track of targets already listed.
   std::set<std::string> emittedTargets;
+  std::set<std::string> utility_targets;
+  std::set<std::string> globals_targets;
+  std::set<std::string> project_targets;
 
   // for each local generator
   for (const auto& localGen : this->LocalGenerators) {
@@ -907,18 +910,30 @@
             (type == cmStateEnums::STATIC_LIBRARY) ||
             (type == cmStateEnums::SHARED_LIBRARY) ||
             (type == cmStateEnums::MODULE_LIBRARY) ||
-            (type == cmStateEnums::OBJECT_LIBRARY) ||
-            (type == cmStateEnums::GLOBAL_TARGET) ||
-            (type == cmStateEnums::UTILITY)) {
-          std::string const& name = target->GetName();
-          if (emittedTargets.insert(name).second) {
-            path = cmStrCat("... ", name);
-            lg->AppendEcho(commands, path);
-          }
+            (type == cmStateEnums::OBJECT_LIBRARY)) {
+          project_targets.insert(target->GetName());
+        } else if (type == cmStateEnums::GLOBAL_TARGET) {
+          globals_targets.insert(target->GetName());
+        } else if (type == cmStateEnums::UTILITY) {
+          utility_targets.insert(target->GetName());
         }
       }
     }
   }
+
+  for (std::string const& name : globals_targets) {
+    path = cmStrCat("... ", name);
+    lg->AppendEcho(commands, path);
+  }
+  for (std::string const& name : utility_targets) {
+    path = cmStrCat("... ", name);
+    lg->AppendEcho(commands, path);
+  }
+  for (std::string const& name : project_targets) {
+    path = cmStrCat("... ", name);
+    lg->AppendEcho(commands, path);
+  }
+
   for (std::string const& o : lg->GetLocalHelp()) {
     path = cmStrCat("... ", o);
     lg->AppendEcho(commands, path);
diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx
index 779753e..f549b6a 100644
--- a/Source/cmGlobalVisualStudio14Generator.cxx
+++ b/Source/cmGlobalVisualStudio14Generator.cxx
@@ -2,7 +2,8 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGlobalVisualStudio14Generator.h"
 
-#include "cmAlgorithms.h"
+#include <cm/vector>
+
 #include "cmDocumentationEntry.h"
 #include "cmLocalVisualStudio10Generator.h"
 #include "cmMakefile.h"
@@ -303,7 +304,7 @@
 
   // Skip SDKs that do not contain <um/windows.h> because that indicates that
   // only the UCRT MSIs were installed for them.
-  cmEraseIf(sdks, NoWindowsH());
+  cm::erase_if(sdks, NoWindowsH());
 
   // Only use the filename, which will be the SDK version.
   for (std::string& i : sdks) {
@@ -313,7 +314,7 @@
   // Skip SDKs that cannot be used with our toolset.
   std::string maxVersion = this->GetWindows10SDKMaxVersion();
   if (!maxVersion.empty()) {
-    cmEraseIf(sdks, WindowsSDKTooRecent(maxVersion));
+    cm::erase_if(sdks, WindowsSDKTooRecent(maxVersion));
   }
 
   // Sort the results to make sure we select the most recent one.
diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h
index 4f2007f..29a5c2c 100644
--- a/Source/cmGlobalVisualStudioGenerator.h
+++ b/Source/cmGlobalVisualStudioGenerator.h
@@ -150,6 +150,8 @@
   bool Open(const std::string& bindir, const std::string& projectName,
             bool dryRun) override;
 
+  bool IsVisualStudio() const override { return true; }
+
 protected:
   cmGlobalVisualStudioGenerator(cmake* cm,
                                 std::string const& platformInGeneratorName);
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 607b2b3..f887284 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -2357,9 +2357,6 @@
   buildSettings->AddAttribute("SECTORDER_FLAGS", this->CreateString(""));
   buildSettings->AddAttribute("USE_HEADERMAP", this->CreateString("NO"));
   cmXCodeObject* group = this->CreateObject(cmXCodeObject::OBJECT_LIST);
-  group->AddObject(this->CreateString("-Wmost"));
-  group->AddObject(this->CreateString("-Wno-four-char-constants"));
-  group->AddObject(this->CreateString("-Wno-unknown-pragmas"));
   group->AddObject(this->CreateString("$(inherited)"));
   buildSettings->AddAttribute("WARNING_CFLAGS", group);
 
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 0c52cc5..c67358f 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -85,7 +85,7 @@
   std::string DefaultComponentName;
 };
 
-cmInstallTargetGenerator* CreateInstallTargetGenerator(
+std::unique_ptr<cmInstallTargetGenerator> CreateInstallTargetGenerator(
   cmTarget& target, const cmInstallCommandArguments& args, bool impLib,
   cmListFileBacktrace const& backtrace, const std::string& destination,
   bool forceOpt = false, bool namelink = false)
@@ -93,18 +93,17 @@
   cmInstallGenerator::MessageLevel message =
     cmInstallGenerator::SelectMessageLevel(target.GetMakefile());
   target.SetHaveInstallRule(true);
-  const char* component = namelink ? args.GetNamelinkComponent().c_str()
-                                   : args.GetComponent().c_str();
-  auto g = new cmInstallTargetGenerator(
-    target.GetName(), destination.c_str(), impLib,
-    args.GetPermissions().c_str(), args.GetConfigurations(), component,
-    message, args.GetExcludeFromAll(), args.GetOptional() || forceOpt,
-    backtrace);
-  target.AddInstallGenerator(g);
+  const std::string& component =
+    namelink ? args.GetNamelinkComponent() : args.GetComponent();
+  auto g = cm::make_unique<cmInstallTargetGenerator>(
+    target.GetName(), destination, impLib, args.GetPermissions(),
+    args.GetConfigurations(), component, message, args.GetExcludeFromAll(),
+    args.GetOptional() || forceOpt, backtrace);
+  target.AddInstallGenerator(g.get());
   return g;
 }
 
-cmInstallTargetGenerator* CreateInstallTargetGenerator(
+std::unique_ptr<cmInstallTargetGenerator> CreateInstallTargetGenerator(
   cmTarget& target, const cmInstallCommandArguments& args, bool impLib,
   cmListFileBacktrace const& backtrace, bool forceOpt = false,
   bool namelink = false)
@@ -114,20 +113,20 @@
                                       namelink);
 }
 
-cmInstallFilesGenerator* CreateInstallFilesGenerator(
+std::unique_ptr<cmInstallFilesGenerator> CreateInstallFilesGenerator(
   cmMakefile* mf, const std::vector<std::string>& absFiles,
   const cmInstallCommandArguments& args, bool programs,
   const std::string& destination)
 {
   cmInstallGenerator::MessageLevel message =
     cmInstallGenerator::SelectMessageLevel(mf);
-  return new cmInstallFilesGenerator(
-    absFiles, destination.c_str(), programs, args.GetPermissions().c_str(),
-    args.GetConfigurations(), args.GetComponent().c_str(), message,
-    args.GetExcludeFromAll(), args.GetRename().c_str(), args.GetOptional());
+  return cm::make_unique<cmInstallFilesGenerator>(
+    absFiles, destination, programs, args.GetPermissions(),
+    args.GetConfigurations(), args.GetComponent(), message,
+    args.GetExcludeFromAll(), args.GetRename(), args.GetOptional());
 }
 
-cmInstallFilesGenerator* CreateInstallFilesGenerator(
+std::unique_ptr<cmInstallFilesGenerator> CreateInstallFilesGenerator(
   cmMakefile* mf, const std::vector<std::string>& absFiles,
   const cmInstallCommandArguments& args, bool programs)
 {
@@ -196,13 +195,15 @@
         status.SetError("given a directory as value of SCRIPT argument.");
         return false;
       }
-      helper.Makefile->AddInstallGenerator(new cmInstallScriptGenerator(
-        script.c_str(), false, component.c_str(), exclude_from_all));
+      helper.Makefile->AddInstallGenerator(
+        cm::make_unique<cmInstallScriptGenerator>(script, false, component,
+                                                  exclude_from_all));
     } else if (doing_code) {
       doing_code = false;
       std::string const& code = arg;
-      helper.Makefile->AddInstallGenerator(new cmInstallScriptGenerator(
-        code.c_str(), true, component.c_str(), exclude_from_all));
+      helper.Makefile->AddInstallGenerator(
+        cm::make_unique<cmInstallScriptGenerator>(code, true, component,
+                                                  exclude_from_all));
     }
   }
 
@@ -449,16 +450,16 @@
   for (cmTarget* ti : targets) {
     // Handle each target type.
     cmTarget& target = *ti;
-    cmInstallTargetGenerator* archiveGenerator = nullptr;
-    cmInstallTargetGenerator* libraryGenerator = nullptr;
-    cmInstallTargetGenerator* namelinkGenerator = nullptr;
-    cmInstallTargetGenerator* runtimeGenerator = nullptr;
-    cmInstallTargetGenerator* objectGenerator = nullptr;
-    cmInstallTargetGenerator* frameworkGenerator = nullptr;
-    cmInstallTargetGenerator* bundleGenerator = nullptr;
-    cmInstallFilesGenerator* privateHeaderGenerator = nullptr;
-    cmInstallFilesGenerator* publicHeaderGenerator = nullptr;
-    cmInstallFilesGenerator* resourceGenerator = nullptr;
+    std::unique_ptr<cmInstallTargetGenerator> archiveGenerator;
+    std::unique_ptr<cmInstallTargetGenerator> libraryGenerator;
+    std::unique_ptr<cmInstallTargetGenerator> namelinkGenerator;
+    std::unique_ptr<cmInstallTargetGenerator> runtimeGenerator;
+    std::unique_ptr<cmInstallTargetGenerator> objectGenerator;
+    std::unique_ptr<cmInstallTargetGenerator> frameworkGenerator;
+    std::unique_ptr<cmInstallTargetGenerator> bundleGenerator;
+    std::unique_ptr<cmInstallFilesGenerator> privateHeaderGenerator;
+    std::unique_ptr<cmInstallFilesGenerator> publicHeaderGenerator;
+    std::unique_ptr<cmInstallFilesGenerator> resourceGenerator;
 
     // Track whether this is a namelink-only rule.
     bool namelinkOnly = false;
@@ -485,7 +486,7 @@
             runtimeGenerator = CreateInstallTargetGenerator(
               target, runtimeArgs, false, helper.Makefile->GetBacktrace());
           }
-          if ((archiveGenerator == nullptr) && (runtimeGenerator == nullptr)) {
+          if (!archiveGenerator && !runtimeGenerator) {
             archiveGenerator = CreateInstallTargetGenerator(
               target, archiveArgs, true, helper.Makefile->GetBacktrace(),
               helper.GetArchiveDestination(nullptr));
@@ -712,43 +713,18 @@
       }
     }
 
-    // Keep track of whether we're installing anything in each category
-    installsArchive = installsArchive || archiveGenerator != nullptr;
-    installsLibrary = installsLibrary || libraryGenerator != nullptr;
-    installsNamelink = installsNamelink || namelinkGenerator != nullptr;
-    installsRuntime = installsRuntime || runtimeGenerator != nullptr;
-    installsObject = installsObject || objectGenerator != nullptr;
-    installsFramework = installsFramework || frameworkGenerator != nullptr;
-    installsBundle = installsBundle || bundleGenerator != nullptr;
-    installsPrivateHeader =
-      installsPrivateHeader || privateHeaderGenerator != nullptr;
-    installsPublicHeader =
-      installsPublicHeader || publicHeaderGenerator != nullptr;
-    installsResource = installsResource || resourceGenerator;
-
-    helper.Makefile->AddInstallGenerator(archiveGenerator);
-    helper.Makefile->AddInstallGenerator(libraryGenerator);
-    helper.Makefile->AddInstallGenerator(namelinkGenerator);
-    helper.Makefile->AddInstallGenerator(runtimeGenerator);
-    helper.Makefile->AddInstallGenerator(objectGenerator);
-    helper.Makefile->AddInstallGenerator(frameworkGenerator);
-    helper.Makefile->AddInstallGenerator(bundleGenerator);
-    helper.Makefile->AddInstallGenerator(privateHeaderGenerator);
-    helper.Makefile->AddInstallGenerator(publicHeaderGenerator);
-    helper.Makefile->AddInstallGenerator(resourceGenerator);
-
     // Add this install rule to an export if one was specified and
     // this is not a namelink-only rule.
     if (!exports.empty() && !namelinkOnly) {
       auto te = cm::make_unique<cmTargetExport>();
       te->TargetName = target.GetName();
-      te->ArchiveGenerator = archiveGenerator;
-      te->BundleGenerator = bundleGenerator;
-      te->FrameworkGenerator = frameworkGenerator;
-      te->HeaderGenerator = publicHeaderGenerator;
-      te->LibraryGenerator = libraryGenerator;
-      te->RuntimeGenerator = runtimeGenerator;
-      te->ObjectsGenerator = objectGenerator;
+      te->ArchiveGenerator = archiveGenerator.get();
+      te->BundleGenerator = bundleGenerator.get();
+      te->FrameworkGenerator = frameworkGenerator.get();
+      te->HeaderGenerator = publicHeaderGenerator.get();
+      te->LibraryGenerator = libraryGenerator.get();
+      te->RuntimeGenerator = runtimeGenerator.get();
+      te->ObjectsGenerator = objectGenerator.get();
       te->InterfaceIncludeDirectories =
         cmJoin(includesArgs.GetIncludeDirs(), ";");
 
@@ -756,6 +732,29 @@
         ->GetExportSets()[exports]
         .AddTargetExport(std::move(te));
     }
+
+    // Keep track of whether we're installing anything in each category
+    installsArchive = installsArchive || archiveGenerator;
+    installsLibrary = installsLibrary || libraryGenerator;
+    installsNamelink = installsNamelink || namelinkGenerator;
+    installsRuntime = installsRuntime || runtimeGenerator;
+    installsObject = installsObject || objectGenerator;
+    installsFramework = installsFramework || frameworkGenerator;
+    installsBundle = installsBundle || bundleGenerator;
+    installsPrivateHeader = installsPrivateHeader || privateHeaderGenerator;
+    installsPublicHeader = installsPublicHeader || publicHeaderGenerator;
+    installsResource = installsResource || resourceGenerator;
+
+    helper.Makefile->AddInstallGenerator(std::move(archiveGenerator));
+    helper.Makefile->AddInstallGenerator(std::move(libraryGenerator));
+    helper.Makefile->AddInstallGenerator(std::move(namelinkGenerator));
+    helper.Makefile->AddInstallGenerator(std::move(runtimeGenerator));
+    helper.Makefile->AddInstallGenerator(std::move(objectGenerator));
+    helper.Makefile->AddInstallGenerator(std::move(frameworkGenerator));
+    helper.Makefile->AddInstallGenerator(std::move(bundleGenerator));
+    helper.Makefile->AddInstallGenerator(std::move(privateHeaderGenerator));
+    helper.Makefile->AddInstallGenerator(std::move(publicHeaderGenerator));
+    helper.Makefile->AddInstallGenerator(std::move(resourceGenerator));
   }
 
   // Tell the global generator about any installation component names
@@ -943,7 +942,7 @@
   bool exclude_from_all = false;
   bool message_never = false;
   std::vector<std::string> dirs;
-  const char* destination = nullptr;
+  const std::string* destination = nullptr;
   std::string permissions_file;
   std::string permissions_dir;
   std::vector<std::string> configurations;
@@ -1102,7 +1101,7 @@
     } else if (doing == DoingConfigurations) {
       configurations.push_back(args[i]);
     } else if (doing == DoingDestination) {
-      destination = args[i].c_str();
+      destination = &args[i];
       doing = DoingNone;
     } else if (doing == DoingType) {
       if (allowedTypes.count(args[i]) == 0) {
@@ -1188,7 +1187,7 @@
       return false;
     }
     destinationStr = helper.GetDestinationForType(nullptr, type);
-    destination = destinationStr.c_str();
+    destination = &destinationStr;
   } else if (!type.empty()) {
     status.SetError(cmStrCat(args[0],
                              " given both TYPE and DESTINATION "
@@ -1200,10 +1199,10 @@
     cmInstallGenerator::SelectMessageLevel(helper.Makefile, message_never);
 
   // Create the directory install generator.
-  helper.Makefile->AddInstallGenerator(new cmInstallDirectoryGenerator(
-    dirs, destination, permissions_file.c_str(), permissions_dir.c_str(),
-    configurations, component.c_str(), message, exclude_from_all,
-    literal_args.c_str(), optional));
+  helper.Makefile->AddInstallGenerator(
+    cm::make_unique<cmInstallDirectoryGenerator>(
+      dirs, *destination, permissions_file, permissions_dir, configurations,
+      component, message, exclude_from_all, literal_args, optional));
 
   // Tell the global generator about any installation component names
   // specified.
@@ -1291,12 +1290,11 @@
     cmInstallGenerator::SelectMessageLevel(helper.Makefile);
 
   // Create the export install generator.
-  cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator(
-    &exportSet, ica.GetDestination().c_str(), ica.GetPermissions().c_str(),
-    ica.GetConfigurations(), ica.GetComponent().c_str(), message,
-    ica.GetExcludeFromAll(), fname.c_str(), name_space.c_str(), exportOld,
-    true);
-  helper.Makefile->AddInstallGenerator(exportGenerator);
+  helper.Makefile->AddInstallGenerator(
+    cm::make_unique<cmInstallExportGenerator>(
+      &exportSet, ica.GetDestination(), ica.GetPermissions(),
+      ica.GetConfigurations(), ica.GetComponent(), message,
+      ica.GetExcludeFromAll(), fname, name_space, exportOld, true));
 
   return true;
 #else
@@ -1405,12 +1403,11 @@
     cmInstallGenerator::SelectMessageLevel(helper.Makefile);
 
   // Create the export install generator.
-  cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator(
-    &exportSet, ica.GetDestination().c_str(), ica.GetPermissions().c_str(),
-    ica.GetConfigurations(), ica.GetComponent().c_str(), message,
-    ica.GetExcludeFromAll(), fname.c_str(), name_space.c_str(), exportOld,
-    false);
-  helper.Makefile->AddInstallGenerator(exportGenerator);
+  helper.Makefile->AddInstallGenerator(
+    cm::make_unique<cmInstallExportGenerator>(
+      &exportSet, ica.GetDestination(), ica.GetPermissions(),
+      ica.GetConfigurations(), ica.GetComponent(), message,
+      ica.GetExcludeFromAll(), fname, name_space, exportOld, false));
 
   return true;
 }
diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx
index 259c7f7..175e7cf 100644
--- a/Source/cmInstallDirectoryGenerator.cxx
+++ b/Source/cmInstallDirectoryGenerator.cxx
@@ -2,6 +2,8 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmInstallDirectoryGenerator.h"
 
+#include <utility>
+
 #include "cmGeneratorExpression.h"
 #include "cmInstallType.h"
 #include "cmLocalGenerator.h"
@@ -10,18 +12,18 @@
 #include "cmSystemTools.h"
 
 cmInstallDirectoryGenerator::cmInstallDirectoryGenerator(
-  std::vector<std::string> const& dirs, const char* dest,
-  const char* file_permissions, const char* dir_permissions,
-  std::vector<std::string> const& configurations, const char* component,
-  MessageLevel message, bool exclude_from_all, const char* literal_args,
+  std::vector<std::string> const& dirs, std::string const& dest,
+  std::string file_permissions, std::string dir_permissions,
+  std::vector<std::string> const& configurations, std::string const& component,
+  MessageLevel message, bool exclude_from_all, std::string literal_args,
   bool optional)
   : cmInstallGenerator(dest, configurations, component, message,
                        exclude_from_all)
   , LocalGenerator(nullptr)
   , Directories(dirs)
-  , FilePermissions(file_permissions)
-  , DirPermissions(dir_permissions)
-  , LiteralArguments(literal_args)
+  , FilePermissions(std::move(file_permissions))
+  , DirPermissions(std::move(dir_permissions))
+  , LiteralArguments(std::move(literal_args))
   , Optional(optional)
 {
   // We need per-config actions if destination have generator expressions.
diff --git a/Source/cmInstallDirectoryGenerator.h b/Source/cmInstallDirectoryGenerator.h
index 84c0694..bec89df 100644
--- a/Source/cmInstallDirectoryGenerator.h
+++ b/Source/cmInstallDirectoryGenerator.h
@@ -21,12 +21,13 @@
 {
 public:
   cmInstallDirectoryGenerator(std::vector<std::string> const& dirs,
-                              const char* dest, const char* file_permissions,
-                              const char* dir_permissions,
+                              std::string const& dest,
+                              std::string file_permissions,
+                              std::string dir_permissions,
                               std::vector<std::string> const& configurations,
-                              const char* component, MessageLevel message,
-                              bool exclude_from_all, const char* literal_args,
-                              bool optional = false);
+                              std::string const& component,
+                              MessageLevel message, bool exclude_from_all,
+                              std::string literal_args, bool optional = false);
   ~cmInstallDirectoryGenerator() override;
 
   bool Compute(cmLocalGenerator* lg) override;
@@ -41,11 +42,11 @@
                                Indent indent,
                                std::vector<std::string> const& dirs);
   cmLocalGenerator* LocalGenerator;
-  std::vector<std::string> Directories;
-  std::string FilePermissions;
-  std::string DirPermissions;
-  std::string LiteralArguments;
-  bool Optional;
+  std::vector<std::string> const Directories;
+  std::string const FilePermissions;
+  std::string const DirPermissions;
+  std::string const LiteralArguments;
+  bool const Optional;
 };
 
 #endif
diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx
index cba68be..2c53a28 100644
--- a/Source/cmInstallExportGenerator.cxx
+++ b/Source/cmInstallExportGenerator.cxx
@@ -18,16 +18,16 @@
 #include "cmSystemTools.h"
 
 cmInstallExportGenerator::cmInstallExportGenerator(
-  cmExportSet* exportSet, const char* destination,
-  const char* file_permissions, std::vector<std::string> const& configurations,
-  const char* component, MessageLevel message, bool exclude_from_all,
-  const char* filename, const char* name_space, bool exportOld, bool android)
+  cmExportSet* exportSet, std::string const& destination,
+  std::string file_permissions, std::vector<std::string> const& configurations,
+  std::string const& component, MessageLevel message, bool exclude_from_all,
+  std::string filename, std::string name_space, bool exportOld, bool android)
   : cmInstallGenerator(destination, configurations, component, message,
                        exclude_from_all)
   , ExportSet(exportSet)
-  , FilePermissions(file_permissions)
-  , FileName(filename)
-  , Namespace(name_space)
+  , FilePermissions(std::move(file_permissions))
+  , FileName(std::move(filename))
+  , Namespace(std::move(name_space))
   , ExportOld(exportOld)
   , LocalGenerator(nullptr)
 {
diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h
index f44127e..cf28b35 100644
--- a/Source/cmInstallExportGenerator.h
+++ b/Source/cmInstallExportGenerator.h
@@ -23,12 +23,12 @@
 class cmInstallExportGenerator : public cmInstallGenerator
 {
 public:
-  cmInstallExportGenerator(cmExportSet* exportSet, const char* dest,
-                           const char* file_permissions,
+  cmInstallExportGenerator(cmExportSet* exportSet, std::string const& dest,
+                           std::string file_permissions,
                            const std::vector<std::string>& configurations,
-                           const char* component, MessageLevel message,
-                           bool exclude_from_all, const char* filename,
-                           const char* name_space, bool exportOld,
+                           std::string const& component, MessageLevel message,
+                           bool exclude_from_all, std::string filename,
+                           std::string name_space, bool exportOld,
                            bool android);
   ~cmInstallExportGenerator() override;
 
@@ -52,11 +52,11 @@
   void ComputeTempDir();
   size_t GetMaxConfigLength() const;
 
-  cmExportSet* ExportSet;
-  std::string FilePermissions;
-  std::string FileName;
-  std::string Namespace;
-  bool ExportOld;
+  cmExportSet* const ExportSet;
+  std::string const FilePermissions;
+  std::string const FileName;
+  std::string const Namespace;
+  bool const ExportOld;
   cmLocalGenerator* LocalGenerator;
 
   std::string TempDir;
diff --git a/Source/cmInstallFilesCommand.cxx b/Source/cmInstallFilesCommand.cxx
index efbcb98..3c59f01 100644
--- a/Source/cmInstallFilesCommand.cxx
+++ b/Source/cmInstallFilesCommand.cxx
@@ -2,6 +2,8 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmInstallFilesCommand.h"
 
+#include <cm/memory>
+
 #include "cmExecutionStatus.h"
 #include "cmGeneratorExpression.h"
 #include "cmGlobalGenerator.h"
@@ -113,17 +115,17 @@
   }
 
   // Use a file install generator.
-  const char* no_permissions = "";
-  const char* no_rename = "";
+  const std::string no_permissions;
+  const std::string no_rename;
   bool no_exclude_from_all = false;
   std::string no_component =
     makefile.GetSafeDefinition("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME");
   std::vector<std::string> no_configurations;
   cmInstallGenerator::MessageLevel message =
     cmInstallGenerator::SelectMessageLevel(&makefile);
-  makefile.AddInstallGenerator(new cmInstallFilesGenerator(
-    files, destination.c_str(), false, no_permissions, no_configurations,
-    no_component.c_str(), message, no_exclude_from_all, no_rename));
+  makefile.AddInstallGenerator(cm::make_unique<cmInstallFilesGenerator>(
+    files, destination, false, no_permissions, no_configurations, no_component,
+    message, no_exclude_from_all, no_rename));
 }
 
 /**
diff --git a/Source/cmInstallFilesGenerator.cxx b/Source/cmInstallFilesGenerator.cxx
index f5b69a5..ad2f84e 100644
--- a/Source/cmInstallFilesGenerator.cxx
+++ b/Source/cmInstallFilesGenerator.cxx
@@ -2,6 +2,8 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmInstallFilesGenerator.h"
 
+#include <utility>
+
 #include "cmGeneratorExpression.h"
 #include "cmInstallType.h"
 #include "cmStringAlgorithms.h"
@@ -9,16 +11,17 @@
 class cmLocalGenerator;
 
 cmInstallFilesGenerator::cmInstallFilesGenerator(
-  std::vector<std::string> const& files, const char* dest, bool programs,
-  const char* file_permissions, std::vector<std::string> const& configurations,
-  const char* component, MessageLevel message, bool exclude_from_all,
-  const char* rename, bool optional)
+  std::vector<std::string> const& files, std::string const& dest,
+  bool programs, std::string file_permissions,
+  std::vector<std::string> const& configurations, std::string const& component,
+  MessageLevel message, bool exclude_from_all, std::string rename,
+  bool optional)
   : cmInstallGenerator(dest, configurations, component, message,
                        exclude_from_all)
   , LocalGenerator(nullptr)
   , Files(files)
-  , FilePermissions(file_permissions)
-  , Rename(rename)
+  , FilePermissions(std::move(file_permissions))
+  , Rename(std::move(rename))
   , Programs(programs)
   , Optional(optional)
 {
diff --git a/Source/cmInstallFilesGenerator.h b/Source/cmInstallFilesGenerator.h
index a680037..8266603 100644
--- a/Source/cmInstallFilesGenerator.h
+++ b/Source/cmInstallFilesGenerator.h
@@ -21,11 +21,11 @@
 {
 public:
   cmInstallFilesGenerator(std::vector<std::string> const& files,
-                          const char* dest, bool programs,
-                          const char* file_permissions,
+                          std::string const& dest, bool programs,
+                          std::string file_permissions,
                           std::vector<std::string> const& configurations,
-                          const char* component, MessageLevel message,
-                          bool exclude_from_all, const char* rename,
+                          std::string const& component, MessageLevel message,
+                          bool exclude_from_all, std::string rename,
                           bool optional = false);
   ~cmInstallFilesGenerator() override;
 
@@ -42,11 +42,11 @@
                            std::vector<std::string> const& files);
 
   cmLocalGenerator* LocalGenerator;
-  std::vector<std::string> Files;
-  std::string FilePermissions;
-  std::string Rename;
-  bool Programs;
-  bool Optional;
+  std::vector<std::string> const Files;
+  std::string const FilePermissions;
+  std::string const Rename;
+  bool const Programs;
+  bool const Optional;
 };
 
 #endif
diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx
index ec17361..0665895 100644
--- a/Source/cmInstallGenerator.cxx
+++ b/Source/cmInstallGenerator.cxx
@@ -3,16 +3,17 @@
 #include "cmInstallGenerator.h"
 
 #include <ostream>
+#include <utility>
 
 #include "cmMakefile.h"
 #include "cmSystemTools.h"
 
 cmInstallGenerator::cmInstallGenerator(
-  const char* destination, std::vector<std::string> const& configurations,
-  const char* component, MessageLevel message, bool exclude_from_all)
+  std::string destination, std::vector<std::string> const& configurations,
+  std::string component, MessageLevel message, bool exclude_from_all)
   : cmScriptGenerator("CMAKE_INSTALL_CONFIG_NAME", configurations)
-  , Destination(destination ? destination : "")
-  , Component(component ? component : "")
+  , Destination(std::move(destination))
+  , Component(std::move(component))
   , Message(message)
   , ExcludeFromAll(exclude_from_all)
 {
@@ -139,8 +140,8 @@
   os << ")\n";
 }
 
-std::string cmInstallGenerator::CreateComponentTest(const char* component,
-                                                    bool exclude_from_all)
+std::string cmInstallGenerator::CreateComponentTest(
+  const std::string& component, bool exclude_from_all)
 {
   std::string result = R"("x${CMAKE_INSTALL_COMPONENT}x" STREQUAL "x)";
   result += component;
@@ -158,7 +159,7 @@
 
   // Begin this block of installation.
   std::string component_test =
-    this->CreateComponentTest(this->Component.c_str(), this->ExcludeFromAll);
+    this->CreateComponentTest(this->Component, this->ExcludeFromAll);
   os << indent << "if(" << component_test << ")\n";
 
   // Generate the script possibly with per-configuration code.
diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h
index 024027d..d786d24 100644
--- a/Source/cmInstallGenerator.h
+++ b/Source/cmInstallGenerator.h
@@ -30,9 +30,9 @@
     MessageNever
   };
 
-  cmInstallGenerator(const char* destination,
+  cmInstallGenerator(std::string destination,
                      std::vector<std::string> const& configurations,
-                     const char* component, MessageLevel message,
+                     std::string component, MessageLevel message,
                      bool exclude_from_all);
   ~cmInstallGenerator() override;
 
@@ -65,14 +65,14 @@
 protected:
   void GenerateScript(std::ostream& os) override;
 
-  std::string CreateComponentTest(const char* component,
+  std::string CreateComponentTest(const std::string& component,
                                   bool exclude_from_all);
 
   // Information shared by most generator types.
-  std::string Destination;
-  std::string Component;
-  MessageLevel Message;
-  bool ExcludeFromAll;
+  std::string const Destination;
+  std::string const Component;
+  MessageLevel const Message;
+  bool const ExcludeFromAll;
 };
 
 #endif
diff --git a/Source/cmInstallProgramsCommand.cxx b/Source/cmInstallProgramsCommand.cxx
index 2088eae..be07fd4 100644
--- a/Source/cmInstallProgramsCommand.cxx
+++ b/Source/cmInstallProgramsCommand.cxx
@@ -2,6 +2,8 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmInstallProgramsCommand.h"
 
+#include <cm/memory>
+
 #include "cmExecutionStatus.h"
 #include "cmGeneratorExpression.h"
 #include "cmGlobalGenerator.h"
@@ -87,17 +89,17 @@
   }
 
   // Use a file install generator.
-  const char* no_permissions = "";
-  const char* no_rename = "";
+  const std::string no_permissions;
+  const std::string no_rename;
   bool no_exclude_from_all = false;
   std::string no_component =
     makefile.GetSafeDefinition("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME");
   std::vector<std::string> no_configurations;
   cmInstallGenerator::MessageLevel message =
     cmInstallGenerator::SelectMessageLevel(&makefile);
-  makefile.AddInstallGenerator(new cmInstallFilesGenerator(
-    files, destination.c_str(), true, no_permissions, no_configurations,
-    no_component.c_str(), message, no_exclude_from_all, no_rename));
+  makefile.AddInstallGenerator(cm::make_unique<cmInstallFilesGenerator>(
+    files, destination, true, no_permissions, no_configurations, no_component,
+    message, no_exclude_from_all, no_rename));
 }
 
 /**
diff --git a/Source/cmInstallScriptGenerator.cxx b/Source/cmInstallScriptGenerator.cxx
index ea29455..7cdf3b4 100644
--- a/Source/cmInstallScriptGenerator.cxx
+++ b/Source/cmInstallScriptGenerator.cxx
@@ -3,6 +3,7 @@
 #include "cmInstallScriptGenerator.h"
 
 #include <ostream>
+#include <utility>
 #include <vector>
 
 #include "cmGeneratorExpression.h"
@@ -11,13 +12,12 @@
 #include "cmPolicies.h"
 #include "cmScriptGenerator.h"
 
-cmInstallScriptGenerator::cmInstallScriptGenerator(const char* script,
-                                                   bool code,
-                                                   const char* component,
-                                                   bool exclude_from_all)
-  : cmInstallGenerator(nullptr, std::vector<std::string>(), component,
+cmInstallScriptGenerator::cmInstallScriptGenerator(
+  std::string script, bool code, std::string const& component,
+  bool exclude_from_all)
+  : cmInstallGenerator("", std::vector<std::string>(), component,
                        MessageDefault, exclude_from_all)
-  , Script(script)
+  , Script(std::move(script))
   , Code(code)
   , AllowGenex(false)
 {
diff --git a/Source/cmInstallScriptGenerator.h b/Source/cmInstallScriptGenerator.h
index 7efa321..0a9c4ba 100644
--- a/Source/cmInstallScriptGenerator.h
+++ b/Source/cmInstallScriptGenerator.h
@@ -19,8 +19,9 @@
 class cmInstallScriptGenerator : public cmInstallGenerator
 {
 public:
-  cmInstallScriptGenerator(const char* script, bool code,
-                           const char* component, bool exclude_from_all);
+  cmInstallScriptGenerator(std::string script, bool code,
+                           std::string const& component,
+                           bool exclude_from_all);
   ~cmInstallScriptGenerator() override;
 
   bool Compute(cmLocalGenerator* lg) override;
@@ -32,8 +33,8 @@
   void AddScriptInstallRule(std::ostream& os, Indent indent,
                             std::string const& script);
 
-  std::string Script;
-  bool Code;
+  std::string const Script;
+  bool const Code;
   cmLocalGenerator* LocalGenerator;
   bool AllowGenex;
 };
diff --git a/Source/cmInstallSubdirectoryGenerator.cxx b/Source/cmInstallSubdirectoryGenerator.cxx
index 8a0fefa..12bc92b 100644
--- a/Source/cmInstallSubdirectoryGenerator.cxx
+++ b/Source/cmInstallSubdirectoryGenerator.cxx
@@ -2,7 +2,9 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmInstallSubdirectoryGenerator.h"
 
+#include <memory>
 #include <sstream>
+#include <utility>
 #include <vector>
 
 #include "cmLocalGenerator.h"
@@ -12,11 +14,11 @@
 #include "cmSystemTools.h"
 
 cmInstallSubdirectoryGenerator::cmInstallSubdirectoryGenerator(
-  cmMakefile* makefile, const char* binaryDirectory, bool excludeFromAll)
-  : cmInstallGenerator(nullptr, std::vector<std::string>(), nullptr,
-                       MessageDefault, excludeFromAll)
+  cmMakefile* makefile, std::string binaryDirectory, bool excludeFromAll)
+  : cmInstallGenerator("", std::vector<std::string>(), "", MessageDefault,
+                       excludeFromAll)
   , Makefile(makefile)
-  , BinaryDirectory(binaryDirectory)
+  , BinaryDirectory(std::move(binaryDirectory))
 {
 }
 
@@ -24,7 +26,7 @@
 
 bool cmInstallSubdirectoryGenerator::HaveInstall()
 {
-  for (auto generator : this->Makefile->GetInstallGenerators()) {
+  for (const auto& generator : this->Makefile->GetInstallGenerators()) {
     if (generator->HaveInstall()) {
       return true;
     }
diff --git a/Source/cmInstallSubdirectoryGenerator.h b/Source/cmInstallSubdirectoryGenerator.h
index b99bdd5..f9cd0f1 100644
--- a/Source/cmInstallSubdirectoryGenerator.h
+++ b/Source/cmInstallSubdirectoryGenerator.h
@@ -20,7 +20,7 @@
 {
 public:
   cmInstallSubdirectoryGenerator(cmMakefile* makefile,
-                                 const char* binaryDirectory,
+                                 std::string binaryDirectory,
                                  bool excludeFromAll);
   ~cmInstallSubdirectoryGenerator() override;
 
@@ -33,8 +33,8 @@
 protected:
   void GenerateScript(std::ostream& os) override;
 
-  cmMakefile* Makefile;
-  std::string BinaryDirectory;
+  cmMakefile* const Makefile;
+  std::string const BinaryDirectory;
   cmLocalGenerator* LocalGenerator;
 };
 
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index 69c9b7e..e05daa8 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -25,15 +25,15 @@
 #include "cmake.h"
 
 cmInstallTargetGenerator::cmInstallTargetGenerator(
-  std::string targetName, const char* dest, bool implib,
-  const char* file_permissions, std::vector<std::string> const& configurations,
-  const char* component, MessageLevel message, bool exclude_from_all,
+  std::string targetName, std::string const& dest, bool implib,
+  std::string file_permissions, std::vector<std::string> const& configurations,
+  std::string const& component, MessageLevel message, bool exclude_from_all,
   bool optional, cmListFileBacktrace backtrace)
   : cmInstallGenerator(dest, configurations, component, message,
                        exclude_from_all)
   , TargetName(std::move(targetName))
   , Target(nullptr)
-  , FilePermissions(file_permissions)
+  , FilePermissions(std::move(file_permissions))
   , ImportLibrary(implib)
   , Optional(optional)
   , Backtrace(std::move(backtrace))
diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h
index 8730454..e21001f 100644
--- a/Source/cmInstallTargetGenerator.h
+++ b/Source/cmInstallTargetGenerator.h
@@ -23,11 +23,11 @@
 {
 public:
   cmInstallTargetGenerator(
-    std::string targetName, const char* dest, bool implib,
-    const char* file_permissions,
-    std::vector<std::string> const& configurations, const char* component,
-    MessageLevel message, bool exclude_from_all, bool optional,
-    cmListFileBacktrace backtrace = cmListFileBacktrace());
+    std::string targetName, std::string const& dest, bool implib,
+    std::string file_permissions,
+    std::vector<std::string> const& configurations,
+    std::string const& component, MessageLevel message, bool exclude_from_all,
+    bool optional, cmListFileBacktrace backtrace = cmListFileBacktrace());
   ~cmInstallTargetGenerator() override;
 
   /** Select the policy for installing shared library linkable name
@@ -106,13 +106,13 @@
                                const std::string& toDestDirPath);
   void IssueCMP0095Warning(const std::string& unescapedRpath);
 
-  std::string TargetName;
+  std::string const TargetName;
   cmGeneratorTarget* Target;
-  std::string FilePermissions;
+  std::string const FilePermissions;
   NamelinkModeType NamelinkMode;
-  bool ImportLibrary;
-  bool Optional;
-  cmListFileBacktrace Backtrace;
+  bool const ImportLibrary;
+  bool const Optional;
+  cmListFileBacktrace const Backtrace;
 };
 
 #endif
diff --git a/Source/cmJsonObjects.cxx b/Source/cmJsonObjects.cxx
index 54edabc..dd36386 100644
--- a/Source/cmJsonObjects.cxx
+++ b/Source/cmJsonObjects.cxx
@@ -487,10 +487,10 @@
     result[kHAS_INSTALL_RULE] = true;
 
     Json::Value installPaths = Json::arrayValue;
-    auto targetGenerators = target->Makefile->GetInstallGenerators();
-    for (auto installGenerator : targetGenerators) {
+    for (const auto& installGenerator :
+         target->Makefile->GetInstallGenerators()) {
       auto installTargetGenerator =
-        dynamic_cast<cmInstallTargetGenerator*>(installGenerator);
+        dynamic_cast<cmInstallTargetGenerator*>(installGenerator.get());
       if (installTargetGenerator != nullptr &&
           installTargetGenerator->GetTarget()->Target == target->Target) {
         auto dest = installTargetGenerator->GetDestination(config);
@@ -643,9 +643,9 @@
     // associated generators.
     bool hasInstallRule = false;
     for (const auto generator : projectIt.second) {
-      for (const auto installGen :
+      for (const auto& installGen :
            generator->GetMakefile()->GetInstallGenerators()) {
-        if (!dynamic_cast<cmInstallSubdirectoryGenerator*>(installGen)) {
+        if (!dynamic_cast<cmInstallSubdirectoryGenerator*>(installGen.get())) {
           hasInstallRule = true;
           break;
         }
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 1da6efe..d1a3454 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -315,9 +315,7 @@
   }
 
   // Ask each test generator to write its code.
-  std::vector<cmTestGenerator*> const& testers =
-    this->Makefile->GetTestGenerators();
-  for (cmTestGenerator* tester : testers) {
+  for (const auto& tester : this->Makefile->GetTestGenerators()) {
     tester->Compute(this);
     tester->Generate(fout, config, configurationTypes);
   }
@@ -363,9 +361,7 @@
 
 void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config)
 {
-  std::vector<cmGeneratorExpressionEvaluationFile*> ef =
-    this->Makefile->GetEvaluationFiles();
-  for (cmGeneratorExpressionEvaluationFile* geef : ef) {
+  for (const auto& geef : this->Makefile->GetEvaluationFiles()) {
     geef->CreateOutputFile(this, config);
   }
 }
@@ -373,8 +369,7 @@
 void cmLocalGenerator::ProcessEvaluationFiles(
   std::vector<std::string>& generatedFiles)
 {
-  for (cmGeneratorExpressionEvaluationFile* geef :
-       this->Makefile->GetEvaluationFiles()) {
+  for (const auto& geef : this->Makefile->GetEvaluationFiles()) {
     geef->Generate(this);
     if (cmSystemTools::GetFatalErrorOccured()) {
       return;
@@ -557,18 +552,17 @@
 
   // Ask each install generator to write its code.
   cmPolicies::PolicyStatus status = this->GetPolicyStatus(cmPolicies::CMP0082);
-  std::vector<cmInstallGenerator*> const& installers =
-    this->Makefile->GetInstallGenerators();
+  auto const& installers = this->Makefile->GetInstallGenerators();
   bool haveSubdirectoryInstall = false;
   bool haveInstallAfterSubdirectory = false;
   if (status == cmPolicies::WARN) {
-    for (cmInstallGenerator* installer : installers) {
+    for (const auto& installer : installers) {
       installer->CheckCMP0082(haveSubdirectoryInstall,
                               haveInstallAfterSubdirectory);
       installer->Generate(fout, config, configurationTypes);
     }
   } else {
-    for (cmInstallGenerator* installer : installers) {
+    for (const auto& installer : installers) {
       installer->Generate(fout, config, configurationTypes);
     }
   }
@@ -1177,7 +1171,7 @@
     }
 
     for (std::string const& i : impDirVec) {
-      if (implicitSet.insert(cmSystemTools::GetRealPath(i)).second) {
+      if (implicitSet.insert(this->GlobalGenerator->GetRealPath(i)).second) {
         implicitDirs.emplace_back(i);
       }
     }
@@ -1188,7 +1182,7 @@
                       &lang](std::string const& dir) {
     return (
       // Do not exclude directories that are not in an excluded set.
-      ((!cmContains(implicitSet, cmSystemTools::GetRealPath(dir))) &&
+      ((!cmContains(implicitSet, this->GlobalGenerator->GetRealPath(dir))) &&
        (!cmContains(implicitExclude, dir)))
       // Do not exclude entries of the CPATH environment variable even though
       // they are implicitly searched by the compiler.  They are meant to be
@@ -2009,8 +2003,16 @@
 
   // Treat the name as relative to the source directory in which it
   // was given.
-  dep = cmStrCat(this->StateSnapshot.GetDirectory().GetCurrentSource(), '/',
-                 inName);
+  dep = cmStrCat(this->GetCurrentSourceDirectory(), '/', inName);
+
+  // If the in-source path does not exist, assume it instead lives in the
+  // binary directory.
+  if (!cmSystemTools::FileExists(dep)) {
+    dep = cmStrCat(this->GetCurrentBinaryDirectory(), '/', inName);
+  }
+
+  dep = cmSystemTools::CollapseFullPath(dep, this->GetBinaryDirectory());
+
   return true;
 }
 
@@ -2220,10 +2222,11 @@
 static void AddInlineVisibilityCompileOption(std::string& flags,
                                              cmGeneratorTarget const* target,
                                              cmLocalGenerator* lg,
-                                             std::string* warnCMP0063)
+                                             std::string* warnCMP0063,
+                                             const std::string& lang)
 {
   std::string compileOption =
-    "CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN";
+    cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN");
   const char* opt = lg->GetMakefile()->GetDefinition(compileOption);
   if (!opt) {
     return;
@@ -2265,8 +2268,8 @@
 
   AddVisibilityCompileOption(flags, target, this, lang, pWarnCMP0063);
 
-  if (lang == "CXX") {
-    AddInlineVisibilityCompileOption(flags, target, this, pWarnCMP0063);
+  if (lang == "CXX" || lang == "OBJCXX") {
+    AddInlineVisibilityCompileOption(flags, target, this, pWarnCMP0063, lang);
   }
 
   if (!warnCMP0063.empty() && this->WarnCMP0063.insert(target).second) {
@@ -2418,163 +2421,170 @@
 
 void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
 {
-  // FIXME: Handle all configurations in multi-config generators.
-  std::string config;
-  if (!this->GetGlobalGenerator()->IsMultiConfig()) {
-    config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+  std::vector<std::string> configsList;
+  std::string configDefault = this->Makefile->GetConfigurations(configsList);
+  if (configsList.empty()) {
+    configsList.push_back(configDefault);
   }
-  const std::string buildType = cmSystemTools::UpperCase(config);
 
-  // FIXME: Refactor collection of sources to not evaluate object libraries.
-  std::vector<cmSourceFile*> sources;
-  target->GetSourceFiles(sources, buildType);
+  for (std::string const& config : configsList) {
+    const std::string buildType = cmSystemTools::UpperCase(config);
 
-  for (const std::string& lang : { "C", "CXX", "OBJC", "OBJCXX" }) {
-    auto langSources =
-      std::count_if(sources.begin(), sources.end(), [lang](cmSourceFile* sf) {
-        return lang == sf->GetLanguage() &&
-          !sf->GetProperty("SKIP_PRECOMPILE_HEADERS");
-      });
-    if (langSources == 0) {
-      continue;
-    }
+    // FIXME: Refactor collection of sources to not evaluate object libraries.
+    std::vector<cmSourceFile*> sources;
+    target->GetSourceFiles(sources, buildType);
 
-    const std::string pchSource = target->GetPchSource(config, lang);
-    const std::string pchHeader = target->GetPchHeader(config, lang);
-
-    if (pchSource.empty() || pchHeader.empty()) {
-      continue;
-    }
-
-    const std::string pchExtension =
-      this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION");
-
-    if (pchExtension.empty()) {
-      continue;
-    }
-
-    const char* pchReuseFrom =
-      target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
-
-    auto pch_sf = this->Makefile->GetOrCreateSource(
-      pchSource, false, cmSourceFileLocationKind::Known);
-
-    if (!this->GetGlobalGenerator()->IsXcode()) {
-      if (!pchReuseFrom) {
-        target->AddSource(pchSource, true);
+    for (const std::string& lang : { "C", "CXX", "OBJC", "OBJCXX" }) {
+      auto langSources = std::count_if(
+        sources.begin(), sources.end(), [lang](cmSourceFile* sf) {
+          return lang == sf->GetLanguage() &&
+            !sf->GetProperty("SKIP_PRECOMPILE_HEADERS");
+        });
+      if (langSources == 0) {
+        continue;
       }
 
-      const std::string pchFile = target->GetPchFile(config, lang);
+      const std::string pchSource = target->GetPchSource(config, lang);
+      const std::string pchHeader = target->GetPchHeader(config, lang);
 
-      // Exclude the pch files from linking
-      if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
+      if (pchSource.empty() || pchHeader.empty()) {
+        continue;
+      }
+
+      const std::string pchExtension =
+        this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION");
+
+      if (pchExtension.empty()) {
+        continue;
+      }
+
+      const char* pchReuseFrom =
+        target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
+
+      auto pch_sf = this->Makefile->GetOrCreateSource(
+        pchSource, false, cmSourceFileLocationKind::Known);
+
+      if (!this->GetGlobalGenerator()->IsXcode()) {
         if (!pchReuseFrom) {
-          pch_sf->SetProperty("OBJECT_OUTPUTS", pchFile.c_str());
-        } else {
-          auto reuseTarget =
-            this->GlobalGenerator->FindGeneratorTarget(pchReuseFrom);
-
-          if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) {
-
-            const std::string pdb_prefix =
-              this->GetGlobalGenerator()->IsMultiConfig()
-              ? cmStrCat(this->GlobalGenerator->GetCMakeCFGIntDir(), "/")
-              : "";
-
-            const std::string target_compile_pdb_dir = cmStrCat(
-              target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/",
-              target->GetName(), ".dir/");
-
-            const std::string copy_script =
-              cmStrCat(target_compile_pdb_dir, "copy_idb_pdb.cmake");
-            cmGeneratedFileStream file(copy_script);
-
-            file << "# CMake generated file\n";
-            for (auto extension : { ".pdb", ".idb" }) {
-              const std::string from_file = cmStrCat(
-                reuseTarget->GetLocalGenerator()->GetCurrentBinaryDirectory(),
-                "/", pchReuseFrom, ".dir/${PDB_PREFIX}", pchReuseFrom,
-                extension);
-
-              const std::string to_dir = cmStrCat(
-                target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/",
-                target->GetName(), ".dir/${PDB_PREFIX}");
-
-              const std::string to_file =
-                cmStrCat(to_dir, pchReuseFrom, extension);
-
-              std::string dest_file = to_file;
-
-              const std::string prefix = target->GetSafeProperty("PREFIX");
-              if (!prefix.empty()) {
-                dest_file = cmStrCat(to_dir, prefix, pchReuseFrom, extension);
-              }
-
-              file << "if (EXISTS \"" << from_file << "\" AND \"" << from_file
-                   << "\" IS_NEWER_THAN \"" << dest_file << "\")\n";
-              file << "  file(COPY \"" << from_file << "\""
-                   << " DESTINATION \"" << to_dir << "\")\n";
-              if (!prefix.empty()) {
-                file << "  file(REMOVE \"" << dest_file << "\")\n";
-                file << "  file(RENAME \"" << to_file << "\" \"" << dest_file
-                     << "\")\n";
-              }
-              file << "endif()\n";
-            }
-
-            cmCustomCommandLines commandLines = cmMakeSingleCommandLine(
-              { cmSystemTools::GetCMakeCommand(),
-                cmStrCat("-DPDB_PREFIX=", pdb_prefix), "-P", copy_script });
-
-            const std::string no_main_dependency;
-            const std::vector<std::string> no_deps;
-            const char* no_message = "";
-            const char* no_current_dir = nullptr;
-            std::vector<std::string> no_byproducts;
-
-            std::vector<std::string> outputs;
-            outputs.push_back(cmStrCat(target_compile_pdb_dir, pdb_prefix,
-                                       pchReuseFrom, ".pdb"));
-
-            if (this->GetGlobalGenerator()->IsMultiConfig()) {
-              this->AddCustomCommandToTarget(
-                target->GetName(), outputs, no_deps, commandLines,
-                cmCustomCommandType::PRE_BUILD, no_message, no_current_dir);
-            } else {
-              cmImplicitDependsList no_implicit_depends;
-              cmSourceFile* copy_rule = this->AddCustomCommandToOutput(
-                outputs, no_byproducts, no_deps, no_main_dependency,
-                no_implicit_depends, commandLines, no_message, no_current_dir);
-
-              if (copy_rule) {
-                target->AddSource(copy_rule->ResolveFullPath());
-              }
-            }
-
-            target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
-                                        target_compile_pdb_dir);
-          }
-
-          std::string pchSourceObj =
-            reuseTarget->GetPchFileObject(config, lang);
-
-          // Link to the pch object file
-          target->Target->AppendProperty(
-            "LINK_FLAGS",
-            cmStrCat(" ", this->ConvertToOutputFormat(pchSourceObj, SHELL)),
-            true);
+          target->AddSource(pchSource, true);
         }
-      } else {
-        pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str());
-      }
 
-      // Add pchHeader to source files, which will
-      // be grouped as "Precompile Header File"
-      auto pchHeader_sf = this->Makefile->GetOrCreateSource(
-        pchHeader, false, cmSourceFileLocationKind::Known);
-      std::string err;
-      pchHeader_sf->ResolveFullPath(&err);
-      target->AddSource(pchHeader);
+        const std::string pchFile = target->GetPchFile(config, lang);
+
+        // Exclude the pch files from linking
+        if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
+          if (!pchReuseFrom) {
+            pch_sf->SetProperty("OBJECT_OUTPUTS", pchFile.c_str());
+          } else {
+            auto reuseTarget =
+              this->GlobalGenerator->FindGeneratorTarget(pchReuseFrom);
+
+            if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) {
+
+              const std::string pdb_prefix =
+                this->GetGlobalGenerator()->IsMultiConfig()
+                ? cmStrCat(this->GlobalGenerator->GetCMakeCFGIntDir(), "/")
+                : "";
+
+              const std::string target_compile_pdb_dir = cmStrCat(
+                target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/",
+                target->GetName(), ".dir/");
+
+              const std::string copy_script =
+                cmStrCat(target_compile_pdb_dir, "copy_idb_pdb.cmake");
+              cmGeneratedFileStream file(copy_script);
+
+              file << "# CMake generated file\n";
+              for (auto extension : { ".pdb", ".idb" }) {
+                const std::string from_file =
+                  cmStrCat(reuseTarget->GetLocalGenerator()
+                             ->GetCurrentBinaryDirectory(),
+                           "/", pchReuseFrom, ".dir/${PDB_PREFIX}",
+                           pchReuseFrom, extension);
+
+                const std::string to_dir = cmStrCat(
+                  target->GetLocalGenerator()->GetCurrentBinaryDirectory(),
+                  "/", target->GetName(), ".dir/${PDB_PREFIX}");
+
+                const std::string to_file =
+                  cmStrCat(to_dir, pchReuseFrom, extension);
+
+                std::string dest_file = to_file;
+
+                const std::string prefix = target->GetSafeProperty("PREFIX");
+                if (!prefix.empty()) {
+                  dest_file =
+                    cmStrCat(to_dir, prefix, pchReuseFrom, extension);
+                }
+
+                file << "if (EXISTS \"" << from_file << "\" AND \""
+                     << from_file << "\" IS_NEWER_THAN \"" << dest_file
+                     << "\")\n";
+                file << "  file(COPY \"" << from_file << "\""
+                     << " DESTINATION \"" << to_dir << "\")\n";
+                if (!prefix.empty()) {
+                  file << "  file(REMOVE \"" << dest_file << "\")\n";
+                  file << "  file(RENAME \"" << to_file << "\" \"" << dest_file
+                       << "\")\n";
+                }
+                file << "endif()\n";
+              }
+
+              cmCustomCommandLines commandLines = cmMakeSingleCommandLine(
+                { cmSystemTools::GetCMakeCommand(),
+                  cmStrCat("-DPDB_PREFIX=", pdb_prefix), "-P", copy_script });
+
+              const std::string no_main_dependency;
+              const std::vector<std::string> no_deps;
+              const char* no_message = "";
+              const char* no_current_dir = nullptr;
+              std::vector<std::string> no_byproducts;
+
+              std::vector<std::string> outputs;
+              outputs.push_back(cmStrCat(target_compile_pdb_dir, pdb_prefix,
+                                         pchReuseFrom, ".pdb"));
+
+              if (this->GetGlobalGenerator()->IsVisualStudio()) {
+                this->AddCustomCommandToTarget(
+                  target->GetName(), outputs, no_deps, commandLines,
+                  cmCustomCommandType::PRE_BUILD, no_message, no_current_dir);
+              } else {
+                cmImplicitDependsList no_implicit_depends;
+                cmSourceFile* copy_rule = this->AddCustomCommandToOutput(
+                  outputs, no_byproducts, no_deps, no_main_dependency,
+                  no_implicit_depends, commandLines, no_message,
+                  no_current_dir);
+
+                if (copy_rule) {
+                  target->AddSource(copy_rule->ResolveFullPath());
+                }
+              }
+
+              target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
+                                          target_compile_pdb_dir);
+            }
+
+            std::string pchSourceObj =
+              reuseTarget->GetPchFileObject(config, lang);
+
+            // Link to the pch object file
+            target->Target->AppendProperty(
+              "LINK_FLAGS",
+              cmStrCat(" ", this->ConvertToOutputFormat(pchSourceObj, SHELL)),
+              true);
+          }
+        } else {
+          pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str());
+        }
+
+        // Add pchHeader to source files, which will
+        // be grouped as "Precompile Header File"
+        auto pchHeader_sf = this->Makefile->GetOrCreateSource(
+          pchHeader, false, cmSourceFileLocationKind::Known);
+        std::string err;
+        pchHeader_sf->ResolveFullPath(&err);
+        target->AddSource(pchHeader);
+      }
     }
   }
 }
@@ -2632,7 +2642,7 @@
       chunk = std::min(itemsLeft, batchSize);
 
       std::string filename = cmStrCat(filename_base, "unity_", batch,
-                                      (lang == "C") ? ".c" : ".cxx");
+                                      (lang == "C") ? "_c.c" : "_cxx.cxx");
 
       const std::string filename_tmp = cmStrCat(filename, ".tmp");
       {
@@ -2994,7 +3004,7 @@
 {
 public:
   cmInstallTargetGeneratorLocal(cmLocalGenerator* lg, std::string const& t,
-                                const char* dest, bool implib)
+                                std::string const& dest, bool implib)
     : cmInstallTargetGenerator(
         t, dest, implib, "", std::vector<std::string>(), "Unspecified",
         cmInstallGenerator::SelectMessageLevel(lg->GetMakefile()), false,
@@ -3018,7 +3028,7 @@
 
     // Include the user-specified pre-install script for this target.
     if (const char* preinstall = l->GetProperty("PRE_INSTALL_SCRIPT")) {
-      cmInstallScriptGenerator g(preinstall, false, nullptr, false);
+      cmInstallScriptGenerator g(preinstall, false, "", false);
       g.Generate(os, config, configurationTypes);
     }
 
@@ -3039,8 +3049,8 @@
         case cmStateEnums::STATIC_LIBRARY:
         case cmStateEnums::MODULE_LIBRARY: {
           // Use a target install generator.
-          cmInstallTargetGeneratorLocal g(this, l->GetName(),
-                                          destination.c_str(), false);
+          cmInstallTargetGeneratorLocal g(this, l->GetName(), destination,
+                                          false);
           g.Generate(os, config, configurationTypes);
         } break;
         case cmStateEnums::SHARED_LIBRARY: {
@@ -3048,19 +3058,19 @@
           // Special code to handle DLL.  Install the import library
           // to the normal destination and the DLL to the runtime
           // destination.
-          cmInstallTargetGeneratorLocal g1(this, l->GetName(),
-                                           destination.c_str(), true);
+          cmInstallTargetGeneratorLocal g1(this, l->GetName(), destination,
+                                           true);
           g1.Generate(os, config, configurationTypes);
           // We also skip over the leading slash given by the user.
           destination = l->Target->GetRuntimeInstallPath().substr(1);
           cmSystemTools::ConvertToUnixSlashes(destination);
-          cmInstallTargetGeneratorLocal g2(this, l->GetName(),
-                                           destination.c_str(), false);
+          cmInstallTargetGeneratorLocal g2(this, l->GetName(), destination,
+                                           false);
           g2.Generate(os, config, configurationTypes);
 #else
           // Use a target install generator.
-          cmInstallTargetGeneratorLocal g(this, l->GetName(),
-                                          destination.c_str(), false);
+          cmInstallTargetGeneratorLocal g(this, l->GetName(), destination,
+                                          false);
           g.Generate(os, config, configurationTypes);
 #endif
         } break;
@@ -3071,7 +3081,7 @@
 
     // Include the user-specified post-install script for this target.
     if (const char* postinstall = l->GetProperty("POST_INSTALL_SCRIPT")) {
-      cmInstallScriptGenerator g(postinstall, false, nullptr, false);
+      cmInstallScriptGenerator g(postinstall, false, "", false);
       g.Generate(os, config, configurationTypes);
     }
   }
@@ -3281,7 +3291,8 @@
   // CMakeFiles/<target>.dir/CMakeFiles/<target>.dir/generated_source_file.obj
   const char* unitySourceFile = source.GetProperty("UNITY_SOURCE_FILE");
   const char* pchExtension = source.GetProperty("PCH_EXTENSION");
-  if (unitySourceFile || pchExtension) {
+  const bool isPchObject = objectName.find("cmake_pch") != std::string::npos;
+  if (unitySourceFile || pchExtension || isPchObject) {
     if (pchExtension) {
       customOutputExtension = pchExtension;
     }
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index 6967097..be1dd0d 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -64,7 +64,7 @@
 
   if (this->GetGlobalGenerator()->IsMultiConfig()) {
     for (auto const& config : this->GetConfigNames()) {
-      this->WriteProcessedMakefile(this->GetConfigFileStream(config));
+      this->WriteProcessedMakefile(this->GetImplFileStream(config));
     }
   }
   this->WriteProcessedMakefile(this->GetCommonFileStream());
@@ -154,10 +154,10 @@
 
 // Private methods.
 
-cmGeneratedFileStream& cmLocalNinjaGenerator::GetConfigFileStream(
+cmGeneratedFileStream& cmLocalNinjaGenerator::GetImplFileStream(
   const std::string& config) const
 {
-  return *this->GetGlobalNinjaGenerator()->GetConfigFileStream(config);
+  return *this->GetGlobalNinjaGenerator()->GetImplFileStream(config);
 }
 
 cmGeneratedFileStream& cmLocalNinjaGenerator::GetCommonFileStream() const
@@ -186,7 +186,7 @@
 
   if (this->GetGlobalGenerator()->IsMultiConfig()) {
     for (auto const& config : this->GetConfigNames()) {
-      auto& stream = this->GetConfigFileStream(config);
+      auto& stream = this->GetImplFileStream(config);
       this->WriteProjectHeader(stream);
       this->WriteNinjaRequiredVersion(stream);
       this->WriteNinjaConfigurationVariable(stream, config);
@@ -560,7 +560,7 @@
     build.Outputs = std::move(ninjaOutputs);
     build.ExplicitDeps = std::move(ninjaDeps);
     build.OrderOnlyDeps = orderOnlyDeps;
-    gg->WriteBuild(this->GetConfigFileStream(config), build);
+    gg->WriteBuild(this->GetImplFileStream(config), build);
   } else {
     std::string customStep = cmSystemTools::GetFilenameName(ninjaOutputs[0]);
     // Hash full path to make unique.
diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h
index 0445879..ef160e7 100644
--- a/Source/cmLocalNinjaGenerator.h
+++ b/Source/cmLocalNinjaGenerator.h
@@ -86,7 +86,7 @@
     bool forceFullPaths = false) override;
 
 private:
-  cmGeneratedFileStream& GetConfigFileStream(const std::string& config) const;
+  cmGeneratedFileStream& GetImplFileStream(const std::string& config) const;
   cmGeneratedFileStream& GetCommonFileStream() const;
   cmGeneratedFileStream& GetRulesFileStream() const;
 
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index f6a0e34..dbdde48 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -9,12 +9,12 @@
 #include <utility>
 
 #include <cm/memory>
+#include <cm/vector>
 #include <cmext/algorithm>
 
 #include "cmsys/FStream.hxx"
 #include "cmsys/Terminal.h"
 
-#include "cmAlgorithms.h"
 #include "cmCustomCommand.h" // IWYU pragma: keep
 #include "cmCustomCommandGenerator.h"
 #include "cmFileTimeCache.h"
@@ -1876,7 +1876,7 @@
     std::string binaryDir = this->GetState()->GetBinaryDirectory();
     if (this->Makefile->IsOn("CMAKE_DEPENDS_IN_PROJECT_ONLY")) {
       std::string const& sourceDir = this->GetState()->GetSourceDirectory();
-      cmEraseIf(includes, ::NotInProjectDir(sourceDir, binaryDir));
+      cm::erase_if(includes, ::NotInProjectDir(sourceDir, binaryDir));
     }
     for (std::string const& include : includes) {
       cmakefileStream << "  \""
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 7683855..1a6b7b2 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -146,7 +146,7 @@
   // out of date.
   std::string stampName =
     cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles");
-  cmSystemTools::MakeDirectory(stampName.c_str());
+  cmSystemTools::MakeDirectory(stampName);
   stampName += "/generate.stamp";
   cmsys::ofstream stamp(stampName.c_str());
   stamp << "# CMake generation timestamp file for this directory.\n";
@@ -257,12 +257,11 @@
                               "--check-stamp-file", stampName });
   std::string comment = cmStrCat("Building Custom Rule ", makefileIn);
   const char* no_working_directory = nullptr;
-  std::string fullpathStampName =
-    cmSystemTools::CollapseFullPath(stampName.c_str());
+  std::string fullpathStampName = cmSystemTools::CollapseFullPath(stampName);
   this->AddCustomCommandToOutput(fullpathStampName, listFiles, makefileIn,
                                  commandLines, comment.c_str(),
                                  no_working_directory, true, false);
-  if (cmSourceFile* file = this->Makefile->GetSource(makefileIn.c_str())) {
+  if (cmSourceFile* file = this->Makefile->GetSource(makefileIn)) {
     // Finalize the source file path now since we're adding this after
     // the generator validated all project-named sources.
     file->ResolveFullPath();
@@ -279,7 +278,7 @@
 {
   fout << "\t<Configurations>\n";
   for (std::string const& config : configs) {
-    this->WriteConfiguration(fout, config.c_str(), libName, target);
+    this->WriteConfiguration(fout, config, libName, target);
   }
   fout << "\t</Configurations>\n";
 }
@@ -530,6 +529,14 @@
     "linkIncrementalNo", 0 },
   { "LinkIncremental", "INCREMENTAL:YES", "link incremental",
     "linkIncrementalYes", 0 },
+  { "EnableCOMDATFolding", "OPT:NOICF", "Do not remove redundant COMDATs",
+    "optNoFolding", 0 },
+  { "EnableCOMDATFolding", "OPT:ICF", "Remove redundant COMDATs", "optFolding",
+    0 },
+  { "OptimizeReferences", "OPT:NOREF", "Keep unreferenced data",
+    "optNoReferences", 0 },
+  { "OptimizeReferences", "OPT:REF", "Eliminate unreferenced data",
+    "optReferences", 0 },
   { "", "", "", "", 0 }
 };
 
@@ -572,7 +579,7 @@
       this->Stream << this->LG->EscapeForXML("\n");
     }
     std::string script = this->LG->ConstructScript(ccg);
-    this->Stream << this->LG->EscapeForXML(script.c_str());
+    this->Stream << this->LG->EscapeForXML(script);
   }
 
 private:
@@ -725,13 +732,13 @@
       : target->GetDirectory(configName);
     /* clang-format off */
     fout << "\t\t\tOutputDirectory=\""
-         << this->ConvertToXMLOutputPathSingle(outDir.c_str()) << "\"\n";
+         << this->ConvertToXMLOutputPathSingle(outDir) << "\"\n";
     /* clang-format on */
   }
 
   /* clang-format off */
   fout << "\t\t\tIntermediateDirectory=\""
-       << this->ConvertToXMLOutputPath(intermediateDir.c_str())
+       << this->ConvertToXMLOutputPath(intermediateDir)
        << "\"\n"
        << "\t\t\tConfigurationType=\"" << configType << "\"\n"
        << "\t\t\tUseOfMFC=\"" << mfcFlag << "\"\n"
@@ -780,8 +787,7 @@
     } else {
       modDir = ".";
     }
-    fout << "\t\t\t\tModulePath=\""
-         << this->ConvertToXMLOutputPath(modDir.c_str())
+    fout << "\t\t\t\tModulePath=\"" << this->ConvertToXMLOutputPath(modDir)
          << "\\$(ConfigurationName)\"\n";
   }
   targetOptions.OutputAdditionalIncludeDirectories(
@@ -794,7 +800,7 @@
     std::string pdb = target->GetCompilePDBPath(configName);
     if (!pdb.empty()) {
       fout << "\t\t\t\tProgramDataBaseFileName=\""
-           << this->ConvertToXMLOutputPathSingle(pdb.c_str()) << "\"\n";
+           << this->ConvertToXMLOutputPathSingle(pdb) << "\"\n";
     }
   }
   fout << "/>\n"; // end of <Tool Name=VCCLCompilerTool
@@ -871,7 +877,7 @@
       fout << "\n\t\t\t\tAdditionalManifestFiles=\"";
       for (cmSourceFile const* manifest : manifest_srcs) {
         std::string m = manifest->GetFullPath();
-        fout << this->ConvertToXMLOutputPath(m.c_str()) << ";";
+        fout << this->ConvertToXMLOutputPath(m) << ";";
       }
       fout << "\"";
     }
@@ -938,7 +944,7 @@
   }
   std::string configTypeUpper = cmSystemTools::UpperCase(configName);
   std::string linkFlagsConfig = cmStrCat("LINK_FLAGS_", configTypeUpper);
-  targetLinkFlags = target->GetProperty(linkFlagsConfig.c_str());
+  targetLinkFlags = target->GetProperty(linkFlagsConfig);
   if (targetLinkFlags) {
     extraLinkOptions += " ";
     extraLinkOptions += targetLinkFlags;
@@ -977,7 +983,7 @@
       fout << "\t\t\t<Tool\n"
            << "\t\t\t\tName=\"" << tool << "\"\n";
       fout << "\t\t\t\tOutputFile=\""
-           << this->ConvertToXMLOutputPathSingle(libpath.c_str()) << "\"/>\n";
+           << this->ConvertToXMLOutputPathSingle(libpath) << "\"/>\n";
       break;
     }
     case cmStateEnums::STATIC_LIBRARY: {
@@ -1007,7 +1013,7 @@
         fout << "\t\t\t\tAdditionalOptions=\"" << libflags << "\"\n";
       }
       fout << "\t\t\t\tOutputFile=\""
-           << this->ConvertToXMLOutputPathSingle(libpath.c_str()) << "\"/>\n";
+           << this->ConvertToXMLOutputPathSingle(libpath) << "\"/>\n";
       break;
     }
     case cmStateEnums::SHARED_LIBRARY:
@@ -1049,7 +1055,7 @@
       temp =
         cmStrCat(target->GetDirectory(configName), '/', targetNames.Output);
       fout << "\t\t\t\tOutputFile=\""
-           << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
+           << this->ConvertToXMLOutputPathSingle(temp) << "\"\n";
       this->WriteTargetVersionAttribute(fout, target);
       linkOptions.OutputFlagMap(fout, 4);
       fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
@@ -1058,7 +1064,7 @@
       temp =
         cmStrCat(target->GetPDBDirectory(configName), '/', targetNames.PDB);
       fout << "\t\t\t\tProgramDatabaseFile=\""
-           << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
+           << this->ConvertToXMLOutputPathSingle(temp) << "\"\n";
       if (targetOptions.IsDebug()) {
         fout << "\t\t\t\tGenerateDebugInformation=\"true\"\n";
       }
@@ -1070,7 +1076,7 @@
         }
       }
       std::string stackVar = cmStrCat("CMAKE_", linkLanguage, "_STACK_SIZE");
-      const char* stackVal = this->Makefile->GetDefinition(stackVar.c_str());
+      const char* stackVal = this->Makefile->GetDefinition(stackVar);
       if (stackVal) {
         fout << "\t\t\t\tStackReserveSize=\"" << stackVal << "\"\n";
       }
@@ -1078,7 +1084,7 @@
         target->GetDirectory(configName, cmStateEnums::ImportLibraryArtifact),
         '/', targetNames.ImportLibrary);
       fout << "\t\t\t\tImportLibrary=\""
-           << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"";
+           << this->ConvertToXMLOutputPathSingle(temp) << "\"";
       if (this->FortranProject) {
         fout << "\n\t\t\t\tLinkDLL=\"true\"";
       }
@@ -1124,14 +1130,14 @@
       temp =
         cmStrCat(target->GetDirectory(configName), '/', targetNames.Output);
       fout << "\t\t\t\tOutputFile=\""
-           << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"\n";
+           << this->ConvertToXMLOutputPathSingle(temp) << "\"\n";
       this->WriteTargetVersionAttribute(fout, target);
       linkOptions.OutputFlagMap(fout, 4);
       fout << "\t\t\t\tAdditionalLibraryDirectories=\"";
       this->OutputLibraryDirectories(fout, cli.GetDirectories());
       fout << "\"\n";
       std::string path = this->ConvertToXMLOutputPathSingle(
-        target->GetPDBDirectory(configName).c_str());
+        target->GetPDBDirectory(configName));
       fout << "\t\t\t\tProgramDatabaseFile=\"" << path << "/"
            << targetNames.PDB << "\"\n";
       if (targetOptions.IsDebug()) {
@@ -1159,7 +1165,7 @@
              << "\"\n";
       }
       std::string stackVar = cmStrCat("CMAKE_", linkLanguage, "_STACK_SIZE");
-      const char* stackVal = this->Makefile->GetDefinition(stackVar.c_str());
+      const char* stackVal = this->Makefile->GetDefinition(stackVar);
       if (stackVal) {
         fout << "\t\t\t\tStackReserveSize=\"" << stackVal << "\"";
       }
@@ -1167,7 +1173,7 @@
         target->GetDirectory(configName, cmStateEnums::ImportLibraryArtifact),
         '/', targetNames.ImportLibrary);
       fout << "\t\t\t\tImportLibrary=\""
-           << this->ConvertToXMLOutputPathSingle(temp.c_str()) << "\"/>\n";
+           << this->ConvertToXMLOutputPathSingle(temp) << "\"/>\n";
       break;
     }
     case cmStateEnums::UTILITY:
@@ -1248,8 +1254,8 @@
   for (auto const& lib : libs) {
     if (lib.IsPath) {
       std::string rel =
-        lg->MaybeConvertToRelativePath(currentBinDir, lib.Value.c_str());
-      fout << lg->ConvertToXMLOutputPath(rel.c_str()) << " ";
+        lg->MaybeConvertToRelativePath(currentBinDir, lib.Value);
+      fout << lg->ConvertToXMLOutputPath(rel) << " ";
     } else if (!lib.Target ||
                lib.Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
       fout << lib.Value << " ";
@@ -1274,7 +1280,7 @@
     if (!obj->GetObjectLibrary().empty()) {
       std::string const& objFile = obj->GetFullPath();
       std::string rel = lg->MaybeConvertToRelativePath(currentBinDir, objFile);
-      fout << sep << lg->ConvertToXMLOutputPath(rel.c_str());
+      fout << sep << lg->ConvertToXMLOutputPath(rel);
       sep = " ";
     }
   }
@@ -1295,9 +1301,8 @@
     }
 
     // Switch to a relative path specification if it is shorter.
-    if (cmSystemTools::FileIsFullPath(dir.c_str())) {
-      std::string rel =
-        this->MaybeConvertToRelativePath(currentBinDir, dir.c_str());
+    if (cmSystemTools::FileIsFullPath(dir)) {
+      std::string rel = this->MaybeConvertToRelativePath(currentBinDir, dir);
       if (rel.size() < dir.size()) {
         dir = rel;
       }
@@ -1306,9 +1311,8 @@
     // First search a configuration-specific subdirectory and then the
     // original directory.
     fout << comma
-         << this->ConvertToXMLOutputPath(
-              (dir + "/$(ConfigurationName)").c_str())
-         << "," << this->ConvertToXMLOutputPath(dir.c_str());
+         << this->ConvertToXMLOutputPath(dir + "/$(ConfigurationName)") << ","
+         << this->ConvertToXMLOutputPath(dir);
     comma = ",";
   }
 }
@@ -1510,13 +1514,13 @@
       for (std::vector<std::string>::iterator j = depends.begin();
            j != depends.end(); ++j) {
         fc.AdditionalDeps += sep;
-        fc.AdditionalDeps += lg->ConvertToXMLOutputPath(j->c_str());
+        fc.AdditionalDeps += lg->ConvertToXMLOutputPath(*j);
         sep = ";";
         needfc = true;
       }
     }
 
-    const std::string& linkLanguage = gt->GetLinkerLanguage(config.c_str());
+    const std::string& linkLanguage = gt->GetLinkerLanguage(config);
     // If HEADER_FILE_ONLY is set, we must suppress this generation in
     // the project file
     fc.ExcludedFromBuild = sf.GetPropertyAsBool("HEADER_FILE_ONLY") ||
@@ -1621,7 +1625,7 @@
       FCInfo fcinfo(this, target, acs, configs);
 
       fout << "\t\t\t<File\n";
-      std::string d = this->ConvertToXMLOutputPathSingle(source.c_str());
+      std::string d = this->ConvertToXMLOutputPathSingle(source);
       // Tell MS-Dev what the source is.  If the compiler knows how to
       // build it, then it will.
       fout << "\t\t\t\tRelativePath=\"" << d << "\">\n";
@@ -1751,21 +1755,21 @@
       fout << "\t\t\t\t\t<Tool\n"
            << "\t\t\t\t\tName=\"" << compileTool << "\"\n"
            << "\t\t\t\t\tAdditionalOptions=\""
-           << this->EscapeForXML(fc.CompileFlags.c_str()) << "\"/>\n";
+           << this->EscapeForXML(fc.CompileFlags) << "\"/>\n";
     }
 
     std::string comment = this->ConstructComment(ccg);
     std::string script = this->ConstructScript(ccg);
     if (this->FortranProject) {
-      cmSystemTools::ReplaceString(script, "$(Configuration)", config.c_str());
+      cmSystemTools::ReplaceString(script, "$(Configuration)", config);
     }
     /* clang-format off */
     fout << "\t\t\t\t\t<Tool\n"
          << "\t\t\t\t\tName=\"" << customTool << "\"\n"
          << "\t\t\t\t\tDescription=\""
-         << this->EscapeForXML(comment.c_str()) << "\"\n"
+         << this->EscapeForXML(comment) << "\"\n"
          << "\t\t\t\t\tCommandLine=\""
-         << this->EscapeForXML(script.c_str()) << "\"\n"
+         << this->EscapeForXML(script) << "\"\n"
          << "\t\t\t\t\tAdditionalDependencies=\"";
     /* clang-format on */
     if (ccg.GetDepends().empty()) {
@@ -1781,8 +1785,8 @@
       for (std::string const& d : ccg.GetDepends()) {
         // Get the real name of the dependency in case it is a CMake target.
         std::string dep;
-        if (this->GetRealDependency(d.c_str(), config.c_str(), dep)) {
-          fout << this->ConvertToXMLOutputPath(dep.c_str()) << ";";
+        if (this->GetRealDependency(d, config, dep)) {
+          fout << this->ConvertToXMLOutputPath(dep) << ";";
         }
       }
     }
@@ -1794,7 +1798,7 @@
       // Write a rule for the output generated by this command.
       const char* sep = "";
       for (std::string const& output : ccg.GetOutputs()) {
-        fout << sep << this->ConvertToXMLOutputPathSingle(output.c_str());
+        fout << sep << this->ConvertToXMLOutputPathSingle(output);
         sep = ";";
       }
     }
@@ -1940,7 +1944,7 @@
   this->WriteProjectSCC(fout, target);
   /* clang-format off */
   fout<< "\tKeyword=\"" << keyword << "\">\n"
-       << "\tProjectGUID=\"{" << gg->GetGUID(libName.c_str()) << "}\">\n"
+       << "\tProjectGUID=\"{" << gg->GetGUID(libName) << "}\">\n"
        << "\t<Platforms>\n"
        << "\t\t<Platform\n\t\t\tName=\"" << gg->GetPlatformName() << "\"/>\n"
        << "\t</Platforms>\n";
@@ -1975,7 +1979,7 @@
     keyword = "Win32Proj";
   }
   fout << "\tName=\"" << projLabel << "\"\n";
-  fout << "\tProjectGUID=\"{" << gg->GetGUID(libName.c_str()) << "}\"\n";
+  fout << "\tProjectGUID=\"{" << gg->GetGUID(libName) << "}\"\n";
   this->WriteProjectSCC(fout, target);
   if (const char* targetFrameworkVersion =
         target->GetProperty("VS_DOTNET_TARGET_FRAMEWORK_VERSION")) {
@@ -2029,7 +2033,7 @@
 }
 
 std::string cmLocalVisualStudio7Generator::ConvertToXMLOutputPath(
-  const char* path)
+  const std::string& path)
 {
   std::string ret =
     this->ConvertToOutputFormat(path, cmOutputConverter::SHELL);
@@ -2041,7 +2045,7 @@
 }
 
 std::string cmLocalVisualStudio7Generator::ConvertToXMLOutputPathSingle(
-  const char* path)
+  const std::string& path)
 {
   std::string ret =
     this->ConvertToOutputFormat(path, cmOutputConverter::SHELL);
@@ -2122,8 +2126,7 @@
   std::string guidStoreName = cmStrCat(name, "_GUID_CMAKE");
   // save the GUID in the cache
   this->GlobalGenerator->GetCMakeInstance()->AddCacheEntry(
-    guidStoreName.c_str(), parser.GUID.c_str(), "Stored GUID",
-    cmStateEnums::INTERNAL);
+    guidStoreName, parser.GUID.c_str(), "Stored GUID", cmStateEnums::INTERNAL);
 }
 
 std::string cmLocalVisualStudio7Generator::GetTargetDirectory(
diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h
index 22a5f9a..745766c 100644
--- a/Source/cmLocalVisualStudio7Generator.h
+++ b/Source/cmLocalVisualStudio7Generator.h
@@ -101,8 +101,8 @@
   void WriteConfiguration(std::ostream& fout, const std::string& configName,
                           const std::string& libName, cmGeneratorTarget* tgt);
   std::string EscapeForXML(const std::string& s);
-  std::string ConvertToXMLOutputPath(const char* path);
-  std::string ConvertToXMLOutputPathSingle(const char* path);
+  std::string ConvertToXMLOutputPath(const std::string& path);
+  std::string ConvertToXMLOutputPathSingle(const std::string& path);
   void OutputTargetRules(std::ostream& fout, const std::string& configName,
                          cmGeneratorTarget* target,
                          const std::string& libName);
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index fa7bce1..59995be 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -17,6 +17,7 @@
 #include <cm/iterator>
 #include <cm/memory>
 #include <cm/optional>
+#include <cm/vector>
 #include <cmext/algorithm>
 
 #include "cmsys/FStream.hxx"
@@ -123,15 +124,7 @@
 #endif
 }
 
-cmMakefile::~cmMakefile()
-{
-  cmDeleteAll(this->InstallGenerators);
-  cmDeleteAll(this->TestGenerators);
-  cmDeleteAll(this->SourceFiles);
-  cmDeleteAll(this->Tests);
-  cmDeleteAll(this->ImportedTargetsOwned);
-  cmDeleteAll(this->EvaluationFiles);
-}
+cmMakefile::~cmMakefile() = default;
 
 cmDirectoryId cmMakefile::GetDirectoryId() const
 {
@@ -139,7 +132,7 @@
   // If we ever need to expose this to CMake language code we should
   // add a read-only property in cmMakefile::GetProperty.
   char buf[32];
-  sprintf(buf, "<%p>",
+  sprintf(buf, "(%p)",
           static_cast<void const*>(this)); // cast avoids format warning
   return std::string(buf);
 }
@@ -347,6 +340,9 @@
       for (std::string const& arg : args) {
         val["args"].append(arg);
       }
+      val["time"] = cmSystemTools::GetTime();
+      val["frame"] =
+        static_cast<std::uint64_t>(this->ExecutionStatusStack.size());
       msg << Json::writeString(builder, val);
 #endif
       break;
@@ -773,12 +769,13 @@
   std::unique_ptr<cmCompiledGeneratorExpression> condition,
   bool inputIsContent)
 {
-  this->EvaluationFiles.push_back(new cmGeneratorExpressionEvaluationFile(
-    inputFile, std::move(outputName), std::move(condition), inputIsContent,
-    this->GetPolicyStatus(cmPolicies::CMP0070)));
+  this->EvaluationFiles.push_back(
+    cm::make_unique<cmGeneratorExpressionEvaluationFile>(
+      inputFile, std::move(outputName), std::move(condition), inputIsContent,
+      this->GetPolicyStatus(cmPolicies::CMP0070)));
 }
 
-std::vector<cmGeneratorExpressionEvaluationFile*>
+const std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>&
 cmMakefile::GetEvaluationFiles() const
 {
   return this->EvaluationFiles;
@@ -840,12 +837,12 @@
   // we don't want cmake to re-run if a configured file is created and deleted
   // during processing as that would make it a transient file that can't
   // influence the build process
-  cmEraseIf(this->OutputFiles, file_not_persistent());
+  cm::erase_if(this->OutputFiles, file_not_persistent());
 
   // if a configured file is used as input for another configured file,
   // and then deleted it will show up in the input list files so we
   // need to scan those too
-  cmEraseIf(this->ListFiles, file_not_persistent());
+  cm::erase_if(this->ListFiles, file_not_persistent());
 }
 
 // Generate the output file
@@ -1424,6 +1421,20 @@
   this->RecursionDepth = parent->RecursionDepth;
 }
 
+void cmMakefile::AddInstallGenerator(std::unique_ptr<cmInstallGenerator> g)
+{
+  if (g) {
+    this->InstallGenerators.push_back(std::move(g));
+  }
+}
+
+void cmMakefile::AddTestGenerator(std::unique_ptr<cmTestGenerator> g)
+{
+  if (g) {
+    this->TestGenerators.push_back(std::move(g));
+  }
+}
+
 void cmMakefile::PushFunctionScope(std::string const& fileName,
                                    const cmPolicies::PolicyMap& pm)
 {
@@ -1739,8 +1750,8 @@
     this->UnConfiguredDirectories.push_back(subMf);
   }
 
-  this->AddInstallGenerator(new cmInstallSubdirectoryGenerator(
-    subMf, binPath.c_str(), excludeFromAll));
+  this->AddInstallGenerator(cm::make_unique<cmInstallSubdirectoryGenerator>(
+    subMf, binPath, excludeFromAll));
 }
 
 const std::string& cmMakefile::GetCurrentSourceDirectory() const
@@ -2103,18 +2114,18 @@
 
   // Look through all the source files that have custom commands and see if the
   // custom command has the passed source file as an output.
-  for (cmSourceFile* src : this->SourceFiles) {
+  for (const auto& src : this->SourceFiles) {
     // Does this source file have a custom command?
     if (src->GetCustomCommand()) {
       // Does the output of the custom command match the source file name?
       if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) {
         // Return the first matching output.
-        return src;
+        return src.get();
       }
       if (kind == cmSourceOutputKind::OutputOrByproduct) {
         if (AnyOutputMatches(name, src->GetCustomCommand()->GetByproducts())) {
           // Do not return the source yet as there might be a matching output.
-          fallback = src;
+          fallback = src.get();
         }
       }
     }
@@ -3472,24 +3483,25 @@
                                        bool generated,
                                        cmSourceFileLocationKind kind)
 {
-  cmSourceFile* sf = new cmSourceFile(this, sourceName, kind);
+  auto sf = cm::make_unique<cmSourceFile>(this, sourceName, kind);
   if (generated) {
     sf->SetProperty("GENERATED", "1");
   }
-  this->SourceFiles.push_back(sf);
 
   auto name =
     this->GetCMakeInstance()->StripExtension(sf->GetLocation().GetName());
 #if defined(_WIN32) || defined(__APPLE__)
   name = cmSystemTools::LowerCase(name);
 #endif
-  this->SourceFileSearchIndex[name].push_back(sf);
+  this->SourceFileSearchIndex[name].push_back(sf.get());
   // for "Known" paths add direct lookup (used for faster lookup in GetSource)
   if (kind == cmSourceFileLocationKind::Known) {
-    this->KnownFileSearchIndex[sourceName] = sf;
+    this->KnownFileSearchIndex[sourceName] = sf.get();
   }
 
-  return sf;
+  this->SourceFiles.push_back(std::move(sf));
+
+  return this->SourceFiles.back().get();
 }
 
 cmSourceFile* cmMakefile::GetOrCreateSource(const std::string& sourceName,
@@ -4083,9 +4095,10 @@
   if (test) {
     return test;
   }
-  test = new cmTest(this);
-  test->SetName(testName);
-  this->Tests[testName] = test;
+  auto newTest = cm::make_unique<cmTest>(this);
+  test = newTest.get();
+  newTest->SetName(testName);
+  this->Tests[testName] = std::move(newTest);
   return test;
 }
 
@@ -4093,7 +4106,7 @@
 {
   auto mi = this->Tests.find(testName);
   if (mi != this->Tests.end()) {
-    return mi->second;
+    return mi->second.get();
   }
   return nullptr;
 }
@@ -4101,7 +4114,7 @@
 void cmMakefile::GetTests(const std::string& config,
                           std::vector<cmTest*>& tests)
 {
-  for (auto generator : this->GetTestGenerators()) {
+  for (const auto& generator : this->GetTestGenerators()) {
     if (generator->TestsForConfig(config)) {
       tests.push_back(generator->GetTest());
     }
@@ -4214,8 +4227,8 @@
   this->GetGlobalGenerator()->IndexTarget(target.get());
 
   // Transfer ownership to this cmMakefile object.
-  this->ImportedTargetsOwned.push_back(target.get());
-  return target.release();
+  this->ImportedTargetsOwned.push_back(std::move(target));
+  return this->ImportedTargetsOwned.back().get();
 }
 
 cmTarget* cmMakefile::FindTargetToUse(const std::string& name,
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 085c1d6..b13716b 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -431,7 +431,7 @@
   /** Get the target map - const version */
   cmTargetMap const& GetTargets() const { return this->Targets; }
 
-  const std::vector<cmTarget*>& GetOwnedImportedTargets() const
+  const std::vector<std::unique_ptr<cmTarget>>& GetOwnedImportedTargets() const
   {
     return this->ImportedTargetsOwned;
   }
@@ -727,7 +727,7 @@
   /**
    * Get all the source files this makefile knows about
    */
-  const std::vector<cmSourceFile*>& GetSourceFiles() const
+  const std::vector<std::unique_ptr<cmSourceFile>>& GetSourceFiles() const
   {
     return this->SourceFiles;
   }
@@ -794,28 +794,22 @@
   //! Initialize a makefile from its parent
   void InitializeFromParent(cmMakefile* parent);
 
-  void AddInstallGenerator(cmInstallGenerator* g)
-  {
-    if (g) {
-      this->InstallGenerators.push_back(g);
-    }
-  }
-  std::vector<cmInstallGenerator*>& GetInstallGenerators()
+  void AddInstallGenerator(std::unique_ptr<cmInstallGenerator> g);
+
+  std::vector<std::unique_ptr<cmInstallGenerator>>& GetInstallGenerators()
   {
     return this->InstallGenerators;
   }
-  const std::vector<cmInstallGenerator*>& GetInstallGenerators() const
+  const std::vector<std::unique_ptr<cmInstallGenerator>>&
+  GetInstallGenerators() const
   {
     return this->InstallGenerators;
   }
 
-  void AddTestGenerator(cmTestGenerator* g)
-  {
-    if (g) {
-      this->TestGenerators.push_back(g);
-    }
-  }
-  const std::vector<cmTestGenerator*>& GetTestGenerators() const
+  void AddTestGenerator(std::unique_ptr<cmTestGenerator> g);
+
+  const std::vector<std::unique_ptr<cmTestGenerator>>& GetTestGenerators()
+    const
   {
     return this->TestGenerators;
   }
@@ -948,7 +942,8 @@
     std::unique_ptr<cmCompiledGeneratorExpression> outputName,
     std::unique_ptr<cmCompiledGeneratorExpression> condition,
     bool inputIsContent);
-  std::vector<cmGeneratorExpressionEvaluationFile*> GetEvaluationFiles() const;
+  const std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>&
+  GetEvaluationFiles() const;
 
   std::vector<cmExportBuildFileGenerator*> GetExportBuildFileGenerators()
     const;
@@ -983,8 +978,7 @@
   using TargetsVec = std::vector<cmTarget*>;
   TargetsVec OrderedTargets;
 
-  using SourceFileVec = std::vector<cmSourceFile*>;
-  SourceFileVec SourceFiles;
+  std::vector<std::unique_ptr<cmSourceFile>> SourceFiles;
 
   // Because cmSourceFile names are compared in a fuzzy way (see
   // cmSourceFileLocation::Match()) we can't have a straight mapping from
@@ -992,14 +986,15 @@
   // Name portion of the cmSourceFileLocation and then compare on the list of
   // cmSourceFiles that might match that name.  Note that on platforms which
   // have a case-insensitive filesystem we store the key in all lowercase.
-  using SourceFileMap = std::unordered_map<std::string, SourceFileVec>;
+  using SourceFileMap =
+    std::unordered_map<std::string, std::vector<cmSourceFile*>>;
   SourceFileMap SourceFileSearchIndex;
 
   // For "Known" paths we can store a direct filename to cmSourceFile map
   std::unordered_map<std::string, cmSourceFile*> KnownFileSearchIndex;
 
   // Tests
-  std::map<std::string, cmTest*> Tests;
+  std::map<std::string, std::unique_ptr<cmTest>> Tests;
 
   // The set of include directories that are marked as system include
   // directories.
@@ -1008,8 +1003,8 @@
   std::vector<std::string> ListFiles;
   std::vector<std::string> OutputFiles;
 
-  std::vector<cmInstallGenerator*> InstallGenerators;
-  std::vector<cmTestGenerator*> TestGenerators;
+  std::vector<std::unique_ptr<cmInstallGenerator>> InstallGenerators;
+  std::vector<std::unique_ptr<cmTestGenerator>> TestGenerators;
 
   std::string ComplainFileRegularExpression;
   std::string DefineFlags;
@@ -1060,13 +1055,14 @@
   std::vector<cmMakefile*> UnConfiguredDirectories;
   std::vector<cmExportBuildFileGenerator*> ExportBuildFileGenerators;
 
-  std::vector<cmGeneratorExpressionEvaluationFile*> EvaluationFiles;
+  std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>
+    EvaluationFiles;
 
   std::vector<cmExecutionStatus*> ExecutionStatusStack;
   friend class cmMakefileCall;
   friend class cmParseFileScope;
 
-  std::vector<cmTarget*> ImportedTargetsOwned;
+  std::vector<std::unique_ptr<cmTarget>> ImportedTargetsOwned;
   using TargetMap = std::unordered_map<std::string, cmTarget*>;
   TargetMap ImportedTargets;
 
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 77b6bc2..714d01e 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -4,10 +4,10 @@
 
 #include <cassert>
 #include <cstdio>
-#include <memory>
 #include <sstream>
 #include <utility>
 
+#include <cm/memory>
 #include <cmext/algorithm>
 
 #include "cmComputeLinkInformation.h"
@@ -38,12 +38,7 @@
 
 cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target)
   : cmCommonTargetGenerator(target)
-  , OSXBundleGenerator(nullptr)
-  , MacOSXContentGenerator(nullptr)
 {
-  this->BuildFileStream = nullptr;
-  this->InfoFileStream = nullptr;
-  this->FlagFileStream = nullptr;
   this->CustomCommandDriver = OnBuild;
   this->LocalGenerator =
     static_cast<cmLocalUnixMakefileGenerator3*>(target->GetLocalGenerator());
@@ -55,31 +50,28 @@
         cm->GetState()->GetGlobalProperty("RULE_MESSAGES")) {
     this->NoRuleMessages = cmIsOff(ruleStatus);
   }
-  MacOSXContentGenerator = new MacOSXContentGeneratorType(this);
+  MacOSXContentGenerator = cm::make_unique<MacOSXContentGeneratorType>(this);
 }
 
-cmMakefileTargetGenerator::~cmMakefileTargetGenerator()
-{
-  delete MacOSXContentGenerator;
-}
+cmMakefileTargetGenerator::~cmMakefileTargetGenerator() = default;
 
-cmMakefileTargetGenerator* cmMakefileTargetGenerator::New(
+std::unique_ptr<cmMakefileTargetGenerator> cmMakefileTargetGenerator::New(
   cmGeneratorTarget* tgt)
 {
-  cmMakefileTargetGenerator* result = nullptr;
+  std::unique_ptr<cmMakefileTargetGenerator> result;
 
   switch (tgt->GetType()) {
     case cmStateEnums::EXECUTABLE:
-      result = new cmMakefileExecutableTargetGenerator(tgt);
+      result = cm::make_unique<cmMakefileExecutableTargetGenerator>(tgt);
       break;
     case cmStateEnums::STATIC_LIBRARY:
     case cmStateEnums::SHARED_LIBRARY:
     case cmStateEnums::MODULE_LIBRARY:
     case cmStateEnums::OBJECT_LIBRARY:
-      result = new cmMakefileLibraryTargetGenerator(tgt);
+      result = cm::make_unique<cmMakefileLibraryTargetGenerator>(tgt);
       break;
     case cmStateEnums::UTILITY:
-      result = new cmMakefileUtilityTargetGenerator(tgt);
+      result = cm::make_unique<cmMakefileUtilityTargetGenerator>(tgt);
       break;
     default:
       return result;
@@ -139,9 +131,9 @@
 
   // Open the rule file.  This should be copy-if-different because the
   // rules may depend on this file itself.
-  this->BuildFileStream =
-    new cmGeneratedFileStream(this->BuildFileNameFull, false,
-                              this->GlobalGenerator->GetMakefileEncoding());
+  this->BuildFileStream = cm::make_unique<cmGeneratedFileStream>(
+    this->BuildFileNameFull, false,
+    this->GlobalGenerator->GetMakefileEncoding());
   if (!this->BuildFileStream) {
     return;
   }
@@ -247,11 +239,11 @@
   this->GeneratorTarget->GetHeaderSources(headerSources,
                                           this->GetConfigName());
   this->OSXBundleGenerator->GenerateMacOSXContentStatements(
-    headerSources, this->MacOSXContentGenerator, this->GetConfigName());
+    headerSources, this->MacOSXContentGenerator.get(), this->GetConfigName());
   std::vector<cmSourceFile const*> extraSources;
   this->GeneratorTarget->GetExtraSources(extraSources, this->GetConfigName());
   this->OSXBundleGenerator->GenerateMacOSXContentStatements(
-    extraSources, this->MacOSXContentGenerator, this->GetConfigName());
+    extraSources, this->MacOSXContentGenerator.get(), this->GetConfigName());
   const char* pchExtension =
     this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION");
   std::vector<cmSourceFile const*> externalObjects;
@@ -316,9 +308,9 @@
   // rules may depend on this file itself.
   this->FlagFileNameFull =
     cmStrCat(this->TargetBuildDirectoryFull, "/flags.make");
-  this->FlagFileStream =
-    new cmGeneratedFileStream(this->FlagFileNameFull, false,
-                              this->GlobalGenerator->GetMakefileEncoding());
+  this->FlagFileStream = cm::make_unique<cmGeneratedFileStream>(
+    this->FlagFileNameFull, false,
+    this->GlobalGenerator->GetMakefileEncoding());
   if (!this->FlagFileStream) {
     return;
   }
@@ -1057,7 +1049,8 @@
   this->InfoFileNameFull = cmStrCat(dir, "/DependInfo.cmake");
   this->InfoFileNameFull =
     this->LocalGenerator->ConvertToFullPath(this->InfoFileNameFull);
-  this->InfoFileStream = new cmGeneratedFileStream(this->InfoFileNameFull);
+  this->InfoFileStream =
+    cm::make_unique<cmGeneratedFileStream>(this->InfoFileNameFull);
   if (!this->InfoFileStream) {
     return;
   }
@@ -1524,9 +1517,9 @@
 
 void cmMakefileTargetGenerator::CloseFileStreams()
 {
-  delete this->BuildFileStream;
-  delete this->InfoFileStream;
-  delete this->FlagFileStream;
+  this->BuildFileStream.reset();
+  this->InfoFileStream.reset();
+  this->FlagFileStream.reset();
 }
 
 void cmMakefileTargetGenerator::CreateLinkScript(
diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h
index fd62933..ec6b314 100644
--- a/Source/cmMakefileTargetGenerator.h
+++ b/Source/cmMakefileTargetGenerator.h
@@ -34,10 +34,15 @@
 public:
   // constructor to set the ivars
   cmMakefileTargetGenerator(cmGeneratorTarget* target);
+  cmMakefileTargetGenerator(const cmMakefileTargetGenerator&) = delete;
   ~cmMakefileTargetGenerator() override;
 
+  cmMakefileTargetGenerator& operator=(const cmMakefileTargetGenerator&) =
+    delete;
+
   // construct using this factory call
-  static cmMakefileTargetGenerator* New(cmGeneratorTarget* tgt);
+  static std::unique_ptr<cmMakefileTargetGenerator> New(
+    cmGeneratorTarget* tgt);
 
   /* the main entry point for this class. Writes the Makefiles associated
      with this target */
@@ -195,11 +200,11 @@
   std::string TargetBuildDirectoryFull;
 
   // the stream for the build file
-  cmGeneratedFileStream* BuildFileStream;
+  std::unique_ptr<cmGeneratedFileStream> BuildFileStream;
 
   // the stream for the flag file
   std::string FlagFileNameFull;
-  cmGeneratedFileStream* FlagFileStream;
+  std::unique_ptr<cmGeneratedFileStream> FlagFileStream;
   class StringList : public std::vector<std::string>
   {
   };
@@ -207,7 +212,7 @@
 
   // the stream for the info file
   std::string InfoFileNameFull;
-  cmGeneratedFileStream* InfoFileStream;
+  std::unique_ptr<cmGeneratedFileStream> InfoFileStream;
 
   // files to clean
   std::set<std::string> CleanFiles;
@@ -236,7 +241,7 @@
   // macOS content info.
   std::set<std::string> MacContentFolders;
   std::unique_ptr<cmOSXBundleGenerator> OSXBundleGenerator;
-  MacOSXContentGeneratorType* MacOSXContentGenerator;
+  std::unique_ptr<MacOSXContentGeneratorType> MacOSXContentGenerator;
 };
 
 #endif
diff --git a/Source/cmMarkAsAdvancedCommand.cxx b/Source/cmMarkAsAdvancedCommand.cxx
index ca46e14..45043fa 100644
--- a/Source/cmMarkAsAdvancedCommand.cxx
+++ b/Source/cmMarkAsAdvancedCommand.cxx
@@ -4,8 +4,11 @@
 
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmPolicies.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmake.h"
 
@@ -28,14 +31,63 @@
     }
     i = 1;
   }
+
+  cmMakefile& mf = status.GetMakefile();
+  cmState* state = mf.GetState();
+
   for (; i < args.size(); ++i) {
     std::string const& variable = args[i];
-    cmState* state = status.GetMakefile().GetState();
-    if (!state->GetCacheEntryValue(variable)) {
-      status.GetMakefile().GetCMakeInstance()->AddCacheEntry(
-        variable, nullptr, nullptr, cmStateEnums::UNINITIALIZED);
-      overwrite = true;
+
+    bool issueMessage = false;
+    bool oldBehavior = false;
+    bool ignoreVariable = false;
+    switch (mf.GetPolicyStatus(cmPolicies::CMP0102)) {
+      case cmPolicies::WARN:
+        if (mf.PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0102")) {
+          if (!state->GetCacheEntryValue(variable)) {
+            issueMessage = true;
+          }
+        }
+        CM_FALLTHROUGH;
+      case cmPolicies::OLD:
+        oldBehavior = true;
+        break;
+      case cmPolicies::NEW:
+      case cmPolicies::REQUIRED_IF_USED:
+      case cmPolicies::REQUIRED_ALWAYS:
+        if (!state->GetCacheEntryValue(variable)) {
+          ignoreVariable = true;
+        }
+        break;
     }
+
+    // First see if we should issue a message about CMP0102
+    if (issueMessage) {
+      std::string err = cmStrCat(
+        "Policy CMP0102 is not set: The variable named \"", variable,
+        "\" is not in the cache. This results in an empty cache entry which "
+        "is no longer created when policy CMP0102 is set to NEW. Run \"cmake "
+        "--help-policy CMP0102\" for policy details. Use the cmake_policy "
+        "command to set the policy and suppress this warning.");
+      mf.IssueMessage(MessageType::AUTHOR_WARNING, err);
+    }
+
+    // If it's not in the cache and we're using the new behavior, nothing to
+    // see here.
+    if (ignoreVariable) {
+      continue;
+    }
+
+    // Check if we want the old behavior of making a dummy cache entry.
+    if (oldBehavior) {
+      if (!state->GetCacheEntryValue(variable)) {
+        status.GetMakefile().GetCMakeInstance()->AddCacheEntry(
+          variable, nullptr, nullptr, cmStateEnums::UNINITIALIZED);
+        overwrite = true;
+      }
+    }
+
+    // We need a cache entry to do this.
     if (!state->GetCacheEntryValue(variable)) {
       cmSystemTools::Error("This should never happen...");
       return false;
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index 987f241..437548a 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -11,8 +11,8 @@
 #include <utility>
 
 #include <cm/memory>
+#include <cm/vector>
 
-#include "cmAlgorithms.h"
 #include "cmComputeLinkInformation.h"
 #include "cmCustomCommand.h" // IWYU pragma: keep
 #include "cmCustomCommandGenerator.h"
@@ -72,6 +72,11 @@
   // Write the build statements
   bool firstForConfig = true;
   for (auto const& fileConfig : this->GetConfigNames()) {
+    if (!this->GetGlobalGenerator()
+           ->GetCrossConfigs(fileConfig)
+           .count(config)) {
+      continue;
+    }
     this->WriteObjectBuildStatements(config, fileConfig, firstForConfig);
     firstForConfig = false;
   }
@@ -79,17 +84,24 @@
   if (this->GetGeneratorTarget()->GetType() == cmStateEnums::OBJECT_LIBRARY) {
     this->WriteObjectLibStatement(config);
   } else {
-    // If this target has cuda language link inputs, and we need to do
-    // device linking
-    this->WriteDeviceLinkStatement(config);
     firstForConfig = true;
     for (auto const& fileConfig : this->GetConfigNames()) {
+      if (!this->GetGlobalGenerator()
+             ->GetCrossConfigs(fileConfig)
+             .count(config)) {
+        continue;
+      }
+      // If this target has cuda language link inputs, and we need to do
+      // device linking
+      this->WriteDeviceLinkStatement(config, fileConfig, firstForConfig);
       this->WriteLinkStatement(config, fileConfig, firstForConfig);
       firstForConfig = false;
     }
   }
-  this->GetGlobalGenerator()->AddTargetAlias(
-    this->GetTargetName(), this->GetGeneratorTarget(), "all");
+  if (this->GetGlobalGenerator()->EnableCrossConfigBuild()) {
+    this->GetGlobalGenerator()->AddTargetAlias(
+      this->GetTargetName(), this->GetGeneratorTarget(), "all");
+  }
 
   // Find ADDITIONAL_CLEAN_FILES
   this->AdditionalCleanFiles(config);
@@ -243,7 +255,7 @@
     }
 
     // If there is no ranlib the command will be ":".  Skip it.
-    cmEraseIf(linkCmds, cmNinjaRemoveNoOpCommands());
+    cm::erase_if(linkCmds, cmNinjaRemoveNoOpCommands());
 
     rule.Command = this->GetLocalGenerator()->BuildCommandLine(linkCmds);
 
@@ -379,7 +391,7 @@
     }
 
     // If there is no ranlib the command will be ":".  Skip it.
-    cmEraseIf(linkCmds, cmNinjaRemoveNoOpCommands());
+    cm::erase_if(linkCmds, cmNinjaRemoveNoOpCommands());
 
     linkCmds.insert(linkCmds.begin(), "$PRE_LINK");
     linkCmds.emplace_back("$POST_BUILD");
@@ -551,7 +563,8 @@
 }
 
 void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement(
-  const std::string& config)
+  const std::string& config, const std::string& fileConfig,
+  bool firstForConfig)
 {
   cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator();
   if (!globalGen->GetLanguageEnabled("CUDA")) {
@@ -574,12 +587,42 @@
   std::string const& objExt =
     this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION");
 
-  std::string const targetOutputReal = ConvertToNinjaPath(
-    genTarget->ObjectDirectory + "cmake_device_link" + objExt);
+  std::string targetOutputDir =
+    cmStrCat(this->GetLocalGenerator()->GetTargetDirectory(genTarget),
+             globalGen->ConfigDirectory(config), "/");
+  targetOutputDir = globalGen->ExpandCFGIntDir(targetOutputDir, config);
 
-  std::string const targetOutputImplib = ConvertToNinjaPath(
+  std::string targetOutputReal =
+    ConvertToNinjaPath(targetOutputDir + "cmake_device_link" + objExt);
+
+  std::string targetOutputImplib = ConvertToNinjaPath(
     genTarget->GetFullPath(config, cmStateEnums::ImportLibraryArtifact));
 
+  if (config != fileConfig) {
+    std::string targetOutputFileConfigDir =
+      cmStrCat(this->GetLocalGenerator()->GetTargetDirectory(genTarget),
+               globalGen->ConfigDirectory(fileConfig), "/");
+    targetOutputFileConfigDir =
+      globalGen->ExpandCFGIntDir(targetOutputDir, fileConfig);
+    if (targetOutputDir == targetOutputFileConfigDir) {
+      return;
+    }
+
+    if (!genTarget->GetFullName(config, cmStateEnums::ImportLibraryArtifact)
+           .empty() &&
+        !genTarget
+           ->GetFullName(fileConfig, cmStateEnums::ImportLibraryArtifact)
+           .empty() &&
+        targetOutputImplib ==
+          ConvertToNinjaPath(genTarget->GetFullPath(
+            fileConfig, cmStateEnums::ImportLibraryArtifact))) {
+      return;
+    }
+  }
+
+  if (firstForConfig) {
+    globalGen->GetByproductsForCleanTarget(config).push_back(targetOutputReal);
+  }
   this->DeviceLinkObject = targetOutputReal;
 
   // Write comments.
@@ -770,9 +813,9 @@
   }
 
   // Write comments.
-  cmGlobalNinjaGenerator::WriteDivider(this->GetConfigFileStream(fileConfig));
+  cmGlobalNinjaGenerator::WriteDivider(this->GetImplFileStream(fileConfig));
   const cmStateEnums::TargetType targetType = gt->GetType();
-  this->GetConfigFileStream(fileConfig)
+  this->GetImplFileStream(fileConfig)
     << "# Link build statements for " << cmState::GetTargetTypeName(targetType)
     << " target " << this->GetTargetName() << "\n\n";
 
@@ -1142,7 +1185,7 @@
 
   // Write the build statement for this target.
   bool usedResponseFile = false;
-  globalGen->WriteBuild(this->GetConfigFileStream(fileConfig), linkBuild,
+  globalGen->WriteBuild(this->GetImplFileStream(fileConfig), linkBuild,
                         commandLineLengthLimit, &usedResponseFile);
   this->WriteLinkRule(usedResponseFile, config);
 
@@ -1156,7 +1199,7 @@
       }
       build.ExplicitDeps.push_back(targetOutputReal);
       build.Variables = std::move(symlinkVars);
-      globalGen->WriteBuild(this->GetConfigFileStream(fileConfig), build);
+      globalGen->WriteBuild(this->GetImplFileStream(fileConfig), build);
     } else {
       cmNinjaBuild build("CMAKE_SYMLINK_LIBRARY");
       build.Comment = "Create library symlink " + targetOutput;
@@ -1182,7 +1225,7 @@
       build.ExplicitDeps.push_back(targetOutputReal);
       build.Variables = std::move(symlinkVars);
 
-      globalGen->WriteBuild(this->GetConfigFileStream(fileConfig), build);
+      globalGen->WriteBuild(this->GetImplFileStream(fileConfig), build);
     }
   }
 
diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h
index cda76d8..9de99b9 100644
--- a/Source/cmNinjaNormalTargetGenerator.h
+++ b/Source/cmNinjaNormalTargetGenerator.h
@@ -31,7 +31,9 @@
 
   void WriteLinkStatement(const std::string& config,
                           const std::string& fileConfig, bool firstForConfig);
-  void WriteDeviceLinkStatement(const std::string& config);
+  void WriteDeviceLinkStatement(const std::string& config,
+                                const std::string& fileConfig,
+                                bool firstForConfig);
 
   void WriteObjectLibStatement(const std::string& config);
 
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index bd19b28..455d809 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -68,10 +68,10 @@
 
 cmNinjaTargetGenerator::~cmNinjaTargetGenerator() = default;
 
-cmGeneratedFileStream& cmNinjaTargetGenerator::GetConfigFileStream(
+cmGeneratedFileStream& cmNinjaTargetGenerator::GetImplFileStream(
   const std::string& config) const
 {
-  return *this->GetGlobalGenerator()->GetConfigFileStream(config);
+  return *this->GetGlobalGenerator()->GetImplFileStream(config);
 }
 
 cmGeneratedFileStream& cmNinjaTargetGenerator::GetCommonFileStream() const
@@ -815,8 +815,8 @@
   bool firstForConfig)
 {
   // Write comments.
-  cmGlobalNinjaGenerator::WriteDivider(this->GetConfigFileStream(fileConfig));
-  this->GetConfigFileStream(fileConfig)
+  cmGlobalNinjaGenerator::WriteDivider(this->GetImplFileStream(fileConfig));
+  this->GetImplFileStream(fileConfig)
     << "# Object build statements for "
     << cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType())
     << " target " << this->GetTargetName() << "\n\n";
@@ -901,8 +901,8 @@
       orderOnlyDeps.push_back(this->ConvertToNinjaPath(tgtDir));
     }
 
-    this->GetGlobalGenerator()->WriteBuild(
-      this->GetConfigFileStream(fileConfig), build);
+    this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
+                                           build);
   }
 
   {
@@ -935,11 +935,11 @@
       this->GeneratorTarget, build.OrderOnlyDeps, config, fileConfig,
       DependOnTargetArtifact);
 
-    this->GetGlobalGenerator()->WriteBuild(
-      this->GetConfigFileStream(fileConfig), build);
+    this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
+                                           build);
   }
 
-  this->GetConfigFileStream(fileConfig) << "\n";
+  this->GetImplFileStream(fileConfig) << "\n";
 
   if (!this->Configs[config].SwiftOutputMap.empty()) {
     std::string const mapFilePath =
@@ -1177,8 +1177,8 @@
     this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
                                ppBuild.Variables);
 
-    this->GetGlobalGenerator()->WriteBuild(
-      this->GetConfigFileStream(fileConfig), ppBuild, commandLineLengthLimit);
+    this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
+                                           ppBuild, commandLineLengthLimit);
   }
   if (needDyndep) {
     std::string const dyndep = this->GetDyndepFilePath(language, config);
@@ -1196,6 +1196,13 @@
   this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
                              vars);
 
+  if (!pchSource.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) {
+    if (source->GetFullPath() == pchSource) {
+      this->addPoolNinjaVariable("JOB_POOL_PRECOMPILE_HEADER",
+                                 this->GetGeneratorTarget(), vars);
+    }
+  }
+
   this->SetMsvcTargetPdbVariable(vars, config);
 
   objBuild.RspFile = objectFileName + ".rsp";
@@ -1203,8 +1210,8 @@
   if (language == "Swift") {
     this->EmitSwiftDependencyInfo(source, config);
   } else {
-    this->GetGlobalGenerator()->WriteBuild(
-      this->GetConfigFileStream(fileConfig), objBuild, commandLineLengthLimit);
+    this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
+                                           objBuild, commandLineLengthLimit);
   }
 
   if (const char* objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) {
@@ -1214,8 +1221,8 @@
     std::transform(build.Outputs.begin(), build.Outputs.end(),
                    build.Outputs.begin(), MapToNinjaPath());
     build.ExplicitDeps = objBuild.Outputs;
-    this->GetGlobalGenerator()->WriteBuild(
-      this->GetConfigFileStream(fileConfig), build);
+    this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
+                                           build);
   }
 }
 
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
index 22dd7b8..bca12b1 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -47,7 +47,7 @@
 protected:
   bool SetMsvcTargetPdbVariable(cmNinjaVars&, const std::string& config) const;
 
-  cmGeneratedFileStream& GetConfigFileStream(const std::string& config) const;
+  cmGeneratedFileStream& GetImplFileStream(const std::string& config) const;
   cmGeneratedFileStream& GetCommonFileStream() const;
   cmGeneratedFileStream& GetRulesFileStream() const;
 
diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx
index 0cddb12..a42d65d 100644
--- a/Source/cmNinjaUtilityTargetGenerator.cxx
+++ b/Source/cmNinjaUtilityTargetGenerator.cxx
@@ -164,6 +164,6 @@
     cmNinjaBuild phonyAlias("phony");
     gg->AppendTargetOutputs(genTarget, phonyAlias.Outputs, "");
     phonyAlias.ExplicitDeps = phonyBuild.Outputs;
-    gg->WriteBuild(this->GetConfigFileStream(config), phonyAlias);
+    gg->WriteBuild(this->GetImplFileStream(config), phonyAlias);
   }
 }
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 8d292ac..1366ff0 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -299,7 +299,13 @@
          "libraries.",                                                        \
          3, 17, 0, cmPolicies::WARN)                                          \
   SELECT(POLICY, CMP0100, "Let AUTOMOC and AUTOUIC process .hh files.", 3,    \
-         17, 0, cmPolicies::WARN)
+         17, 0, cmPolicies::WARN)                                             \
+  SELECT(POLICY, CMP0101,                                                     \
+         "target_compile_options honors BEFORE keyword in all scopes.", 3,    \
+         17, 0, cmPolicies::WARN)                                             \
+  SELECT(POLICY, CMP0102,                                                     \
+         "mark_as_advanced() does nothing if a cache entry does not exist.",  \
+         3, 17, 0, cmPolicies::WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 46f1716..ebb522b 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -883,7 +883,7 @@
   // The reason is that their file names might be discovered from source files
   // at generation time.
   if (this->MocOrUicEnabled()) {
-    for (cmSourceFile* sf : this->Makefile->GetSourceFiles()) {
+    for (const auto& sf : this->Makefile->GetSourceFiles()) {
       // sf->GetExtension() is only valid after sf->ResolveFullPath() ...
       // Since we're iterating over source files that might be not in the
       // target we need to check for path errors (not existing files).
@@ -896,15 +896,15 @@
         cmSystemTools::LowerCase(sf->GetExtension());
 
       if (cm->IsHeaderExtension(extLower)) {
-        if (!cmContains(this->AutogenTarget.Headers, sf)) {
-          auto muf = makeMUFile(sf, fullPath, false);
+        if (!cmContains(this->AutogenTarget.Headers, sf.get())) {
+          auto muf = makeMUFile(sf.get(), fullPath, false);
           if (muf->SkipMoc || muf->SkipUic) {
             addMUHeader(std::move(muf), extLower);
           }
         }
       } else if (cm->IsSourceExtension(extLower)) {
-        if (!cmContains(this->AutogenTarget.Sources, sf)) {
-          auto muf = makeMUFile(sf, fullPath, false);
+        if (!cmContains(this->AutogenTarget.Sources, sf.get())) {
+          auto muf = makeMUFile(sf.get(), fullPath, false);
           if (muf->SkipMoc || muf->SkipUic) {
             addMUSource(std::move(muf));
           }
@@ -1219,7 +1219,10 @@
     // Register info file as generated by CMake
     this->Makefile->AddCMakeOutputFile(qrc.InfoFile);
     // Register file at target
-    this->AddGeneratedSource(qrc.OutputFile, this->Rcc);
+    {
+      cmSourceFile* sf = this->AddGeneratedSource(qrc.OutputFile, this->Rcc);
+      sf->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "On");
+    }
 
     std::vector<std::string> ccOutput;
     ccOutput.push_back(qrc.OutputFile);
@@ -1514,27 +1517,30 @@
   return true;
 }
 
-void cmQtAutoGenInitializer::RegisterGeneratedSource(
+cmSourceFile* cmQtAutoGenInitializer::RegisterGeneratedSource(
   std::string const& filename)
 {
   cmSourceFile* gFile = this->Makefile->GetOrCreateSource(filename, true);
   gFile->SetProperty("GENERATED", "1");
   gFile->SetProperty("SKIP_AUTOGEN", "1");
+  return gFile;
 }
 
-bool cmQtAutoGenInitializer::AddGeneratedSource(std::string const& filename,
-                                                GenVarsT const& genVars,
-                                                bool prepend)
+cmSourceFile* cmQtAutoGenInitializer::AddGeneratedSource(
+  std::string const& filename, GenVarsT const& genVars, bool prepend)
 {
   // Register source at makefile
-  this->RegisterGeneratedSource(filename);
+  cmSourceFile* gFile = this->RegisterGeneratedSource(filename);
   // Add source file to target
   this->GenTarget->AddSource(filename, prepend);
+
   // Add source file to source group
-  return this->AddToSourceGroup(filename, genVars.GenNameUpper);
+  this->AddToSourceGroup(filename, genVars.GenNameUpper);
+
+  return gFile;
 }
 
-bool cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName,
+void cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName,
                                               cm::string_view genNameUpper)
 {
   cmSourceGroup* sourceGroup = nullptr;
@@ -1565,14 +1571,12 @@
           cmStrCat(genNameUpper, " error in ", property,
                    ": Could not find or create the source group ",
                    cmQtAutoGen::Quoted(groupName)));
-        return false;
       }
     }
   }
   if (sourceGroup != nullptr) {
     sourceGroup->AddGroupFile(fileName);
   }
-  return true;
 }
 
 void cmQtAutoGenInitializer::AddCleanFile(std::string const& fileName)
diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h
index 847e4e5..8cedf14 100644
--- a/Source/cmQtAutoGenInitializer.h
+++ b/Source/cmQtAutoGenInitializer.h
@@ -129,10 +129,11 @@
   bool SetupWriteAutogenInfo();
   bool SetupWriteRccInfo();
 
-  void RegisterGeneratedSource(std::string const& filename);
-  bool AddGeneratedSource(std::string const& filename, GenVarsT const& genVars,
-                          bool prepend = false);
-  bool AddToSourceGroup(std::string const& fileName,
+  cmSourceFile* RegisterGeneratedSource(std::string const& filename);
+  cmSourceFile* AddGeneratedSource(std::string const& filename,
+                                   GenVarsT const& genVars,
+                                   bool prepend = false);
+  void AddToSourceGroup(std::string const& fileName,
                         cm::string_view genNameUpper);
   void AddCleanFile(std::string const& fileName);
 
diff --git a/Source/cmScriptGenerator.h b/Source/cmScriptGenerator.h
index c8bb1ab..7d676c9 100644
--- a/Source/cmScriptGenerator.h
+++ b/Source/cmScriptGenerator.h
@@ -71,7 +71,7 @@
 
   std::string CreateConfigTest(const std::string& config);
   std::string CreateConfigTest(std::vector<std::string> const& configs);
-  std::string CreateComponentTest(const char* component);
+  std::string CreateComponentTest(const std::string& component);
 
   // Information shared by most generator types.
   std::string RuntimeConfigVariable;
diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx
index 2a345eb..60adf7f 100644
--- a/Source/cmSourceFile.cxx
+++ b/Source/cmSourceFile.cxx
@@ -128,7 +128,7 @@
   // The file is not generated.  It must exist on disk.
   cmMakefile const* makefile = this->Location.GetMakefile();
   // Location path
-  std::string const lPath = this->Location.GetFullPath();
+  std::string const& lPath = this->Location.GetFullPath();
   // List of extension lists
   std::array<std::vector<std::string> const*, 2> const extsLists = {
     { &makefile->GetCMakeInstance()->GetSourceExtensions(),
@@ -145,7 +145,7 @@
       return true;
     }
     // Try full path with extension
-    for (auto exts : extsLists) {
+    for (auto& exts : extsLists) {
       for (std::string const& ext : *exts) {
         if (!ext.empty()) {
           std::string extPath = cmStrCat(fullPath, '.', ext);
diff --git a/Source/cmSourceFileLocation.cxx b/Source/cmSourceFileLocation.cxx
index df702b0..5f807b8 100644
--- a/Source/cmSourceFileLocation.cxx
+++ b/Source/cmSourceFileLocation.cxx
@@ -31,7 +31,8 @@
   this->AmbiguousExtension = true;
   this->Directory = cmSystemTools::GetFilenamePath(name);
   if (cmSystemTools::FileIsFullPath(this->Directory)) {
-    this->Directory = cmSystemTools::CollapseFullPath(this->Directory);
+    this->Directory = cmSystemTools::CollapseFullPath(
+      this->Directory, mf->GetHomeOutputDirectory());
   }
   this->Name = cmSystemTools::GetFilenameName(name);
   if (kind == cmSourceFileLocationKind::Known) {
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index 9d83a72..35f07a1 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -150,8 +150,7 @@
 cmStateEnums::CacheEntryType cmState::GetCacheEntryType(
   std::string const& key) const
 {
-  cmCacheManager::CacheIterator it =
-    this->CacheManager->GetCacheIterator(key.c_str());
+  cmCacheManager::CacheIterator it = this->CacheManager->GetCacheIterator(key);
   return it.GetType();
 }
 
@@ -165,8 +164,7 @@
                                     std::string const& propertyName,
                                     std::string const& value)
 {
-  cmCacheManager::CacheIterator it =
-    this->CacheManager->GetCacheIterator(key.c_str());
+  cmCacheManager::CacheIterator it = this->CacheManager->GetCacheIterator(key);
   it.SetProperty(propertyName, value.c_str());
 }
 
@@ -174,24 +172,21 @@
                                         std::string const& propertyName,
                                         bool value)
 {
-  cmCacheManager::CacheIterator it =
-    this->CacheManager->GetCacheIterator(key.c_str());
+  cmCacheManager::CacheIterator it = this->CacheManager->GetCacheIterator(key);
   it.SetProperty(propertyName, value);
 }
 
 std::vector<std::string> cmState::GetCacheEntryPropertyList(
   const std::string& key)
 {
-  cmCacheManager::CacheIterator it =
-    this->CacheManager->GetCacheIterator(key.c_str());
+  cmCacheManager::CacheIterator it = this->CacheManager->GetCacheIterator(key);
   return it.GetPropertyList();
 }
 
 const char* cmState::GetCacheEntryProperty(std::string const& key,
                                            std::string const& propertyName)
 {
-  cmCacheManager::CacheIterator it =
-    this->CacheManager->GetCacheIterator(key.c_str());
+  cmCacheManager::CacheIterator it = this->CacheManager->GetCacheIterator(key);
   if (!it.PropertyExists(propertyName)) {
     return nullptr;
   }
@@ -201,8 +196,8 @@
 bool cmState::GetCacheEntryPropertyAsBool(std::string const& key,
                                           std::string const& propertyName)
 {
-  return this->CacheManager->GetCacheIterator(key.c_str())
-    .GetPropertyAsBool(propertyName);
+  return this->CacheManager->GetCacheIterator(key).GetPropertyAsBool(
+    propertyName);
 }
 
 void cmState::AddCacheEntry(const std::string& key, const char* value,
@@ -254,15 +249,14 @@
                                        const std::string& property,
                                        const std::string& value, bool asString)
 {
-  this->CacheManager->GetCacheIterator(key.c_str())
-    .AppendProperty(property, value.c_str(), asString);
+  this->CacheManager->GetCacheIterator(key).AppendProperty(property, value,
+                                                           asString);
 }
 
 void cmState::RemoveCacheEntryProperty(std::string const& key,
                                        std::string const& propertyName)
 {
-  this->CacheManager->GetCacheIterator(key.c_str())
-    .SetProperty(propertyName, nullptr);
+  this->CacheManager->GetCacheIterator(key).SetProperty(propertyName, nullptr);
 }
 
 cmStateSnapshot cmState::Reset()
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 9563321..d46bf56 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -513,9 +513,11 @@
       this->GetType() != cmStateEnums::UTILITY) {
     initProp("JOB_POOL_COMPILE");
     initProp("JOB_POOL_LINK");
+    initProp("JOB_POOL_PRECOMPILE_HEADER");
   }
 
   if (impl->TargetType <= cmStateEnums::UTILITY) {
+    initProp("DOTNET_TARGET_FRAMEWORK");
     initProp("DOTNET_TARGET_FRAMEWORK_VERSION");
   }
 
@@ -937,14 +939,7 @@
   return impl->OriginalLinkLibraries;
 }
 
-void cmTarget::AddLinkLibrary(cmMakefile& mf, const std::string& lib,
-                              cmTargetLinkLibraryType llt)
-{
-  this->AddLinkLibrary(mf, lib, lib, llt);
-}
-
 void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
-                              std::string const& libRef,
                               cmTargetLinkLibraryType llt)
 {
   cmTarget* tgt = mf.FindTargetToUse(lib);
@@ -953,13 +948,13 @@
 
     const std::string libName =
       (isNonImportedTarget && llt != GENERAL_LibraryType)
-      ? targetNameGenex(libRef)
-      : libRef;
+      ? targetNameGenex(lib)
+      : lib;
     this->AppendProperty("LINK_LIBRARIES",
                          this->GetDebugGeneratorExpressions(libName, llt));
   }
 
-  if (cmGeneratorExpression::Find(lib) != std::string::npos || lib != libRef ||
+  if (cmGeneratorExpression::Find(lib) != std::string::npos ||
       (tgt &&
        (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
         tgt->GetType() == cmStateEnums::OBJECT_LIBRARY)) ||
@@ -1562,8 +1557,12 @@
 static void cmTargetCheckIMPORTED_GLOBAL(const cmTarget* target,
                                          cmMakefile* context)
 {
-  std::vector<cmTarget*> targets = context->GetOwnedImportedTargets();
-  auto it = std::find(targets.begin(), targets.end(), target);
+  const auto& targets = context->GetOwnedImportedTargets();
+  auto it =
+    std::find_if(targets.begin(), targets.end(),
+                 [&](const std::unique_ptr<cmTarget>& importTarget) -> bool {
+                   return target == importTarget.get();
+                 });
   if (it == targets.end()) {
     std::ostringstream e;
     e << "Attempt to promote imported target \"" << target->GetName()
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index bdf8c0f..ca37f0d 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -110,10 +110,8 @@
   //! Clear the dependency information recorded for this target, if any.
   void ClearDependencyInformation(cmMakefile& mf);
 
-  void AddLinkLibrary(cmMakefile& mf, const std::string& lib,
-                      cmTargetLinkLibraryType llt);
   void AddLinkLibrary(cmMakefile& mf, std::string const& lib,
-                      std::string const& libRef, cmTargetLinkLibraryType llt);
+                      cmTargetLinkLibraryType llt);
 
   enum TLLSignature
   {
diff --git a/Source/cmTargetCompileOptionsCommand.cxx b/Source/cmTargetCompileOptionsCommand.cxx
index e39b726..dee2c10 100644
--- a/Source/cmTargetCompileOptionsCommand.cxx
+++ b/Source/cmTargetCompileOptionsCommand.cxx
@@ -5,6 +5,7 @@
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmPolicies.h"
 #include "cmStringAlgorithms.h"
 #include "cmTarget.h"
 #include "cmTargetPropCommandBase.h"
@@ -27,10 +28,16 @@
 
   bool HandleDirectContent(cmTarget* tgt,
                            const std::vector<std::string>& content,
-                           bool /*prepend*/, bool /*system*/) override
+                           bool prepend, bool /*system*/) override
   {
+    cmPolicies::PolicyStatus policyStatus =
+      this->Makefile->GetPolicyStatus(cmPolicies::CMP0101);
+    if (policyStatus == cmPolicies::OLD || policyStatus == cmPolicies::WARN) {
+      prepend = false;
+    }
+
     cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
-    tgt->InsertCompileOption(this->Join(content), lfbt);
+    tgt->InsertCompileOption(this->Join(content), lfbt, prepend);
     return true; // Successfully handled.
   }
 
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
index e1ac6a8..df751da 100644
--- a/Source/cmTargetLinkLibrariesCommand.cxx
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -3,7 +3,10 @@
 #include "cmTargetLinkLibrariesCommand.h"
 
 #include <cstring>
+#include <memory>
 #include <sstream>
+#include <unordered_set>
+#include <utility>
 
 #include "cmExecutionStatus.h"
 #include "cmGeneratorExpression.h"
@@ -34,15 +37,30 @@
 
 const char* LinkLibraryTypeNames[3] = { "general", "debug", "optimized" };
 
+struct TLL
+{
+  cmMakefile& Makefile;
+  cmTarget* Target;
+  bool WarnRemoteInterface = false;
+  bool RejectRemoteLinking = false;
+  bool EncodeRemoteReference = false;
+  std::string DirectoryId;
+  std::unordered_set<std::string> Props;
+
+  TLL(cmMakefile& mf, cmTarget* target);
+  ~TLL();
+
+  bool HandleLibrary(ProcessingState currentProcessingState,
+                     const std::string& lib, cmTargetLinkLibraryType llt);
+  void AppendProperty(std::string const& prop, std::string const& value);
+  void AffectsProperty(std::string const& prop);
+};
+
 } // namespace
 
 static void LinkLibraryTypeSpecifierWarning(cmMakefile& mf, int left,
                                             int right);
 
-static bool HandleLibrary(cmMakefile& mf, cmTarget* target,
-                          ProcessingState currentProcessingState,
-                          const std::string& lib, cmTargetLinkLibraryType llt);
-
 bool cmTargetLinkLibrariesCommand(std::vector<std::string> const& args,
                                   cmExecutionStatus& status)
 {
@@ -64,11 +82,9 @@
   cmTarget* target =
     mf.GetCMakeInstance()->GetGlobalGenerator()->FindTarget(args[0]);
   if (!target) {
-    const std::vector<cmTarget*>& importedTargets =
-      mf.GetOwnedImportedTargets();
-    for (cmTarget* importedTarget : importedTargets) {
+    for (const auto& importedTarget : mf.GetOwnedImportedTargets()) {
       if (importedTarget->GetName() == args[0]) {
-        target = importedTarget;
+        target = importedTarget.get();
         break;
       }
     }
@@ -149,6 +165,8 @@
     return true;
   }
 
+  TLL tll(mf, target);
+
   // Keep track of link configuration specifiers.
   cmTargetLinkLibraryType llt = GENERAL_LibraryType;
   bool haveLLT = false;
@@ -247,7 +265,7 @@
     } else if (haveLLT) {
       // The link type was specified by the previous argument.
       haveLLT = false;
-      if (!HandleLibrary(mf, target, currentProcessingState, args[i], llt)) {
+      if (!tll.HandleLibrary(currentProcessingState, args[i], llt)) {
         return false;
       }
     } else {
@@ -268,7 +286,7 @@
           llt = OPTIMIZED_LibraryType;
         }
       }
-      if (!HandleLibrary(mf, target, currentProcessingState, args[i], llt)) {
+      if (!tll.HandleLibrary(currentProcessingState, args[i], llt)) {
         return false;
       }
     }
@@ -311,21 +329,48 @@
       "\" instead of a library name.  The first specifier will be ignored."));
 }
 
-static bool HandleLibrary(cmMakefile& mf, cmTarget* target,
-                          ProcessingState currentProcessingState,
-                          const std::string& lib, cmTargetLinkLibraryType llt)
+namespace {
+
+TLL::TLL(cmMakefile& mf, cmTarget* target)
+  : Makefile(mf)
+  , Target(target)
 {
-  if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY &&
+  if (&this->Makefile != this->Target->GetMakefile()) {
+    // The LHS target was created in another directory.
+    switch (this->Makefile.GetPolicyStatus(cmPolicies::CMP0079)) {
+      case cmPolicies::WARN:
+        this->WarnRemoteInterface = true;
+        CM_FALLTHROUGH;
+      case cmPolicies::OLD:
+        this->RejectRemoteLinking = true;
+        break;
+      case cmPolicies::REQUIRED_ALWAYS:
+      case cmPolicies::REQUIRED_IF_USED:
+      case cmPolicies::NEW:
+        this->EncodeRemoteReference = true;
+        break;
+    }
+  }
+  if (this->EncodeRemoteReference) {
+    cmDirectoryId const dirId = this->Makefile.GetDirectoryId();
+    this->DirectoryId = cmStrCat(CMAKE_DIRECTORY_ID_SEP, dirId.String);
+  }
+}
+
+bool TLL::HandleLibrary(ProcessingState currentProcessingState,
+                        const std::string& lib, cmTargetLinkLibraryType llt)
+{
+  if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY &&
       currentProcessingState != ProcessingKeywordLinkInterface) {
-    mf.IssueMessage(
+    this->Makefile.IssueMessage(
       MessageType::FATAL_ERROR,
       "INTERFACE library can only be used with the INTERFACE keyword of "
       "target_link_libraries");
     return false;
   }
-  if (target->IsImported() &&
+  if (this->Target->IsImported() &&
       currentProcessingState != ProcessingKeywordLinkInterface) {
-    mf.IssueMessage(
+    this->Makefile.IssueMessage(
       MessageType::FATAL_ERROR,
       "IMPORTED library can only be used with the INTERFACE keyword of "
       "target_link_libraries");
@@ -340,11 +385,12 @@
      currentProcessingState == ProcessingKeywordLinkInterface)
     ? cmTarget::KeywordTLLSignature
     : cmTarget::PlainTLLSignature;
-  if (!target->PushTLLCommandTrace(sig, mf.GetExecutionContext())) {
+  if (!this->Target->PushTLLCommandTrace(
+        sig, this->Makefile.GetExecutionContext())) {
     std::ostringstream e;
     const char* modal = nullptr;
     MessageType messageType = MessageType::AUTHOR_WARNING;
-    switch (mf.GetPolicyStatus(cmPolicies::CMP0023)) {
+    switch (this->Makefile.GetPolicyStatus(cmPolicies::CMP0023)) {
       case cmPolicies::WARN:
         e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0023) << "\n";
         modal = "should";
@@ -365,73 +411,38 @@
       e << "The " << existingSig
         << " signature for target_link_libraries has "
            "already been used with the target \""
-        << target->GetName()
+        << this->Target->GetName()
         << "\".  All uses of target_link_libraries with a target " << modal
         << " be either all-keyword or all-plain.\n";
-      target->GetTllSignatureTraces(e,
-                                    sig == cmTarget::KeywordTLLSignature
-                                      ? cmTarget::PlainTLLSignature
-                                      : cmTarget::KeywordTLLSignature);
-      mf.IssueMessage(messageType, e.str());
+      this->Target->GetTllSignatureTraces(e,
+                                          sig == cmTarget::KeywordTLLSignature
+                                            ? cmTarget::PlainTLLSignature
+                                            : cmTarget::KeywordTLLSignature);
+      this->Makefile.IssueMessage(messageType, e.str());
       if (messageType == MessageType::FATAL_ERROR) {
         return false;
       }
     }
   }
 
-  bool warnRemoteInterface = false;
-  bool rejectRemoteLinking = false;
-  bool encodeRemoteReference = false;
-  if (&mf != target->GetMakefile()) {
-    // The LHS target was created in another directory.
-    switch (mf.GetPolicyStatus(cmPolicies::CMP0079)) {
-      case cmPolicies::WARN:
-        warnRemoteInterface = true;
-        CM_FALLTHROUGH;
-      case cmPolicies::OLD:
-        rejectRemoteLinking = true;
-        break;
-      case cmPolicies::REQUIRED_ALWAYS:
-      case cmPolicies::REQUIRED_IF_USED:
-      case cmPolicies::NEW:
-        encodeRemoteReference = true;
-        break;
-    }
-  }
-
-  std::string libRef;
-  if (encodeRemoteReference && !cmSystemTools::FileIsFullPath(lib)) {
-    // This is a library name added by a caller that is not in the
-    // same directory as the target was created.  Add a suffix to
-    // the name to tell ResolveLinkItem to look up the name in the
-    // caller's directory.
-    cmDirectoryId const dirId = mf.GetDirectoryId();
-    libRef = lib + CMAKE_DIRECTORY_ID_SEP + dirId.String;
-  } else {
-    // This is an absolute path or a library name added by a caller
-    // in the same directory as the target was created.  We can use
-    // the original name directly.
-    libRef = lib;
-  }
-
   // Handle normal case where the command was called with another keyword than
   // INTERFACE / LINK_INTERFACE_LIBRARIES or none at all. (The "LINK_LIBRARIES"
   // property of the target on the LHS shall be populated.)
   if (currentProcessingState != ProcessingKeywordLinkInterface &&
       currentProcessingState != ProcessingPlainLinkInterface) {
 
-    if (rejectRemoteLinking) {
-      mf.IssueMessage(
+    if (this->RejectRemoteLinking) {
+      this->Makefile.IssueMessage(
         MessageType::FATAL_ERROR,
         cmStrCat("Attempt to add link library \"", lib, "\" to target \"",
-                 target->GetName(),
+                 this->Target->GetName(),
                  "\" which is not built in this "
                  "directory.\nThis is allowed only when policy CMP0079 "
                  "is set to NEW."));
       return false;
     }
 
-    cmTarget* tgt = mf.GetGlobalGenerator()->FindTarget(lib);
+    cmTarget* tgt = this->Makefile.GetGlobalGenerator()->FindTarget(lib);
 
     if (tgt && (tgt->GetType() != cmStateEnums::STATIC_LIBRARY) &&
         (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) &&
@@ -439,7 +450,7 @@
         (tgt->GetType() != cmStateEnums::OBJECT_LIBRARY) &&
         (tgt->GetType() != cmStateEnums::INTERFACE_LIBRARY) &&
         !tgt->IsExecutableWithExports()) {
-      mf.IssueMessage(
+      this->Makefile.IssueMessage(
         MessageType::FATAL_ERROR,
         cmStrCat(
           "Target \"", lib, "\" of type ",
@@ -449,15 +460,16 @@
           "executables with the ENABLE_EXPORTS property set."));
     }
 
-    target->AddLinkLibrary(mf, lib, libRef, llt);
+    this->AffectsProperty("LINK_LIBRARIES");
+    this->Target->AddLinkLibrary(this->Makefile, lib, llt);
   }
 
-  if (warnRemoteInterface) {
-    mf.IssueMessage(
+  if (this->WarnRemoteInterface) {
+    this->Makefile.IssueMessage(
       MessageType::AUTHOR_WARNING,
       cmStrCat(
         cmPolicies::GetPolicyWarning(cmPolicies::CMP0079), "\nTarget\n  ",
-        target->GetName(),
+        this->Target->GetName(),
         "\nis not created in this "
         "directory.  For compatibility with older versions of CMake, link "
         "library\n  ",
@@ -472,15 +484,15 @@
   // STATIC library.)
   if (currentProcessingState == ProcessingKeywordPrivateInterface ||
       currentProcessingState == ProcessingPlainPrivateInterface) {
-    if (target->GetType() == cmStateEnums::STATIC_LIBRARY ||
-        target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
+    if (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY ||
+        this->Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
       std::string configLib =
-        target->GetDebugGeneratorExpressions(libRef, llt);
+        this->Target->GetDebugGeneratorExpressions(lib, llt);
       if (cmGeneratorExpression::IsValidTargetName(lib) ||
           cmGeneratorExpression::Find(lib) != std::string::npos) {
         configLib = "$<LINK_ONLY:" + configLib + ">";
       }
-      target->AppendProperty("INTERFACE_LINK_LIBRARIES", configLib);
+      this->AppendProperty("INTERFACE_LINK_LIBRARIES", configLib);
     }
     return true;
   }
@@ -488,8 +500,8 @@
   // Handle general case where the command was called with another keyword than
   // PRIVATE / LINK_PRIVATE or none at all. (The "INTERFACE_LINK_LIBRARIES"
   // property of the target on the LHS shall be populated.)
-  target->AppendProperty("INTERFACE_LINK_LIBRARIES",
-                         target->GetDebugGeneratorExpressions(libRef, llt));
+  this->AppendProperty("INTERFACE_LINK_LIBRARIES",
+                       this->Target->GetDebugGeneratorExpressions(lib, llt));
 
   // Stop processing if called without any keyword.
   if (currentProcessingState == ProcessingLinkLibraries) {
@@ -497,13 +509,13 @@
   }
   // Stop processing if policy CMP0022 is set to NEW.
   const cmPolicies::PolicyStatus policy22Status =
-    target->GetPolicyStatusCMP0022();
+    this->Target->GetPolicyStatusCMP0022();
   if (policy22Status != cmPolicies::OLD &&
       policy22Status != cmPolicies::WARN) {
     return true;
   }
   // Stop processing if called with an INTERFACE library on the LHS.
-  if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+  if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
     return true;
   }
 
@@ -513,7 +525,7 @@
   {
     // Get the list of configurations considered to be DEBUG.
     std::vector<std::string> debugConfigs =
-      mf.GetCMakeInstance()->GetDebugConfigs();
+      this->Makefile.GetCMakeInstance()->GetDebugConfigs();
     std::string prop;
 
     // Include this library in the link interface for the target.
@@ -521,22 +533,49 @@
       // Put in the DEBUG configuration interfaces.
       for (std::string const& dc : debugConfigs) {
         prop = cmStrCat("LINK_INTERFACE_LIBRARIES_", dc);
-        target->AppendProperty(prop, libRef);
+        this->AppendProperty(prop, lib);
       }
     }
     if (llt == OPTIMIZED_LibraryType || llt == GENERAL_LibraryType) {
       // Put in the non-DEBUG configuration interfaces.
-      target->AppendProperty("LINK_INTERFACE_LIBRARIES", libRef);
+      this->AppendProperty("LINK_INTERFACE_LIBRARIES", lib);
 
       // Make sure the DEBUG configuration interfaces exist so that the
       // general one will not be used as a fall-back.
       for (std::string const& dc : debugConfigs) {
         prop = cmStrCat("LINK_INTERFACE_LIBRARIES_", dc);
-        if (!target->GetProperty(prop)) {
-          target->SetProperty(prop, "");
+        if (!this->Target->GetProperty(prop)) {
+          this->Target->SetProperty(prop, "");
         }
       }
     }
   }
   return true;
 }
+
+void TLL::AppendProperty(std::string const& prop, std::string const& value)
+{
+  this->AffectsProperty(prop);
+  this->Target->AppendProperty(prop, value);
+}
+
+void TLL::AffectsProperty(std::string const& prop)
+{
+  if (!this->EncodeRemoteReference) {
+    return;
+  }
+  // Add a wrapper to the expression to tell LookupLinkItems to look up
+  // names in the caller's directory.
+  if (this->Props.insert(prop).second) {
+    this->Target->AppendProperty(prop, this->DirectoryId);
+  }
+}
+
+TLL::~TLL()
+{
+  for (std::string const& prop : this->Props) {
+    this->Target->AppendProperty(prop, CMAKE_DIRECTORY_ID_SEP);
+  }
+}
+
+} // namespace
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index f707bb4..fd94bc9 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -483,23 +483,33 @@
       }
       e1.Element("ProjectName", projLabel);
       {
-        // TODO: add deprecation warning for VS_* property?
-        const char* targetFrameworkVersion =
-          this->GeneratorTarget->GetProperty(
-            "VS_DOTNET_TARGET_FRAMEWORK_VERSION");
-        if (!targetFrameworkVersion) {
-          targetFrameworkVersion = this->GeneratorTarget->GetProperty(
-            "DOTNET_TARGET_FRAMEWORK_VERSION");
-        }
-        if (!targetFrameworkVersion && this->ProjectType == csproj &&
-            this->GlobalGenerator->TargetsWindowsCE() &&
-            this->GlobalGenerator->GetVersion() ==
-              cmGlobalVisualStudioGenerator::VS12) {
-          // VS12 .NETCF default to .NET framework 3.9
-          targetFrameworkVersion = "v3.9";
-        }
-        if (targetFrameworkVersion) {
-          e1.Element("TargetFrameworkVersion", targetFrameworkVersion);
+        const char* targetFramework =
+          this->GeneratorTarget->GetProperty("DOTNET_TARGET_FRAMEWORK");
+        if (targetFramework) {
+          if (std::strchr(targetFramework, ';') != nullptr) {
+            e1.Element("TargetFrameworks", targetFramework);
+          } else {
+            e1.Element("TargetFramework", targetFramework);
+          }
+        } else {
+          // TODO: add deprecation warning for VS_* property?
+          const char* targetFrameworkVersion =
+            this->GeneratorTarget->GetProperty(
+              "VS_DOTNET_TARGET_FRAMEWORK_VERSION");
+          if (!targetFrameworkVersion) {
+            targetFrameworkVersion = this->GeneratorTarget->GetProperty(
+              "DOTNET_TARGET_FRAMEWORK_VERSION");
+          }
+          if (!targetFrameworkVersion && this->ProjectType == csproj &&
+              this->GlobalGenerator->TargetsWindowsCE() &&
+              this->GlobalGenerator->GetVersion() ==
+                cmGlobalVisualStudioGenerator::VS12) {
+            // VS12 .NETCF default to .NET framework 3.9
+            targetFrameworkVersion = "v3.9";
+          }
+          if (targetFrameworkVersion) {
+            e1.Element("TargetFrameworkVersion", targetFrameworkVersion);
+          }
         }
         if (this->ProjectType == vcxproj &&
             this->GlobalGenerator->TargetsWindowsCE()) {
@@ -4110,6 +4120,9 @@
     e2.Element("Project", "{" + this->GlobalGenerator->GetGUID(name) + "}");
     e2.Element("Name", name);
     this->WriteDotNetReferenceCustomTags(e2, name);
+    if (dt->IsCSharpOnly() || cmHasLiteralSuffix(path, "csproj")) {
+      e2.Element("SkipGetTargetFrameworkProperties", "true");
+    }
 
     // Don't reference targets that don't produce any output.
     if (dt->GetManagedType("") == cmGeneratorTarget::ManagedType::Undefined) {
diff --git a/Tests/CMakeCommands/target_link_libraries/SubDirB/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/SubDirB/CMakeLists.txt
index 7c918e6..06d1111 100644
--- a/Tests/CMakeCommands/target_link_libraries/SubDirB/CMakeLists.txt
+++ b/Tests/CMakeCommands/target_link_libraries/SubDirB/CMakeLists.txt
@@ -2,7 +2,11 @@
 
 # Link to a target imported in this directory that would not normally
 # be visible to the directory in which TopDir is defined.
-target_link_libraries(TopDir PUBLIC SameNameImported)
+target_link_libraries(TopDir PUBLIC debug SameNameImported optimized SameNameImported)
+
+# Link to a list of targets imported in this directory that would not
+# normally be visible to the directory in which TopDir is defined.
+target_link_libraries(TopDir PUBLIC "$<1:SameNameImported;SameNameImported>")
 
 # Link SubDirA to a target imported in this directory that has the same
 # name as a target imported in SubDirA's directory.  We verify when
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 4fdd7c8..6fad175 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -1616,6 +1616,7 @@
       set(tutorial_build_options -DUSE_MYMATH:BOOL=OFF)
     endif()
     add_test(${tutorial_test_name} ${CMAKE_CTEST_COMMAND}
+      -C "Release"
       --build-and-test
       "${CMake_SOURCE_DIR}/Help/guide/tutorial/${step_name}"
       ${tutorial_build_dir}_Build
@@ -1627,11 +1628,11 @@
   endfunction()
 
   if(NOT CMake_TEST_EXTERNAL_CMAKE)
-    foreach(STP RANGE 2 11)
+    foreach(STP RANGE 2 12)
       add_tutorial_test(Step${STP} TRUE)
     endforeach()
     add_tutorial_test(Complete TRUE)
-    foreach(STP RANGE 3 11)
+    foreach(STP RANGE 3 12)
       add_tutorial_test(Step${STP} FALSE)
     endforeach()
     add_tutorial_test(Complete FALSE)
diff --git a/Tests/CMakeTests/CMakeLists.txt b/Tests/CMakeTests/CMakeLists.txt
index 1619081..e32d693 100644
--- a/Tests/CMakeTests/CMakeLists.txt
+++ b/Tests/CMakeTests/CMakeLists.txt
@@ -33,8 +33,9 @@
 AddCMakeTest(CMakeHostSystemInformation "")
 
 AddCMakeTest(FileDownload "")
-set_property(TEST CMake.FileDownload PROPERTY
+set_tests_properties(CMake.FileDownload PROPERTIES
   PASS_REGULAR_EXPRESSION "file already exists with expected MD5 sum"
+  FAIL_REGULAR_EXPRESSION "Unexpected status"
   )
 AddCMakeTest(FileDownloadBadHash "")
 set_property(TEST CMake.FileDownloadBadHash PROPERTY
diff --git a/Tests/CMakeTests/FileDownloadTest.cmake.in b/Tests/CMakeTests/FileDownloadTest.cmake.in
index 3935449..76c0000 100644
--- a/Tests/CMakeTests/FileDownloadTest.cmake.in
+++ b/Tests/CMakeTests/FileDownloadTest.cmake.in
@@ -1,23 +1,50 @@
+# We do not contact any real URLs, but do try a bogus one.
+# Remove any proxy configuration that may change behavior.
+unset(ENV{http_proxy})
+unset(ENV{https_proxy})
+
+set(timeout 4)
+
 if(NOT "@CMAKE_CURRENT_SOURCE_DIR@" MATCHES "^/")
   set(slash /)
 endif()
 set(url "file://${slash}@CMAKE_CURRENT_SOURCE_DIR@/FileDownloadInput.png")
 set(dir "@CMAKE_CURRENT_BINARY_DIR@/downloads")
 
+# Beware Windows asynchronous file/directory removal, rename and then
+# remove the renamed dir so we can be certain the dir isn't there when
+# we get to the file() commands below
+if(EXISTS "${dir}")
+  file(RENAME ${dir} "${dir}_beingRemoved")
+  file(REMOVE_RECURSE "${dir}_beingRemoved")
+endif()
+
+function(__reportIfWrongStatus statusPair expectedStatusCode)
+  list(GET statusPair 0 statusCode)
+  if(NOT statusCode EQUAL expectedStatusCode)
+    message(SEND_ERROR
+            "Unexpected status: ${statusCode}, expected: ${expectedStatusCode}")
+  endif()
+endfunction()
+
 message(STATUS "FileDownload:1")
 file(DOWNLOAD
   ${url}
   ${dir}/file1.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
+  STATUS status
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:2")
 file(DOWNLOAD
   ${url}
   ${dir}/file2.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
+  STATUS status
   SHOW_PROGRESS
   )
+__reportIfWrongStatus("${status}" 0)
 
 # Two calls in a row, exactly the same arguments.
 # Since downloaded file should exist already for 2nd call,
@@ -31,82 +58,108 @@
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
+  STATUS status
   EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:4")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH SHA1=67eee17f79d9ac557284fc0b8ad19f25723fb578
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:5")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH SHA224=ba283726bbb602776818b463943189afd91836cb7ee5dd6e2c7b5ae4
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:6")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH SHA256=cf3334b1275071e1da6e8c396ccb72cf1b2388d8c937526f3af26230affb9423
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:7")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH SHA384=43a5d13978d97c660db44481aee0604cb4ff6ca0775cd5c2cd68cd8000e107e507c4caf6c228941231041e282ffb8950
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:8")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH SHA512=6984e0909a1018030ccaa418e3be1654223cdccff0fe6adc745f9aea7e377f178be53b9fc7d54a6f81c2b62ef9ddcd38ba1978fedf4c5e7139baaf355eefad5b
   )
+__reportIfWrongStatus("${status}" 0)
+
 message(STATUS "FileDownload:9")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH MD5=dbd330d52f4dbd60115d4191904ded92
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:10")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92
   )
+__reportIfWrongStatus("${status}" 0)
+# Print status because we check its message too
 message(STATUS "${status}")
 
 message(STATUS "FileDownload:11")
 file(DOWNLOAD
-  badhostname.png
+  badhostname.invalid
   ${dir}/file11.png
-  TIMEOUT 2
+  TIMEOUT 30
   STATUS status
   )
 message(STATUS "${status}")
-list(GET status 0 status_code)
-if(NOT ${status_code} EQUAL 6)
-  message(SEND_ERROR "error: expected status code 6 for bad host name, got: ${status_code}")
+__reportIfWrongStatus("${status}" 6) # 6 corresponds to an unresolvable host name
+
+message(STATUS "FileDownload:12")
+set(absFile "@CMAKE_CURRENT_BINARY_DIR@/file12.png")
+if(EXISTS "${absFile}")
+  file(RENAME ${absFile} "${absFile}_beingRemoved")
+  file(REMOVE "${absFile}_beingRemoved")
+endif()
+file(DOWNLOAD
+  ${url}
+  file12.png
+  TIMEOUT ${timeout}
+  EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92
+  STATUS status
+  )
+__reportIfWrongStatus("${status}" 0)
+if(NOT EXISTS file12.png)
+  message(SEND_ERROR "file12.png not downloaded: ${status}")
 endif()
diff --git a/Tests/CMakeTests/FileTestScript.cmake b/Tests/CMakeTests/FileTestScript.cmake
index 9a43569..145f28a 100644
--- a/Tests/CMakeTests/FileTestScript.cmake
+++ b/Tests/CMakeTests/FileTestScript.cmake
@@ -183,7 +183,7 @@
 elseif(testname STREQUAL download_wrong_number_of_args) # fail
   file(DOWNLOAD zzzz://bogus/ffff)
 
-elseif(testname STREQUAL download_file_with_no_path) # fail
+elseif(testname STREQUAL download_file_with_no_path) # pass
   file(DOWNLOAD zzzz://bogus/ffff ffff)
 
 elseif(testname STREQUAL download_missing_time) # fail
diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description1.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description1.cmake
index 86a74b2..f46a575 100644
--- a/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description1.cmake
+++ b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description1.cmake
@@ -65,9 +65,10 @@
                                       "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: `${dpkg_description}` != `${expected_description}`")
       endif()
     elseif(dpkg_package_name STREQUAL "mylib-libraries")
-      if(NOT dpkg_description MATCHES "main description\n.*")
+      set(expected_description "main description")
+      if(NOT dpkg_description STREQUAL expected_description)
         set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all}
-                                      "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: `${dpkg_description}` =~ `main description.*`")
+                                      "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: `${dpkg_description}` != `${expected_description}`")
       endif()
     else()
       set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all}
diff --git a/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description2.cmake b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description2.cmake
index d53c73d..c00921a 100644
--- a/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description2.cmake
+++ b/Tests/CPackComponentsDEB/RunCPackVerifyResult-components-description2.cmake
@@ -53,9 +53,10 @@
     message(STATUS "package='${dpkg_package_name}', description='${dpkg_description}'")
 
     if(dpkg_package_name STREQUAL "mylib-applications" OR dpkg_package_name STREQUAL "mylib-headers")
-      if(NOT dpkg_description MATCHES "main description 2\n.*")
+      set(expected_description "main description 2")
+      if(NOT dpkg_description STREQUAL expected_description)
         set(dpkgdeb_output_errors_all ${dpkgdeb_output_errors_all}
-                                      "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: `${dpkg_description}` =~ `main description 2`")
+                                      "dpkg-deb: ${_f}: Incorrect description for package ${dpkg_package_name}: `${dpkg_description}` != `${expected_description}`")
       endif()
     elseif(dpkg_package_name STREQUAL "mylib-libraries")
       set(expected_description "main description 2\n  library description")
diff --git a/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake b/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
index f70cd24..01b37c5 100644
--- a/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
+++ b/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
@@ -27,7 +27,7 @@
   message(STATUS "CPack_output=${CPack_output}")
 endif()
 
-set(expected_file_mask "${CPackNSISGenerator_BINARY_DIR}/_CPack_Packages/win32/NSIS/*.nsi")
+set(expected_file_mask "${CPackNSISGenerator_BINARY_DIR}/_CPack_Packages/*/NSIS/*.nsi")
 file(GLOB project_file "${expected_file_mask}")
 
 message(STATUS "project_file='${project_file}'")
diff --git a/Tests/Cuda/CMakeLists.txt b/Tests/Cuda/CMakeLists.txt
index 5ba82d8..58b9b03 100644
--- a/Tests/Cuda/CMakeLists.txt
+++ b/Tests/Cuda/CMakeLists.txt
@@ -14,4 +14,12 @@
 ADD_TEST_MACRO(Cuda.IncludePathNoToolkit IncludePathNoToolkit)
 ADD_TEST_MACRO(Cuda.ProperDeviceLibraries ProperDeviceLibraries)
 ADD_TEST_MACRO(Cuda.ProperLinkFlags ProperLinkFlags)
+ADD_TEST_MACRO(Cuda.SharedRuntimePlusToolkit SharedRuntimePlusToolkit)
+
+# The CUDA only ships the shared version of the toolkit libraries
+# on windows
+if(NOT WIN32)
+  ADD_TEST_MACRO(Cuda.StaticRuntimePlusToolkit StaticRuntimePlusToolkit)
+endif()
+
 ADD_TEST_MACRO(Cuda.WithC CudaWithC)
diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/CMakeLists.txt b/Tests/Cuda/SharedRuntimePlusToolkit/CMakeLists.txt
new file mode 100644
index 0000000..48df558
--- /dev/null
+++ b/Tests/Cuda/SharedRuntimePlusToolkit/CMakeLists.txt
@@ -0,0 +1,35 @@
+cmake_minimum_required(VERSION 3.15)
+project(SharedRuntimePlusToolkit CXX)
+
+#Goal for this example:
+# Validate that with c++ we can use some components of the CUDA toolkit, and
+# specify the cuda runtime
+find_package(CUDAToolkit REQUIRED)
+
+add_library(Common OBJECT curand.cpp nppif.cpp)
+target_link_libraries(Common PRIVATE CUDA::toolkit)
+set_target_properties(Common PROPERTIES POSITION_INDEPENDENT_CODE ON)
+
+#shared runtime with shared toolkit libraries
+add_library(SharedToolkit SHARED shared.cpp)
+target_link_libraries(SharedToolkit PRIVATE Common PUBLIC CUDA::curand CUDA::nppif)
+target_link_libraries(SharedToolkit PUBLIC CUDA::cudart)
+
+# The CUDA only ships the shared version of the toolkit libraries
+# on windows
+if(NOT WIN32)
+  #shared runtime with static toolkit libraries
+  add_library(StaticToolkit SHARED static.cpp)
+  target_link_libraries(StaticToolkit PRIVATE Common CUDA::curand_static CUDA::nppif_static)
+  target_link_libraries(StaticToolkit PUBLIC CUDA::cudart)
+
+  #static runtime with mixed toolkit libraries
+  add_library(MixedToolkit SHARED mixed.cpp)
+  target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand_static CUDA::nppif)
+  target_link_libraries(MixedToolkit PUBLIC CUDA::cudart)
+endif()
+
+add_executable(SharedRuntimePlusToolkit main.cpp)
+target_link_libraries(SharedRuntimePlusToolkit PRIVATE SharedToolkit
+                      $<TARGET_NAME_IF_EXISTS:StaticToolkit>
+                      $<TARGET_NAME_IF_EXISTS:MixedToolkit>)
diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/curand.cpp b/Tests/Cuda/SharedRuntimePlusToolkit/curand.cpp
new file mode 100644
index 0000000..fdd7b53
--- /dev/null
+++ b/Tests/Cuda/SharedRuntimePlusToolkit/curand.cpp
@@ -0,0 +1,65 @@
+// Comes from:
+// https://docs.nvidia.com/cuda/curand/host-api-overview.html#host-api-example
+
+#ifdef _WIN32
+#  define EXPORT __declspec(dllexport)
+#else
+#  define EXPORT
+#endif
+
+/*
+ * This program uses the host CURAND API to generate 100
+ * pseudorandom floats.
+ */
+#include <cuda.h>
+#include <curand.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define CUDA_CALL(x)                                                          \
+  do {                                                                        \
+    if ((x) != cudaSuccess) {                                                 \
+      printf("Error at %s:%d\n", __FILE__, __LINE__);                         \
+      return EXIT_FAILURE;                                                    \
+    }                                                                         \
+  } while (0)
+#define CURAND_CALL(x)                                                        \
+  do {                                                                        \
+    if ((x) != CURAND_STATUS_SUCCESS) {                                       \
+      printf("Error at %s:%d\n", __FILE__, __LINE__);                         \
+      return EXIT_FAILURE;                                                    \
+    }                                                                         \
+  } while (0)
+
+EXPORT int curand_main()
+{
+  size_t n = 100;
+  size_t i;
+  curandGenerator_t gen;
+  float *devData, *hostData;
+
+  /* Allocate n floats on host */
+  hostData = (float*)calloc(n, sizeof(float));
+
+  /* Allocate n floats on device */
+  CUDA_CALL(cudaMalloc((void**)&devData, n * sizeof(float)));
+
+  /* Create pseudo-random number generator */
+  CURAND_CALL(curandCreateGenerator(&gen, CURAND_RNG_PSEUDO_DEFAULT));
+
+  /* Set seed */
+  CURAND_CALL(curandSetPseudoRandomGeneratorSeed(gen, 1234ULL));
+
+  /* Generate n floats on device */
+  CURAND_CALL(curandGenerateUniform(gen, devData, n));
+
+  /* Copy device memory to host */
+  CUDA_CALL(
+    cudaMemcpy(hostData, devData, n * sizeof(float), cudaMemcpyDeviceToHost));
+
+  /* Cleanup */
+  CURAND_CALL(curandDestroyGenerator(gen));
+  CUDA_CALL(cudaFree(devData));
+  free(hostData);
+  return EXIT_SUCCESS;
+}
diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/main.cpp b/Tests/Cuda/SharedRuntimePlusToolkit/main.cpp
new file mode 100644
index 0000000..2a4da22
--- /dev/null
+++ b/Tests/Cuda/SharedRuntimePlusToolkit/main.cpp
@@ -0,0 +1,23 @@
+
+#ifdef _WIN32
+#  define IMPORT __declspec(dllimport)
+IMPORT int shared_version();
+int static_version()
+{
+  return 0;
+}
+int mixed_version()
+{
+  return 0;
+}
+#else
+int shared_version();
+int static_version();
+int mixed_version();
+#endif
+
+int main()
+{
+  return mixed_version() == 0 && shared_version() == 0 &&
+    static_version() == 0;
+}
diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/mixed.cpp b/Tests/Cuda/SharedRuntimePlusToolkit/mixed.cpp
new file mode 100644
index 0000000..6de6886
--- /dev/null
+++ b/Tests/Cuda/SharedRuntimePlusToolkit/mixed.cpp
@@ -0,0 +1,16 @@
+
+#ifdef _WIN32
+#  define IMPORT __declspec(dllimport)
+#  define EXPORT __declspec(dllexport)
+#else
+#  define IMPORT
+#  define EXPORT
+#endif
+
+IMPORT int curand_main();
+IMPORT int nppif_main();
+
+EXPORT int mixed_version()
+{
+  return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/nppif.cpp b/Tests/Cuda/SharedRuntimePlusToolkit/nppif.cpp
new file mode 100644
index 0000000..ac5341c
--- /dev/null
+++ b/Tests/Cuda/SharedRuntimePlusToolkit/nppif.cpp
@@ -0,0 +1,92 @@
+// Comes from
+// https://devtalk.nvidia.com/default/topic/1037482/gpu-accelerated-libraries/help-me-help-you-with-modern-cmake-and-cuda-mwe-for-npp/post/5271066/#5271066
+
+#ifdef _WIN32
+#  define EXPORT __declspec(dllexport)
+#else
+#  define EXPORT
+#endif
+
+#include <cstdio>
+#include <iostream>
+
+#include <assert.h>
+#include <cuda_runtime_api.h>
+#include <nppi_filtering_functions.h>
+
+EXPORT int nppif_main()
+{
+  /**
+   * 8-bit unsigned single-channel 1D row convolution.
+   */
+  const int simgrows = 32;
+  const int simgcols = 32;
+  Npp8u *d_pSrc, *d_pDst;
+  const int nMaskSize = 3;
+  NppiSize oROI;
+  oROI.width = simgcols - nMaskSize;
+  oROI.height = simgrows;
+  const int simgsize = simgrows * simgcols * sizeof(d_pSrc[0]);
+  const int dimgsize = oROI.width * oROI.height * sizeof(d_pSrc[0]);
+  const int simgpix = simgrows * simgcols;
+  const int dimgpix = oROI.width * oROI.height;
+  const int nSrcStep = simgcols * sizeof(d_pSrc[0]);
+  const int nDstStep = oROI.width * sizeof(d_pDst[0]);
+  const int pixval = 1;
+  const int nDivisor = 1;
+  const Npp32s h_pKernel[nMaskSize] = { pixval, pixval, pixval };
+  Npp32s* d_pKernel;
+  const Npp32s nAnchor = 2;
+  cudaError_t err = cudaMalloc((void**)&d_pSrc, simgsize);
+  if (err != cudaSuccess) {
+    fprintf(stderr, "Cuda error %d\n", __LINE__);
+    return 1;
+  }
+  err = cudaMalloc((void**)&d_pDst, dimgsize);
+  if (err != cudaSuccess) {
+    fprintf(stderr, "Cuda error %d\n", __LINE__);
+    return 1;
+  }
+  err = cudaMalloc((void**)&d_pKernel, nMaskSize * sizeof(d_pKernel[0]));
+  if (err != cudaSuccess) {
+    fprintf(stderr, "Cuda error %d\n", __LINE__);
+    return 1;
+  }
+  // set image to pixval initially
+  err = cudaMemset(d_pSrc, pixval, simgsize);
+  if (err != cudaSuccess) {
+    fprintf(stderr, "Cuda error %d\n", __LINE__);
+    return 1;
+  }
+  err = cudaMemset(d_pDst, 0, dimgsize);
+  if (err != cudaSuccess) {
+    fprintf(stderr, "Cuda error %d\n", __LINE__);
+    return 1;
+  }
+  err = cudaMemcpy(d_pKernel, h_pKernel, nMaskSize * sizeof(d_pKernel[0]),
+                   cudaMemcpyHostToDevice);
+  if (err != cudaSuccess) {
+    fprintf(stderr, "Cuda error %d\n", __LINE__);
+    return 1;
+  }
+  // copy src to dst
+  NppStatus ret =
+    nppiFilterRow_8u_C1R(d_pSrc, nSrcStep, d_pDst, nDstStep, oROI, d_pKernel,
+                         nMaskSize, nAnchor, nDivisor);
+  assert(ret == NPP_NO_ERROR);
+  Npp8u* h_imgres = new Npp8u[dimgpix];
+  err = cudaMemcpy(h_imgres, d_pDst, dimgsize, cudaMemcpyDeviceToHost);
+  if (err != cudaSuccess) {
+    fprintf(stderr, "Cuda error %d\n", __LINE__);
+    return 1;
+  }
+  // test for filtering
+  for (int i = 0; i < dimgpix; i++) {
+    if (h_imgres[i] != (pixval * pixval * nMaskSize)) {
+      fprintf(stderr, "h_imgres at index %d failed to match\n", i);
+      return 1;
+    }
+  }
+
+  return 0;
+}
diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/shared.cpp b/Tests/Cuda/SharedRuntimePlusToolkit/shared.cpp
new file mode 100644
index 0000000..f3c3dbc
--- /dev/null
+++ b/Tests/Cuda/SharedRuntimePlusToolkit/shared.cpp
@@ -0,0 +1,16 @@
+
+#ifdef _WIN32
+#  define IMPORT __declspec(dllimport)
+#  define EXPORT __declspec(dllexport)
+#else
+#  define IMPORT
+#  define EXPORT
+#endif
+
+int curand_main();
+int nppif_main();
+
+EXPORT int shared_version()
+{
+  return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/Cuda/SharedRuntimePlusToolkit/static.cpp b/Tests/Cuda/SharedRuntimePlusToolkit/static.cpp
new file mode 100644
index 0000000..6932fa3
--- /dev/null
+++ b/Tests/Cuda/SharedRuntimePlusToolkit/static.cpp
@@ -0,0 +1,16 @@
+
+#ifdef _WIN32
+#  define IMPORT __declspec(dllimport)
+#  define EXPORT __declspec(dllexport)
+#else
+#  define IMPORT
+#  define EXPORT
+#endif
+
+IMPORT int curand_main();
+IMPORT int nppif_main();
+
+EXPORT int static_version()
+{
+  return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/CMakeLists.txt b/Tests/Cuda/StaticRuntimePlusToolkit/CMakeLists.txt
new file mode 100644
index 0000000..df6c392
--- /dev/null
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/CMakeLists.txt
@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 3.15)
+project(StaticRuntimePlusToolkit CXX)
+
+#Goal for this example:
+# Validate that with c++ we can use some components of the CUDA toolkit, and
+# specify the cuda runtime
+find_package(CUDAToolkit REQUIRED)
+
+add_library(Common OBJECT curand.cpp nppif.cpp)
+target_link_libraries(Common PRIVATE CUDA::toolkit)
+set_target_properties(Common PROPERTIES POSITION_INDEPENDENT_CODE ON)
+
+#static runtime with shared toolkit libraries
+add_library(SharedToolkit SHARED shared.cpp)
+target_link_libraries(SharedToolkit PRIVATE Common PUBLIC CUDA::curand CUDA::nppif)
+target_link_libraries(SharedToolkit PUBLIC CUDA::cudart_static)
+
+#static runtime with static toolkit libraries
+add_library(StaticToolkit SHARED static.cpp)
+target_link_libraries(StaticToolkit PRIVATE Common CUDA::curand_static CUDA::nppif_static)
+target_link_libraries(StaticToolkit PUBLIC CUDA::cudart_static)
+
+#static runtime with mixed toolkit libraries
+add_library(MixedToolkit SHARED mixed.cpp)
+target_link_libraries(MixedToolkit PRIVATE Common CUDA::curand CUDA::nppif_static)
+target_link_libraries(MixedToolkit PUBLIC CUDA::cudart_static)
+
+add_executable(StaticRuntimePlusToolkit main.cpp)
+target_link_libraries(StaticRuntimePlusToolkit PRIVATE SharedToolkit StaticToolkit MixedToolkit)
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/curand.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/curand.cpp
new file mode 100644
index 0000000..95872f0
--- /dev/null
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/curand.cpp
@@ -0,0 +1,59 @@
+// Comes from:
+// https://docs.nvidia.com/cuda/curand/host-api-overview.html#host-api-example
+
+/*
+ * This program uses the host CURAND API to generate 100
+ * pseudorandom floats.
+ */
+#include <cuda.h>
+#include <curand.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define CUDA_CALL(x)                                                          \
+  do {                                                                        \
+    if ((x) != cudaSuccess) {                                                 \
+      printf("Error at %s:%d\n", __FILE__, __LINE__);                         \
+      return EXIT_FAILURE;                                                    \
+    }                                                                         \
+  } while (0)
+#define CURAND_CALL(x)                                                        \
+  do {                                                                        \
+    if ((x) != CURAND_STATUS_SUCCESS) {                                       \
+      printf("Error at %s:%d\n", __FILE__, __LINE__);                         \
+      return EXIT_FAILURE;                                                    \
+    }                                                                         \
+  } while (0)
+
+int curand_main()
+{
+  size_t n = 100;
+  size_t i;
+  curandGenerator_t gen;
+  float *devData, *hostData;
+
+  /* Allocate n floats on host */
+  hostData = (float*)calloc(n, sizeof(float));
+
+  /* Allocate n floats on device */
+  CUDA_CALL(cudaMalloc((void**)&devData, n * sizeof(float)));
+
+  /* Create pseudo-random number generator */
+  CURAND_CALL(curandCreateGenerator(&gen, CURAND_RNG_PSEUDO_DEFAULT));
+
+  /* Set seed */
+  CURAND_CALL(curandSetPseudoRandomGeneratorSeed(gen, 1234ULL));
+
+  /* Generate n floats on device */
+  CURAND_CALL(curandGenerateUniform(gen, devData, n));
+
+  /* Copy device memory to host */
+  CUDA_CALL(
+    cudaMemcpy(hostData, devData, n * sizeof(float), cudaMemcpyDeviceToHost));
+
+  /* Cleanup */
+  CURAND_CALL(curandDestroyGenerator(gen));
+  CUDA_CALL(cudaFree(devData));
+  free(hostData);
+  return EXIT_SUCCESS;
+}
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/main.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/main.cpp
new file mode 100644
index 0000000..5a09f8e
--- /dev/null
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/main.cpp
@@ -0,0 +1,11 @@
+
+
+int shared_version();
+int static_version();
+int mixed_version();
+
+int main()
+{
+  return mixed_version() == 0 && shared_version() == 0 &&
+    static_version() == 0;
+}
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/mixed.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/mixed.cpp
new file mode 100644
index 0000000..a05140d
--- /dev/null
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/mixed.cpp
@@ -0,0 +1,8 @@
+
+int curand_main();
+int nppif_main();
+
+int mixed_version()
+{
+  return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/nppif.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/nppif.cpp
new file mode 100644
index 0000000..2871090
--- /dev/null
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/nppif.cpp
@@ -0,0 +1,86 @@
+// Comes from
+// https://devtalk.nvidia.com/default/topic/1037482/gpu-accelerated-libraries/help-me-help-you-with-modern-cmake-and-cuda-mwe-for-npp/post/5271066/#5271066
+
+#include <cstdio>
+#include <iostream>
+
+#include <assert.h>
+#include <cuda_runtime_api.h>
+#include <nppi_filtering_functions.h>
+
+int nppif_main()
+{
+  /**
+   * 8-bit unsigned single-channel 1D row convolution.
+   */
+  const int simgrows = 32;
+  const int simgcols = 32;
+  Npp8u *d_pSrc, *d_pDst;
+  const int nMaskSize = 3;
+  NppiSize oROI;
+  oROI.width = simgcols - nMaskSize;
+  oROI.height = simgrows;
+  const int simgsize = simgrows * simgcols * sizeof(d_pSrc[0]);
+  const int dimgsize = oROI.width * oROI.height * sizeof(d_pSrc[0]);
+  const int simgpix = simgrows * simgcols;
+  const int dimgpix = oROI.width * oROI.height;
+  const int nSrcStep = simgcols * sizeof(d_pSrc[0]);
+  const int nDstStep = oROI.width * sizeof(d_pDst[0]);
+  const int pixval = 1;
+  const int nDivisor = 1;
+  const Npp32s h_pKernel[nMaskSize] = { pixval, pixval, pixval };
+  Npp32s* d_pKernel;
+  const Npp32s nAnchor = 2;
+  cudaError_t err = cudaMalloc((void**)&d_pSrc, simgsize);
+  if (err != cudaSuccess) {
+    fprintf(stderr, "Cuda error %d\n", __LINE__);
+    return 1;
+  }
+  err = cudaMalloc((void**)&d_pDst, dimgsize);
+  if (err != cudaSuccess) {
+    fprintf(stderr, "Cuda error %d\n", __LINE__);
+    return 1;
+  }
+  err = cudaMalloc((void**)&d_pKernel, nMaskSize * sizeof(d_pKernel[0]));
+  if (err != cudaSuccess) {
+    fprintf(stderr, "Cuda error %d\n", __LINE__);
+    return 1;
+  }
+  // set image to pixval initially
+  err = cudaMemset(d_pSrc, pixval, simgsize);
+  if (err != cudaSuccess) {
+    fprintf(stderr, "Cuda error %d\n", __LINE__);
+    return 1;
+  }
+  err = cudaMemset(d_pDst, 0, dimgsize);
+  if (err != cudaSuccess) {
+    fprintf(stderr, "Cuda error %d\n", __LINE__);
+    return 1;
+  }
+  err = cudaMemcpy(d_pKernel, h_pKernel, nMaskSize * sizeof(d_pKernel[0]),
+                   cudaMemcpyHostToDevice);
+  if (err != cudaSuccess) {
+    fprintf(stderr, "Cuda error %d\n", __LINE__);
+    return 1;
+  }
+  // copy src to dst
+  NppStatus ret =
+    nppiFilterRow_8u_C1R(d_pSrc, nSrcStep, d_pDst, nDstStep, oROI, d_pKernel,
+                         nMaskSize, nAnchor, nDivisor);
+  assert(ret == NPP_NO_ERROR);
+  Npp8u* h_imgres = new Npp8u[dimgpix];
+  err = cudaMemcpy(h_imgres, d_pDst, dimgsize, cudaMemcpyDeviceToHost);
+  if (err != cudaSuccess) {
+    fprintf(stderr, "Cuda error %d\n", __LINE__);
+    return 1;
+  }
+  // test for filtering
+  for (int i = 0; i < dimgpix; i++) {
+    if (h_imgres[i] != (pixval * pixval * nMaskSize)) {
+      fprintf(stderr, "h_imgres at index %d failed to match\n", i);
+      return 1;
+    }
+  }
+
+  return 0;
+}
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/shared.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/shared.cpp
new file mode 100644
index 0000000..9967b66
--- /dev/null
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/shared.cpp
@@ -0,0 +1,8 @@
+
+int curand_main();
+int nppif_main();
+
+int shared_version()
+{
+  return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/Cuda/StaticRuntimePlusToolkit/static.cpp b/Tests/Cuda/StaticRuntimePlusToolkit/static.cpp
new file mode 100644
index 0000000..ca7eb4c
--- /dev/null
+++ b/Tests/Cuda/StaticRuntimePlusToolkit/static.cpp
@@ -0,0 +1,8 @@
+
+int curand_main();
+int nppif_main();
+
+int static_version()
+{
+  return curand_main() == 0 && nppif_main() == 0;
+}
diff --git a/Tests/CustomCommand/CMakeLists.txt b/Tests/CustomCommand/CMakeLists.txt
index 70e8476..196fea3 100644
--- a/Tests/CustomCommand/CMakeLists.txt
+++ b/Tests/CustomCommand/CMakeLists.txt
@@ -535,6 +535,7 @@
 add_custom_target(command_expand_lists ALL DEPENDS "${gen_file}")
 set_property(TARGET command_expand_lists PROPERTY CMPARGS "${cmp_args}")
 
+# This also tests that `./` is squeezed out of the resulting path.
 set(depends_path "./depended_upon_path.txt")
 
 add_custom_command(
@@ -549,3 +550,19 @@
 )
 
 add_custom_target(depends_on_path ALL DEPENDS "depends_on_path.txt")
+
+add_custom_command(
+  OUTPUT "depends_on_in_source_path.txt"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/main.cxx" depends_on_in_source_path.txt
+  DEPENDS main.cxx
+)
+
+add_custom_target(depends_on_in_source_path ALL DEPENDS "depends_on_in_source_path.txt")
+
+add_custom_command(
+  OUTPUT "depends_on_in_rel_source_path.txt"
+  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/main.cxx" depends_on_in_rel_source_path.txt
+  DEPENDS ./main.cxx
+)
+
+add_custom_target(depends_on_in_rel_source_path ALL DEPENDS "depends_on_in_rel_source_path.txt")
diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt
index 7c81aea..387fe6b 100644
--- a/Tests/ExportImport/Export/CMakeLists.txt
+++ b/Tests/ExportImport/Export/CMakeLists.txt
@@ -156,6 +156,7 @@
 cmake_policy(POP)
 
 cmake_policy(PUSH)
+cmake_policy(SET CMP0022 NEW)
 cmake_policy(SET CMP0079 NEW)
 add_library(TopDirLib STATIC testTopDirLib.c)
 add_subdirectory(SubDirLinkA)
diff --git a/Tests/ExportImport/Export/SubDirLinkA/CMakeLists.txt b/Tests/ExportImport/Export/SubDirLinkA/CMakeLists.txt
index 1c3c9dc..1aa41d2 100644
--- a/Tests/ExportImport/Export/SubDirLinkA/CMakeLists.txt
+++ b/Tests/ExportImport/Export/SubDirLinkA/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_library(SubDirLinkAImported IMPORTED INTERFACE)
 target_compile_definitions(SubDirLinkAImported INTERFACE DEF_SubDirLinkAImportedForExport)
 
-target_link_libraries(TopDirLib PUBLIC SubDirLinkAImported)
+target_link_libraries(TopDirLib PUBLIC debug "$<1:SubDirLinkAImported;SubDirLinkAImported>" optimized "$<1:SubDirLinkAImported;SubDirLinkAImported>")
 
 add_library(SubDirLinkA STATIC SubDirLinkA.c)
diff --git a/Tests/RunCMake/CMP0102/CMP0102-Common.cmake b/Tests/RunCMake/CMP0102/CMP0102-Common.cmake
new file mode 100644
index 0000000..61fdad6
--- /dev/null
+++ b/Tests/RunCMake/CMP0102/CMP0102-Common.cmake
@@ -0,0 +1,2 @@
+
+mark_as_advanced(CMP0102_TEST_VARIABLE)
diff --git a/Tests/RunCMake/CMP0102/CMP0102-NEW.cmake b/Tests/RunCMake/CMP0102/CMP0102-NEW.cmake
new file mode 100644
index 0000000..bdf769f
--- /dev/null
+++ b/Tests/RunCMake/CMP0102/CMP0102-NEW.cmake
@@ -0,0 +1,13 @@
+
+cmake_policy(SET CMP0102 NEW)
+
+include (CMP0102-Common.cmake)
+get_property(is_type_set CACHE CMP0102_TEST_VARIABLE
+  PROPERTY TYPE SET)
+if (is_type_set)
+  get_property(type CACHE CMP0102_TEST_VARIABLE
+    PROPERTY TYPE)
+  message(FATAL_ERROR
+    "There is a cache entry for an undefined variable after "
+    "`mark_as_advanced`.")
+endif ()
diff --git a/Tests/RunCMake/CMP0102/CMP0102-OLD.cmake b/Tests/RunCMake/CMP0102/CMP0102-OLD.cmake
new file mode 100644
index 0000000..5c20dd3
--- /dev/null
+++ b/Tests/RunCMake/CMP0102/CMP0102-OLD.cmake
@@ -0,0 +1,18 @@
+
+cmake_policy(SET CMP0102 OLD)
+
+include (CMP0102-Common.cmake)
+get_property(is_type_set CACHE CMP0102_TEST_VARIABLE
+  PROPERTY TYPE SET)
+if (NOT is_type_set)
+  message(FATAL_ERROR
+    "There is a cache entry for an undefined variable after "
+    "`mark_as_advanced`.")
+endif ()
+get_property(type CACHE CMP0102_TEST_VARIABLE
+  PROPERTY TYPE)
+if (NOT type STREQUAL "UNINITIALIZED")
+  message(FATAL_ERROR
+    "The cache type for CMP0102_TEST_VARIABLE is not "
+    "UNINITIALIZED")
+endif ()
diff --git a/Tests/RunCMake/CMP0102/CMP0102-WARN-Default.cmake b/Tests/RunCMake/CMP0102/CMP0102-WARN-Default.cmake
new file mode 100644
index 0000000..d6ebe4d
--- /dev/null
+++ b/Tests/RunCMake/CMP0102/CMP0102-WARN-Default.cmake
@@ -0,0 +1,16 @@
+
+include (CMP0102-Common.cmake)
+get_property(is_type_set CACHE CMP0102_TEST_VARIABLE
+  PROPERTY TYPE SET)
+if (NOT is_type_set)
+  message(FATAL_ERROR
+    "There is a cache entry for an undefined variable after "
+    "`mark_as_advanced`.")
+endif ()
+get_property(type CACHE CMP0102_TEST_VARIABLE
+  PROPERTY TYPE)
+if (NOT type STREQUAL "UNINITIALIZED")
+  message(FATAL_ERROR
+    "The cache type for CMP0102_TEST_VARIABLE is not "
+    "UNINITIALIZED")
+endif ()
diff --git a/Tests/RunCMake/CMP0102/CMP0102-WARN-stderr.txt b/Tests/RunCMake/CMP0102/CMP0102-WARN-stderr.txt
new file mode 100644
index 0000000..bb56ec2
--- /dev/null
+++ b/Tests/RunCMake/CMP0102/CMP0102-WARN-stderr.txt
@@ -0,0 +1,10 @@
+CMake Warning \(dev\) at CMP0102-Common.cmake:2 \(mark_as_advanced\):
+  Policy CMP0102 is not set: The variable named "CMP0102_TEST_VARIABLE" is
+  not in the cache.  This results in an empty cache entry which is no longer
+  created when policy CMP0102 is set to NEW.  Run "cmake --help-policy
+  CMP0102" for policy details.  Use the cmake_policy command to set the
+  policy and suppress this warning.
+Call Stack \(most recent call first\):
+  CMP0102-WARN.cmake:4 \(include\)
+  CMakeLists.txt:3 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0102/CMP0102-WARN.cmake b/Tests/RunCMake/CMP0102/CMP0102-WARN.cmake
new file mode 100644
index 0000000..e9a45f1
--- /dev/null
+++ b/Tests/RunCMake/CMP0102/CMP0102-WARN.cmake
@@ -0,0 +1,18 @@
+
+set(CMAKE_POLICY_WARNING_CMP0102 1)
+
+include (CMP0102-Common.cmake)
+get_property(is_type_set CACHE CMP0102_TEST_VARIABLE
+  PROPERTY TYPE SET)
+if (NOT is_type_set)
+  message(FATAL_ERROR
+    "There is a cache entry for an undefined variable after "
+    "`mark_as_advanced`.")
+endif ()
+get_property(type CACHE CMP0102_TEST_VARIABLE
+  PROPERTY TYPE)
+if (NOT type STREQUAL "UNINITIALIZED")
+  message(FATAL_ERROR
+    "The cache type for CMP0102_TEST_VARIABLE is not "
+    "UNINITIALIZED")
+endif ()
diff --git a/Tests/RunCMake/CMP0102/CMakeLists.txt b/Tests/RunCMake/CMP0102/CMakeLists.txt
new file mode 100644
index 0000000..ef2163c
--- /dev/null
+++ b/Tests/RunCMake/CMP0102/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.1)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0102/RunCMakeTest.cmake b/Tests/RunCMake/CMP0102/RunCMakeTest.cmake
new file mode 100644
index 0000000..9b5df74
--- /dev/null
+++ b/Tests/RunCMake/CMP0102/RunCMakeTest.cmake
@@ -0,0 +1,6 @@
+include(RunCMake)
+
+run_cmake(CMP0102-OLD)
+run_cmake(CMP0102-NEW)
+run_cmake(CMP0102-WARN)
+run_cmake(CMP0102-WARN-Default)
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index a46393e..cd6e9ae 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -115,6 +115,7 @@
 endif()
 add_RunCMake_test(CMP0069)
 add_RunCMake_test(CMP0081)
+add_RunCMake_test(CMP0102)
 
 # The test for Policy 65 requires the use of the
 # CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode
@@ -140,6 +141,9 @@
   if(CMake_TEST_Qt5 AND Qt5Core_FOUND)
     list(APPEND NinjaMultiConfig_ARGS -DCMake_TEST_Qt5=1)
   endif()
+  if(DEFINED CMake_TEST_CUDA)
+    list(APPEND NinjaMultiConfig_ARGS -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
+  endif()
   add_RunCMake_test(NinjaMultiConfig)
 endif()
 add_RunCMake_test(CTest)
@@ -349,6 +353,7 @@
 add_RunCMake_test(interface_library)
 add_RunCMake_test(no_install_prefix)
 add_RunCMake_test(configure_file)
+add_RunCMake_test(CTestTimeout -DTIMEOUT=${CTestTestTimeout_TIME})
 add_RunCMake_test(CTestTimeoutAfterMatch)
 
 # ctresalloc links against CMakeLib and CTestLib, which means it can't be built
@@ -450,7 +455,7 @@
 
 add_RunCMake_test(target_compile_definitions)
 add_RunCMake_test(target_compile_features)
-add_RunCMake_test(target_compile_options)
+add_RunCMake_test(target_compile_options -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
 add_RunCMake_test(target_include_directories)
 add_RunCMake_test(target_sources)
 add_RunCMake_test(CheckModules)
@@ -600,6 +605,9 @@
   STGZ
   External
   )
+if(APPLE)
+  list(APPEND cpack_tests DragNDrop)
+endif()
 add_RunCMake_test_group(CPack "${cpack_tests}")
 # add a test to make sure symbols are exported from a shared library
 # for MSVC compilers CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS property is used
diff --git a/Tests/RunCMake/CPack/DragNDrop/Helpers.cmake b/Tests/RunCMake/CPack/DragNDrop/Helpers.cmake
new file mode 100644
index 0000000..023e597
--- /dev/null
+++ b/Tests/RunCMake/CPack/DragNDrop/Helpers.cmake
@@ -0,0 +1,54 @@
+set(ALL_FILES_GLOB "*.dmg")
+
+function(getPackageContent FILE RESULT_VAR)
+  get_filename_component(path_ "${FILE}" DIRECTORY)
+  file(REMOVE_RECURSE "${path_}/content")
+  file(MAKE_DIRECTORY "${path_}/content")
+  execute_process(COMMAND ${HDIUTIL_EXECUTABLE} attach -mountroot ${path_}/content -nobrowse ${FILE}
+          RESULT_VARIABLE attach_result_
+          ERROR_VARIABLE attach_error_
+          OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+  if(attach_result_)
+    message(FATAL_ERROR "Failed to attach DMG: '${attach_result_}';"
+          " '${attach_error_}'.")
+  endif()
+
+  file(GLOB_RECURSE package_content_ LIST_DIRECTORIES true RELATIVE
+      "${path_}/content" "${path_}/content/*")
+  # Some versions of macOS have .Trashes, others do not.
+  list(FILTER package_content_ EXCLUDE REGEX "/.Trashes$")
+  set(${RESULT_VAR} "${package_content_}" PARENT_SCOPE)
+
+  execute_process(COMMAND ${HDIUTIL_EXECUTABLE} detach ${path_}/content/volume-name
+          RESULT_VARIABLE detach_result_
+          ERROR_VARIABLE detach_error_
+          OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+  if(detach_result_)
+    message(FATAL_ERROR "Failed to detach DMG: '${detach_result_}';"
+          " '${detach_error_}'.")
+  endif()
+endfunction()
+
+function(getPackageNameGlobexpr NAME COMPONENT VERSION REVISION FILE_NO RESULT_VAR)
+  if(COMPONENT)
+    set(COMPONENT "-${COMPONENT}")
+  endif()
+
+  set(${RESULT_VAR} "${NAME}-${VERSION}-Darwin${COMPONENT}.dmg" PARENT_SCOPE)
+endfunction()
+
+function(getPackageContentList FILE RESULT_VAR)
+  getPackageContent("${FILE}" package_content_)
+
+  set(${RESULT_VAR} "${package_content_}" PARENT_SCOPE)
+endfunction()
+
+function(toExpectedContentList FILE_NO CONTENT_VAR)
+  set(prefix_ "volume-name")
+  list(TRANSFORM ${CONTENT_VAR} PREPEND "${prefix_}" OUTPUT_VARIABLE prepared_)
+  list(APPEND prepared_ "${prefix_}")
+
+  set(${CONTENT_VAR} "${prepared_}" PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/DragNDrop/Prerequirements.cmake b/Tests/RunCMake/CPack/DragNDrop/Prerequirements.cmake
new file mode 100644
index 0000000..f0aaf2c
--- /dev/null
+++ b/Tests/RunCMake/CPack/DragNDrop/Prerequirements.cmake
@@ -0,0 +1,8 @@
+function(get_test_prerequirements found_var config_file)
+  find_program(HDIUTIL_EXECUTABLE hdiutil)
+
+  if(HDIUTIL_EXECUTABLE)
+    file(WRITE "${config_file}" "set(HDIUTIL_EXECUTABLE \"${HDIUTIL_EXECUTABLE}\")")
+    set(${found_var} true PARENT_SCOPE)
+  endif()
+endfunction()
diff --git a/Tests/RunCMake/CPack/DragNDrop/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/DragNDrop/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..aa6c8ff
--- /dev/null
+++ b/Tests/RunCMake/CPack/DragNDrop/packaging_COMPONENT_default.cmake
@@ -0,0 +1,3 @@
+set(CPACK_COMPONENTS_GROUPING "IGNORE")
+set(CPACK_DMG_DISABLE_APPLICATIONS_SYMLINK ON)
+set(CPACK_DMG_VOLUME_NAME "volume-name")
diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake
index 76d16e1..0fb0cc4 100644
--- a/Tests/RunCMake/CPack/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake
@@ -5,7 +5,7 @@
 
 # run_cpack_test args: TEST_NAME "GENERATORS" RUN_CMAKE_BUILD_STEP "PACKAGING_TYPES"
 run_cpack_test(CUSTOM_BINARY_SPEC_FILE "RPM.CUSTOM_BINARY_SPEC_FILE" false "MONOLITHIC;COMPONENT")
-run_cpack_test(CUSTOM_NAMES "RPM.CUSTOM_NAMES;DEB.CUSTOM_NAMES;TGZ" true "COMPONENT")
+run_cpack_test(CUSTOM_NAMES "RPM.CUSTOM_NAMES;DEB.CUSTOM_NAMES;TGZ;DragNDrop" true "COMPONENT")
 run_cpack_test(DEBUGINFO "RPM.DEBUGINFO;DEB.DEBUGINFO" true "COMPONENT")
 run_cpack_test_subtests(DEFAULT_PERMISSIONS "CMAKE_var_set;CPACK_var_set;both_set;invalid_CMAKE_var;invalid_CPACK_var" "RPM.DEFAULT_PERMISSIONS;DEB.DEFAULT_PERMISSIONS" false "MONOLITHIC;COMPONENT")
 run_cpack_test(DEPENDENCIES "RPM.DEPENDENCIES;DEB.DEPENDENCIES" true "COMPONENT")
@@ -38,7 +38,7 @@
 run_cpack_test_subtests(EXTERNAL "none;good;good_multi;bad_major;bad_minor;invalid_good;invalid_bad;stage_and_package" "External" false "MONOLITHIC;COMPONENT")
 run_cpack_test_subtests(
   DEB_DESCRIPTION
-  "CPACK_DEBIAN_PACKAGE_DESCRIPTION;CPACK_PACKAGE_DESCRIPTION;CPACK_PACKAGE_DESCRIPTION_FILE"
+  "CPACK_DEBIAN_PACKAGE_DESCRIPTION;CPACK_PACKAGE_DESCRIPTION;CPACK_PACKAGE_DESCRIPTION_FILE;CPACK_NO_PACKAGE_DESCRIPTION"
   "DEB.DEB_DESCRIPTION"
   false
   "MONOLITHIC;COMPONENT"
diff --git a/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/ExpectedFiles.cmake
index 07226df..9ac19e2 100644
--- a/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/ExpectedFiles.cmake
+++ b/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/ExpectedFiles.cmake
@@ -12,4 +12,7 @@
 elseif(GENERATOR_TYPE STREQUAL "TGZ")
   set(EXPECTED_FILE_2 "second.tar.gz")
   set(EXPECTED_FILE_3 "pkg_3_abc.tar.gz")
+elseif(GENERATOR_TYPE STREQUAL "DragNDrop")
+  set(EXPECTED_FILE_2 "second.dmg")
+  set(EXPECTED_FILE_3 "pkg_3_abc.dmg")
 endif()
diff --git a/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/test.cmake b/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/test.cmake
index 4c20e41..899258e 100644
--- a/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/test.cmake
+++ b/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/test.cmake
@@ -10,6 +10,9 @@
 elseif(GENERATOR_TYPE STREQUAL "TGZ")
   set(CPACK_ARCHIVE_PKG_2_FILE_NAME "second")
   set(CPACK_ARCHIVE_PKG_3_FILE_NAME "pkg_3_abc")
+elseif(GENERATOR_TYPE STREQUAL "DragNDrop")
+  set(CPACK_DMG_PKG_2_FILE_NAME "second")
+  set(CPACK_DMG_PKG_3_FILE_NAME "pkg_3_abc")
 endif()
 
 install(FILES CMakeLists.txt DESTINATION foo COMPONENT pkg_1)
diff --git a/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/VerifyResult.cmake
index e9ac13a..a8e2e7a 100644
--- a/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/VerifyResult.cmake
+++ b/Tests/RunCMake/CPack/tests/DEB_DESCRIPTION/VerifyResult.cmake
@@ -56,6 +56,8 @@
 # workaround required!
 if(RunCMake_SUBTEST_SUFFIX STREQUAL "CPACK_PACKAGE_DESCRIPTION_FILE" AND PACKAGING_TYPE STREQUAL "MONOLITHIC")
   string(APPEND _expected_description "\n  ." )
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "CPACK_NO_PACKAGE_DESCRIPTION")
+  set(_expected_description [[ Description: This is the summary line]])
 endif()
 
 foreach(_file_no RANGE 1 ${EXPECTED_FILES_COUNT})
diff --git a/Tests/RunCMake/CTest/CMakeCTestArguments-test-check.cmake b/Tests/RunCMake/CTest/CMakeCTestArguments-test-check.cmake
new file mode 100644
index 0000000..3e05953
--- /dev/null
+++ b/Tests/RunCMake/CTest/CMakeCTestArguments-test-check.cmake
@@ -0,0 +1,4 @@
+set(log "${RunCMake_TEST_BINARY_DIR}/output-log.txt")
+if(NOT EXISTS "${log}")
+  set(RunCMake_TEST_FAILED "The expected output log file is missing:\n  ${log}")
+endif()
diff --git a/Tests/RunCMake/CTest/CMakeCTestArguments.cmake b/Tests/RunCMake/CTest/CMakeCTestArguments.cmake
new file mode 100644
index 0000000..37f2933
--- /dev/null
+++ b/Tests/RunCMake/CTest/CMakeCTestArguments.cmake
@@ -0,0 +1,2 @@
+include(CTest)
+add_test(NAME CMakeCTestArguments COMMAND ${CMAKE_COMMAND} -E echo CMakeCTestArguments)
diff --git a/Tests/RunCMake/CTest/RunCMakeTest.cmake b/Tests/RunCMake/CTest/RunCMakeTest.cmake
index 1392240..761224a 100644
--- a/Tests/RunCMake/CTest/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CTest/RunCMakeTest.cmake
@@ -5,3 +5,16 @@
 unset(RunCMake_TEST_OPTIONS)
 
 run_cmake(NotOn)
+
+function(run_CMakeCTestArguments)
+  run_cmake_with_options(CMakeCTestArguments "-DCMAKE_CTEST_ARGUMENTS=--quiet\\;--output-log\\;output-log.txt")
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMakeCTestArguments-build)
+  if(RunCMake_GENERATOR MATCHES "Make|Ninja")
+    set(test "test")
+  else()
+    set(test "RUN_TESTS")
+  endif()
+  run_cmake_command(CMakeCTestArguments-test ${CMAKE_COMMAND} --build . --config Debug --target "${test}")
+endfunction()
+run_CMakeCTestArguments()
diff --git a/Tests/RunCMake/CTestTimeout/Basic-stdout.txt b/Tests/RunCMake/CTestTimeout/Basic-stdout.txt
new file mode 100644
index 0000000..30ed178
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/Basic-stdout.txt
@@ -0,0 +1,6 @@
+Test project [^
+]*/Tests/RunCMake/CTestTimeout/Basic-build
+    Start 1: TestTimeout
+1/1 Test #1: TestTimeout ......................\*\*\*Timeout +[0-9.]+ sec
++
+0% tests passed, 1 tests failed out of 1
diff --git a/Tests/RunCMake/CTestTimeout/CMakeLists.txt.in b/Tests/RunCMake/CTestTimeout/CMakeLists.txt.in
new file mode 100644
index 0000000..20faa94
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/CMakeLists.txt.in
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.16)
+project(CTestTest@CASE_NAME@ C)
+include(CTest)
+
+add_executable(TestTimeout TestTimeout.c)
+
+if(NOT TIMEOUT)
+  set(TIMEOUT 4)
+endif()
+target_compile_definitions(TestTimeout PRIVATE TIMEOUT=${TIMEOUT})
+
+add_test(NAME TestTimeout COMMAND TestTimeout)
+set_property(TEST TestTimeout PROPERTY TIMEOUT ${TIMEOUT})
+
+@CASE_CMAKELISTS_SUFFIX_CODE@
diff --git a/Tests/RunCMake/CTestTimeout/Fork-stdout.txt b/Tests/RunCMake/CTestTimeout/Fork-stdout.txt
new file mode 100644
index 0000000..284e4b1
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/Fork-stdout.txt
@@ -0,0 +1,6 @@
+Test project [^
+]*/Tests/RunCMake/CTestTimeout/Fork-build
+    Start 1: TestTimeout
+1/1 Test #1: TestTimeout ......................\*\*\*Timeout +[0-9.]+ sec
++
+0% tests passed, 1 tests failed out of 1
diff --git a/Tests/RunCMake/CTestTimeout/RunCMakeTest.cmake b/Tests/RunCMake/CTestTimeout/RunCMakeTest.cmake
new file mode 100644
index 0000000..7e96b6d
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/RunCMakeTest.cmake
@@ -0,0 +1,22 @@
+include(RunCTest)
+
+if(NOT TIMEOUT)
+  # Give the process time to load and start running.
+  set(TIMEOUT 4)
+endif()
+
+function(run_ctest_timeout CASE_NAME)
+  configure_file(${RunCMake_SOURCE_DIR}/TestTimeout.c
+                 ${RunCMake_BINARY_DIR}/${CASE_NAME}/TestTimeout.c COPYONLY)
+  run_ctest(${CASE_NAME})
+endfunction()
+
+run_ctest_timeout(Basic)
+
+if(UNIX)
+  string(CONCAT CASE_CMAKELISTS_SUFFIX_CODE [[
+    target_compile_definitions(TestTimeout PRIVATE FORK)
+]])
+  run_ctest_timeout(Fork)
+  unset(CASE_CMAKELISTS_SUFFIX_CODE)
+endif()
diff --git a/Tests/RunCMake/CTestTimeout/TestTimeout.c b/Tests/RunCMake/CTestTimeout/TestTimeout.c
new file mode 100644
index 0000000..5a008a7
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/TestTimeout.c
@@ -0,0 +1,24 @@
+#if defined(_WIN32)
+#  include <windows.h>
+#else
+#  include <unistd.h>
+#endif
+
+#include <stdio.h>
+
+int main(void)
+{
+#ifdef FORK
+  pid_t pid = fork();
+  if (pid != 0) {
+    return 0;
+  }
+#endif
+
+#if defined(_WIN32)
+  Sleep((TIMEOUT + 4) * 1000);
+#else
+  sleep((TIMEOUT + 4));
+#endif
+  return 0;
+}
diff --git a/Tests/RunCMake/CTestTimeout/test.cmake.in b/Tests/RunCMake/CTestTimeout/test.cmake.in
new file mode 100644
index 0000000..be2625b
--- /dev/null
+++ b/Tests/RunCMake/CTestTimeout/test.cmake.in
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 3.16)
+@CASE_TEST_PREFIX_CODE@
+
+set(CTEST_SITE                          "test-site")
+set(CTEST_BUILD_NAME                    "test-build-name")
+set(CTEST_SOURCE_DIRECTORY              "@RunCMake_BINARY_DIR@/@CASE_NAME@")
+set(CTEST_BINARY_DIRECTORY              "@RunCMake_BINARY_DIR@/@CASE_NAME@-build")
+set(CTEST_CMAKE_GENERATOR               "@RunCMake_GENERATOR@")
+set(CTEST_CMAKE_GENERATOR_PLATFORM      "@RunCMake_GENERATOR_PLATFORM@")
+set(CTEST_CMAKE_GENERATOR_TOOLSET       "@RunCMake_GENERATOR_TOOLSET@")
+set(CTEST_BUILD_CONFIGURATION           "$ENV{CMAKE_CONFIG_TYPE}")
+
+ctest_start(Experimental)
+ctest_configure(OPTIONS "-DTIMEOUT=@TIMEOUT@")
+ctest_build()
+ctest_test()
diff --git a/Tests/RunCMake/CommandLine/trace-json-v1-check.py b/Tests/RunCMake/CommandLine/trace-json-v1-check.py
index 14febaf..e617b76 100755
--- a/Tests/RunCMake/CommandLine/trace-json-v1-check.py
+++ b/Tests/RunCMake/CommandLine/trace-json-v1-check.py
@@ -46,6 +46,7 @@
     {
         'args': msg_args,
         'cmd': 'message',
+        'frame': 3 if expand else 2
     },
 ]
 
@@ -59,14 +60,17 @@
 
     for i in fp.readlines():
         line = json.loads(i)
-        assert sorted(line.keys()) == ['args', 'cmd', 'file', 'line']
+        assert sorted(line.keys()) == ['args', 'cmd', 'file', 'frame', 'line', 'time']
         assert isinstance(line['args'], list)
         assert isinstance(line['cmd'], unicode)
         assert isinstance(line['file'], unicode)
+        assert isinstance(line['frame'], int)
         assert isinstance(line['line'], int)
+        assert isinstance(line['time'], float)
 
         for j in required_traces:
-            if j['cmd'] == line['cmd'] and j['args'] == line['args']:
-                j['found'] = True
+            # Compare the subset of required keys with line
+            if {k: line[k] for k in j} == j:
+                required_traces.remove(j)
 
-assert all([x.get('found', False) == True for x in required_traces])
+assert not required_traces
diff --git a/Tests/RunCMake/FPHSA/FindNameMismatch.cmake b/Tests/RunCMake/FPHSA/FindNameMismatch.cmake
new file mode 100644
index 0000000..540aa67
--- /dev/null
+++ b/Tests/RunCMake/FPHSA/FindNameMismatch.cmake
@@ -0,0 +1,4 @@
+set("${CMAKE_FIND_PACKAGE_NAME}_MODULE" "${CMAKE_CURRENT_LIST_FILE}")
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(NAMEMISMATCH REQUIRED_VARS "${CMAKE_FIND_PACKAGE_NAME}_MODULE")
+set("${CMAKE_FIND_PACKAGE_NAME}_FOUND" 1)
diff --git a/Tests/RunCMake/FPHSA/FindNameMismatchOld.cmake b/Tests/RunCMake/FPHSA/FindNameMismatchOld.cmake
new file mode 100644
index 0000000..d155ea7
--- /dev/null
+++ b/Tests/RunCMake/FPHSA/FindNameMismatchOld.cmake
@@ -0,0 +1,4 @@
+set("${CMAKE_FIND_PACKAGE_NAME}_MODULE" "${CMAKE_CURRENT_LIST_FILE}")
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(NAMEMISMATCH "old signature" "${CMAKE_FIND_PACKAGE_NAME}_MODULE")
+set("${CMAKE_FIND_PACKAGE_NAME}_FOUND" 1)
diff --git a/Tests/RunCMake/FPHSA/FindNameMismatchSuppressed.cmake b/Tests/RunCMake/FPHSA/FindNameMismatchSuppressed.cmake
new file mode 100644
index 0000000..042a59a
--- /dev/null
+++ b/Tests/RunCMake/FPHSA/FindNameMismatchSuppressed.cmake
@@ -0,0 +1,6 @@
+set("${CMAKE_FIND_PACKAGE_NAME}_MODULE" "${CMAKE_CURRENT_LIST_FILE}")
+include(FindPackageHandleStandardArgs)
+set(FPHSA_NAME_MISMATCHED 1)
+find_package_handle_standard_args(NAMEMISMATCH "old signature" "${CMAKE_FIND_PACKAGE_NAME}_MODULE")
+unset(FPHSA_NAME_MISMATCHED)
+set("${CMAKE_FIND_PACKAGE_NAME}_FOUND" 1)
diff --git a/Tests/RunCMake/FPHSA/FindNameMismatchSuppressedArg.cmake b/Tests/RunCMake/FPHSA/FindNameMismatchSuppressedArg.cmake
new file mode 100644
index 0000000..6a0e964
--- /dev/null
+++ b/Tests/RunCMake/FPHSA/FindNameMismatchSuppressedArg.cmake
@@ -0,0 +1,4 @@
+set("${CMAKE_FIND_PACKAGE_NAME}_MODULE" "${CMAKE_CURRENT_LIST_FILE}")
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(NAMEMISMATCH NAME_MISMATCHED REQUIRED_VARS "${CMAKE_FIND_PACKAGE_NAME}_MODULE")
+set("${CMAKE_FIND_PACKAGE_NAME}_FOUND" 1)
diff --git a/Tests/RunCMake/FPHSA/FindNameMismatchSuppressedCompat.cmake b/Tests/RunCMake/FPHSA/FindNameMismatchSuppressedCompat.cmake
new file mode 100644
index 0000000..791cfee
--- /dev/null
+++ b/Tests/RunCMake/FPHSA/FindNameMismatchSuppressedCompat.cmake
@@ -0,0 +1,6 @@
+set("${CMAKE_FIND_PACKAGE_NAME}_MODULE" "${CMAKE_CURRENT_LIST_FILE}")
+include(FindPackageHandleStandardArgs)
+set(FPHSA_NAME_MISMATCHED 1)
+find_package_handle_standard_args(NAMEMISMATCH REQUIRED_VARS "${CMAKE_FIND_PACKAGE_NAME}_MODULE")
+unset(FPHSA_NAME_MISMATCHED)
+set("${CMAKE_FIND_PACKAGE_NAME}_FOUND" 1)
diff --git a/Tests/RunCMake/FPHSA/NameMismatch-stderr.txt b/Tests/RunCMake/FPHSA/NameMismatch-stderr.txt
new file mode 100644
index 0000000..722b50b
--- /dev/null
+++ b/Tests/RunCMake/FPHSA/NameMismatch-stderr.txt
@@ -0,0 +1,23 @@
+CMake Warning \(dev\) at .*/Modules/FindPackageHandleStandardArgs.cmake:[0-9]+ \(message\):
+  The package name passed to `find_package_handle_standard_args`
+  \(NAMEMISMATCH\) does not match the name of the calling package
+  \(NameMismatch\).  This can lead to problems in calling code that expects
+  `find_package` result variables \(e.g., `_FOUND`\) to follow a certain
+  pattern.
+Call Stack \(most recent call first\):
+  FindNameMismatch.cmake:3 \(find_package_handle_standard_args\)
+  NameMismatch.cmake:3 \(find_package\)
+  CMakeLists.txt:3 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\) at .*/Modules/FindPackageHandleStandardArgs.cmake:[0-9]+ \(message\):
+  The package name passed to `find_package_handle_standard_args`
+  \(NAMEMISMATCH\) does not match the name of the calling package
+  \(NameMismatchOld\).  This can lead to problems in calling code that expects
+  `find_package` result variables \(e.g., `_FOUND`\) to follow a certain
+  pattern.
+Call Stack \(most recent call first\):
+  FindNameMismatchOld.cmake:3 \(find_package_handle_standard_args\)
+  NameMismatch.cmake:4 \(find_package\)
+  CMakeLists.txt:3 \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/FPHSA/NameMismatch.cmake b/Tests/RunCMake/FPHSA/NameMismatch.cmake
new file mode 100644
index 0000000..9ca3cc6
--- /dev/null
+++ b/Tests/RunCMake/FPHSA/NameMismatch.cmake
@@ -0,0 +1,7 @@
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}")
+
+find_package(NameMismatch REQUIRED)
+find_package(NameMismatchOld REQUIRED)
+find_package(NameMismatchSuppressed REQUIRED)
+find_package(NameMismatchSuppressedCompat REQUIRED)
+find_package(NameMismatchSuppressedArg REQUIRED)
diff --git a/Tests/RunCMake/FPHSA/RunCMakeTest.cmake b/Tests/RunCMake/FPHSA/RunCMakeTest.cmake
index f3e6c3e..286915d 100644
--- a/Tests/RunCMake/FPHSA/RunCMakeTest.cmake
+++ b/Tests/RunCMake/FPHSA/RunCMakeTest.cmake
@@ -1,6 +1,7 @@
 include(RunCMake)
 
 run_cmake(BadFoundVar)
+run_cmake(NameMismatch)
 
 # The pseudo module will "find" a package with the given version. Check if the
 # version selection code in FPHSA works correctly.
diff --git a/Tests/RunCMake/NinjaMultiConfig/CudaSimple-all-clean-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CudaSimple-all-clean-build-check.cmake
new file mode 100644
index 0000000..45f684b
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CudaSimple-all-clean-build-check.cmake
@@ -0,0 +1,21 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simplecudaexe_Debug}
+    ${TARGET_OBJECT_FILES_simplecudashared_Debug}
+    ${TARGET_OBJECT_FILES_simplecudaobj_Debug}
+
+    ${TARGET_OBJECT_FILES_simplecudaexe_Release}
+    ${TARGET_OBJECT_FILES_simplecudashared_Release}
+    ${TARGET_OBJECT_FILES_simplecudaobj_Release}
+
+    ${TARGET_OBJECT_FILES_simplecudaexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplecudashared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplecudaobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simplecudaexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simplecudashared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simplecudaobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/CudaSimple-debug-target-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/CudaSimple-debug-target-build-check.cmake
new file mode 100644
index 0000000..b0fca18
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CudaSimple-debug-target-build-check.cmake
@@ -0,0 +1,27 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simplecudaexe_Debug}
+    ${TARGET_OBJECT_FILES_simplecudaexe_Debug}
+
+    ${TARGET_FILE_simplecudashared_Debug}
+    ${TARGET_LINKER_FILE_simplecudashared_Debug}
+    ${TARGET_OBJECT_FILES_simplecudashared_Debug}
+
+    ${TARGET_OBJECT_FILES_simplecudaobj_Debug}
+
+  EXCLUDE
+
+    ${TARGET_OBJECT_FILES_simplecudaexe_Release}
+    ${TARGET_OBJECT_FILES_simplecudashared_Release}
+    ${TARGET_OBJECT_FILES_simplecudaobj_Release}
+
+    ${TARGET_OBJECT_FILES_simplecudaexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplecudashared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplecudaobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simplecudaexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simplecudashared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simplecudaobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/CudaSimple.cmake b/Tests/RunCMake/NinjaMultiConfig/CudaSimple.cmake
new file mode 100644
index 0000000..2e9b1cb
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/CudaSimple.cmake
@@ -0,0 +1,21 @@
+enable_language(CUDA)
+file(TOUCH ${CMAKE_BINARY_DIR}/empty.cmake)
+
+add_library(simplecudaobj OBJECT simplelib.cu)
+set_target_properties(simplecudaobj
+                      PROPERTIES
+                      POSITION_INDEPENDENT_CODE ON)
+
+add_library(simplecudashared SHARED )
+target_link_libraries(simplecudashared PRIVATE simplecudaobj)
+set_target_properties(simplecudaobj simplecudashared
+                      PROPERTIES
+                      CUDA_SEPARABLE_COMPILATION ON)
+
+add_executable(simplecudaexe main.cu )
+target_link_libraries(simplecudaexe PRIVATE simplecudashared)
+
+include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake)
+generate_output_files(simplecudaexe simplecudashared simplecudaobj)
+
+file(APPEND "${CMAKE_BINARY_DIR}/target_files.cmake" "set(GENERATED_FILES [==[${CMAKE_BINARY_DIR}/empty.cmake]==])\n")
diff --git a/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
index 4b51ddb..9fd64b0 100644
--- a/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
+++ b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
@@ -76,8 +76,9 @@
 set(RunCMake_TEST_NO_CLEAN 1)
 
 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Simple-build)
-set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE=RelWithDebInfo")
+set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE=RelWithDebInfo;-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE=ON")
 run_cmake_configure(Simple)
+unset(RunCMake_TEST_OPTIONS)
 include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
 run_cmake_build(Simple debug-target Debug simpleexe)
 run_ninja(Simple debug-target build-Debug.ninja simplestatic)
@@ -102,9 +103,49 @@
 execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 1)
 file(TOUCH "${RunCMake_TEST_BINARY_DIR}/empty.cmake")
 run_ninja(Simple reconfigure-noconfig build.ninja simpleexe)
+run_ninja(Simple default-build-file-clean build.ninja clean)
+run_ninja(Simple default-build-file-clean-minsizerel build.ninja clean:MinSizeRel)
+run_ninja(Simple default-build-file-all build.ninja all)
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SimpleDefaultBuildAlias-build)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE=Release;-DCMAKE_NINJA_MULTI_DEFAULT_BUILD_ALIAS=all;-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE=ON")
+run_cmake_configure(SimpleDefaultBuildAlias)
+unset(RunCMake_TEST_OPTIONS)
+include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
+run_ninja(SimpleDefaultBuildAlias target build.ninja simpleexe)
+run_ninja(SimpleDefaultBuildAlias all build.ninja all)
+run_ninja(SimpleDefaultBuildAlias clean build.ninja clean)
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SimpleNoCross-build)
+run_cmake_configure(SimpleNoCross)
+include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
+run_cmake_build(SimpleNoCross debug-target Debug simpleexe)
+run_ninja(SimpleNoCross debug-target build-Debug.ninja simplestatic:Debug)
+run_ninja(SimpleNoCross relwithdebinfo-in-release-graph-target build-Release.ninja simplestatic:RelWithDebInfo)
+run_cmake_build(SimpleNoCross relwithdebinfo-in-release-graph-all Release all:RelWithDebInfo)
+run_cmake_build(SimpleNoCross relwithdebinfo-in-release-graph-clean Release clean:RelWithDebInfo)
+run_ninja(SimpleNoCross all-target build-Debug.ninja simplestatic:all)
+run_ninja(SimpleNoCross all-all build-Debug.ninja all:all)
+run_cmake_build(SimpleNoCross all-clean Debug clean:all)
+
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SimpleCrossConfigs-build)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE=ON;-DCMAKE_NINJA_MULTI_CROSS_CONFIGS=Debug\\;Release")
+run_cmake_configure(SimpleCrossConfigs)
+include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
+run_ninja(SimpleCrossConfigs release-in-release-graph build-Release.ninja simpleexe)
+run_cmake_build(SimpleCrossConfigs debug-in-release-graph Release simpleexe:Debug)
+run_cmake_build(SimpleCrossConfigs relwithdebinfo-in-release-graph Release simpleexe:RelWithDebInfo)
+run_ninja(SimpleCrossConfigs relwithdebinfo-in-relwithdebinfo-graph build-RelWithDebInfo.ninja simpleexe:RelWithDebInfo)
+run_ninja(SimpleCrossConfigs release-in-relwithdebinfo-graph build-RelWithDebInfo.ninja simplestatic:Release)
+run_cmake_build(SimpleCrossConfigs all-in-relwithdebinfo-graph RelWithDebInfo simplestatic:all)
+run_ninja(SimpleCrossConfigs clean-all-in-release-graph build-Release.ninja clean:all)
+run_cmake_build(SimpleCrossConfigs all-all-in-release-graph Release all:all)
+run_cmake_build(SimpleCrossConfigs all-relwithdebinfo-in-release-graph Release all:RelWithDebInfo)
 
 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CustomCommandGenerator-build)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE=ON")
 run_cmake_configure(CustomCommandGenerator)
+unset(RunCMake_TEST_OPTIONS)
 include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
 run_cmake_build(CustomCommandGenerator debug Debug generated)
 run_cmake_command(CustomCommandGenerator-debug-generated "${TARGET_FILE_generated_Debug}")
@@ -119,7 +160,9 @@
 run_cmake_command(CustomCommandGenerator-release-in-debug-graph-generated "${TARGET_FILE_generated_Release}")
 
 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CustomCommandsAndTargets-build)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE=ON")
 run_cmake_configure(CustomCommandsAndTargets)
+unset(RunCMake_TEST_OPTIONS)
 include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
 run_cmake_build(CustomCommandsAndTargets release-command Release SubdirCommand)
 #FIXME Get this working
@@ -133,9 +176,9 @@
 run_ninja(CustomCommandsAndTargets release-targetpostbuild build-Release.ninja SubdirTargetPostBuild)
 
 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/PostfixAndLocation-build)
-set(RunCMake_TEST_OPTIONS "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release")
+set(RunCMake_TEST_OPTIONS "-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release;-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE=ON")
 run_cmake_configure(PostfixAndLocation)
-set(RunCMake_TEST_OPTIONS)
+unset(RunCMake_TEST_OPTIONS)
 include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
 run_cmake_build(PostfixAndLocation release-in-release-graph Release mylib:Release)
 run_cmake_build(PostfixAndLocation debug-in-release-graph Release mylib:Debug)
@@ -148,14 +191,16 @@
 run_cmake_build(Clean release-clean Release clean)
 
 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/AdditionalCleanFiles-build)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE=ON")
 run_cmake_configure(AdditionalCleanFiles)
+unset(RunCMake_TEST_OPTIONS)
 run_cmake_build(AdditionalCleanFiles release-clean Release clean)
 run_ninja(AdditionalCleanFiles all-clean build-Debug.ninja clean:all)
 
 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Install-build)
-set(RunCMake_TEST_OPTIONS -DCMAKE_INSTALL_PREFIX=${RunCMake_TEST_BINARY_DIR}/install)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_PREFIX=${RunCMake_TEST_BINARY_DIR}/install;-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE=ON")
 run_cmake_configure(Install)
-set(RunCMake_TEST_OPTIONS)
+unset(RunCMake_TEST_OPTIONS)
 include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
 run_cmake_build(Install release-install Release install)
 run_ninja(Install debug-in-release-graph-install build-Release.ninja install:Debug)
@@ -165,9 +210,19 @@
 #run_cmake_configure(AutoMocExecutable)
 #run_cmake_build(AutoMocExecutable debug-in-release-graph Release exe)
 
+if(CMake_TEST_CUDA)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CudaSimple-build)
+  run_cmake_configure(CudaSimple)
+  include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
+  run_cmake_build(CudaSimple debug-target Debug simplecudaexe)
+  run_ninja(CudaSimple all-clean build-Debug.ninja clean:Debug)
+endif()
+
 if(CMake_TEST_Qt5)
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Qt5-build)
+  set(RunCMake_TEST_OPTIONS "-DCMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE=ON")
   run_cmake_configure(Qt5)
+  unset(RunCMake_TEST_OPTIONS)
   include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
   run_cmake_build(Qt5 debug-in-release-graph Release exe:Debug)
 endif()
diff --git a/Tests/RunCMake/NinjaMultiConfig/Simple-default-build-file-all-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple-default-build-file-all-ninja-check.cmake
new file mode 100644
index 0000000..4e6e654
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-default-build-file-all-ninja-check.cmake
@@ -0,0 +1,49 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simpleexe_Debug}
+    ${TARGET_OBJECT_FILES_simpleexe_Debug}
+
+    ${TARGET_FILE_simpleshared_Debug}
+    ${TARGET_LINKER_FILE_simpleshared_Debug}
+    ${TARGET_OBJECT_FILES_simpleshared_Debug}
+
+    ${TARGET_FILE_simplestatic_Debug}
+    ${TARGET_LINKER_FILE_simplestatic_Debug}
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Debug}
+
+    ${TARGET_FILE_simpleexe_Release}
+    ${TARGET_OBJECT_FILES_simpleexe_Release}
+
+    ${TARGET_FILE_simpleshared_Release}
+    ${TARGET_LINKER_FILE_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+
+    ${TARGET_FILE_simplestatic_Release}
+    ${TARGET_LINKER_FILE_simplestatic_Release}
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Release}
+
+    ${TARGET_FILE_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+
+    ${TARGET_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_LINKER_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+
+    ${TARGET_FILE_simplestatic_RelWithDebInfo}
+    ${TARGET_LINKER_FILE_simplestatic_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/Simple-default-build-file-clean-minsizerel-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple-default-build-file-clean-minsizerel-ninja-check.cmake
new file mode 100644
index 0000000..c09ae65
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-default-build-file-clean-minsizerel-ninja-check.cmake
@@ -0,0 +1,41 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simpleexe_Debug}
+    ${TARGET_OBJECT_FILES_simpleexe_Debug}
+
+    ${TARGET_FILE_simpleshared_Debug}
+    ${TARGET_LINKER_FILE_simpleshared_Debug}
+    ${TARGET_OBJECT_FILES_simpleshared_Debug}
+
+    ${TARGET_FILE_simplestatic_Debug}
+    ${TARGET_LINKER_FILE_simplestatic_Debug}
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Debug}
+
+    ${TARGET_FILE_simpleexe_Release}
+    ${TARGET_OBJECT_FILES_simpleexe_Release}
+
+    ${TARGET_FILE_simpleshared_Release}
+    ${TARGET_LINKER_FILE_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+
+    ${TARGET_FILE_simplestatic_Release}
+    ${TARGET_LINKER_FILE_simplestatic_Release}
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Release}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/Simple-default-build-file-clean-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/Simple-default-build-file-clean-ninja-check.cmake
new file mode 100644
index 0000000..43213dd
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/Simple-default-build-file-clean-ninja-check.cmake
@@ -0,0 +1,49 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simpleexe_Debug}
+    ${TARGET_OBJECT_FILES_simpleexe_Debug}
+
+    ${TARGET_FILE_simpleshared_Debug}
+    ${TARGET_LINKER_FILE_simpleshared_Debug}
+    ${TARGET_OBJECT_FILES_simpleshared_Debug}
+
+    ${TARGET_FILE_simplestatic_Debug}
+    ${TARGET_LINKER_FILE_simplestatic_Debug}
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Debug}
+
+    ${TARGET_FILE_simpleexe_Release}
+    ${TARGET_OBJECT_FILES_simpleexe_Release}
+
+    ${TARGET_FILE_simpleshared_Release}
+    ${TARGET_LINKER_FILE_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+
+    ${TARGET_FILE_simplestatic_Release}
+    ${TARGET_LINKER_FILE_simplestatic_Release}
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Release}
+
+    ${TARGET_FILE_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+
+    ${TARGET_FILE_simpleshared_MinSizeRel}
+    ${TARGET_LINKER_FILE_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+
+    ${TARGET_FILE_simplestatic_MinSizeRel}
+    ${TARGET_LINKER_FILE_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-all-in-release-graph-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-all-in-release-graph-build-check.cmake
new file mode 100644
index 0000000..fee5951
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-all-in-release-graph-build-check.cmake
@@ -0,0 +1,45 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simpleexe_Debug}
+    ${TARGET_OBJECT_FILES_simpleexe_Debug}
+
+    ${TARGET_FILE_simpleshared_Debug}
+    ${TARGET_LINKER_FILE_simpleshared_Debug}
+    ${TARGET_OBJECT_FILES_simpleshared_Debug}
+
+    ${TARGET_FILE_simplestatic_Debug}
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Debug}
+
+    ${TARGET_FILE_simpleexe_Release}
+    ${TARGET_OBJECT_FILES_simpleexe_Release}
+
+    ${TARGET_FILE_simpleshared_Release}
+    ${TARGET_LINKER_FILE_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+
+    ${TARGET_FILE_simplestatic_Release}
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Release}
+
+    ${TARGET_FILE_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+
+    ${TARGET_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_LINKER_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-in-relwithdebinfo-graph-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-in-relwithdebinfo-graph-build-check.cmake
new file mode 100644
index 0000000..fee5951
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-in-relwithdebinfo-graph-build-check.cmake
@@ -0,0 +1,45 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simpleexe_Debug}
+    ${TARGET_OBJECT_FILES_simpleexe_Debug}
+
+    ${TARGET_FILE_simpleshared_Debug}
+    ${TARGET_LINKER_FILE_simpleshared_Debug}
+    ${TARGET_OBJECT_FILES_simpleshared_Debug}
+
+    ${TARGET_FILE_simplestatic_Debug}
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Debug}
+
+    ${TARGET_FILE_simpleexe_Release}
+    ${TARGET_OBJECT_FILES_simpleexe_Release}
+
+    ${TARGET_FILE_simpleshared_Release}
+    ${TARGET_LINKER_FILE_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+
+    ${TARGET_FILE_simplestatic_Release}
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Release}
+
+    ${TARGET_FILE_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+
+    ${TARGET_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_LINKER_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-relwithdebinfo-in-release-graph-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-relwithdebinfo-in-release-graph-build-check.cmake
new file mode 100644
index 0000000..fee5951
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-relwithdebinfo-in-release-graph-build-check.cmake
@@ -0,0 +1,45 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simpleexe_Debug}
+    ${TARGET_OBJECT_FILES_simpleexe_Debug}
+
+    ${TARGET_FILE_simpleshared_Debug}
+    ${TARGET_LINKER_FILE_simpleshared_Debug}
+    ${TARGET_OBJECT_FILES_simpleshared_Debug}
+
+    ${TARGET_FILE_simplestatic_Debug}
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Debug}
+
+    ${TARGET_FILE_simpleexe_Release}
+    ${TARGET_OBJECT_FILES_simpleexe_Release}
+
+    ${TARGET_FILE_simpleshared_Release}
+    ${TARGET_LINKER_FILE_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+
+    ${TARGET_FILE_simplestatic_Release}
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Release}
+
+    ${TARGET_FILE_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+
+    ${TARGET_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_LINKER_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-relwithdebinfo-in-release-graph-build-result.txt b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-relwithdebinfo-in-release-graph-build-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-relwithdebinfo-in-release-graph-build-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-relwithdebinfo-in-release-graph-build-stderr.txt b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-relwithdebinfo-in-release-graph-build-stderr.txt
new file mode 100644
index 0000000..fa8b462
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-all-relwithdebinfo-in-release-graph-build-stderr.txt
@@ -0,0 +1 @@
+^ninja: error: unknown target 'all:RelWithDebInfo'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-clean-all-in-release-graph-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-clean-all-in-release-graph-ninja-check.cmake
new file mode 100644
index 0000000..6c94369
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-clean-all-in-release-graph-ninja-check.cmake
@@ -0,0 +1,31 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+
+    ${TARGET_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_LINKER_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simpleexe_Debug}
+    ${TARGET_OBJECT_FILES_simpleshared_Debug}
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+    ${TARGET_OBJECT_FILES_simpleobj_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleexe_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+    ${TARGET_OBJECT_FILES_simpleobj_Release}
+
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-debug-in-release-graph-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-debug-in-release-graph-build-check.cmake
new file mode 100644
index 0000000..b6c77ab
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-debug-in-release-graph-build-check.cmake
@@ -0,0 +1,37 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simpleexe_Debug}
+    ${TARGET_OBJECT_FILES_simpleexe_Debug}
+
+    ${TARGET_FILE_simpleshared_Debug}
+    ${TARGET_LINKER_FILE_simpleshared_Debug}
+    ${TARGET_OBJECT_FILES_simpleshared_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Debug}
+
+    ${TARGET_FILE_simpleexe_Release}
+    ${TARGET_OBJECT_FILES_simpleexe_Release}
+
+    ${TARGET_FILE_simpleshared_Release}
+    ${TARGET_LINKER_FILE_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Release}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-release-in-release-graph-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-release-in-release-graph-ninja-check.cmake
new file mode 100644
index 0000000..d8b5218
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-release-in-release-graph-ninja-check.cmake
@@ -0,0 +1,31 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simpleexe_Release}
+    ${TARGET_OBJECT_FILES_simpleexe_Release}
+
+    ${TARGET_FILE_simpleshared_Release}
+    ${TARGET_LINKER_FILE_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Release}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simpleexe_Debug}
+    ${TARGET_OBJECT_FILES_simpleshared_Debug}
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+    ${TARGET_OBJECT_FILES_simpleobj_Debug}
+
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-release-in-relwithdebinfo-graph-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-release-in-relwithdebinfo-graph-ninja-check.cmake
new file mode 100644
index 0000000..1a37aa3
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-release-in-relwithdebinfo-graph-ninja-check.cmake
@@ -0,0 +1,44 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simpleexe_Debug}
+    ${TARGET_OBJECT_FILES_simpleexe_Debug}
+
+    ${TARGET_FILE_simpleshared_Debug}
+    ${TARGET_LINKER_FILE_simpleshared_Debug}
+    ${TARGET_OBJECT_FILES_simpleshared_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Debug}
+
+    ${TARGET_FILE_simpleexe_Release}
+    ${TARGET_OBJECT_FILES_simpleexe_Release}
+
+    ${TARGET_FILE_simpleshared_Release}
+    ${TARGET_LINKER_FILE_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+
+    ${TARGET_FILE_simplestatic_Release}
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Release}
+
+    ${TARGET_FILE_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+
+    ${TARGET_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_LINKER_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-relwithdebinfo-in-release-graph-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-relwithdebinfo-in-release-graph-build-check.cmake
new file mode 100644
index 0000000..b6c77ab
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-relwithdebinfo-in-release-graph-build-check.cmake
@@ -0,0 +1,37 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simpleexe_Debug}
+    ${TARGET_OBJECT_FILES_simpleexe_Debug}
+
+    ${TARGET_FILE_simpleshared_Debug}
+    ${TARGET_LINKER_FILE_simpleshared_Debug}
+    ${TARGET_OBJECT_FILES_simpleshared_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Debug}
+
+    ${TARGET_FILE_simpleexe_Release}
+    ${TARGET_OBJECT_FILES_simpleexe_Release}
+
+    ${TARGET_FILE_simpleshared_Release}
+    ${TARGET_LINKER_FILE_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Release}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-relwithdebinfo-in-release-graph-build-result.txt b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-relwithdebinfo-in-release-graph-build-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-relwithdebinfo-in-release-graph-build-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-relwithdebinfo-in-release-graph-build-stderr.txt b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-relwithdebinfo-in-release-graph-build-stderr.txt
new file mode 100644
index 0000000..f3a825c
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-relwithdebinfo-in-release-graph-build-stderr.txt
@@ -0,0 +1 @@
+^ninja: error: unknown target 'simpleexe:RelWithDebInfo'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-relwithdebinfo-in-relwithdebinfo-graph-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-relwithdebinfo-in-relwithdebinfo-graph-ninja-check.cmake
new file mode 100644
index 0000000..7eddb2f
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs-relwithdebinfo-in-relwithdebinfo-graph-ninja-check.cmake
@@ -0,0 +1,43 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simpleexe_Debug}
+    ${TARGET_OBJECT_FILES_simpleexe_Debug}
+
+    ${TARGET_FILE_simpleshared_Debug}
+    ${TARGET_LINKER_FILE_simpleshared_Debug}
+    ${TARGET_OBJECT_FILES_simpleshared_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Debug}
+
+    ${TARGET_FILE_simpleexe_Release}
+    ${TARGET_OBJECT_FILES_simpleexe_Release}
+
+    ${TARGET_FILE_simpleshared_Release}
+    ${TARGET_LINKER_FILE_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Release}
+
+    ${TARGET_FILE_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+
+    ${TARGET_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_LINKER_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs.cmake
new file mode 100644
index 0000000..2a5b708
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleCrossConfigs.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_SOURCE_DIR}/Simple.cmake")
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAlias-all-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAlias-all-ninja-check.cmake
new file mode 100644
index 0000000..c171e3d
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAlias-all-ninja-check.cmake
@@ -0,0 +1,56 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simpleexe_Debug}
+    ${TARGET_OBJECT_FILES_simpleexe_Debug}
+
+    ${TARGET_FILE_simpleshared_Debug}
+    ${TARGET_LINKER_FILE_simpleshared_Debug}
+    ${TARGET_OBJECT_FILES_simpleshared_Debug}
+
+    ${TARGET_FILE_simplestatic_Debug}
+    ${TARGET_LINKER_FILE_simplestatic_Debug}
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Debug}
+
+    ${TARGET_FILE_simpleexe_Release}
+    ${TARGET_OBJECT_FILES_simpleexe_Release}
+
+    ${TARGET_FILE_simpleshared_Release}
+    ${TARGET_LINKER_FILE_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+
+    ${TARGET_FILE_simplestatic_Release}
+    ${TARGET_LINKER_FILE_simplestatic_Release}
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Release}
+
+    ${TARGET_FILE_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+
+    ${TARGET_FILE_simpleshared_MinSizeRel}
+    ${TARGET_LINKER_FILE_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+
+    ${TARGET_FILE_simplestatic_MinSizeRel}
+    ${TARGET_LINKER_FILE_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+
+    ${TARGET_FILE_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+
+    ${TARGET_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_LINKER_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+
+    ${TARGET_FILE_simplestatic_RelWithDebInfo}
+    ${TARGET_LINKER_FILE_simplestatic_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAlias-clean-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAlias-clean-ninja-check.cmake
new file mode 100644
index 0000000..0f919df
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAlias-clean-ninja-check.cmake
@@ -0,0 +1,25 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simpleexe_Debug}
+    ${TARGET_OBJECT_FILES_simpleshared_Debug}
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+    ${TARGET_OBJECT_FILES_simpleobj_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleexe_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+    ${TARGET_OBJECT_FILES_simpleobj_Release}
+
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAlias-target-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAlias-target-ninja-check.cmake
new file mode 100644
index 0000000..de4505c
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAlias-target-ninja-check.cmake
@@ -0,0 +1,49 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simpleexe_Debug}
+    ${TARGET_OBJECT_FILES_simpleexe_Debug}
+
+    ${TARGET_FILE_simpleshared_Debug}
+    ${TARGET_LINKER_FILE_simpleshared_Debug}
+    ${TARGET_OBJECT_FILES_simpleshared_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Debug}
+
+    ${TARGET_FILE_simpleexe_Release}
+    ${TARGET_OBJECT_FILES_simpleexe_Release}
+
+    ${TARGET_FILE_simpleshared_Release}
+    ${TARGET_LINKER_FILE_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Release}
+
+    ${TARGET_FILE_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+
+    ${TARGET_FILE_simpleshared_MinSizeRel}
+    ${TARGET_LINKER_FILE_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+
+    ${TARGET_FILE_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+
+    ${TARGET_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_LINKER_FILE_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAlias.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAlias.cmake
new file mode 100644
index 0000000..2a5b708
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleDefaultBuildAlias.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_SOURCE_DIR}/Simple.cmake")
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-all-ninja-result.txt b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-all-ninja-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-all-ninja-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-all-ninja-stderr.txt b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-all-ninja-stderr.txt
new file mode 100644
index 0000000..905a355
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-all-ninja-stderr.txt
@@ -0,0 +1 @@
+^ninja: error: unknown target 'all:all'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-clean-build-result.txt b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-clean-build-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-clean-build-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-clean-build-stderr.txt b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-clean-build-stderr.txt
new file mode 100644
index 0000000..43528de
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-clean-build-stderr.txt
@@ -0,0 +1 @@
+^ninja: error: unknown target 'clean:all'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-target-ninja-result.txt b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-target-ninja-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-target-ninja-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-target-ninja-stderr.txt b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-target-ninja-stderr.txt
new file mode 100644
index 0000000..6db4bcc
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-all-target-ninja-stderr.txt
@@ -0,0 +1 @@
+^ninja: error: unknown target 'simplestatic:all'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-debug-target-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-debug-target-build-check.cmake
new file mode 100644
index 0000000..6bb7773
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-debug-target-build-check.cmake
@@ -0,0 +1,31 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simpleexe_Debug}
+    ${TARGET_OBJECT_FILES_simpleexe_Debug}
+
+    ${TARGET_FILE_simpleshared_Debug}
+    ${TARGET_LINKER_FILE_simpleshared_Debug}
+    ${TARGET_OBJECT_FILES_simpleshared_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Debug}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleexe_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+    ${TARGET_OBJECT_FILES_simpleobj_Release}
+
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-debug-target-ninja-check.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-debug-target-ninja-check.cmake
new file mode 100644
index 0000000..c8a735a
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-debug-target-ninja-check.cmake
@@ -0,0 +1,32 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${GENERATED_FILES}
+
+    ${TARGET_FILE_simpleexe_Debug}
+    ${TARGET_OBJECT_FILES_simpleexe_Debug}
+
+    ${TARGET_FILE_simpleshared_Debug}
+    ${TARGET_LINKER_FILE_simpleshared_Debug}
+    ${TARGET_OBJECT_FILES_simpleshared_Debug}
+
+    ${TARGET_FILE_simplestatic_Debug}
+    ${TARGET_OBJECT_FILES_simplestatic_Debug}
+
+    ${TARGET_OBJECT_FILES_simpleobj_Debug}
+
+  EXCLUDE
+    ${TARGET_OBJECT_FILES_simpleexe_Release}
+    ${TARGET_OBJECT_FILES_simpleshared_Release}
+    ${TARGET_OBJECT_FILES_simplestatic_Release}
+    ${TARGET_OBJECT_FILES_simpleobj_Release}
+
+    ${TARGET_OBJECT_FILES_simpleexe_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleshared_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simplestatic_MinSizeRel}
+    ${TARGET_OBJECT_FILES_simpleobj_MinSizeRel}
+
+    ${TARGET_OBJECT_FILES_simpleexe_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleshared_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simplestatic_RelWithDebInfo}
+    ${TARGET_OBJECT_FILES_simpleobj_RelWithDebInfo}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-all-build-result.txt b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-all-build-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-all-build-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-all-build-stderr.txt b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-all-build-stderr.txt
new file mode 100644
index 0000000..fa8b462
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-all-build-stderr.txt
@@ -0,0 +1 @@
+^ninja: error: unknown target 'all:RelWithDebInfo'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-clean-build-result.txt b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-clean-build-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-clean-build-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-clean-build-stderr.txt b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-clean-build-stderr.txt
new file mode 100644
index 0000000..70eef2f
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-clean-build-stderr.txt
@@ -0,0 +1 @@
+^ninja: error: unknown target 'clean:RelWithDebInfo'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-target-ninja-result.txt b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-target-ninja-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-target-ninja-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-target-ninja-stderr.txt b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-target-ninja-stderr.txt
new file mode 100644
index 0000000..1a1fe9e
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross-relwithdebinfo-in-release-graph-target-ninja-stderr.txt
@@ -0,0 +1 @@
+^ninja: error: unknown target 'simplestatic:RelWithDebInfo'$
diff --git a/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross.cmake b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross.cmake
new file mode 100644
index 0000000..2a5b708
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/SimpleNoCross.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_SOURCE_DIR}/Simple.cmake")
diff --git a/Tests/RunCMake/NinjaMultiConfig/main.cu b/Tests/RunCMake/NinjaMultiConfig/main.cu
new file mode 100644
index 0000000..563b9b2
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/main.cu
@@ -0,0 +1,15 @@
+
+#include <cuda.h>
+
+#ifdef _WIN32
+#  define IMPORT __declspec(dllimport)
+#else
+#  define IMPORT
+#endif
+
+IMPORT int simplelib();
+
+int main(void)
+{
+  return simplelib();
+}
diff --git a/Tests/RunCMake/NinjaMultiConfig/simplelib.cu b/Tests/RunCMake/NinjaMultiConfig/simplelib.cu
new file mode 100644
index 0000000..7fc0812
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/simplelib.cu
@@ -0,0 +1,9 @@
+#include <cuda.h>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+  int simplelib()
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/PrecompileHeaders/DisabledPch-check.cmake b/Tests/RunCMake/PrecompileHeaders/DisabledPch-check.cmake
index 494bcf7..cc719be 100644
--- a/Tests/RunCMake/PrecompileHeaders/DisabledPch-check.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/DisabledPch-check.cmake
@@ -1,4 +1,7 @@
 set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foo.dir/cmake_pch.h")
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foo.dir/Debug/cmake_pch.h")
+endif()
 set(foobar_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.h")
 
 if (NOT EXISTS ${foo_pch_header})
diff --git a/Tests/RunCMake/PrecompileHeaders/PchDebugGenex-check.cmake b/Tests/RunCMake/PrecompileHeaders/PchDebugGenex-check.cmake
new file mode 100644
index 0000000..cb94ee5
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchDebugGenex-check.cmake
@@ -0,0 +1,17 @@
+if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  return()
+endif()
+
+set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foo.dir/Debug/cmake_pch.h")
+
+if (NOT EXISTS ${foo_pch_header})
+  set(RunCMake_TEST_FAILED "Generated foo pch header ${foo_pch_header} does not exist")
+  return()
+endif()
+
+file(STRINGS ${foo_pch_header} foo_pch_header_strings)
+
+if (NOT foo_pch_header_strings MATCHES ";#include \"[^\"]*PrecompileHeaders/include/foo.h\";#include <stdio.h>(;|$)")
+  set(RunCMake_TEST_FAILED "Generated foo pch header\n  ${foo_pch_header}\nhas bad content:\n  ${foo_pch_header_strings}")
+  return()
+endif()
diff --git a/Tests/RunCMake/PrecompileHeaders/PchDebugGenex.cmake b/Tests/RunCMake/PrecompileHeaders/PchDebugGenex.cmake
new file mode 100644
index 0000000..854689f
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchDebugGenex.cmake
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.15)
+project(PchDebugGenex C)
+
+add_library(foo foo.c)
+target_include_directories(foo PUBLIC include)
+target_precompile_headers(foo PUBLIC
+  "$<$<CONFIG:Debug>:${CMAKE_CURRENT_SOURCE_DIR}/include/foo.h>"
+  <stdio.h>
+)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchInterface-check.cmake b/Tests/RunCMake/PrecompileHeaders/PchInterface-check.cmake
index 4e62b81..28c6ba4 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchInterface-check.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchInterface-check.cmake
@@ -1,5 +1,9 @@
 set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foo.dir/cmake_pch.h")
 set(foobar_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.h")
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foo.dir/Debug/cmake_pch.h")
+  set(foobar_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/Debug/cmake_pch.h")
+endif()
 
 if (NOT EXISTS ${foo_pch_header})
   set(RunCMake_TEST_FAILED "Generated foo pch header ${foo_pch_header} does not exist")
diff --git a/Tests/RunCMake/PrecompileHeaders/PchMultilanguage-check.cmake b/Tests/RunCMake/PrecompileHeaders/PchMultilanguage-check.cmake
index cc01ecb..1696037 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchMultilanguage-check.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchMultilanguage-check.cmake
@@ -1,5 +1,9 @@
 set(foobar_pch_h_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.h")
 set(foobar_pch_hxx_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/cmake_pch.hxx")
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(foobar_pch_h_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/Debug/cmake_pch.h")
+  set(foobar_pch_hxx_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/foobar.dir/Debug/cmake_pch.hxx")
+endif()
 
 if (NOT EXISTS ${foobar_pch_h_header})
   set(RunCMake_TEST_FAILED "Generated foobar C pch header ${foobar_pch_h_header} does not exist")
diff --git a/Tests/RunCMake/PrecompileHeaders/PchPrologueEpilogue-check.cmake b/Tests/RunCMake/PrecompileHeaders/PchPrologueEpilogue-check.cmake
index 9018664..f1504a7 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchPrologueEpilogue-check.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchPrologueEpilogue-check.cmake
@@ -1,4 +1,7 @@
 set(main_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/main.dir/cmake_pch.hxx")
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(main_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/main.dir/Debug/cmake_pch.hxx")
+endif()
 
 file(STRINGS ${main_pch_header} main_pch_header_strings)
 string(REGEX MATCH "#pragma warning\\(push, 0\\).*#include.*pch.h.*#pragma warning\\(pop\\)" matched_code ${main_pch_header_strings})
diff --git a/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake b/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake
index 8d2f4f9..f587c7d 100644
--- a/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake
@@ -13,6 +13,7 @@
 endfunction()
 
 run_cmake(DisabledPch)
+run_cmake(PchDebugGenex)
 run_test(PchInterface)
 run_cmake(PchPrologueEpilogue)
 run_test(SkipPrecompileHeaders)
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_batchsize-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_batchsize-check.cmake
index 32bb8e7..72cc2b9 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_batchsize-check.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_batchsize-check.cmake
@@ -1,5 +1,5 @@
-set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
-set(unitybuild_c1 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_1.c")
+set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_c.c")
+set(unitybuild_c1 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_1_c.c")
 if(NOT EXISTS "${unitybuild_c0}")
   set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c0} does not exist.")
   return()
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c-check.cmake
index c980df0..024286d 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_c-check.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c-check.cmake
@@ -1,4 +1,4 @@
-set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
+set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_c.c")
 if(NOT EXISTS "${unitybuild_c}")
   set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c} does not exist.")
   return()
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx-check.cmake
index 32c2992..269d545 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx-check.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx-check.cmake
@@ -1,10 +1,10 @@
-set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
+set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_c.c")
 if(NOT EXISTS "${unitybuild_c}")
   set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c} does not exist.")
   return()
 endif()
 
-set(unitybuild_cxx "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.cxx")
+set(unitybuild_cxx "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_cxx.cxx")
 if(NOT EXISTS "${unitybuild_cxx}")
   set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_cxx} does not exist.")
   return()
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build-check.cmake
index cb71ea3..22d2fc6 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build-check.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_no_unity_build-check.cmake
@@ -1,4 +1,4 @@
-set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
+set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_c.c")
 if(EXISTS "${unitybuild_c}")
   set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c} should not exist.")
   return()
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include-check.cmake
index 8fcb18f..e0935c7 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include-check.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include-check.cmake
@@ -1,4 +1,4 @@
-set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
+set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_c.c")
 file(STRINGS ${unitybuild_c} unitybuild_c_strings)
 string(REGEX MATCH "#define NOMINMAX.*#include.*s1.c.*#undef NOMINMAX" matched_code ${unitybuild_c_strings})
 if(NOT matched_code)
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_cxx-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_cxx-check.cmake
index 89a037a..9ef4c21 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_cxx-check.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_cxx-check.cmake
@@ -1,4 +1,4 @@
-set(unitybuild_cxx "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.cxx")
+set(unitybuild_cxx "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_cxx.cxx")
 if(NOT EXISTS "${unitybuild_cxx}")
   set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_cxx} does not exist.")
   return()
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_default_batchsize-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_default_batchsize-check.cmake
index 7dfc007..9d39a70 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_default_batchsize-check.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_default_batchsize-check.cmake
@@ -1,4 +1,4 @@
-set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
+set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_c.c")
 file(STRINGS ${unitybuild_c0} unitybuild_c_strings REGEX "/s[0-9]+.c\"$" )
 list(LENGTH unitybuild_c_strings number_of_includes)
 if(NOT number_of_includes EQUAL 8)
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_order-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_order-check.cmake
index 533a89c..f26ec2e 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_order-check.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_order-check.cmake
@@ -1,4 +1,4 @@
-set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
+set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_c.c")
 file(STRINGS ${unitybuild_c} unitybuild_c_strings)
 string(REGEX MATCH ".*#include.*s3.c.*#include.*s1.c.*#include.*s2.c.*" matched_code ${unitybuild_c_strings})
 if(NOT matched_code)
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_skip-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_skip-check.cmake
index fdd45bc..e94ad72 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_skip-check.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_skip-check.cmake
@@ -1,4 +1,4 @@
-set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
+set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_c.c")
 file(STRINGS ${unitybuild_c} unitybuild_c_strings)
 
 string(REGEX MATCH "\\/s[1-6].c" matched_files_1_6 ${unitybuild_c_strings})
diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
index 5cbe333..8a04f78 100644
--- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
@@ -53,3 +53,6 @@
 else()
   run_cmake(UnityBuildNative)
 endif()
+
+run_cmake(VsDotnetTargetFramework)
+run_cmake(VsDotnetTargetFrameworkVersion)
diff --git a/Tests/RunCMake/VS10Project/UnityBuildNative-check.cmake b/Tests/RunCMake/VS10Project/UnityBuildNative-check.cmake
index 87f247d..693dcd9 100644
--- a/Tests/RunCMake/VS10Project/UnityBuildNative-check.cmake
+++ b/Tests/RunCMake/VS10Project/UnityBuildNative-check.cmake
@@ -1,4 +1,4 @@
-set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
+set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_c.c")
 if(NOT EXISTS "${unitybuild_c0}")
   set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c0} does not exist.")
   return()
@@ -32,7 +32,7 @@
 endif()
 
 string(REPLACE "\\" "/" unity_source_line "${unity_source_line}")
-string(FIND "${unity_source_line}" "CMakeFiles/tgt.dir/Unity/unity_0.c" unity_source_file_position)
+string(FIND "${unity_source_line}" "CMakeFiles/tgt.dir/Unity/unity_0_c.c" unity_source_file_position)
 if (unity_source_file_position EQUAL "-1")
   set(RunCMake_TEST_FAILED "Generated project should include the generated unity source file.")
   return()
diff --git a/Tests/RunCMake/VS10Project/UnityBuildPre2017-check.cmake b/Tests/RunCMake/VS10Project/UnityBuildPre2017-check.cmake
index 1c6bab8..17e7b46 100644
--- a/Tests/RunCMake/VS10Project/UnityBuildPre2017-check.cmake
+++ b/Tests/RunCMake/VS10Project/UnityBuildPre2017-check.cmake
@@ -1,4 +1,4 @@
-set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
+set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0_c.c")
 if(NOT EXISTS "${unitybuild_c0}")
   set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c0} does not exist.")
   return()
@@ -28,7 +28,7 @@
 endforeach()
 
 string(REPLACE "\\" "/" unity_source_line ${unity_source_line})
-string(FIND "${unity_source_line}" "CMakeFiles/tgt.dir/Unity/unity_0.c" unity_source_file_position)
+string(FIND "${unity_source_line}" "CMakeFiles/tgt.dir/Unity/unity_0_c.c" unity_source_file_position)
 if (unity_source_file_position EQUAL "-1")
   set(RunCMake_TEST_FAILED "Generated project should include the generated unity source file.")
   return()
diff --git a/Tests/RunCMake/VS10Project/VSDotnetTargetFrameworkVersion.cmake b/Tests/RunCMake/VS10Project/VSDotnetTargetFrameworkVersion.cmake
new file mode 100644
index 0000000..8e0e0b4
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VSDotnetTargetFrameworkVersion.cmake
@@ -0,0 +1,10 @@
+enable_language(CSharp)
+if(NOT CMAKE_CSharp_COMPILER)
+  return()
+endif()
+
+set(CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION "v4.6.1")
+add_library(foo SHARED foo.cs)
+
+set(CMAKE_DOTNET_TARGET_FRAMEWORK "netcoreapp3.1")
+add_library(bar SHARED foo.cs)
diff --git a/Tests/RunCMake/VS10Project/VsDotnetTargetFramework-check.cmake b/Tests/RunCMake/VS10Project/VsDotnetTargetFramework-check.cmake
new file mode 100644
index 0000000..e656639
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsDotnetTargetFramework-check.cmake
@@ -0,0 +1,40 @@
+set(files foo.csproj bar.csproj)
+
+set(inLib1 FALSE)
+set(targetFrameworkInLib1 FALSE)
+
+set(inLib2 FALSE)
+set(targetFrameworksInLib2 FALSE)
+
+foreach(file ${files})
+  set(csProjectFile ${RunCMake_TEST_BINARY_DIR}/${file})
+
+  if(NOT EXISTS "${csProjectFile}")
+    set(RunCMake_TEST_FAILED "Project file ${csProjectFile} does not exist.")
+    return()
+  endif()
+
+  file(STRINGS "${csProjectFile}" lines)
+
+  foreach(line IN LISTS lines)
+    if(NOT inLib1)
+      if(line MATCHES " *<TargetFramework>netcoreapp3.1</TargetFramework> *$")
+        set(targetFrameworkInLib1  TRUE)
+        set(inLib1  TRUE)
+      endif()
+    elseif(NOT inLib2)
+      if(line MATCHES " *<TargetFrameworks>netcoreapp3.1;net461</TargetFrameworks> *$")
+        set(targetFrameworksInLib2  TRUE)
+        set(inLib2 TRUE)
+      endif()
+    endif()
+  endforeach()
+endforeach()
+
+if(NOT targetFrameworkInLib1)
+  set(RunCMake_TEST_FAILED "TargetFramework not set correctly.")
+endif()
+
+if(NOT targetFrameworksInLib2)
+  set(RunCMake_TEST_FAILED "TargetFrameworks not set correctly.")
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsDotnetTargetFramework.cmake b/Tests/RunCMake/VS10Project/VsDotnetTargetFramework.cmake
new file mode 100644
index 0000000..f553679
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsDotnetTargetFramework.cmake
@@ -0,0 +1,11 @@
+enable_language(CSharp)
+if(NOT CMAKE_CSharp_COMPILER)
+    return()
+endif()
+
+set(CMAKE_DOTNET_TARGET_FRAMEWORK "netcoreapp3.1")
+set(CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION "net461")
+add_library(foo SHARED foo.cs)
+
+set(CMAKE_DOTNET_TARGET_FRAMEWORK "netcoreapp3.1;net461")
+add_library(bar SHARED foo.cs)
diff --git a/Tests/RunCMake/VS10Project/VsDotnetTargetFrameworkVersion-check.cmake b/Tests/RunCMake/VS10Project/VsDotnetTargetFrameworkVersion-check.cmake
new file mode 100644
index 0000000..d2c3c3b
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsDotnetTargetFrameworkVersion-check.cmake
@@ -0,0 +1,40 @@
+set(files foo.csproj bar.csproj)
+
+set(inLib1 FALSE)
+set(targetFrameworkInLib1 FALSE)
+
+set(inLib2 FALSE)
+set(targetFrameworksInLib2 FALSE)
+
+foreach(file ${files})
+  set(csProjectFile ${RunCMake_TEST_BINARY_DIR}/${file})
+
+  if(NOT EXISTS "${csProjectFile}")
+    set(RunCMake_TEST_FAILED "Project file ${csProjectFile} does not exist.")
+    return()
+  endif()
+
+  file(STRINGS "${csProjectFile}" lines)
+
+  foreach(line IN LISTS lines)
+    if(NOT inLib1)
+      if(line MATCHES " *<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> *$")
+        set(targetFrameworkInLib1  TRUE)
+        set(inLib1  TRUE)
+      endif()
+    elseif(NOT inLib2)
+      if(line MATCHES " *<TargetFramework>netcoreapp3.1</TargetFramework> *$")
+        set(targetFrameworksInLib2  TRUE)
+        set(inLib2 TRUE)
+      endif()
+    endif()
+  endforeach()
+endforeach()
+
+if(NOT targetFrameworkInLib1)
+  set(RunCMake_TEST_FAILED "TargetFrameworkVersion not set correctly.")
+endif()
+
+if(NOT targetFrameworksInLib2)
+  set(RunCMake_TEST_FAILED "TargetFramework not set correctly.")
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsPrecompileHeaders-check.cmake b/Tests/RunCMake/VS10Project/VsPrecompileHeaders-check.cmake
index 91cea0e..9c214f1 100644
--- a/Tests/RunCMake/VS10Project/VsPrecompileHeaders-check.cmake
+++ b/Tests/RunCMake/VS10Project/VsPrecompileHeaders-check.cmake
@@ -1,4 +1,4 @@
-set(pch_header "CMakeFiles/tgt.dir/cmake_pch.hxx")
+set(pch_header "CMakeFiles/tgt.dir/Debug/cmake_pch.hxx")
 set(pch_source [=[CMakeFiles\\tgt.dir\\cmake_pch.cxx]=])
 
 if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/${pch_header}")
diff --git a/Tests/RunCMake/XcodeProject/XcodePrecompileHeaders-check.cmake b/Tests/RunCMake/XcodeProject/XcodePrecompileHeaders-check.cmake
index aa3eafc..4e85db6 100644
--- a/Tests/RunCMake/XcodeProject/XcodePrecompileHeaders-check.cmake
+++ b/Tests/RunCMake/XcodeProject/XcodePrecompileHeaders-check.cmake
@@ -1,4 +1,4 @@
-set(pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/cmake_pch.hxx")
+set(pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Debug/cmake_pch.hxx")
 
 if(NOT EXISTS "${pch_header}")
   set(RunCMake_TEST_FAILED "Generated PCH header ${pch_header} does not exist.")
diff --git a/Tests/RunCMake/include_external_msproject/RunCMakeTest.cmake b/Tests/RunCMake/include_external_msproject/RunCMakeTest.cmake
index 47dac34..7ed0773 100644
--- a/Tests/RunCMake/include_external_msproject/RunCMakeTest.cmake
+++ b/Tests/RunCMake/include_external_msproject/RunCMakeTest.cmake
@@ -5,3 +5,7 @@
 run_cmake(CustomTypePlatform)
 run_cmake(CustomGuidTypePlatform)
 run_cmake(CustomConfig)
+
+if(RunCMake_GENERATOR MATCHES "Visual Studio ([^9]|9[0-9])")
+  run_cmake(SkipGetTargetFrameworkProperties)
+endif()
diff --git a/Tests/RunCMake/include_external_msproject/SkipGetTargetFrameworkProperties-check.cmake b/Tests/RunCMake/include_external_msproject/SkipGetTargetFrameworkProperties-check.cmake
new file mode 100644
index 0000000..375b231
--- /dev/null
+++ b/Tests/RunCMake/include_external_msproject/SkipGetTargetFrameworkProperties-check.cmake
@@ -0,0 +1,21 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/ALL_BUILD.vcxproj" all_build)
+
+macro(project_reference EXTERNAL_PROJECT)
+  string(REGEX MATCH
+    "<ProjectReference.Include=.${${EXTERNAL_PROJECT}}.>.*</SkipGetTargetFrameworkProperties>"
+    EndOfProjectReference
+    ${all_build}
+    )
+endmacro()
+
+set(external_project "external.project")
+project_reference(external_project)
+if(NOT ${EndOfProjectReference} MATCHES ".*</ProjectReference>")
+  set(RunCMake_TEST_FAILED "${test} is being set unexpectedly.")
+endif()
+
+set(external_project "external.csproj")
+project_reference(external_project)
+if(${EndOfProjectReference} MATCHES ".*</ProjectReference>")
+  set(RunCMake_TEST_FAILED "${test} is not set.")
+endif()
diff --git a/Tests/RunCMake/include_external_msproject/SkipGetTargetFrameworkProperties.cmake b/Tests/RunCMake/include_external_msproject/SkipGetTargetFrameworkProperties.cmake
new file mode 100644
index 0000000..f660bd0
--- /dev/null
+++ b/Tests/RunCMake/include_external_msproject/SkipGetTargetFrameworkProperties.cmake
@@ -0,0 +1,5 @@
+include_external_msproject(external1 external.project
+                           GUID aaa-bbb-ccc-000)
+
+include_external_msproject(external2 external.csproj
+                           GUID aaa-bbb-ccc-001)
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs2-stderr.txt b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs2-stderr.txt
index 94f0f46..50fa81f 100644
--- a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs2-stderr.txt
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs2-stderr.txt
@@ -13,6 +13,11 @@
 This warning is for project developers\.  Use -Wno-dev to suppress it\.
 
 CMake Error at file-GET_RUNTIME_DEPENDENCIES-badargs2\.cmake:[0-9]+ \(file\):
-  file Keyword missing value: BUNDLE_EXECUTABLE
+  file Keywords missing values:
+
+    RESOLVED_DEPENDENCIES_VAR
+    UNRESOLVED_DEPENDENCIES_VAR
+    CONFLICTING_DEPENDENCIES_PREFIX
+    BUNDLE_EXECUTABLE
 Call Stack \(most recent call first\):
   CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs2.cmake b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs2.cmake
index 138ab95..ac6af85 100644
--- a/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs2.cmake
+++ b/Tests/RunCMake/install/file-GET_RUNTIME_DEPENDENCIES-badargs2.cmake
@@ -1,2 +1,15 @@
-file(GET_RUNTIME_DEPENDENCIES BUNDLE_EXECUTABLE)
+file(GET_RUNTIME_DEPENDENCIES
+  RESOLVED_DEPENDENCIES_VAR
+  UNRESOLVED_DEPENDENCIES_VAR
+  CONFLICTING_DEPENDENCIES_PREFIX
+  BUNDLE_EXECUTABLE
+  EXECUTABLES
+  LIBRARIES
+  MODULES
+  DIRECTORIES
+  PRE_INCLUDE_REGEXES
+  PRE_EXCLUDE_REGEXES
+  POST_INCLUDE_REGEXES
+  POST_EXCLUDE_REGEXES
+  )
 message(FATAL_ERROR "This message should not be displayed")
diff --git a/Tests/RunCMake/target_compile_options/BEFORE_keyword.cmake b/Tests/RunCMake/target_compile_options/BEFORE_keyword.cmake
new file mode 100644
index 0000000..8016230
--- /dev/null
+++ b/Tests/RunCMake/target_compile_options/BEFORE_keyword.cmake
@@ -0,0 +1,8 @@
+
+add_executable (CMP0101_OLD CMP0101.c)
+target_compile_options (main PRIVATE -UBEFORE_KEYWORD)
+target_compile_options (main BEFORE PRIVATE -DBEFORE_KEYWORD)
+
+add_executable (CMP0101_NEW CMP0101.c)
+target_compile_options (main PRIVATE -UBEFORE_KEYWORD)
+target_compile_options (main BEFORE PRIVATE -DBEFORE_KEYWORD)
diff --git a/Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-NEW-result.txt b/Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-NEW-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-NEW-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-OLD-result.txt b/Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-OLD-result.txt
new file mode 100644
index 0000000..8d98f9d
--- /dev/null
+++ b/Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-OLD-result.txt
@@ -0,0 +1 @@
+.*
diff --git a/Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-OLD-stdout.txt b/Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-OLD-stdout.txt
new file mode 100644
index 0000000..850aa65
--- /dev/null
+++ b/Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword-OLD-stdout.txt
@@ -0,0 +1 @@
+BEFORE not honored
diff --git a/Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword.cmake b/Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword.cmake
new file mode 100644
index 0000000..577427f
--- /dev/null
+++ b/Tests/RunCMake/target_compile_options/CMP0101-BEFORE_keyword.cmake
@@ -0,0 +1,15 @@
+
+enable_language(C)
+
+cmake_policy (SET CMP0101 OLD)
+
+add_executable (CMP0101_OLD CMP0101.c)
+target_compile_options (CMP0101_OLD PRIVATE -UBEFORE_KEYWORD)
+target_compile_options (CMP0101_OLD BEFORE PRIVATE -DBEFORE_KEYWORD)
+
+
+cmake_policy (SET CMP0101 NEW)
+
+add_executable (CMP0101_NEW CMP0101.c)
+target_compile_options (CMP0101_NEW PRIVATE -UBEFORE_KEYWORD)
+target_compile_options (CMP0101_NEW BEFORE PRIVATE -DBEFORE_KEYWORD)
diff --git a/Tests/RunCMake/target_compile_options/CMP0101.c b/Tests/RunCMake/target_compile_options/CMP0101.c
new file mode 100644
index 0000000..250869a
--- /dev/null
+++ b/Tests/RunCMake/target_compile_options/CMP0101.c
@@ -0,0 +1,9 @@
+
+#if defined(BEFORE_KEYWORD)
+#  error "BEFORE not honored"
+#endif
+
+int main()
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/target_compile_options/RunCMakeTest.cmake b/Tests/RunCMake/target_compile_options/RunCMakeTest.cmake
index b67c598..9f51a9a 100644
--- a/Tests/RunCMake/target_compile_options/RunCMakeTest.cmake
+++ b/Tests/RunCMake/target_compile_options/RunCMakeTest.cmake
@@ -1,3 +1,21 @@
 include(RunCMake)
 
 run_cmake(empty_keyword_args)
+
+if (CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
+  macro(run_cmake_target test subtest target)
+    set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
+    set(RunCMake_TEST_OUTPUT_MERGE 1)
+    set(RunCMake_TEST_NO_CLEAN 1)
+    run_cmake_command(${test}-${subtest} ${CMAKE_COMMAND} --build . --target ${target} ${ARGN})
+
+    unset(RunCMake_TEST_BINARY_DIR)
+    unset(RunCMake_TEST_OUTPUT_MERGE)
+    unset(RunCMake_TEST_NO_CLEAN)
+  endmacro()
+
+  run_cmake(CMP0101-BEFORE_keyword)
+
+  run_cmake_target(CMP0101-BEFORE_keyword OLD CMP0101_OLD)
+  run_cmake_target(CMP0101-BEFORE_keyword NEW CMP0101_NEW)
+endif()
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW-stdout.txt b/Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW-stdout.txt
index 89cd806..1c5cf45 100644
--- a/Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW-stdout.txt
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW-stdout.txt
@@ -1 +1 @@
--- INTERFACE_LINK_LIBRARIES='foo::@<[Xx0-9A-Fa-f]+>'
+-- INTERFACE_LINK_LIBRARIES='::@\([Xx0-9A-Fa-f]+\);\$<\$<CONFIG:DEBUG>:\$<1:foo;foo>>;\$<\$<NOT:\$<CONFIG:DEBUG>>:\$<1:foo;foo>>;::@'
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD-stdout.txt b/Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD-stdout.txt
index e575e16..4eb06d9 100644
--- a/Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD-stdout.txt
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD-stdout.txt
@@ -1 +1 @@
--- INTERFACE_LINK_LIBRARIES='foo'
+-- INTERFACE_LINK_LIBRARIES='\$<\$<CONFIG:DEBUG>:\$<1:foo;foo>>;\$<\$<NOT:\$<CONFIG:DEBUG>>:\$<1:foo;foo>>'
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stderr.txt b/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stderr.txt
index 6dd7d30..4c09a1f 100644
--- a/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stderr.txt
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stderr.txt
@@ -10,7 +10,25 @@
   is not created in this directory.  For compatibility with older versions of
   CMake, link library
 
-    foo
+    \$<1:foo;foo>
+
+  will be looked up in the directory in which the target was created rather
+  than in this calling directory.
+This warning is for project developers.  Use -Wno-dev to suppress it.
++
+CMake Warning \(dev\) at CMP0079-iface/CMakeLists.txt:[0-9]+ \(target_link_libraries\):
+  Policy CMP0079 is not set: target_link_libraries allows use with targets in
+  other directories.  Run "cmake --help-policy CMP0079" for policy details.
+  Use the cmake_policy command to set the policy and suppress this warning.
+
+  Target
+
+    top
+
+  is not created in this directory.  For compatibility with older versions of
+  CMake, link library
+
+    \$<1:foo;foo>
 
   will be looked up in the directory in which the target was created rather
   than in this calling directory.
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stdout.txt b/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stdout.txt
index e575e16..4eb06d9 100644
--- a/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stdout.txt
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stdout.txt
@@ -1 +1 @@
--- INTERFACE_LINK_LIBRARIES='foo'
+-- INTERFACE_LINK_LIBRARIES='\$<\$<CONFIG:DEBUG>:\$<1:foo;foo>>;\$<\$<NOT:\$<CONFIG:DEBUG>>:\$<1:foo;foo>>'
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface/CMakeLists.txt b/Tests/RunCMake/target_link_libraries/CMP0079-iface/CMakeLists.txt
index 4b15b32..e410607 100644
--- a/Tests/RunCMake/target_link_libraries/CMP0079-iface/CMakeLists.txt
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface/CMakeLists.txt
@@ -1 +1 @@
-target_link_libraries(top INTERFACE foo)
+target_link_libraries(top INTERFACE debug "$<1:foo;foo>" optimized "$<1:foo;foo>")
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-stderr.txt b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-stderr.txt
index 8ef35c1..9e38bec 100644
--- a/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-stderr.txt
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-stderr.txt
@@ -1,5 +1,5 @@
 ^CMake Error at CMP0079-link-NEW-bogus.cmake:[0-9]+ \(add_executable\):
-  Target "top" links to target "foo::@<0xdeadbeef>" but the target was not
+  Target "top" links to target "::@\(0xdeadbeef\)" but the target was not
   found.  Perhaps a find_package\(\) call is missing for an IMPORTED target, or
   an ALIAS target is missing\?
 Call Stack \(most recent call first\):
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus.cmake b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus.cmake
index 8622f14..8932521 100644
--- a/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus.cmake
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus.cmake
@@ -3,4 +3,4 @@
 enable_language(C)
 
 add_executable(top empty.c)
-set_property(TARGET top APPEND PROPERTY LINK_LIBRARIES "foo::@<0xdeadbeef>")
+set_property(TARGET top APPEND PROPERTY LINK_LIBRARIES "::@(0xdeadbeef);foo;::@")
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-stdout.txt b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-stdout.txt
index 84b30bd..fa5d4a3 100644
--- a/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-stdout.txt
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-stdout.txt
@@ -1 +1 @@
--- LINK_LIBRARIES='foo::@<[Xx0-9A-Fa-f]+>'
+-- LINK_LIBRARIES='::@\([Xx0-9A-Fa-f]+\);foo;::@'
diff --git a/Utilities/Sphinx/cmake.py b/Utilities/Sphinx/cmake.py
index d903dbe..f164fd0 100644
--- a/Utilities/Sphinx/cmake.py
+++ b/Utilities/Sphinx/cmake.py
@@ -191,6 +191,7 @@
     'cpack_gen':  _cmake_index_entry('cpack generator'),
     'envvar':     _cmake_index_entry('envvar'),
     'generator':  _cmake_index_entry('generator'),
+    'guide':      _cmake_index_entry('guide'),
     'manual':     _cmake_index_entry('manual'),
     'module':     _cmake_index_entry('module'),
     'policy':     _cmake_index_entry('policy'),
@@ -251,7 +252,7 @@
         env = self.document.settings.env
 
         # Treat some documents as cmake domain objects.
-        objtype, sep, tail = env.docname.rpartition('/')
+        objtype, sep, tail = env.docname.partition('/')
         make_index_entry = _cmake_index_objs.get(objtype)
         if make_index_entry:
             title = self.parse_title(env.docname)
@@ -373,6 +374,7 @@
         'cpack_gen':  ObjType('cpack_gen',  'cpack_gen'),
         'envvar':     ObjType('envvar',     'envvar'),
         'generator':  ObjType('generator',  'generator'),
+        'guide':      ObjType('guide',      'guide'),
         'variable':   ObjType('variable',   'variable'),
         'module':     ObjType('module',     'module'),
         'policy':     ObjType('policy',     'policy'),
@@ -407,6 +409,7 @@
         'cpack_gen':  CMakeXRefRole(),
         'envvar':     CMakeXRefRole(),
         'generator':  CMakeXRefRole(),
+        'guide':      CMakeXRefRole(),
         'variable':   CMakeXRefRole(),
         'module':     CMakeXRefRole(),
         'policy':     CMakeXRefRole(),
diff --git a/Utilities/Sphinx/create_identifiers.py b/Utilities/Sphinx/create_identifiers.py
index 6716b48..b5cd914 100755
--- a/Utilities/Sphinx/create_identifiers.py
+++ b/Utilities/Sphinx/create_identifiers.py
@@ -25,6 +25,7 @@
              ("envvar", "envvar"),
              ("variable", "variable"),
              ("generator", "generator"),
+             ("guide", "guide"),
              ("target property", "prop_tgt"),
              ("test property", "prop_test"),
              ("source file property", "prop_sf"),
diff --git a/Utilities/cmlibarchive/CMakeLists.txt b/Utilities/cmlibarchive/CMakeLists.txt
index 60c8316..26a9aa9 100644
--- a/Utilities/cmlibarchive/CMakeLists.txt
+++ b/Utilities/cmlibarchive/CMakeLists.txt
@@ -281,7 +281,6 @@
   ENDIF(USE_BZIP2_DLL)
 ENDIF(BZIP2_FOUND)
 MARK_AS_ADVANCED(CLEAR BZIP2_INCLUDE_DIR)
-MARK_AS_ADVANCED(CLEAR BZIP2_LIBRARIES)
 
 
 #
diff --git a/Utilities/std/.gitattributes b/Utilities/std/.gitattributes
index 789a754..ad5459d 100644
--- a/Utilities/std/.gitattributes
+++ b/Utilities/std/.gitattributes
@@ -1,2 +1,2 @@
-cm/* our-c-style
-cmext/* our-c-style
+cm/** our-c-style
+cmext/** our-c-style
diff --git a/Utilities/std/cm/bits/erase_if.hxx b/Utilities/std/cm/bits/erase_if.hxx
new file mode 100644
index 0000000..8952fb5
--- /dev/null
+++ b/Utilities/std/cm/bits/erase_if.hxx
@@ -0,0 +1,29 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#ifndef cm_bits_erase_if_hxx
+#define cm_bits_erase_if_hxx
+
+namespace cm {
+namespace internals {
+
+template <typename Container, typename Predicate>
+void erase_if(Container& cont, Predicate pred)
+{
+  for (typename Container::iterator iter = cont.begin(), last = cont.end();
+       iter != last;) {
+    if (pred(*iter)) {
+      iter = cont.erase(iter);
+    } else {
+      ++iter;
+    }
+  }
+}
+
+} // namespace internals
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/deque b/Utilities/std/cm/deque
new file mode 100644
index 0000000..4bb6725
--- /dev/null
+++ b/Utilities/std/cm/deque
@@ -0,0 +1,40 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cm_deque
+#define cm_deque
+
+#include <algorithm>
+#include <deque> // IWYU pragma: export
+
+namespace cm {
+
+// should be updated when C++20 is finalized
+#if (__cplusplus > 201703L ||                                                 \
+     (defined(_MSVC_LANG) && _MSVC_LANG > 201703)) &&                         \
+  defined(__cpp_lib_erase_if)
+
+using std::erase;
+using std::erase_if;
+
+#else
+
+template <typename T, typename Allocator, typename V>
+inline void erase(std::deque<T, Allocator>& cont, const V& value)
+{
+  cont.erase(std::remove(cont.begin(), cont.end(), value), cont.end());
+}
+
+template <typename T, typename Allocator, typename Predicate>
+inline void erase_if(std::deque<T, Allocator>& cont, Predicate pred)
+{
+  cont.erase(std::remove_if(cont.begin(), cont.end(), pred), cont.end());
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/list b/Utilities/std/cm/list
new file mode 100644
index 0000000..ba5d94a
--- /dev/null
+++ b/Utilities/std/cm/list
@@ -0,0 +1,39 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cm_list
+#define cm_list
+
+#include <list> // IWYU pragma: export
+
+namespace cm {
+
+// should be updated when C++20 is finalized
+#if (__cplusplus > 201703L ||                                                 \
+     (defined(_MSVC_LANG) && _MSVC_LANG > 201703)) &&                         \
+  defined(__cpp_lib_erase_if)
+
+using std::erase;
+using std::erase_if;
+
+#else
+
+template <typename T, typename Allocator, typename V>
+inline void erase(std::list<T, Allocator>& cont, const V& value)
+{
+  cont.remove_if([&](auto& elem) { return elem == value; });
+}
+
+template <typename T, typename Allocator, typename Predicate>
+inline void erase_if(std::list<T, Allocator>& cont, Predicate pred)
+{
+  cont.remove_if(pred);
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/map b/Utilities/std/cm/map
new file mode 100644
index 0000000..e348dec
--- /dev/null
+++ b/Utilities/std/cm/map
@@ -0,0 +1,44 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cm_map
+#define cm_map
+
+#include <map> // IWYU pragma: export
+
+#include <cm/bits/erase_if.hxx>
+
+namespace cm {
+
+// should be updated when C++20 is finalized
+#if (__cplusplus > 201703L ||                                                 \
+     (defined(_MSVC_LANG) && _MSVC_LANG > 201703)) &&                         \
+  defined(__cpp_lib_erase_if)
+
+using std::erase_if;
+
+#else
+
+template <typename Key, typename T, typename Compare, typename Allocator,
+          typename Predicate>
+inline void erase_if(std::map<Key, T, Compare, Allocator>& cont,
+                     Predicate pred)
+{
+  internals::erase_if(cont, pred);
+}
+
+template <typename Key, typename T, typename Compare, typename Allocator,
+          typename Predicate>
+inline void erase_if(std::multimap<Key, T, Compare, Allocator>& cont,
+                     Predicate pred)
+{
+  internals::erase_if(cont, pred);
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/set b/Utilities/std/cm/set
new file mode 100644
index 0000000..56dd474
--- /dev/null
+++ b/Utilities/std/cm/set
@@ -0,0 +1,43 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cm_set
+#define cm_set
+
+#include <set> // IWYU pragma: export
+
+#include <cm/bits/erase_if.hxx>
+
+namespace cm {
+
+// should be updated when C++20 is finalized
+#if (__cplusplus > 201703L ||                                                 \
+     (defined(_MSVC_LANG) && _MSVC_LANG > 201703)) &&                         \
+  defined(__cpp_lib_erase_if)
+
+using std::erase_if;
+
+#else
+
+template <typename Key, typename Compare, typename Allocator,
+          typename Predicate>
+inline void erase_if(std::set<Key, Compare, Allocator>& cont, Predicate pred)
+{
+  internals::erase_if(cont, pred);
+}
+
+template <typename Key, typename Compare, typename Allocator,
+          typename Predicate>
+inline void erase_if(std::multiset<Key, Compare, Allocator>& cont,
+                     Predicate pred)
+{
+  internals::erase_if(cont, pred);
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/string b/Utilities/std/cm/string
new file mode 100644
index 0000000..cc4c796
--- /dev/null
+++ b/Utilities/std/cm/string
@@ -0,0 +1,42 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cm_string
+#define cm_string
+
+#include <algorithm>
+#include <string> // IWYU pragma: export
+
+namespace cm {
+
+// should be updated when C++20 is finalized
+#if (__cplusplus > 201703L ||                                                 \
+     (defined(_MSVC_LANG) && _MSVC_LANG > 201703)) &&                         \
+  defined(__cpp_lib_erase_if)
+
+using std::erase;
+using std::erase_if;
+
+#else
+
+template <typename T, typename Traits, typename Allocator, typename V>
+inline void erase(std::basic_string<T, Traits, Allocator>& cont,
+                  const V& value)
+{
+  cont.erase(std::remove(cont.begin(), cont.end(), value), cont.end());
+}
+
+template <typename T, typename Traits, typename Allocator, typename Predicate>
+inline void erase_if(std::basic_string<T, Traits, Allocator>& cont,
+                     Predicate pred)
+{
+  cont.erase(std::remove_if(cont.begin(), cont.end(), pred), cont.end());
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/type_traits b/Utilities/std/cm/type_traits
index 4dfe17b..e32c2c6 100644
--- a/Utilities/std/cm/type_traits
+++ b/Utilities/std/cm/type_traits
@@ -33,6 +33,8 @@
 using std::invoke_result;
 using std::invoke_result_t;
 
+using std::void_t;
+
 #else
 
 // Helper classes
@@ -46,6 +48,14 @@
 template <class F, typename... ArgTypes>
 using invoke_result_t = typename invoke_result<F, ArgTypes...>::type;
 
+template <typename... ArgTypes>
+struct make_void
+{
+  typedef void type;
+};
+template <typename... ArgTypes>
+using void_t = typename make_void<ArgTypes...>::type;
+
 #endif
 
 } // namespace cm
diff --git a/Utilities/std/cm/unordered_map b/Utilities/std/cm/unordered_map
new file mode 100644
index 0000000..5b8a456
--- /dev/null
+++ b/Utilities/std/cm/unordered_map
@@ -0,0 +1,45 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cm_unordered_map
+#define cm_unordered_map
+
+#include <unordered_map> // IWYU pragma: export
+
+#include <cm/bits/erase_if.hxx>
+
+namespace cm {
+
+// should be updated when C++20 is finalized
+#if (__cplusplus > 201703L ||                                                 \
+     (defined(_MSVC_LANG) && _MSVC_LANG > 201703)) &&                         \
+  defined(__cpp_lib_erase_if)
+
+using std::erase_if;
+
+#else
+
+template <typename Key, typename T, typename Hash, typename KeyEqual,
+          typename Allocator, typename Predicate>
+inline void erase_if(
+  std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& cont, Predicate pred)
+{
+  internals::erase_if(cont, pred);
+}
+
+template <typename Key, typename T, typename Hash, typename KeyEqual,
+          typename Allocator, typename Predicate>
+inline void erase_if(
+  std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& cont,
+  Predicate pred)
+{
+  internals::erase_if(cont, pred);
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/unordered_set b/Utilities/std/cm/unordered_set
new file mode 100644
index 0000000..9debac4
--- /dev/null
+++ b/Utilities/std/cm/unordered_set
@@ -0,0 +1,45 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cm_unordered_set
+#define cm_unordered_set
+
+#include <unordered_set> // IWYU pragma: export
+
+#include <cm/bits/erase_if.hxx>
+
+namespace cm {
+
+// should be updated when C++20 is finalized
+#if (__cplusplus > 201703L ||                                                 \
+     (defined(_MSVC_LANG) && _MSVC_LANG > 201703)) &&                         \
+  defined(__cpp_lib_erase_if)
+
+using std::erase_if;
+
+#else
+
+template <typename Key, typename Hash, typename KeyEqual, typename Allocator,
+          typename Predicate>
+inline void erase_if(std::unordered_set<Key, Hash, KeyEqual, Allocator>& cont,
+                     Predicate pred)
+{
+  internals::erase_if(cont, pred);
+}
+
+template <typename Key, typename Hash, typename KeyEqual, typename Allocator,
+          typename Predicate>
+inline void erase_if(
+  std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& cont,
+  Predicate pred)
+{
+  internals::erase_if(cont, pred);
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/vector b/Utilities/std/cm/vector
new file mode 100644
index 0000000..2dbe704
--- /dev/null
+++ b/Utilities/std/cm/vector
@@ -0,0 +1,40 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cm_vector
+#define cm_vector
+
+#include <algorithm>
+#include <vector> // IWYU pragma: export
+
+namespace cm {
+
+// should be updated when C++20 is finalized
+#if (__cplusplus > 201703L ||                                                 \
+     (defined(_MSVC_LANG) && _MSVC_LANG > 201703)) &&                         \
+  defined(__cpp_lib_erase_if)
+
+using std::erase;
+using std::erase_if;
+
+#else
+
+template <typename T, typename Allocator, typename V>
+inline void erase(std::vector<T, Allocator>& cont, const V& value)
+{
+  cont.erase(std::remove(cont.begin(), cont.end(), value), cont.end());
+}
+
+template <typename T, typename Allocator, typename Predicate>
+inline void erase_if(std::vector<T, Allocator>& cont, Predicate pred)
+{
+  cont.erase(std::remove_if(cont.begin(), cont.end(), pred), cont.end());
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cmext/memory b/Utilities/std/cmext/memory
index 540a3de..50e79df 100644
--- a/Utilities/std/cmext/memory
+++ b/Utilities/std/cmext/memory
@@ -6,6 +6,8 @@
 #ifndef cmext_memory
 #define cmext_memory
 
+#include <typeinfo>
+
 #include <cm/type_traits>
 
 namespace cm {
@@ -24,7 +26,13 @@
             int> = 0>
 T& dynamic_reference_cast(O& item)
 {
-  return *(dynamic_cast<T*>(item.get()));
+  auto p = dynamic_cast<T*>(item.get());
+
+  if (p == nullptr) {
+    throw std::bad_cast();
+  }
+
+  return *p;
 }
 
 } // namespace cm
diff --git a/Utilities/std/cmext/type_traits b/Utilities/std/cmext/type_traits
new file mode 100644
index 0000000..da6550d
--- /dev/null
+++ b/Utilities/std/cmext/type_traits
@@ -0,0 +1,68 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmext_type_traits
+#define cmext_type_traits
+
+#include <cm/type_traits>
+
+namespace cm {
+
+// type traits for managed pointer types
+template <typename>
+struct is_unique_ptr : std::false_type
+{
+};
+template <typename T>
+struct is_unique_ptr<std::unique_ptr<T>> : std::true_type
+{
+};
+
+// type traits for containers
+template <typename, typename = void_t<>>
+struct is_container : std::false_type
+{
+};
+template <typename T>
+struct is_container<
+  T,
+  cm::void_t<typename T::value_type, typename T::size_type,
+             typename T::difference_type, typename T::iterator>>
+  : std::true_type
+{
+};
+
+template <typename, typename = void_t<>>
+struct is_associative_container : std::false_type
+{
+};
+template <typename T>
+struct is_associative_container<
+  T, cm::void_t<typename T::key_type, typename T::key_compare>>
+  : cm::is_container<T>
+{
+};
+
+template <typename, typename = void_t<>>
+struct is_unordered_associative_container : std::false_type
+{
+};
+template <typename T>
+struct is_unordered_associative_container<
+  T,
+  cm::void_t<typename T::key_type, typename T::hasher, typename T::key_equal,
+             typename T::local_iterator>> : cm::is_container<T>
+{
+};
+
+template <typename T>
+using is_sequence_container =
+  cm::bool_constant<cm::is_container<T>::value &&
+                    !cm::is_associative_container<T>::value &&
+                    !cm::is_unordered_associative_container<T>::value>;
+
+} // namespace cm
+
+#endif